diff options
Diffstat (limited to 'llvm/lib/Target/ARM')
| -rw-r--r-- | llvm/lib/Target/ARM/ARMInstrThumb.td | 4 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/ARMInstrThumb2.td | 10 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 107 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 10 |
4 files changed, 121 insertions, 10 deletions
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td index e7218c66586..d5b65631704 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb.td @@ -491,7 +491,8 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1 in { T1Encoding<{1,1,1,0,0,?}>, Sched<[WriteBr]> { bits<11> target; let Inst{10-0} = target; - } + let AsmMatchConverter = "cvtThumbBranches"; + } // Far jump // Just a pseudo for a tBL instruction. Needed to let regalloc know about @@ -521,6 +522,7 @@ let isBranch = 1, isTerminator = 1 in bits<8> target; let Inst{11-8} = p; let Inst{7-0} = target; + let AsmMatchConverter = "cvtThumbBranches"; } diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td index 7de0901f1c1..ccca41a1d36 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -3336,13 +3336,14 @@ def t2B : T2I<(outs), (ins uncondbrtarget:$target), IIC_Br, let Inst{12} = 1; bits<24> target; - let Inst{26} = target{19}; - let Inst{11} = target{18}; - let Inst{13} = target{17}; + let Inst{26} = target{23}; + let Inst{13} = target{22}; + let Inst{11} = target{21}; let Inst{25-16} = target{20-11}; let Inst{10-0} = target{10-0}; let DecoderMethod = "DecodeT2BInstruction"; -} + let AsmMatchConverter = "cvtThumbBranches"; +} let isNotDuplicable = 1, isIndirectBranch = 1 in { def t2BR_JT : t2PseudoInst<(outs), @@ -3410,6 +3411,7 @@ def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br, let Inst{10-0} = target{11-1}; let DecoderMethod = "DecodeThumb2BCCInstruction"; + let AsmMatchConverter = "cvtThumbBranches"; } // Tail calls. The IOS version of thumb tail calls uses a t2 branch, so diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 80e5c6edb4c..03d3a48f210 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -221,6 +221,9 @@ class ARMAsmParser : public MCTargetAsmParser { // Asm Match Converter Methods void cvtThumbMultiply(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &); + void cvtThumbBranches(MCInst &Inst, + const SmallVectorImpl<MCParsedAsmOperand*> &); + bool validateInstruction(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &Ops); bool processInstruction(MCInst &Inst, @@ -601,7 +604,7 @@ public: template<unsigned width, unsigned scale> bool isUnsignedOffset() const { if (!isImm()) return false; - if (dyn_cast<MCSymbolRefExpr>(Imm.Val)) return true; + if (isa<MCSymbolRefExpr>(Imm.Val)) return true; if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) { int64_t Val = CE->getValue(); int64_t Align = 1LL << scale; @@ -610,6 +613,22 @@ public: } return false; } + // checks whether this operand is an signed offset which fits is a field + // of specified width and scaled by a specific number of bits + template<unsigned width, unsigned scale> + bool isSignedOffset() const { + if (!isImm()) return false; + if (isa<MCSymbolRefExpr>(Imm.Val)) return true; + if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) { + int64_t Val = CE->getValue(); + int64_t Align = 1LL << scale; + int64_t Max = Align * ((1LL << (width-1)) - 1); + int64_t Min = -Align * (1LL << (width-1)); + return ((Val % Align) == 0) && (Val >= Min) && (Val <= Max); + } + return false; + } + // checks whether this operand is a memory operand computed as an offset // applied to PC. the offset may have 8 bits of magnitude and is represented // with two bits of shift. textually it may be either [pc, #imm], #imm or @@ -4102,6 +4121,65 @@ cvtThumbMultiply(MCInst &Inst, ((ARMOperand*)Operands[2])->addCondCodeOperands(Inst, 2); } +void ARMAsmParser:: +cvtThumbBranches(MCInst &Inst, + const SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + int CondOp = -1, ImmOp = -1; + switch(Inst.getOpcode()) { + case ARM::tB: + case ARM::tBcc: CondOp = 1; ImmOp = 2; break; + + case ARM::t2B: + case ARM::t2Bcc: CondOp = 1; ImmOp = 3; break; + + default: llvm_unreachable("Unexpected instruction in cvtThumbBranches"); + } + // first decide whether or not the branch should be conditional + // by looking at it's location relative to an IT block + if(inITBlock()) { + // inside an IT block we cannot have any conditional branches. any + // such instructions needs to be converted to unconditional form + switch(Inst.getOpcode()) { + case ARM::tBcc: Inst.setOpcode(ARM::tB); break; + case ARM::t2Bcc: Inst.setOpcode(ARM::t2B); break; + } + } else { + // outside IT blocks we can only have unconditional branches with AL + // condition code or conditional branches with non-AL condition code + unsigned Cond = static_cast<ARMOperand*>(Operands[CondOp])->getCondCode(); + switch(Inst.getOpcode()) { + case ARM::tB: + case ARM::tBcc: + Inst.setOpcode(Cond == ARMCC::AL ? ARM::tB : ARM::tBcc); + break; + case ARM::t2B: + case ARM::t2Bcc: + Inst.setOpcode(Cond == ARMCC::AL ? ARM::t2B : ARM::t2Bcc); + break; + } + } + + // now decide on encoding size based on branch target range + switch(Inst.getOpcode()) { + // classify tB as either t2B or t1B based on range of immediate operand + case ARM::tB: { + ARMOperand* op = static_cast<ARMOperand*>(Operands[ImmOp]); + if(!op->isSignedOffset<11, 1>() && isThumbTwo()) + Inst.setOpcode(ARM::t2B); + break; + } + // classify tBcc as either t2Bcc or t1Bcc based on range of immediate operand + case ARM::tBcc: { + ARMOperand* op = static_cast<ARMOperand*>(Operands[ImmOp]); + if(!op->isSignedOffset<8, 1>() && isThumbTwo()) + Inst.setOpcode(ARM::t2Bcc); + break; + } + } + ((ARMOperand*)Operands[ImmOp])->addImmOperands(Inst, 1); + ((ARMOperand*)Operands[CondOp])->addCondCodeOperands(Inst, 2); +} + /// Parse an ARM memory expression, return false if successful else return true /// or an error. The first token must be a '[' when called. bool ARMAsmParser:: @@ -5216,6 +5294,7 @@ validateInstruction(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &Operands) { const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); SMLoc Loc = Operands[0]->getStartLoc(); + // Check the IT block state first. // NOTE: BKPT instruction has the interesting property of being // allowed in IT blocks, but not being predicable. It just always @@ -5247,8 +5326,8 @@ validateInstruction(MCInst &Inst, // Check for non-'al' condition codes outside of the IT block. } else if (isThumbTwo() && MCID.isPredicable() && Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() != - ARMCC::AL && Inst.getOpcode() != ARM::tB && - Inst.getOpcode() != ARM::t2B) + ARMCC::AL && Inst.getOpcode() != ARM::tBcc && + Inst.getOpcode() != ARM::t2Bcc) return Error(Loc, "predicated instructions must be in IT block"); switch (Inst.getOpcode()) { @@ -5383,6 +5462,28 @@ validateInstruction(MCInst &Inst, } break; } + // final range checking for Thumb unconditional branch instructions + case ARM::tB: + if(!(static_cast<ARMOperand*>(Operands[2]))->isSignedOffset<11, 1>()) + return Error(Operands[2]->getStartLoc(), "Branch target out of range"); + break; + case ARM::t2B: { + int op = (Operands[2]->isImm()) ? 2 : 3; + if(!(static_cast<ARMOperand*>(Operands[op]))->isSignedOffset<24, 1>()) + return Error(Operands[op]->getStartLoc(), "Branch target out of range"); + break; + } + // final range checking for Thumb conditional branch instructions + case ARM::tBcc: + if(!(static_cast<ARMOperand*>(Operands[2]))->isSignedOffset<8, 1>()) + return Error(Operands[2]->getStartLoc(), "Branch target out of range"); + break; + case ARM::t2Bcc: { + int op = (Operands[2]->isImm()) ? 2 : 3; + if(!(static_cast<ARMOperand*>(Operands[op]))->isSignedOffset<20, 1>()) + return Error(Operands[op]->getStartLoc(), "Branch target out of range"); + break; + } } StringRef DepInfo; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp index a18d465f042..08732201b51 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -638,8 +638,14 @@ getARMBLXTargetOpValue(const MCInst &MI, unsigned OpIdx, uint32_t ARMMCCodeEmitter:: getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups) const { - unsigned Val = - ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_uncondbranch, Fixups); + unsigned Val = 0; + const MCOperand MO = MI.getOperand(OpIdx); + + if(MO.isExpr()) + Val = ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_uncondbranch, Fixups); + else + Val = MO.getImm() >> 1; + bool I = (Val & 0x800000); bool J1 = (Val & 0x400000); bool J2 = (Val & 0x200000); |

