diff options
| author | 2011-10-09 17:56:06 -0700 | |
|---|---|---|
| committer | 2011-10-09 18:19:46 -0700 | |
| commit | e70708051e06119c04be33ca49fb16bef8162059 (patch) | |
| tree | f1ebe2ed4af44c28216642f7b32d6c20d6100d91 /src/compiler/codegen | |
| parent | c10717a0b86d5719556ac3286fcb47aa2f2416fc (diff) | |
Compiler/assembler fix
There are three Thumb encodings for push and pop, and one of
them (Thumb2/t2) requires at least two registers in the push/pop
list. This CL adds the single-register encoding (which is really
just another name for a standard base-modifying load/store).
Change-Id: I963c472a0d5f288654417dbd85758d6b5cc61388
Diffstat (limited to 'src/compiler/codegen')
| -rw-r--r-- | src/compiler/codegen/arm/ArmLIR.h | 2 | ||||
| -rw-r--r-- | src/compiler/codegen/arm/Assemble.cc | 34 |
2 files changed, 36 insertions, 0 deletions
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h index daa13962c0..1e4022ee4b 100644 --- a/src/compiler/codegen/arm/ArmLIR.h +++ b/src/compiler/codegen/arm/ArmLIR.h @@ -693,6 +693,8 @@ typedef enum ArmOpcode { kThumb2SubsRRI12, /* setflags encoding */ kThumb2OrrRRRs, /* orrx [111010100101] rn[19..16] [0000] rd[11..8] [0000] rm[3..0] */ + kThumb2Push1, /* t3 encoding of push */ + kThumb2Pop1, /* t3 encoding of pop */ kArmLast, } ArmOpcode; diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc index bbd97b4d75..af71efe988 100644 --- a/src/compiler/codegen/arm/Assemble.cc +++ b/src/compiler/codegen/arm/Assemble.cc @@ -953,6 +953,16 @@ ArmEncodingMap EncodingMap[kArmLast] = { kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, "orrs", "!0C, !1C, !2C!3H", 2), + ENCODING_MAP(kThumb2Push1, 0xf84d0d04, + kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1, + kFmtUnused, -1, -1, + IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE0 + | IS_STORE, "push1", "!0C", 2), + ENCODING_MAP(kThumb2Pop1, 0xf85d0b04, + kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, kFmtUnused, -1, -1, + kFmtUnused, -1, -1, + IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF0 + | IS_LOAD, "pop1", "!0C", 2), }; @@ -1167,6 +1177,30 @@ STATIC AssemblerStatus assembleInstructions(CompilationUnit* cUnit, } else { lir->operands[1] = delta >> 1; } + } else if (lir->opcode == kThumb2Push || + lir->opcode == kThumb2Pop) { + if (__builtin_popcount(lir->operands[0]) == 1) { + /* + * The standard push/pop multiple instruction + * requires at least two registers in the list. + * If we've got just one, switch to the single-reg + * encoding. + */ + lir->opcode = (lir->opcode == kThumb2Push) + ? kThumb2Push1 : kThumb2Pop1; + int reg = 0; + while (lir->operands[0]) { + if (lir->operands[0] & 0x1) { + break; + } else { + reg++; + lir->operands[0] >>= 1; + } + } + lir->operands[0] = reg; + oatSetupResourceMasks(lir); + res = kRetryAll; + } } else if (lir->opcode == kThumbBCond || lir->opcode == kThumb2BCond) { ArmLIR *targetLIR = (ArmLIR *) lir->generic.target; |