aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Earnshaw <erich@gnu.org>1996-02-19 17:50:20 +0000
committerRichard Earnshaw <erich@gnu.org>1996-02-19 17:50:20 +0000
commit5165176d89089f9c0a0a0d823acc99fb452b6d91 (patch)
tree0e18f6dc10a7de868f2c19941df60c18996fafe4 /gcc
parentd944f453bba09441261a72397b9f7e97f7c7afdb (diff)
downloadgcc-5165176d89089f9c0a0a0d823acc99fb452b6d91.zip
gcc-5165176d89089f9c0a0a0d823acc99fb452b6d91.tar.gz
gcc-5165176d89089f9c0a0a0d823acc99fb452b6d91.tar.bz2
(offsettable_memory_operand): New function.
(alignable_memory_operand): New function. (gen_rotated_half_load): New function. (get_arm_condition_code): Extract the mode of the comparison and use it to generate the correct return value. From-SVN: r11304
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/arm/arm.c127
1 files changed, 116 insertions, 11 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 4816594..37bc901 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -1404,6 +1404,50 @@ arm_not_operand (op, mode)
|| const_ok_for_arm (~INTVAL (op)))));
}
+/* Return TRUE if the operand is a memory reference which contains an
+ offsettable address. */
+int
+offsettable_memory_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode == VOIDmode)
+ mode = GET_MODE (op);
+
+ return (mode == GET_MODE (op)
+ && GET_CODE (op) == MEM
+ && offsettable_address_p (reload_completed | reload_in_progress,
+ mode, XEXP (op, 0)));
+}
+
+/* Return TRUE if the operand is a memory reference which is, or can be
+ made word aligned by adjusting the offset. */
+int
+alignable_memory_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ rtx reg;
+
+ if (mode == VOIDmode)
+ mode = GET_MODE (op);
+
+ if (mode != GET_MODE (op) || GET_CODE (op) != MEM)
+ return 0;
+
+ op = XEXP (op, 0);
+
+ return ((GET_CODE (reg = op) == REG
+ || (GET_CODE (op) == SUBREG
+ && GET_CODE (reg = SUBREG_REG (op)) == REG)
+ || (GET_CODE (op) == PLUS
+ && GET_CODE (XEXP (op, 1)) == CONST_INT
+ && (GET_CODE (reg = XEXP (op, 0)) == REG
+ || (GET_CODE (XEXP (op, 0)) == SUBREG
+ && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
+ && REGNO_POINTER_ALIGN (REGNO (reg)) >= 4);
+}
+
/* Return TRUE for valid operands for the rhs of an FPU instruction. */
int
@@ -2110,6 +2154,35 @@ arm_gen_movstrqi (operands)
return 1;
}
+/* Generate a memory reference for a half word, such that it will be loaded
+ into the top 16 bits of the word. We can assume that the address is
+ known to be alignable and of the form reg, or plus (reg, const). */
+rtx
+gen_rotated_half_load (memref)
+ rtx memref;
+{
+ HOST_WIDE_INT offset = 0;
+ rtx base = XEXP (memref, 0);
+
+ if (GET_CODE (base) == PLUS)
+ {
+ offset = INTVAL (XEXP (base, 1));
+ base = XEXP (base, 0);
+ }
+
+ /* If we aren't allowed to generate unalligned addresses, then fail. */
+ if (TARGET_SHORT_BY_BYTES
+ && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0)))
+ return NULL;
+
+ base = gen_rtx (MEM, SImode, plus_constant (base, offset & ~2));
+
+ if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2))
+ return base;
+
+ return gen_rtx (ROTATE, SImode, base, GEN_INT (16));
+}
+
/* X and Y are two things to compare using CODE. Emit the compare insn and
return the rtx for register 0 in the proper mode. FP means this is a
floating point compare: I don't think that it is needed on the arm. */
@@ -4208,18 +4281,50 @@ int
get_arm_condition_code (comparison)
rtx comparison;
{
- switch (GET_CODE (comparison))
+ enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
+
+ if (GET_MODE_CLASS (mode) != MODE_CC)
+ mode = SELECT_CC_MODE (GET_CODE (comparison), XEXP (comparison, 0),
+ XEXP (comparison, 1));
+
+ switch (mode)
{
- case NE: return (1);
- case EQ: return (0);
- case GE: return (10);
- case GT: return (12);
- case LE: return (13);
- case LT: return (11);
- case GEU: return (2);
- case GTU: return (8);
- case LEU: return (9);
- case LTU: return (3);
+ case CC_NOOVmode:
+ switch (GET_CODE (comparison))
+ {
+ case NE: return 1;
+ case EQ: return 0;
+ case GE: return 5;
+ case LT: return 4;
+ default: abort ();
+ }
+
+ case CC_Zmode:
+ case CCFPmode:
+ switch (GET_CODE (comparison))
+ {
+ case NE: return 1;
+ case EQ: return 0;
+ default: abort ();
+ }
+
+ case CCFPEmode:
+ case CCmode:
+ switch (GET_CODE (comparison))
+ {
+ case NE: return 1;
+ case EQ: return 0;
+ case GE: return 10;
+ case GT: return 12;
+ case LE: return 13;
+ case LT: return 11;
+ case GEU: return 2;
+ case GTU: return 8;
+ case LEU: return 9;
+ case LTU: return 3;
+ default: abort ();
+ }
+
default: abort ();
}
/*NOTREACHED*/