From 20ed2e7939d6a8e804a51897c3af4588deb48be2 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Thu, 1 Sep 2011 00:28:52 +0000 Subject: [PATCH] Thumb2 assembly parsing and encoding for ADD(immediate). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@138922 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrThumb2.td | 5 +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 51 ++++++++++++++++++++--- test/MC/ARM/basic-thumb2-instructions.s | 28 +++++++++++++ test/MC/ARM/thumb-diagnostics.s | 4 +- 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 431c67a5377..4b53d110b36 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -3512,3 +3512,8 @@ def : t2InstAlias<"sbc${s}${p} $Rd, $Rn, $ShiftedRm", (t2SBCrs rGPR:$Rd, rGPR:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; +// Aliases for ADD immediate without the ".w" optional width specifier. +def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm", + (t2ADDri rGPR:$Rd, GPR:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; +def : t2InstAlias<"add${p} $Rd, $Rn, $imm", + (t2ADDri12 rGPR:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>; diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 96ce5cd4493..bba09d4674b 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -3035,6 +3035,8 @@ getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet, bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic, SmallVectorImpl &Operands) { + // FIXME: This is all horribly hacky. We really need a better way to deal + // with optional operands like this in the matcher table. // The 'mov' mnemonic is special. One variant has a cc_out operand, while // another does not. Specifically, the MOVW instruction does not. So we @@ -3058,13 +3060,49 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic, static_cast(Operands[1])->getReg() == 0) return true; // Register-register 'add' for thumb does not have a cc_out operand - // when it's an ADD Rdm, SP, {Rdm|#imm} instruction. + // when it's an ADD Rdm, SP, {Rdm|#imm0_255} instruction. We do + // have to check the immediate range here since Thumb2 has a variant + // that can handle a different range and has a cc_out operand. if (isThumb() && Mnemonic == "add" && Operands.size() == 6 && static_cast(Operands[3])->isReg() && static_cast(Operands[4])->isReg() && static_cast(Operands[4])->getReg() == ARM::SP && - static_cast(Operands[1])->getReg() == 0) + static_cast(Operands[1])->getReg() == 0 && + (static_cast(Operands[5])->isReg() || + static_cast(Operands[5])->isImm0_1020s4())) + return true; + // For Thumb2, add immediate does not have a cc_out operand for the + // imm0_4096 variant. That's the least-preferred variant when + // selecting via the generic "add" mnemonic, so to know that we + // should remove the cc_out operand, we have to explicitly check that + // it's not one of the other variants. Ugh. + if (isThumbTwo() && Mnemonic == "add" && Operands.size() == 6 && + static_cast(Operands[3])->isReg() && + static_cast(Operands[4])->isReg() && + static_cast(Operands[5])->isImm()) { + // Nest conditions rather than one big 'if' statement for readability. + // + // If either register is a high reg, it's either one of the SP + // variants (handled above) or a 32-bit encoding, so we just + // check against T3. + if ((!isARMLowRegister(static_cast(Operands[3])->getReg()) || + !isARMLowRegister(static_cast(Operands[4])->getReg())) && + static_cast(Operands[5])->isT2SOImm()) + return false; + // If both registers are low, we're in an IT block, and the immediate is + // in range, we should use encoding T1 instead, which has a cc_out. + if (inITBlock() && + isARMLowRegister(static_cast(Operands[4])->getReg()) && + isARMLowRegister(static_cast(Operands[4])->getReg()) && + static_cast(Operands[5])->isImm0_7()) + return false; + + // Otherwise, we use encoding T4, which does not have a cc_out + // operand. return true; + } + + // Register-register 'add/sub' for thumb does not have a cc_out operand // when it's an ADD/SUB SP, #imm. Be lenient on count since there's also // the "add/sub SP, SP, #imm" version. If the follow-up operands aren't @@ -3220,10 +3258,11 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, // Some instructions, mostly Thumb, have forms for the same mnemonic that // do and don't have a cc_out optional-def operand. With some spot-checks // of the operand list, we can figure out which variant we're trying to - // parse and adjust accordingly before actually matching. Reason number - // #317 the table driven matcher doesn't fit well with the ARM instruction - // set. - if (shouldOmitCCOutOperand(Mnemonic, Operands)) { + // parse and adjust accordingly before actually matching. We shouldn't ever + // try to remove a cc_out operand that was explicitly set on the the + // mnemonic, of course (CarrySetting == true). Reason number #317 the + // table driven matcher doesn't fit well with the ARM instruction set. + if (!CarrySetting && shouldOmitCCOutOperand(Mnemonic, Operands)) { ARMOperand *Op = static_cast(Operands[1]); Operands.erase(Operands.begin() + 1); delete Op; diff --git a/test/MC/ARM/basic-thumb2-instructions.s b/test/MC/ARM/basic-thumb2-instructions.s index d00566ae04a..492687ea40c 100644 --- a/test/MC/ARM/basic-thumb2-instructions.s +++ b/test/MC/ARM/basic-thumb2-instructions.s @@ -59,6 +59,34 @@ _func: @ CHECK: adcs.w r0, r1, r3, asr #32 @ encoding: [0x51,0xeb,0x23,0x00] +@------------------------------------------------------------------------------ +@ ADD (immediate) +@------------------------------------------------------------------------------ + itet eq + addeq r1, r2, #4 + addwne r5, r3, #1023 + addeq r4, r5, #293 + add r2, sp, #1024 + add r2, r8, #0xff00 + add r2, r3, #257 + addw r2, r3, #257 + add r12, r6, #0x100 + addw r12, r6, #0x100 + adds r1, r2, #0x1f0 + +@ CHECK: itet eq @ encoding: [0x0a,0xbf] +@ CHECK: addeq r1, r2, #4 @ encoding: [0x11,0x1d] +@ CHECK: addwne r5, r3, #1023 @ encoding: [0x03,0xf2,0xff,0x35] +@ CHECK: addweq r4, r5, #293 @ encoding: [0x05,0xf2,0x25,0x14] +@ CHECK: add.w r2, sp, #1024 @ encoding: [0x0d,0xf5,0x80,0x62] +@ CHECK: add.w r2, r8, #65280 @ encoding: [0x08,0xf5,0x7f,0x42] +@ CHECK: addw r2, r3, #257 @ encoding: [0x03,0xf2,0x01,0x12] +@ CHECK: addw r2, r3, #257 @ encoding: [0x03,0xf2,0x01,0x12] +@ CHECK: add.w r12, r6, #256 @ encoding: [0x06,0xf5,0x80,0x7c] +@ CHECK: addw r12, r6, #256 @ encoding: [0x06,0xf2,0x00,0x1c] +@ CHECK: adds.w r1, r2, #496 @ encoding: [0x12,0xf5,0xf8,0x71] + + @------------------------------------------------------------------------------ @ CBZ/CBNZ @------------------------------------------------------------------------------ diff --git a/test/MC/ARM/thumb-diagnostics.s b/test/MC/ARM/thumb-diagnostics.s index ea5d115be94..72572bca5c7 100644 --- a/test/MC/ARM/thumb-diagnostics.s +++ b/test/MC/ARM/thumb-diagnostics.s @@ -134,6 +134,6 @@ error: invalid operand for instruction @ CHECK-ERRORS: error: invalid operand for instruction @ CHECK-ERRORS: add sp, sp, #512 @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: invalid operand for instruction +@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled @ CHECK-ERRORS: add r2, sp, #1024 -@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: ^ -- 2.34.1