diff options
author | Richard Earnshaw <erich@gnu.org> | 1996-02-19 17:50:20 +0000 |
---|---|---|
committer | Richard Earnshaw <erich@gnu.org> | 1996-02-19 17:50:20 +0000 |
commit | 5165176d89089f9c0a0a0d823acc99fb452b6d91 (patch) | |
tree | 0e18f6dc10a7de868f2c19941df60c18996fafe4 | |
parent | d944f453bba09441261a72397b9f7e97f7c7afdb (diff) | |
download | gcc-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
-rw-r--r-- | gcc/config/arm/arm.c | 127 |
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*/ |