diff options
Diffstat (limited to 'llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp')
-rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 93 |
1 files changed, 72 insertions, 21 deletions
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 28b11ad3f1a..cb07d17f194 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -6554,7 +6554,8 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic, // Check against T3. If the second register is the PC, this is an // alternate form of ADR, which uses encoding T4, so check for that too. if (static_cast<ARMOperand &>(*Operands[4]).getReg() != ARM::PC && - static_cast<ARMOperand &>(*Operands[5]).isT2SOImm()) + (static_cast<ARMOperand &>(*Operands[5]).isT2SOImm() || + static_cast<ARMOperand &>(*Operands[5]).isT2SOImmNeg())) return false; // Otherwise, we use encoding T4, which does not have a cc_out @@ -6609,9 +6610,34 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic, static_cast<ARMOperand &>(*Operands[1]).getReg() == 0 && (static_cast<ARMOperand &>(*Operands[4]).isImm() || (Operands.size() == 6 && - static_cast<ARMOperand &>(*Operands[5]).isImm()))) - return true; - + static_cast<ARMOperand &>(*Operands[5]).isImm()))) { + // Thumb2 (add|sub){s}{p}.w GPRnopc, sp, #{T2SOImm} has cc_out + return (!(isThumbTwo() && + (static_cast<ARMOperand &>(*Operands[4]).isT2SOImm() || + static_cast<ARMOperand &>(*Operands[4]).isT2SOImmNeg()))); + } + // Fixme: Should join all the thumb+thumb2 (add|sub) in a single if case + // Thumb2 ADD r0, #4095 -> ADDW r0, r0, #4095 (T4) + // Thumb2 SUB r0, #4095 -> SUBW r0, r0, #4095 + if (isThumbTwo() && (Mnemonic == "add" || Mnemonic == "sub") && + (Operands.size() == 5) && + static_cast<ARMOperand &>(*Operands[3]).isReg() && + static_cast<ARMOperand &>(*Operands[3]).getReg() != ARM::SP && + static_cast<ARMOperand &>(*Operands[3]).getReg() != ARM::PC && + static_cast<ARMOperand &>(*Operands[1]).getReg() == 0 && + static_cast<ARMOperand &>(*Operands[4]).isImm()) { + const ARMOperand &IMM = static_cast<ARMOperand &>(*Operands[4]); + if (IMM.isT2SOImm() || IMM.isT2SOImmNeg()) + return false; // add.w / sub.w + if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(IMM.getImm())) { + const int64_t Value = CE->getValue(); + // Thumb1 imm8 sub / add + if ((Value < ((1 << 7) - 1) << 2) && inITBlock() && (!(Value & 3)) && + isARMLowRegister(static_cast<ARMOperand &>(*Operands[3]).getReg())) + return false; + return true; // Thumb2 T4 addw / subw + } + } return false; } @@ -7707,12 +7733,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, } break; - case ARM::t2ADDri: - case ARM::t2ADDri12: case ARM::t2ADDrr: case ARM::t2ADDrs: - case ARM::t2SUBri: - case ARM::t2SUBri12: case ARM::t2SUBrr: case ARM::t2SUBrs: if (Inst.getOperand(0).getReg() == ARM::SP && @@ -9750,23 +9772,33 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, } break; case ARM::t2ADDri12: - // If the immediate fits for encoding T3 (t2ADDri) and the generic "add" - // mnemonic was used (not "addw"), encoding T3 is preferred. - if (static_cast<ARMOperand &>(*Operands[0]).getToken() != "add" || - ARM_AM::getT2SOImmVal(Inst.getOperand(2).getImm()) == -1) - break; - Inst.setOpcode(ARM::t2ADDri); - Inst.addOperand(MCOperand::createReg(0)); // cc_out - break; case ARM::t2SUBri12: - // If the immediate fits for encoding T3 (t2SUBri) and the generic "sub" - // mnemonic was used (not "subw"), encoding T3 is preferred. - if (static_cast<ARMOperand &>(*Operands[0]).getToken() != "sub" || + case ARM::t2ADDspImm12: + case ARM::t2SUBspImm12: { + // If the immediate fits for encoding T3 and the generic + // mnemonic was used, encoding T3 is preferred. + const StringRef Token = static_cast<ARMOperand &>(*Operands[0]).getToken(); + if ((Token != "add" && Token != "sub") || ARM_AM::getT2SOImmVal(Inst.getOperand(2).getImm()) == -1) break; - Inst.setOpcode(ARM::t2SUBri); + switch (Inst.getOpcode()) { + case ARM::t2ADDri12: + Inst.setOpcode(ARM::t2ADDri); + break; + case ARM::t2SUBri12: + Inst.setOpcode(ARM::t2SUBri); + break; + case ARM::t2ADDspImm12: + Inst.setOpcode(ARM::t2ADDspImm); + break; + case ARM::t2SUBspImm12: + Inst.setOpcode(ARM::t2SUBspImm); + break; + } + Inst.addOperand(MCOperand::createReg(0)); // cc_out - break; + return true; + } case ARM::tADDi8: // If the immediate is in the range 0-7, we want tADDi3 iff Rd was // explicitly specified. From the ARM ARM: "Encoding T1 is preferred @@ -9812,6 +9844,25 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, Inst = TmpInst; return true; } + case ARM::t2ADDspImm: + case ARM::t2SUBspImm: { + // Prefer T1 encoding if possible + if (Inst.getOperand(5).getReg() != 0 || HasWideQualifier) + break; + unsigned V = Inst.getOperand(2).getImm(); + if (V & 3 || V > ((1 << 7) - 1) << 2) + break; + MCInst TmpInst; + TmpInst.setOpcode(Inst.getOpcode() == ARM::t2ADDspImm ? ARM::tADDspi + : ARM::tSUBspi); + TmpInst.addOperand(MCOperand::createReg(ARM::SP)); // destination reg + TmpInst.addOperand(MCOperand::createReg(ARM::SP)); // source reg + TmpInst.addOperand(MCOperand::createImm(V / 4)); // immediate + TmpInst.addOperand(Inst.getOperand(3)); // pred + TmpInst.addOperand(Inst.getOperand(4)); + Inst = TmpInst; + return true; + } case ARM::t2ADDrr: { // If the destination and first source operand are the same, and // there's no setting of the flags, use encoding T2 instead of T3. |