bool parseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
bool parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &, StringRef Mnemonic);
bool parsePrefix(ARMMCExpr::VariantKind &RefKind);
- const MCExpr *applyPrefixToExpr(const MCExpr *E,
- MCSymbolRefExpr::VariantKind Variant);
-
-
bool parseMemRegOffsetShift(ARM_AM::ShiftOpc &ShiftType,
unsigned &ShiftAmount);
bool parseDirectiveWord(unsigned Size, SMLoc L);
bool hasV6Ops() const {
return STI.getFeatureBits() & ARM::HasV6Ops;
}
+ bool hasV7Ops() const {
+ return STI.getFeatureBits() & ARM::HasV7Ops;
+ }
void SwitchMode() {
unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb));
setAvailableFeatures(FB);
}
+ bool isMClass() const {
+ return STI.getFeatureBits() & ARM::FeatureMClass;
+ }
/// @name Auto-generated Match Functions
/// {
OperandMatchResultTy parseBitfield(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parsePostIdxReg(SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*>&);
+ OperandMatchResultTy parseFPImm(SmallVectorImpl<MCParsedAsmOperand*>&);
// Asm Match Converter Methods
+ bool cvtT2LdrdPre(MCInst &Inst, unsigned Opcode,
+ const SmallVectorImpl<MCParsedAsmOperand*> &);
+ bool cvtT2StrdPre(MCInst &Inst, unsigned Opcode,
+ const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
+ bool cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
+ const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode,
/// instruction.
class ARMOperand : public MCParsedAsmOperand {
enum KindTy {
- CondCode,
- CCOut,
- ITCondMask,
- CoprocNum,
- CoprocReg,
- Immediate,
- MemBarrierOpt,
- Memory,
- PostIndexRegister,
- MSRMask,
- ProcIFlags,
- Register,
- RegisterList,
- DPRRegisterList,
- SPRRegisterList,
- ShiftedRegister,
- ShiftedImmediate,
- ShifterImmediate,
- RotateImmediate,
- BitfieldDescriptor,
- Token
+ k_CondCode,
+ k_CCOut,
+ k_ITCondMask,
+ k_CoprocNum,
+ k_CoprocReg,
+ k_Immediate,
+ k_FPImmediate,
+ k_MemBarrierOpt,
+ k_Memory,
+ k_PostIndexRegister,
+ k_MSRMask,
+ k_ProcIFlags,
+ k_VectorIndex,
+ k_Register,
+ k_RegisterList,
+ k_DPRRegisterList,
+ k_SPRRegisterList,
+ k_ShiftedRegister,
+ k_ShiftedImmediate,
+ k_ShifterImmediate,
+ k_RotateImmediate,
+ k_BitfieldDescriptor,
+ k_Token
} Kind;
SMLoc StartLoc, EndLoc;
unsigned RegNum;
} Reg;
+ struct {
+ unsigned Val;
+ } VectorIndex;
+
struct {
const MCExpr *Val;
} Imm;
+ struct {
+ unsigned Val; // encoded 8-bit representation
+ } FPImm;
+
/// Combined record for all forms of ARM address expressions.
struct {
unsigned BaseRegNum;
StartLoc = o.StartLoc;
EndLoc = o.EndLoc;
switch (Kind) {
- case CondCode:
+ case k_CondCode:
CC = o.CC;
break;
- case ITCondMask:
+ case k_ITCondMask:
ITMask = o.ITMask;
break;
- case Token:
+ case k_Token:
Tok = o.Tok;
break;
- case CCOut:
- case Register:
+ case k_CCOut:
+ case k_Register:
Reg = o.Reg;
break;
- case RegisterList:
- case DPRRegisterList:
- case SPRRegisterList:
+ case k_RegisterList:
+ case k_DPRRegisterList:
+ case k_SPRRegisterList:
Registers = o.Registers;
break;
- case CoprocNum:
- case CoprocReg:
+ case k_CoprocNum:
+ case k_CoprocReg:
Cop = o.Cop;
break;
- case Immediate:
+ case k_Immediate:
Imm = o.Imm;
break;
- case MemBarrierOpt:
+ case k_FPImmediate:
+ FPImm = o.FPImm;
+ break;
+ case k_MemBarrierOpt:
MBOpt = o.MBOpt;
break;
- case Memory:
+ case k_Memory:
Mem = o.Mem;
break;
- case PostIndexRegister:
+ case k_PostIndexRegister:
PostIdxReg = o.PostIdxReg;
break;
- case MSRMask:
+ case k_MSRMask:
MMask = o.MMask;
break;
- case ProcIFlags:
+ case k_ProcIFlags:
IFlags = o.IFlags;
break;
- case ShifterImmediate:
+ case k_ShifterImmediate:
ShifterImm = o.ShifterImm;
break;
- case ShiftedRegister:
+ case k_ShiftedRegister:
RegShiftedReg = o.RegShiftedReg;
break;
- case ShiftedImmediate:
+ case k_ShiftedImmediate:
RegShiftedImm = o.RegShiftedImm;
break;
- case RotateImmediate:
+ case k_RotateImmediate:
RotImm = o.RotImm;
break;
- case BitfieldDescriptor:
+ case k_BitfieldDescriptor:
Bitfield = o.Bitfield;
break;
+ case k_VectorIndex:
+ VectorIndex = o.VectorIndex;
+ break;
}
}
SMLoc getEndLoc() const { return EndLoc; }
ARMCC::CondCodes getCondCode() const {
- assert(Kind == CondCode && "Invalid access!");
+ assert(Kind == k_CondCode && "Invalid access!");
return CC.Val;
}
unsigned getCoproc() const {
- assert((Kind == CoprocNum || Kind == CoprocReg) && "Invalid access!");
+ assert((Kind == k_CoprocNum || Kind == k_CoprocReg) && "Invalid access!");
return Cop.Val;
}
StringRef getToken() const {
- assert(Kind == Token && "Invalid access!");
+ assert(Kind == k_Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
}
unsigned getReg() const {
- assert((Kind == Register || Kind == CCOut) && "Invalid access!");
+ assert((Kind == k_Register || Kind == k_CCOut) && "Invalid access!");
return Reg.RegNum;
}
const SmallVectorImpl<unsigned> &getRegList() const {
- assert((Kind == RegisterList || Kind == DPRRegisterList ||
- Kind == SPRRegisterList) && "Invalid access!");
+ assert((Kind == k_RegisterList || Kind == k_DPRRegisterList ||
+ Kind == k_SPRRegisterList) && "Invalid access!");
return Registers;
}
const MCExpr *getImm() const {
- assert(Kind == Immediate && "Invalid access!");
+ assert(Kind == k_Immediate && "Invalid access!");
return Imm.Val;
}
+ unsigned getFPImm() const {
+ assert(Kind == k_FPImmediate && "Invalid access!");
+ return FPImm.Val;
+ }
+
+ unsigned getVectorIndex() const {
+ assert(Kind == k_VectorIndex && "Invalid access!");
+ return VectorIndex.Val;
+ }
+
ARM_MB::MemBOpt getMemBarrierOpt() const {
- assert(Kind == MemBarrierOpt && "Invalid access!");
+ assert(Kind == k_MemBarrierOpt && "Invalid access!");
return MBOpt.Val;
}
ARM_PROC::IFlags getProcIFlags() const {
- assert(Kind == ProcIFlags && "Invalid access!");
+ assert(Kind == k_ProcIFlags && "Invalid access!");
return IFlags.Val;
}
unsigned getMSRMask() const {
- assert(Kind == MSRMask && "Invalid access!");
+ assert(Kind == k_MSRMask && "Invalid access!");
return MMask.Val;
}
- bool isCoprocNum() const { return Kind == CoprocNum; }
- bool isCoprocReg() const { return Kind == CoprocReg; }
- bool isCondCode() const { return Kind == CondCode; }
- bool isCCOut() const { return Kind == CCOut; }
- bool isITMask() const { return Kind == ITCondMask; }
- bool isITCondCode() const { return Kind == CondCode; }
- bool isImm() const { return Kind == Immediate; }
+ bool isCoprocNum() const { return Kind == k_CoprocNum; }
+ bool isCoprocReg() const { return Kind == k_CoprocReg; }
+ bool isCondCode() const { return Kind == k_CondCode; }
+ bool isCCOut() const { return Kind == k_CCOut; }
+ bool isITMask() const { return Kind == k_ITCondMask; }
+ bool isITCondCode() const { return Kind == k_CondCode; }
+ bool isImm() const { return Kind == k_Immediate; }
+ bool isFPImm() const { return Kind == k_FPImmediate; }
+ bool isImm8s4() const {
+ if (Kind != k_Immediate)
+ return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (!CE) return false;
+ int64_t Value = CE->getValue();
+ return ((Value & 3) == 0) && Value >= -1020 && Value <= 1020;
+ }
bool isImm0_1020s4() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return ((Value & 3) == 0) && Value >= 0 && Value <= 1020;
}
bool isImm0_508s4() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return ((Value & 3) == 0) && Value >= 0 && Value <= 508;
}
bool isImm0_255() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value < 256;
}
bool isImm0_7() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value < 8;
}
bool isImm0_15() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value < 16;
}
bool isImm0_31() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value < 32;
}
bool isImm1_16() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value > 0 && Value < 17;
}
bool isImm1_32() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value > 0 && Value < 33;
}
bool isImm0_65535() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value < 65536;
}
bool isImm0_65535Expr() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
// If it's not a constant expression, it'll generate a fixup and be
return Value >= 0 && Value < 65536;
}
bool isImm24bit() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value <= 0xffffff;
}
bool isImmThumbSR() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value > 0 && Value < 33;
}
bool isPKHLSLImm() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value >= 0 && Value < 32;
}
bool isPKHASRImm() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return Value > 0 && Value <= 32;
}
bool isARMSOImm() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return ARM_AM::getSOImmVal(Value) != -1;
}
bool isT2SOImm() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return ARM_AM::getT2SOImmVal(Value) != -1;
}
bool isSetEndImm() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
return Value == 1 || Value == 0;
}
- bool isReg() const { return Kind == Register; }
- bool isRegList() const { return Kind == RegisterList; }
- bool isDPRRegList() const { return Kind == DPRRegisterList; }
- bool isSPRRegList() const { return Kind == SPRRegisterList; }
- bool isToken() const { return Kind == Token; }
- bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
- bool isMemory() const { return Kind == Memory; }
- bool isShifterImm() const { return Kind == ShifterImmediate; }
- bool isRegShiftedReg() const { return Kind == ShiftedRegister; }
- bool isRegShiftedImm() const { return Kind == ShiftedImmediate; }
- bool isRotImm() const { return Kind == RotateImmediate; }
- bool isBitfield() const { return Kind == BitfieldDescriptor; }
- bool isPostIdxRegShifted() const { return Kind == PostIndexRegister; }
+ bool isReg() const { return Kind == k_Register; }
+ bool isRegList() const { return Kind == k_RegisterList; }
+ bool isDPRRegList() const { return Kind == k_DPRRegisterList; }
+ bool isSPRRegList() const { return Kind == k_SPRRegisterList; }
+ bool isToken() const { return Kind == k_Token; }
+ bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; }
+ bool isMemory() const { return Kind == k_Memory; }
+ bool isShifterImm() const { return Kind == k_ShifterImmediate; }
+ bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; }
+ bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; }
+ bool isRotImm() const { return Kind == k_RotateImmediate; }
+ bool isBitfield() const { return Kind == k_BitfieldDescriptor; }
+ bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; }
bool isPostIdxReg() const {
- return Kind == PostIndexRegister && PostIdxReg.ShiftTy == ARM_AM::no_shift;
+ return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy == ARM_AM::no_shift;
}
bool isMemNoOffset() const {
- if (Kind != Memory)
+ if (Kind != k_Memory)
return false;
// No offset of any kind.
return Mem.OffsetRegNum == 0 && Mem.OffsetImm == 0;
}
bool isAddrMode2() const {
- if (Kind != Memory)
+ if (Kind != k_Memory)
return false;
// Check for register offset.
if (Mem.OffsetRegNum) return true;
return Val > -4096 && Val < 4096;
}
bool isAM2OffsetImm() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
// Immediate offset in range [-4095, 4095].
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
return Val > -4096 && Val < 4096;
}
bool isAddrMode3() const {
- if (Kind != Memory)
+ if (Kind != k_Memory)
return false;
// No shifts are legal for AM3.
if (Mem.ShiftType != ARM_AM::no_shift) return false;
return Val > -256 && Val < 256;
}
bool isAM3Offset() const {
- if (Kind != Immediate && Kind != PostIndexRegister)
+ if (Kind != k_Immediate && Kind != k_PostIndexRegister)
return false;
- if (Kind == PostIndexRegister)
+ if (Kind == k_PostIndexRegister)
return PostIdxReg.ShiftTy == ARM_AM::no_shift;
// Immediate offset in range [-255, 255].
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
return (Val > -256 && Val < 256) || Val == INT32_MIN;
}
bool isAddrMode5() const {
- if (Kind != Memory)
+ if (Kind != k_Memory)
return false;
// Check for register offset.
if (Mem.OffsetRegNum) return false;
return (Val >= -1020 && Val <= 1020 && ((Val & 3) == 0)) ||
Val == INT32_MIN;
}
+ bool isMemTBB() const {
+ if (Kind != k_Memory || !Mem.OffsetRegNum || Mem.isNegative ||
+ Mem.ShiftType != ARM_AM::no_shift)
+ return false;
+ return true;
+ }
+ bool isMemTBH() const {
+ if (Kind != k_Memory || !Mem.OffsetRegNum || Mem.isNegative ||
+ Mem.ShiftType != ARM_AM::lsl || Mem.ShiftImm != 1)
+ return false;
+ return true;
+ }
bool isMemRegOffset() const {
- if (Kind != Memory || !Mem.OffsetRegNum)
+ if (Kind != k_Memory || !Mem.OffsetRegNum)
return false;
return true;
}
bool isT2MemRegOffset() const {
- if (Kind != Memory || !Mem.OffsetRegNum || Mem.isNegative)
+ if (Kind != k_Memory || !Mem.OffsetRegNum || Mem.isNegative)
return false;
// Only lsl #{0, 1, 2, 3} allowed.
if (Mem.ShiftType == ARM_AM::no_shift)
bool isMemThumbRR() const {
// Thumb reg+reg addressing is simple. Just two registers, a base and
// an offset. No shifts, negations or any other complicating factors.
- if (Kind != Memory || !Mem.OffsetRegNum || Mem.isNegative ||
+ if (Kind != k_Memory || !Mem.OffsetRegNum || Mem.isNegative ||
Mem.ShiftType != ARM_AM::no_shift)
return false;
return isARMLowRegister(Mem.BaseRegNum) &&
(!Mem.OffsetRegNum || isARMLowRegister(Mem.OffsetRegNum));
}
bool isMemThumbRIs4() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0 ||
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0 ||
!isARMLowRegister(Mem.BaseRegNum))
return false;
// Immediate offset, multiple of 4 in range [0, 124].
return Val >= 0 && Val <= 124 && (Val % 4) == 0;
}
bool isMemThumbRIs2() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0 ||
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0 ||
!isARMLowRegister(Mem.BaseRegNum))
return false;
// Immediate offset, multiple of 4 in range [0, 62].
return Val >= 0 && Val <= 62 && (Val % 2) == 0;
}
bool isMemThumbRIs1() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0 ||
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0 ||
!isARMLowRegister(Mem.BaseRegNum))
return false;
// Immediate offset in range [0, 31].
return Val >= 0 && Val <= 31;
}
bool isMemThumbSPI() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0 || Mem.BaseRegNum != ARM::SP)
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0 || Mem.BaseRegNum != ARM::SP)
return false;
// Immediate offset, multiple of 4 in range [0, 1020].
if (!Mem.OffsetImm) return true;
int64_t Val = Mem.OffsetImm->getValue();
return Val >= 0 && Val <= 1020 && (Val % 4) == 0;
}
+ bool isMemImm8s4Offset() const {
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
+ return false;
+ // Immediate offset a multiple of 4 in range [-1020, 1020].
+ if (!Mem.OffsetImm) return true;
+ int64_t Val = Mem.OffsetImm->getValue();
+ return Val >= -1020 && Val <= 1020 && (Val & 3) == 0;
+ }
+ bool isMemImm0_1020s4Offset() const {
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
+ return false;
+ // Immediate offset a multiple of 4 in range [0, 1020].
+ if (!Mem.OffsetImm) return true;
+ int64_t Val = Mem.OffsetImm->getValue();
+ return Val >= 0 && Val <= 1020 && (Val & 3) == 0;
+ }
bool isMemImm8Offset() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0)
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
return false;
// Immediate offset in range [-255, 255].
if (!Mem.OffsetImm) return true;
int64_t Val = Mem.OffsetImm->getValue();
- return Val > -256 && Val < 256;
+ return (Val == INT32_MIN) || (Val > -256 && Val < 256);
}
bool isMemPosImm8Offset() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0)
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
return false;
// Immediate offset in range [0, 255].
if (!Mem.OffsetImm) return true;
return Val >= 0 && Val < 256;
}
bool isMemNegImm8Offset() const {
- if (Kind != Memory || Mem.OffsetRegNum != 0)
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
return false;
// Immediate offset in range [-255, -1].
if (!Mem.OffsetImm) return true;
// If we have an immediate that's not a constant, treat it as a label
// reference needing a fixup. If it is a constant, it's something else
// and we reject it.
- if (Kind == Immediate && !isa<MCConstantExpr>(getImm()))
+ if (Kind == k_Immediate && !isa<MCConstantExpr>(getImm()))
return true;
- if (Kind != Memory || Mem.OffsetRegNum != 0)
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
return false;
// Immediate offset in range [0, 4095].
if (!Mem.OffsetImm) return true;
// If we have an immediate that's not a constant, treat it as a label
// reference needing a fixup. If it is a constant, it's something else
// and we reject it.
- if (Kind == Immediate && !isa<MCConstantExpr>(getImm()))
+ if (Kind == k_Immediate && !isa<MCConstantExpr>(getImm()))
return true;
- if (Kind != Memory || Mem.OffsetRegNum != 0)
+ if (Kind != k_Memory || Mem.OffsetRegNum != 0)
return false;
// Immediate offset in range [-4095, 4095].
if (!Mem.OffsetImm) return true;
return (Val > -4096 && Val < 4096) || (Val == INT32_MIN);
}
bool isPostIdxImm8() const {
- if (Kind != Immediate)
+ if (Kind != k_Immediate)
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
return (Val > -256 && Val < 256) || (Val == INT32_MIN);
}
- bool isMSRMask() const { return Kind == MSRMask; }
- bool isProcIFlags() const { return Kind == ProcIFlags; }
+ bool isMSRMask() const { return Kind == k_MSRMask; }
+ bool isProcIFlags() const { return Kind == k_ProcIFlags; }
+
+ bool isVectorIndex8() const {
+ if (Kind != k_VectorIndex) return false;
+ return VectorIndex.Val < 8;
+ }
+ bool isVectorIndex16() const {
+ if (Kind != k_VectorIndex) return false;
+ return VectorIndex.Val < 4;
+ }
+ bool isVectorIndex32() const {
+ if (Kind != k_VectorIndex) return false;
+ return VectorIndex.Val < 2;
+ }
+
+
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
// Add as immediates when possible. Null MCExpr = 0.
addExpr(Inst, getImm());
}
+ void addFPImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateImm(getFPImm()));
+ }
+
+ void addImm8s4Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ // FIXME: We really want to scale the value here, but the LDRD/STRD
+ // instruction don't encode operands that way yet.
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
+ }
+
void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
// The immediate is scaled by four in the encoding and is stored
void addAM3OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
- if (Kind == PostIndexRegister) {
+ if (Kind == k_PostIndexRegister) {
int32_t Val =
ARM_AM::getAM3Opc(PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub, 0);
Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum));
Inst.addOperand(MCOperand::CreateImm(Val));
}
+ void addMemImm8s4OffsetOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ int64_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0;
+ Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
+ Inst.addOperand(MCOperand::CreateImm(Val));
+ }
+
+ void addMemImm0_1020s4OffsetOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ // The lower two bits are always zero and as such are not encoded.
+ int32_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() / 4 : 0;
+ Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
+ Inst.addOperand(MCOperand::CreateImm(Val));
+ }
+
void addMemImm8OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
int64_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0;
void addMemUImm12OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
// If this is an immediate, it's a label reference.
- if (Kind == Immediate) {
+ if (Kind == k_Immediate) {
addExpr(Inst, getImm());
Inst.addOperand(MCOperand::CreateImm(0));
return;
void addMemImm12OffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands!");
// If this is an immediate, it's a label reference.
- if (Kind == Immediate) {
+ if (Kind == k_Immediate) {
addExpr(Inst, getImm());
Inst.addOperand(MCOperand::CreateImm(0));
return;
Inst.addOperand(MCOperand::CreateImm(Val));
}
+ void addMemTBBOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
+ Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum));
+ }
+
+ void addMemTBHOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
+ Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum));
+ }
+
void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
unsigned Val = ARM_AM::getAM2Opc(Mem.isNegative ? ARM_AM::sub : ARM_AM::add,
Inst.addOperand(MCOperand::CreateImm(unsigned(getProcIFlags())));
}
+ void addVectorIndex8Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateImm(getVectorIndex()));
+ }
+
+ void addVectorIndex16Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateImm(getVectorIndex()));
+ }
+
+ void addVectorIndex32Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateImm(getVectorIndex()));
+ }
+
virtual void print(raw_ostream &OS) const;
static ARMOperand *CreateITMask(unsigned Mask, SMLoc S) {
- ARMOperand *Op = new ARMOperand(ITCondMask);
+ ARMOperand *Op = new ARMOperand(k_ITCondMask);
Op->ITMask.Mask = Mask;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) {
- ARMOperand *Op = new ARMOperand(CondCode);
+ ARMOperand *Op = new ARMOperand(k_CondCode);
Op->CC.Val = CC;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateCoprocNum(unsigned CopVal, SMLoc S) {
- ARMOperand *Op = new ARMOperand(CoprocNum);
+ ARMOperand *Op = new ARMOperand(k_CoprocNum);
Op->Cop.Val = CopVal;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateCoprocReg(unsigned CopVal, SMLoc S) {
- ARMOperand *Op = new ARMOperand(CoprocReg);
+ ARMOperand *Op = new ARMOperand(k_CoprocReg);
Op->Cop.Val = CopVal;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateCCOut(unsigned RegNum, SMLoc S) {
- ARMOperand *Op = new ARMOperand(CCOut);
+ ARMOperand *Op = new ARMOperand(k_CCOut);
Op->Reg.RegNum = RegNum;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateToken(StringRef Str, SMLoc S) {
- ARMOperand *Op = new ARMOperand(Token);
+ ARMOperand *Op = new ARMOperand(k_Token);
Op->Tok.Data = Str.data();
Op->Tok.Length = Str.size();
Op->StartLoc = S;
}
static ARMOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(Register);
+ ARMOperand *Op = new ARMOperand(k_Register);
Op->Reg.RegNum = RegNum;
Op->StartLoc = S;
Op->EndLoc = E;
unsigned ShiftReg,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(ShiftedRegister);
+ ARMOperand *Op = new ARMOperand(k_ShiftedRegister);
Op->RegShiftedReg.ShiftTy = ShTy;
Op->RegShiftedReg.SrcReg = SrcReg;
Op->RegShiftedReg.ShiftReg = ShiftReg;
unsigned SrcReg,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(ShiftedImmediate);
+ ARMOperand *Op = new ARMOperand(k_ShiftedImmediate);
Op->RegShiftedImm.ShiftTy = ShTy;
Op->RegShiftedImm.SrcReg = SrcReg;
Op->RegShiftedImm.ShiftImm = ShiftImm;
static ARMOperand *CreateShifterImm(bool isASR, unsigned Imm,
SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(ShifterImmediate);
+ ARMOperand *Op = new ARMOperand(k_ShifterImmediate);
Op->ShifterImm.isASR = isASR;
Op->ShifterImm.Imm = Imm;
Op->StartLoc = S;
}
static ARMOperand *CreateRotImm(unsigned Imm, SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(RotateImmediate);
+ ARMOperand *Op = new ARMOperand(k_RotateImmediate);
Op->RotImm.Imm = Imm;
Op->StartLoc = S;
Op->EndLoc = E;
static ARMOperand *CreateBitfield(unsigned LSB, unsigned Width,
SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(BitfieldDescriptor);
+ ARMOperand *Op = new ARMOperand(k_BitfieldDescriptor);
Op->Bitfield.LSB = LSB;
Op->Bitfield.Width = Width;
Op->StartLoc = S;
static ARMOperand *
CreateRegList(const SmallVectorImpl<std::pair<unsigned, SMLoc> > &Regs,
SMLoc StartLoc, SMLoc EndLoc) {
- KindTy Kind = RegisterList;
+ KindTy Kind = k_RegisterList;
- if (llvm::ARMMCRegisterClasses[ARM::DPRRegClassID].
- contains(Regs.front().first))
- Kind = DPRRegisterList;
- else if (llvm::ARMMCRegisterClasses[ARM::SPRRegClassID].
+ if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().first))
+ Kind = k_DPRRegisterList;
+ else if (ARMMCRegisterClasses[ARM::SPRRegClassID].
contains(Regs.front().first))
- Kind = SPRRegisterList;
+ Kind = k_SPRRegisterList;
ARMOperand *Op = new ARMOperand(Kind);
for (SmallVectorImpl<std::pair<unsigned, SMLoc> >::const_iterator
return Op;
}
+ static ARMOperand *CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E,
+ MCContext &Ctx) {
+ ARMOperand *Op = new ARMOperand(k_VectorIndex);
+ Op->VectorIndex.Val = Idx;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
static ARMOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(Immediate);
+ ARMOperand *Op = new ARMOperand(k_Immediate);
Op->Imm.Val = Val;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
+ static ARMOperand *CreateFPImm(unsigned Val, SMLoc S, MCContext &Ctx) {
+ ARMOperand *Op = new ARMOperand(k_FPImmediate);
+ Op->FPImm.Val = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
static ARMOperand *CreateMem(unsigned BaseRegNum,
const MCConstantExpr *OffsetImm,
unsigned OffsetRegNum,
unsigned ShiftImm,
bool isNegative,
SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(Memory);
+ ARMOperand *Op = new ARMOperand(k_Memory);
Op->Mem.BaseRegNum = BaseRegNum;
Op->Mem.OffsetImm = OffsetImm;
Op->Mem.OffsetRegNum = OffsetRegNum;
ARM_AM::ShiftOpc ShiftTy,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
- ARMOperand *Op = new ARMOperand(PostIndexRegister);
+ ARMOperand *Op = new ARMOperand(k_PostIndexRegister);
Op->PostIdxReg.RegNum = RegNum;
Op->PostIdxReg.isAdd = isAdd;
Op->PostIdxReg.ShiftTy = ShiftTy;
}
static ARMOperand *CreateMemBarrierOpt(ARM_MB::MemBOpt Opt, SMLoc S) {
- ARMOperand *Op = new ARMOperand(MemBarrierOpt);
+ ARMOperand *Op = new ARMOperand(k_MemBarrierOpt);
Op->MBOpt.Val = Opt;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) {
- ARMOperand *Op = new ARMOperand(ProcIFlags);
+ ARMOperand *Op = new ARMOperand(k_ProcIFlags);
Op->IFlags.Val = IFlags;
Op->StartLoc = S;
Op->EndLoc = S;
}
static ARMOperand *CreateMSRMask(unsigned MMask, SMLoc S) {
- ARMOperand *Op = new ARMOperand(MSRMask);
+ ARMOperand *Op = new ARMOperand(k_MSRMask);
Op->MMask.Val = MMask;
Op->StartLoc = S;
Op->EndLoc = S;
void ARMOperand::print(raw_ostream &OS) const {
switch (Kind) {
- case CondCode:
+ case k_FPImmediate:
+ OS << "<fpimm " << getFPImm() << "(" << ARM_AM::getFPImmFloat(getFPImm())
+ << ") >";
+ break;
+ case k_CondCode:
OS << "<ARMCC::" << ARMCondCodeToString(getCondCode()) << ">";
break;
- case CCOut:
+ case k_CCOut:
OS << "<ccout " << getReg() << ">";
break;
- case ITCondMask: {
+ case k_ITCondMask: {
static char MaskStr[][6] = { "()", "(t)", "(e)", "(tt)", "(et)", "(te)",
"(ee)", "(ttt)", "(ett)", "(tet)", "(eet)", "(tte)", "(ete)",
"(tee)", "(eee)" };
OS << "<it-mask " << MaskStr[ITMask.Mask] << ">";
break;
}
- case CoprocNum:
+ case k_CoprocNum:
OS << "<coprocessor number: " << getCoproc() << ">";
break;
- case CoprocReg:
+ case k_CoprocReg:
OS << "<coprocessor register: " << getCoproc() << ">";
break;
- case MSRMask:
+ case k_MSRMask:
OS << "<mask: " << getMSRMask() << ">";
break;
- case Immediate:
+ case k_Immediate:
getImm()->print(OS);
break;
- case MemBarrierOpt:
+ case k_MemBarrierOpt:
OS << "<ARM_MB::" << MemBOptToString(getMemBarrierOpt()) << ">";
break;
- case Memory:
+ case k_Memory:
OS << "<memory "
<< " base:" << Mem.BaseRegNum;
OS << ">";
break;
- case PostIndexRegister:
+ case k_PostIndexRegister:
OS << "post-idx register " << (PostIdxReg.isAdd ? "" : "-")
<< PostIdxReg.RegNum;
if (PostIdxReg.ShiftTy != ARM_AM::no_shift)
<< PostIdxReg.ShiftImm;
OS << ">";
break;
- case ProcIFlags: {
+ case k_ProcIFlags: {
OS << "<ARM_PROC::";
unsigned IFlags = getProcIFlags();
for (int i=2; i >= 0; --i)
OS << ">";
break;
}
- case Register:
+ case k_Register:
OS << "<register " << getReg() << ">";
break;
- case ShifterImmediate:
+ case k_ShifterImmediate:
OS << "<shift " << (ShifterImm.isASR ? "asr" : "lsl")
<< " #" << ShifterImm.Imm << ">";
break;
- case ShiftedRegister:
+ case k_ShiftedRegister:
OS << "<so_reg_reg "
<< RegShiftedReg.SrcReg
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(RegShiftedReg.ShiftImm))
<< ARM_AM::getSORegOffset(RegShiftedReg.ShiftImm)
<< ">";
break;
- case ShiftedImmediate:
+ case k_ShiftedImmediate:
OS << "<so_reg_imm "
<< RegShiftedImm.SrcReg
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(RegShiftedImm.ShiftImm))
<< ", " << ARM_AM::getSORegOffset(RegShiftedImm.ShiftImm)
<< ">";
break;
- case RotateImmediate:
+ case k_RotateImmediate:
OS << "<ror " << " #" << (RotImm.Imm * 8) << ">";
break;
- case BitfieldDescriptor:
+ case k_BitfieldDescriptor:
OS << "<bitfield " << "lsb: " << Bitfield.LSB
<< ", width: " << Bitfield.Width << ">";
break;
- case RegisterList:
- case DPRRegisterList:
- case SPRRegisterList: {
+ case k_RegisterList:
+ case k_DPRRegisterList:
+ case k_SPRRegisterList: {
OS << "<register_list ";
const SmallVectorImpl<unsigned> &RegList = getRegList();
OS << ">";
break;
}
- case Token:
+ case k_Token:
OS << "'" << getToken() << "'";
break;
+ case k_VectorIndex:
+ OS << "<vectorindex " << getVectorIndex() << ">";
+ break;
}
}
if (!RegNum) return -1;
Parser.Lex(); // Eat identifier token.
+
+#if 0
+ // Also check for an index operand. This is only legal for vector registers,
+ // but that'll get caught OK in operand matching, so we don't need to
+ // explicitly filter everything else out here.
+ if (Parser.getTok().is(AsmToken::LBrac)) {
+ SMLoc SIdx = Parser.getTok().getLoc();
+ Parser.Lex(); // Eat left bracket token.
+
+ const MCExpr *ImmVal;
+ SMLoc ExprLoc = Parser.getTok().getLoc();
+ if (getParser().ParseExpression(ImmVal))
+ return MatchOperand_ParseFail;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ if (!MCE) {
+ TokError("immediate value expected for vector index");
+ return MatchOperand_ParseFail;
+ }
+
+ SMLoc E = Parser.getTok().getLoc();
+ if (Parser.getTok().isNot(AsmToken::RBrac)) {
+ Error(E, "']' expected");
+ return MatchOperand_ParseFail;
+ }
+
+ Parser.Lex(); // Eat right bracket token.
+
+ Operands.push_back(ARMOperand::CreateVectorIndex(MCE->getValue(),
+ SIdx, E,
+ getContext()));
+ }
+#endif
+
return RegNum;
}
Operands.push_back(ARMOperand::CreateToken(ExclaimTok.getString(),
ExclaimTok.getLoc()));
Parser.Lex(); // Eat exclaim token
+ return false;
+ }
+
+ // Also check for an index operand. This is only legal for vector registers,
+ // but that'll get caught OK in operand matching, so we don't need to
+ // explicitly filter everything else out here.
+ if (Parser.getTok().is(AsmToken::LBrac)) {
+ SMLoc SIdx = Parser.getTok().getLoc();
+ Parser.Lex(); // Eat left bracket token.
+
+ const MCExpr *ImmVal;
+ SMLoc ExprLoc = Parser.getTok().getLoc();
+ if (getParser().ParseExpression(ImmVal))
+ return MatchOperand_ParseFail;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ if (!MCE) {
+ TokError("immediate value expected for vector index");
+ return MatchOperand_ParseFail;
+ }
+
+ SMLoc E = Parser.getTok().getLoc();
+ if (Parser.getTok().isNot(AsmToken::RBrac)) {
+ Error(E, "']' expected");
+ return MatchOperand_ParseFail;
+ }
+
+ Parser.Lex(); // Eat right bracket token.
+
+ Operands.push_back(ARMOperand::CreateVectorIndex(MCE->getValue(),
+ SIdx, E,
+ getContext()));
}
return false;
return MatchOperand_Success;
}
-/// Parse a register list, return it if successful else return null. The first
-/// token must be a '{' when called.
+// For register list parsing, we need to map from raw GPR register numbering
+// to the enumeration values. The enumeration values aren't sorted by
+// register number due to our using "sp", "lr" and "pc" as canonical names.
+static unsigned getNextRegister(unsigned Reg) {
+ // If this is a GPR, we need to do it manually, otherwise we can rely
+ // on the sort ordering of the enumeration since the other reg-classes
+ // are sane.
+ if (!ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg))
+ return Reg + 1;
+ switch(Reg) {
+ default: assert(0 && "Invalid GPR number!");
+ case ARM::R0: return ARM::R1; case ARM::R1: return ARM::R2;
+ case ARM::R2: return ARM::R3; case ARM::R3: return ARM::R4;
+ case ARM::R4: return ARM::R5; case ARM::R5: return ARM::R6;
+ case ARM::R6: return ARM::R7; case ARM::R7: return ARM::R8;
+ case ARM::R8: return ARM::R9; case ARM::R9: return ARM::R10;
+ case ARM::R10: return ARM::R11; case ARM::R11: return ARM::R12;
+ case ARM::R12: return ARM::SP; case ARM::SP: return ARM::LR;
+ case ARM::LR: return ARM::PC; case ARM::PC: return ARM::R0;
+ }
+}
+
+/// Parse a register list.
bool ARMAsmParser::
parseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
assert(Parser.getTok().is(AsmToken::LCurly) &&
"Token is not a Left Curly Brace");
SMLoc S = Parser.getTok().getLoc();
+ Parser.Lex(); // Eat '{' token.
+ SMLoc RegLoc = Parser.getTok().getLoc();
- // Read the rest of the registers in the list.
- unsigned PrevRegNum = 0;
- SmallVector<std::pair<unsigned, SMLoc>, 32> Registers;
-
- do {
- bool IsRange = Parser.getTok().is(AsmToken::Minus);
- Parser.Lex(); // Eat non-identifier token.
-
- const AsmToken &RegTok = Parser.getTok();
- SMLoc RegLoc = RegTok.getLoc();
- if (RegTok.isNot(AsmToken::Identifier)) {
- Error(RegLoc, "register expected");
- return true;
- }
-
- int RegNum = tryParseRegister();
- if (RegNum == -1) {
- Error(RegLoc, "register expected");
- return true;
- }
-
- if (IsRange) {
- int Reg = PrevRegNum;
- do {
- ++Reg;
- Registers.push_back(std::make_pair(Reg, RegLoc));
- } while (Reg != RegNum);
- } else {
- Registers.push_back(std::make_pair(RegNum, RegLoc));
+ // Check the first register in the list to see what register class
+ // this is a list of.
+ int Reg = tryParseRegister();
+ if (Reg == -1)
+ return Error(RegLoc, "register expected");
+
+ MCRegisterClass *RC;
+ if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg))
+ RC = &ARMMCRegisterClasses[ARM::GPRRegClassID];
+ else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg))
+ RC = &ARMMCRegisterClasses[ARM::DPRRegClassID];
+ else if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains(Reg))
+ RC = &ARMMCRegisterClasses[ARM::SPRRegClassID];
+ else
+ return Error(RegLoc, "invalid register in register list");
+
+ // The reglist instructions have at most 16 registers, so reserve
+ // space for that many.
+ SmallVector<std::pair<unsigned, SMLoc>, 16> Registers;
+ // Store the first register.
+ Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
+
+ // This starts immediately after the first register token in the list,
+ // so we can see either a comma or a minus (range separator) as a legal
+ // next token.
+ while (Parser.getTok().is(AsmToken::Comma) ||
+ Parser.getTok().is(AsmToken::Minus)) {
+ if (Parser.getTok().is(AsmToken::Minus)) {
+ Parser.Lex(); // Eat the comma.
+ SMLoc EndLoc = Parser.getTok().getLoc();
+ int EndReg = tryParseRegister();
+ if (EndReg == -1)
+ return Error(EndLoc, "register expected");
+ // If the register is the same as the start reg, there's nothing
+ // more to do.
+ if (Reg == EndReg)
+ continue;
+ // The register must be in the same register class as the first.
+ if (!RC->contains(EndReg))
+ return Error(EndLoc, "invalid register in register list");
+ // Ranges must go from low to high.
+ if (getARMRegisterNumbering(Reg) > getARMRegisterNumbering(EndReg))
+ return Error(EndLoc, "bad range in register list");
+
+ // Add all the registers in the range to the register list.
+ while (Reg != EndReg) {
+ Reg = getNextRegister(Reg);
+ Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
+ }
+ continue;
}
-
- PrevRegNum = RegNum;
- } while (Parser.getTok().is(AsmToken::Comma) ||
- Parser.getTok().is(AsmToken::Minus));
-
- // Process the right curly brace of the list.
- const AsmToken &RCurlyTok = Parser.getTok();
- if (RCurlyTok.isNot(AsmToken::RCurly)) {
- Error(RCurlyTok.getLoc(), "'}' expected");
- return true;
+ Parser.Lex(); // Eat the comma.
+ RegLoc = Parser.getTok().getLoc();
+ int OldReg = Reg;
+ Reg = tryParseRegister();
+ if (Reg == -1)
+ return Error(RegLoc, "register expected");
+ // The register must be in the same register class as the first.
+ if (!RC->contains(Reg))
+ return Error(RegLoc, "invalid register in register list");
+ // List must be monotonically increasing.
+ if (getARMRegisterNumbering(Reg) <= getARMRegisterNumbering(OldReg))
+ return Error(RegLoc, "register list not in ascending order");
+ // VFP register lists must also be contiguous.
+ // It's OK to use the enumeration values directly here rather, as the
+ // VFP register classes have the enum sorted properly.
+ if (RC != &ARMMCRegisterClasses[ARM::GPRRegClassID] &&
+ Reg != OldReg + 1)
+ return Error(RegLoc, "non-contiguous register range");
+ Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
}
- SMLoc E = RCurlyTok.getLoc();
- Parser.Lex(); // Eat right curly brace token.
-
- // Verify the register list.
- bool EmittedWarning = false;
- unsigned HighRegNum = 0;
- BitVector RegMap(32);
- for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
- const std::pair<unsigned, SMLoc> &RegInfo = Registers[i];
- unsigned Reg = getARMRegisterNumbering(RegInfo.first);
-
- if (RegMap[Reg]) {
- Error(RegInfo.second, "register duplicated in register list");
- return true;
- }
-
- if (!EmittedWarning && Reg < HighRegNum)
- Warning(RegInfo.second,
- "register not in ascending order in register list");
-
- RegMap.set(Reg);
- HighRegNum = std::max(Reg, HighRegNum);
- }
+ SMLoc E = Parser.getTok().getLoc();
+ if (Parser.getTok().isNot(AsmToken::RCurly))
+ return Error(E, "'}' expected");
+ Parser.Lex(); // Eat '}' token.
Operands.push_back(ARMOperand::CreateRegList(Registers, S, E));
return false;
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
StringRef IFlagsStr = Tok.getString();
+ // An iflags string of "none" is interpreted to mean that none of the AIF
+ // bits are set. Not a terribly useful instruction, but a valid encoding.
unsigned IFlags = 0;
- for (int i = 0, e = IFlagsStr.size(); i != e; ++i) {
- unsigned Flag = StringSwitch<unsigned>(IFlagsStr.substr(i, 1))
- .Case("a", ARM_PROC::A)
- .Case("i", ARM_PROC::I)
- .Case("f", ARM_PROC::F)
- .Default(~0U);
-
- // If some specific iflag is already set, it means that some letter is
- // present more than once, this is not acceptable.
- if (Flag == ~0U || (IFlags & Flag))
- return MatchOperand_NoMatch;
+ if (IFlagsStr != "none") {
+ for (int i = 0, e = IFlagsStr.size(); i != e; ++i) {
+ unsigned Flag = StringSwitch<unsigned>(IFlagsStr.substr(i, 1))
+ .Case("a", ARM_PROC::A)
+ .Case("i", ARM_PROC::I)
+ .Case("f", ARM_PROC::F)
+ .Default(~0U);
+
+ // If some specific iflag is already set, it means that some letter is
+ // present more than once, this is not acceptable.
+ if (Flag == ~0U || (IFlags & Flag))
+ return MatchOperand_NoMatch;
- IFlags |= Flag;
+ IFlags |= Flag;
+ }
}
Parser.Lex(); // Eat identifier token.
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
StringRef Mask = Tok.getString();
+ if (isMClass()) {
+ // See ARMv6-M 10.1.1
+ unsigned FlagsVal = StringSwitch<unsigned>(Mask)
+ .Case("apsr", 0)
+ .Case("iapsr", 1)
+ .Case("eapsr", 2)
+ .Case("xpsr", 3)
+ .Case("ipsr", 5)
+ .Case("epsr", 6)
+ .Case("iepsr", 7)
+ .Case("msp", 8)
+ .Case("psp", 9)
+ .Case("primask", 16)
+ .Case("basepri", 17)
+ .Case("basepri_max", 18)
+ .Case("faultmask", 19)
+ .Case("control", 20)
+ .Default(~0U);
+
+ if (FlagsVal == ~0U)
+ return MatchOperand_NoMatch;
+
+ if (!hasV7Ops() && FlagsVal >= 17 && FlagsVal <= 19)
+ // basepri, basepri_max and faultmask only valid for V7m.
+ return MatchOperand_NoMatch;
+
+ Parser.Lex(); // Eat identifier token.
+ Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S));
+ return MatchOperand_Success;
+ }
+
// Split spec_reg from flag, example: CPSR_sxf => "CPSR" and "sxf"
size_t Start = 0, Next = Mask.find('_');
StringRef Flags = "";
if (!Flags.empty())
return MatchOperand_NoMatch;
else
- FlagsVal = 0; // No flag
+ FlagsVal = 8; // No flag
}
} else if (SpecReg == "cpsr" || SpecReg == "spsr") {
if (Flags == "all") // cpsr_all is an alias for cpsr_fc
Error(E, "'asr' shift amount must be in range [1,32]");
return MatchOperand_ParseFail;
}
- // asr #32 encoded as asr #0.
+ // asr #32 encoded as asr #0, but is not allowed in Thumb2 mode.
+ if (isThumb() && Val == 32) {
+ Error(E, "'asr #32' shift amount not allowed in Thumb mode");
+ return MatchOperand_ParseFail;
+ }
if (Val == 32) Val = 0;
} else {
// Shift amount must be in [1,32]
parseRotImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
const AsmToken &Tok = Parser.getTok();
SMLoc S = Tok.getLoc();
- if (Tok.isNot(AsmToken::Identifier)) {
- Error(S, "rotate operator 'ror' expected");
- return MatchOperand_ParseFail;
- }
+ if (Tok.isNot(AsmToken::Identifier))
+ return MatchOperand_NoMatch;
StringRef ShiftName = Tok.getString();
- if (ShiftName != "ror" && ShiftName != "ROR") {
- Error(S, "rotate operator 'ror' expected");
- return MatchOperand_ParseFail;
- }
+ if (ShiftName != "ror" && ShiftName != "ROR")
+ return MatchOperand_NoMatch;
Parser.Lex(); // Eat the operator.
// A '#' and a rotate amount.
return MatchOperand_Success;
}
+/// cvtT2LdrdPre - Convert parsed operands to MCInst.
+/// Needed here because the Asm Gen Matcher can't handle properly tied operands
+/// when they refer multiple MIOperands inside a single one.
+bool ARMAsmParser::
+cvtT2LdrdPre(MCInst &Inst, unsigned Opcode,
+ const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ // Rt, Rt2
+ ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
+ ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
+ // Create a writeback register dummy placeholder.
+ Inst.addOperand(MCOperand::CreateReg(0));
+ // addr
+ ((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2);
+ // pred
+ ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
+ return true;
+}
+
+/// cvtT2StrdPre - Convert parsed operands to MCInst.
+/// Needed here because the Asm Gen Matcher can't handle properly tied operands
+/// when they refer multiple MIOperands inside a single one.
+bool ARMAsmParser::
+cvtT2StrdPre(MCInst &Inst, unsigned Opcode,
+ const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ // Create a writeback register dummy placeholder.
+ Inst.addOperand(MCOperand::CreateReg(0));
+ // Rt, Rt2
+ ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
+ ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
+ // addr
+ ((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2);
+ // pred
+ ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
+ return true;
+}
+
/// cvtLdWriteBackRegT2AddrModeImm8 - Convert parsed operands to MCInst.
/// Needed here because the Asm Gen Matcher can't handle properly tied operands
/// when they refer multiple MIOperands inside a single one.
return true;
}
+/// cvtStWriteBackRegT2AddrModeImm8 - Convert parsed operands to MCInst.
+/// Needed here because the Asm Gen Matcher can't handle properly tied operands
+/// when they refer multiple MIOperands inside a single one.
+bool ARMAsmParser::
+cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode,
+ const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ // Create a writeback register dummy placeholder.
+ Inst.addOperand(MCOperand::CreateImm(0));
+ ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
+ ((ARMOperand*)Operands[3])->addMemImm8OffsetOperands(Inst, 2);
+ ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
+ return true;
+}
+
/// cvtLdWriteBackRegAddrMode2 - Convert parsed operands to MCInst.
/// Needed here because the Asm Gen Matcher can't handle properly tied operands
/// when they refer multiple MIOperands inside a single one.
Operands.push_back(ARMOperand::CreateMem(BaseRegNum, 0, 0, ARM_AM::no_shift,
0, false, S, E));
+ // If there's a pre-indexing writeback marker, '!', just add it as a token
+ // operand. It's rather odd, but syntactically valid.
+ if (Parser.getTok().is(AsmToken::Exclaim)) {
+ Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the '!'.
+ }
+
return false;
}
return false;
}
+/// parseFPImm - A floating point immediate expression operand.
+ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+parseFPImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ SMLoc S = Parser.getTok().getLoc();
+
+ if (Parser.getTok().isNot(AsmToken::Hash))
+ return MatchOperand_NoMatch;
+ Parser.Lex(); // Eat the '#'.
+
+ // Handle negation, as that still comes through as a separate token.
+ bool isNegative = false;
+ if (Parser.getTok().is(AsmToken::Minus)) {
+ isNegative = true;
+ Parser.Lex();
+ }
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.is(AsmToken::Real)) {
+ APFloat RealVal(APFloat::IEEEdouble, Tok.getString());
+ uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
+ // If we had a '-' in front, toggle the sign bit.
+ IntVal ^= (uint64_t)isNegative << 63;
+ int Val = ARM_AM::getFP64Imm(APInt(64, IntVal));
+ Parser.Lex(); // Eat the token.
+ if (Val == -1) {
+ TokError("floating point value out of range");
+ return MatchOperand_ParseFail;
+ }
+ Operands.push_back(ARMOperand::CreateFPImm(Val, S, getContext()));
+ return MatchOperand_Success;
+ }
+ if (Tok.is(AsmToken::Integer)) {
+ int64_t Val = Tok.getIntVal();
+ Parser.Lex(); // Eat the token.
+ if (Val > 255 || Val < 0) {
+ TokError("encoded floating point value out of range");
+ return MatchOperand_ParseFail;
+ }
+ Operands.push_back(ARMOperand::CreateFPImm(Val, S, getContext()));
+ return MatchOperand_Success;
+ }
+
+ TokError("invalid floating point immediate");
+ return MatchOperand_ParseFail;
+}
/// Parse a arm instruction operand. For now this parses the operand regardless
/// of the mnemonic.
bool ARMAsmParser::parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
Error(Parser.getTok().getLoc(), "unexpected token in operand");
return true;
case AsmToken::Identifier: {
+ // If this is VMRS, check for the apsr_nzcv operand.
if (!tryParseRegisterWithWriteBack(Operands))
return false;
int Res = tryParseShiftRegister(Operands);
return false;
else if (Res == -1) // irrecoverable error
return true;
+ if (Mnemonic == "vmrs" && Parser.getTok().getString() == "apsr_nzcv") {
+ S = Parser.getTok().getLoc();
+ Parser.Lex();
+ Operands.push_back(ARMOperand::CreateToken("apsr_nzcv", S));
+ return false;
+ }
// Fall though for the Identifier case that is not a register or a
// special name.
return false;
}
-const MCExpr *
-ARMAsmParser::applyPrefixToExpr(const MCExpr *E,
- MCSymbolRefExpr::VariantKind Variant) {
- // Recurse over the given expression, rebuilding it to apply the given variant
- // to the leftmost symbol.
- if (Variant == MCSymbolRefExpr::VK_None)
- return E;
-
- switch (E->getKind()) {
- case MCExpr::Target:
- llvm_unreachable("Can't handle target expr yet");
- case MCExpr::Constant:
- llvm_unreachable("Can't handle lower16/upper16 of constant yet");
-
- case MCExpr::SymbolRef: {
- const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);
-
- if (SRE->getKind() != MCSymbolRefExpr::VK_None)
- return 0;
-
- return MCSymbolRefExpr::Create(&SRE->getSymbol(), Variant, getContext());
- }
-
- case MCExpr::Unary:
- llvm_unreachable("Can't handle unary expressions yet");
-
- case MCExpr::Binary: {
- const MCBinaryExpr *BE = cast<MCBinaryExpr>(E);
- const MCExpr *LHS = applyPrefixToExpr(BE->getLHS(), Variant);
- const MCExpr *RHS = BE->getRHS();
- if (!LHS)
- return 0;
-
- return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext());
- }
- }
-
- assert(0 && "Invalid expression kind!");
- return 0;
-}
-
/// \brief Given a mnemonic, split out possible predication code and carry
/// setting letters to form a canonical mnemonic and flags.
//
bool &CanAcceptPredicationCode) {
if (Mnemonic == "and" || Mnemonic == "lsl" || Mnemonic == "lsr" ||
Mnemonic == "rrx" || Mnemonic == "ror" || Mnemonic == "sub" ||
- Mnemonic == "smull" || Mnemonic == "add" || Mnemonic == "adc" ||
+ Mnemonic == "add" || Mnemonic == "adc" ||
Mnemonic == "mul" || Mnemonic == "bic" || Mnemonic == "asr" ||
- Mnemonic == "umlal" || Mnemonic == "orr" || Mnemonic == "mvn" ||
+ Mnemonic == "orr" || Mnemonic == "mvn" ||
Mnemonic == "rsb" || Mnemonic == "rsc" || Mnemonic == "orn" ||
- Mnemonic == "sbc" || Mnemonic == "mla" || Mnemonic == "umull" ||
- Mnemonic == "eor" || Mnemonic == "smlal" || Mnemonic == "neg" ||
- (Mnemonic == "mov" && !isThumb())) {
+ Mnemonic == "sbc" || Mnemonic == "eor" || Mnemonic == "neg" ||
+ (!isThumb() && (Mnemonic == "smull" || Mnemonic == "mov" ||
+ Mnemonic == "mla" || Mnemonic == "smlal" ||
+ Mnemonic == "umlal" || Mnemonic == "umull"))) {
CanAcceptCarrySet = true;
- } else {
+ } else
CanAcceptCarrySet = false;
- }
if (Mnemonic == "cbnz" || Mnemonic == "setend" || Mnemonic == "dmb" ||
Mnemonic == "cps" || Mnemonic == "mcr2" || Mnemonic == "it" ||
!isThumb()) ||
((Mnemonic.startswith("rfe") || Mnemonic.startswith("srs")) &&
!isThumb()) ||
- Mnemonic.startswith("cps") || (Mnemonic == "movs" && isThumb())) {
+ Mnemonic.startswith("cps") || (Mnemonic == "movs" && isThumbOne())) {
CanAcceptPredicationCode = false;
- } else {
+ } else
CanAcceptPredicationCode = true;
- }
- if (isThumb())
+ if (isThumb()) {
if (Mnemonic == "bkpt" || Mnemonic == "mcr" || Mnemonic == "mcrr" ||
Mnemonic == "mrc" || Mnemonic == "mrrc" || Mnemonic == "cdp")
CanAcceptPredicationCode = false;
+ }
}
bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
// We do this as post-processing of the explicit operands rather than just
// conditionally adding the cc_out in the first place because we need
// to check the type of the parsed immediate operand.
- if (Mnemonic == "mov" && Operands.size() > 4 &&
+ if (Mnemonic == "mov" && Operands.size() > 4 && !isThumb() &&
!static_cast<ARMOperand*>(Operands[4])->isARMSOImm() &&
static_cast<ARMOperand*>(Operands[4])->isImm0_65535Expr() &&
static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
// 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 &&
+ if (((isThumb() && Mnemonic == "add") ||
+ (isThumbTwo() && Mnemonic == "sub")) &&
+ Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->getReg() == ARM::SP &&
(static_cast<ARMOperand*>(Operands[5])->isReg() ||
static_cast<ARMOperand*>(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
+ // For Thumb2, add/sub immediate does not have a cc_out operand for the
+ // imm0_4095 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 &&
+ if (isThumbTwo() && (Mnemonic == "add" || Mnemonic == "sub") &&
+ Operands.size() == 6 &&
static_cast<ARMOperand*>(Operands[3])->isReg() &&
static_cast<ARMOperand*>(Operands[4])->isReg() &&
static_cast<ARMOperand*>(Operands[5])->isImm()) {
// 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<ARMOperand*>(Operands[4])->getReg()) &&
+ isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) &&
isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg()) &&
static_cast<ARMOperand*>(Operands[5])->isImm0_7())
return false;
return true;
}
+ // The thumb2 multiply instruction doesn't have a CCOut register, so
+ // if we have a "mul" mnemonic in Thumb mode, check if we'll be able to
+ // use the 16-bit encoding or not.
+ if (isThumbTwo() && Mnemonic == "mul" && Operands.size() == 6 &&
+ static_cast<ARMOperand*>(Operands[1])->getReg() == 0 &&
+ static_cast<ARMOperand*>(Operands[3])->isReg() &&
+ static_cast<ARMOperand*>(Operands[4])->isReg() &&
+ static_cast<ARMOperand*>(Operands[5])->isReg() &&
+ // If the registers aren't low regs, the destination reg isn't the
+ // same as one of the source regs, or the cc_out operand is zero
+ // outside of an IT block, we have to use the 32-bit encoding, so
+ // remove the cc_out operand.
+ (!isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) ||
+ !isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg()) ||
+ !inITBlock() ||
+ (static_cast<ARMOperand*>(Operands[3])->getReg() !=
+ static_cast<ARMOperand*>(Operands[5])->getReg() &&
+ static_cast<ARMOperand*>(Operands[3])->getReg() !=
+ static_cast<ARMOperand*>(Operands[4])->getReg())))
+ 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
}
if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ SMLoc Loc = getLexer().getLoc();
Parser.EatToEndOfStatement();
- return TokError("unexpected token in argument list");
+ return Error(Loc, "unexpected token in argument list");
}
Parser.Lex(); // Consume the EndOfStatement
// ARM mode 'blx' need special handling, as the register operand version
// is predicable, but the label operand version is not. So, we can't rely
// on the Mnemonic based checking to correctly figure out when to put
- // a CondCode operand in the list. If we're trying to match the label
- // version, remove the CondCode operand here.
+ // a k_CondCode operand in the list. If we're trying to match the label
+ // version, remove the k_CondCode operand here.
if (!isThumb() && Mnemonic == "blx" && Operands.size() == 3 &&
static_cast<ARMOperand*>(Operands[2])->isImm()) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands[1]);
delete Op;
}
}
+ // VCMP{E} does the same thing, but with a different operand count.
+ if ((Mnemonic == "vcmp" || Mnemonic == "vcmpe") && Operands.size() == 5 &&
+ static_cast<ARMOperand*>(Operands[4])->isImm()) {
+ ARMOperand *Op = static_cast<ARMOperand*>(Operands[4]);
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm());
+ if (CE && CE->getValue() == 0) {
+ Operands.erase(Operands.begin() + 4);
+ Operands.push_back(ARMOperand::CreateToken("#0", Op->getStartLoc()));
+ delete Op;
+ }
+ }
// Similarly, the Thumb1 "RSB" instruction has a literal "#0" on the
// end. Convert it to a token here.
if (Mnemonic == "rsb" && isThumb() && Operands.size() == 6 &&
MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
SMLoc Loc = Operands[0]->getStartLoc();
// Check the IT block state first.
- if (inITBlock()) {
+ // NOTE: In Thumb mode, the BKPT instruction has the interesting property of
+ // being allowed in IT blocks, but not being predicable. It just always
+ // executes.
+ if (inITBlock() && Inst.getOpcode() != ARM::tBKPT) {
unsigned bit = 1;
if (ITState.FirstCond)
ITState.FirstCond = false;
// 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::tBcc &&
- Inst.getOpcode() != ARM::t2Bcc)
+ ARMCC::AL && Inst.getOpcode() != ARM::tB &&
+ Inst.getOpcode() != ARM::t2B)
return Error(Loc, "predicated instructions must be in IT block");
switch (Inst.getOpcode()) {
}
case ARM::tSTMIA_UPD: {
bool listContainsBase;
- if (checkLowRegisterList(Inst, 4, 0, 0, listContainsBase))
+ if (checkLowRegisterList(Inst, 4, 0, 0, listContainsBase) && !isThumbTwo())
return Error(Operands[4]->getStartLoc(),
"registers must be in range r0-r7");
break;
if (Inst.getOperand(3).getImm() < 8 && Operands.size() == 6)
Inst.setOpcode(ARM::tADDi3);
break;
+ case ARM::tSUBi8:
+ // 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
+ // to encoding T2 if <Rd> is specified and encoding T2 is preferred
+ // to encoding T1 if <Rd> is omitted."
+ if (Inst.getOperand(3).getImm() < 8 && Operands.size() == 6)
+ Inst.setOpcode(ARM::tSUBi3);
+ break;
+ case ARM::tB:
+ // A Thumb conditional branch outside of an IT block is a tBcc.
+ if (Inst.getOperand(1).getImm() != ARMCC::AL && !inITBlock())
+ Inst.setOpcode(ARM::tBcc);
+ break;
+ case ARM::t2B:
+ // A Thumb2 conditional branch outside of an IT block is a t2Bcc.
+ if (Inst.getOperand(1).getImm() != ARMCC::AL && !inITBlock())
+ Inst.setOpcode(ARM::t2Bcc);
+ break;
case ARM::t2Bcc:
// If the conditional is AL or we're in an IT block, we really want t2B.
if (Inst.getOperand(1).getImm() == ARMCC::AL || inITBlock())
}
break;
}
+ case ARM::tSTMIA_UPD: {
+ // If the register list contains any high registers, we need to use
+ // the 32-bit encoding instead if we're in Thumb2. Otherwise, this
+ // should have generated an error in validateInstruction().
+ unsigned Rn = Inst.getOperand(0).getReg();
+ bool listContainsBase;
+ if (checkLowRegisterList(Inst, 4, Rn, 0, listContainsBase)) {
+ // 16-bit encoding isn't sufficient. Switch to the 32-bit version.
+ assert (isThumbTwo());
+ Inst.setOpcode(ARM::t2STMIA_UPD);
+ }
+ break;
+ }
+ case ARM::t2MOVi: {
+ // If we can use the 16-bit encoding and the user didn't explicitly
+ // request the 32-bit variant, transform it here.
+ if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
+ Inst.getOperand(1).getImm() <= 255 &&
+ ((!inITBlock() && Inst.getOperand(2).getImm() == ARMCC::AL &&
+ Inst.getOperand(4).getReg() == ARM::CPSR) ||
+ (inITBlock() && Inst.getOperand(4).getReg() == 0)) &&
+ (!static_cast<ARMOperand*>(Operands[2])->isToken() ||
+ static_cast<ARMOperand*>(Operands[2])->getToken() != ".w")) {
+ // The operands aren't in the same order for tMOVi8...
+ MCInst TmpInst;
+ TmpInst.setOpcode(ARM::tMOVi8);
+ TmpInst.addOperand(Inst.getOperand(0));
+ TmpInst.addOperand(Inst.getOperand(4));
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(Inst.getOperand(2));
+ TmpInst.addOperand(Inst.getOperand(3));
+ Inst = TmpInst;
+ }
+ break;
+ }
+ case ARM::t2MOVr: {
+ // If we can use the 16-bit encoding and the user didn't explicitly
+ // request the 32-bit variant, transform it here.
+ if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
+ isARMLowRegister(Inst.getOperand(1).getReg()) &&
+ Inst.getOperand(2).getImm() == ARMCC::AL &&
+ Inst.getOperand(4).getReg() == ARM::CPSR &&
+ (!static_cast<ARMOperand*>(Operands[2])->isToken() ||
+ static_cast<ARMOperand*>(Operands[2])->getToken() != ".w")) {
+ // The operands aren't the same for tMOV[S]r... (no cc_out)
+ MCInst TmpInst;
+ TmpInst.setOpcode(Inst.getOperand(4).getReg() ? ARM::tMOVSr : ARM::tMOVr);
+ TmpInst.addOperand(Inst.getOperand(0));
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(Inst.getOperand(2));
+ TmpInst.addOperand(Inst.getOperand(3));
+ Inst = TmpInst;
+ }
+ break;
+ }
+ case ARM::t2SXTH:
+ case ARM::t2SXTB:
+ case ARM::t2UXTH:
+ case ARM::t2UXTB: {
+ // If we can use the 16-bit encoding and the user didn't explicitly
+ // request the 32-bit variant, transform it here.
+ if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
+ isARMLowRegister(Inst.getOperand(1).getReg()) &&
+ Inst.getOperand(2).getImm() == 0 &&
+ (!static_cast<ARMOperand*>(Operands[2])->isToken() ||
+ static_cast<ARMOperand*>(Operands[2])->getToken() != ".w")) {
+ unsigned NewOpc;
+ switch (Inst.getOpcode()) {
+ default: llvm_unreachable("Illegal opcode!");
+ case ARM::t2SXTH: NewOpc = ARM::tSXTH; break;
+ case ARM::t2SXTB: NewOpc = ARM::tSXTB; break;
+ case ARM::t2UXTH: NewOpc = ARM::tUXTH; break;
+ case ARM::t2UXTB: NewOpc = ARM::tUXTB; break;
+ }
+ // The operands aren't the same for thumb1 (no rotate operand).
+ MCInst TmpInst;
+ TmpInst.setOpcode(NewOpc);
+ TmpInst.addOperand(Inst.getOperand(0));
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(Inst.getOperand(3));
+ TmpInst.addOperand(Inst.getOperand(4));
+ Inst = TmpInst;
+ }
+ break;
+ }
case ARM::t2IT: {
// The mask bits for all but the first condition are represented as
// the low bit of the condition code value implies 't'. We currently