#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
class ARMAsmParser : public MCTargetAsmParser {
MCSubtargetInfo &STI;
MCAsmParser &Parser;
+ const MCInstrInfo &MII;
const MCRegisterInfo *MRI;
// Unwind directives state
if (!inITBlock()) return;
// Move to the next instruction in the IT block, if there is one. If not,
// mark the block as done.
- unsigned TZ = CountTrailingZeros_32(ITState.Mask);
+ unsigned TZ = countTrailingZeros(ITState.Mask);
if (++ITState.CurPosition == 5 - TZ)
ITState.CurPosition = ~0U; // Done with the IT block after this.
}
StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
bool &CarrySetting, unsigned &ProcessorIMod,
StringRef &ITMask);
- void getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet,
+ void getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst,
+ bool &CanAcceptCarrySet,
bool &CanAcceptPredicationCode);
bool isThumb() const {
bool isThumbTwo() const {
return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2);
}
+ bool hasThumb() const {
+ return STI.getFeatureBits() & ARM::HasV4TOps;
+ }
bool hasV6Ops() const {
return STI.getFeatureBits() & ARM::HasV6Ops;
}
bool hasV7Ops() const {
return STI.getFeatureBits() & ARM::HasV7Ops;
}
+ bool hasV8Ops() const {
+ return STI.getFeatureBits() & ARM::HasV8Ops;
+ }
+ bool hasARM() const {
+ return !(STI.getFeatureBits() & ARM::FeatureNoARM);
+ }
+
void SwitchMode() {
unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb));
setAvailableFeatures(FB);
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseMemBarrierOptOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
+ OperandMatchResultTy parseInstSyncBarrierOptOperand(
+ SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseProcIFlagsOperand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy parseMSRMaskOperand(
SMLoc &EndLoc);
// Asm Match Converter Methods
- void cvtT2LdrdPre(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtT2StrdPre(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdWriteBackRegAddrMode2(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdWriteBackRegAddrModeImm12(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStWriteBackRegAddrModeImm12(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStWriteBackRegAddrMode2(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStWriteBackRegAddrMode3(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdExtTWriteBackImm(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdExtTWriteBackReg(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStExtTWriteBackImm(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStExtTWriteBackReg(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdrdPre(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtStrdPre(MCInst &Inst, const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtLdWriteBackRegAddrMode3(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
void cvtThumbMultiply(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtVLDwbFixed(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtVLDwbRegister(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtVSTwbFixed(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &);
- void cvtVSTwbRegister(MCInst &Inst,
+ void cvtThumbBranches(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &);
+
bool validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
bool processInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
bool shouldOmitCCOutOperand(StringRef Mnemonic,
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
-
+ bool shouldOmitPredicateOperand(StringRef Mnemonic,
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands);
public:
enum ARMMatchResultTy {
Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY,
};
- ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser)
- : MCTargetAsmParser(), STI(_STI), Parser(_Parser), FPReg(-1) {
+ ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser,
+ const MCInstrInfo &MII)
+ : MCTargetAsmParser(), STI(_STI), Parser(_Parser), MII(MII), FPReg(-1) {
MCAsmParserExtension::Initialize(_Parser);
// Cache the MCRegisterInfo.
- MRI = &getContext().getRegisterInfo();
+ MRI = getContext().getRegisterInfo();
// Initialize the set of available features.
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
k_CoprocOption,
k_Immediate,
k_MemBarrierOpt,
+ k_InstSyncBarrierOpt,
k_Memory,
k_PostIndexRegister,
k_MSRMask,
ARM_MB::MemBOpt Val;
};
+ struct ISBOptOp {
+ ARM_ISB::InstSyncBOpt Val;
+ };
+
struct IFlagsOp {
ARM_PROC::IFlags Val;
};
struct CopOp Cop;
struct CoprocOptionOp CoprocOption;
struct MBOptOp MBOpt;
+ struct ISBOptOp ISBOpt;
struct ITMaskOp ITMask;
struct IFlagsOp IFlags;
struct MMaskOp MMask;
case k_MemBarrierOpt:
MBOpt = o.MBOpt;
break;
+ case k_InstSyncBarrierOpt:
+ ISBOpt = o.ISBOpt;
case k_Memory:
Memory = o.Memory;
break;
return MBOpt.Val;
}
+ ARM_ISB::InstSyncBOpt getInstSyncBarrierOpt() const {
+ assert(Kind == k_InstSyncBarrierOpt && "Invalid access!");
+ return ISBOpt.Val;
+ }
+
ARM_PROC::IFlags getProcIFlags() const {
assert(Kind == k_ProcIFlags && "Invalid access!");
return IFlags.Val;
bool isITMask() const { return Kind == k_ITCondMask; }
bool isITCondCode() const { return Kind == k_CondCode; }
bool isImm() const { return Kind == k_Immediate; }
+ // checks whether this operand is an unsigned offset which fits is a field
+ // of specified width and scaled by a specific number of bits
+ template<unsigned width, unsigned scale>
+ bool isUnsignedOffset() 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);
+ return ((Val % Align) == 0) && (Val >= 0) && (Val <= Max);
+ }
+ 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
+ // relocable expression...
+ bool isThumbMemPC() const {
+ int64_t Val = 0;
+ if (isImm()) {
+ if (isa<MCSymbolRefExpr>(Imm.Val)) return true;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val);
+ if (!CE) return false;
+ Val = CE->getValue();
+ }
+ else if (isMem()) {
+ if(!Memory.OffsetImm || Memory.OffsetRegNum) return false;
+ if(Memory.BaseRegNum != ARM::PC) return false;
+ Val = Memory.OffsetImm->getValue();
+ }
+ else return false;
+ return ((Val % 4) == 0) && (Val >= 0) && (Val <= 1020);
+ }
bool isFPImm() const {
if (!isImm()) return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
int64_t Value = CE->getValue();
return Value >= 0 && Value < 65536;
}
+ bool isImm256_65535Expr() const {
+ if (!isImm()) return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ // If it's not a constant expression, it'll generate a fixup and be
+ // handled later.
+ if (!CE) return true;
+ int64_t Value = CE->getValue();
+ return Value >= 256 && Value < 65536;
+ }
bool isImm0_65535Expr() const {
if (!isImm()) return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Value = CE->getValue();
- return ARM_AM::getT2SOImmVal(~Value) != -1;
+ return ARM_AM::getT2SOImmVal(Value) == -1 &&
+ ARM_AM::getT2SOImmVal(~Value) != -1;
}
bool isT2SOImmNeg() const {
if (!isImm()) return false;
bool isSPRRegList() const { return Kind == k_SPRRegisterList; }
bool isToken() const { return Kind == k_Token; }
bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; }
+ bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; }
bool isMem() const { return Kind == k_Memory; }
bool isShifterImm() const { return Kind == k_ShifterImmediate; }
bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; }
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
int64_t Val = CE->getValue();
- return Val > -4096 && Val < 4096;
+ return (Val == INT32_MIN) || (Val > -4096 && Val < 4096);
}
bool isAddrMode3() const {
// If we have an immediate that's not a constant, treat it as a label
Inst.addOperand(MCOperand::CreateImm(-CE->getValue()));
}
+ void addUnsignedOffset_b8s2Operands(MCInst &Inst, unsigned N) const {
+ if(const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm())) {
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue() >> 2));
+ return;
+ }
+
+ const MCSymbolRefExpr *SR = dyn_cast<MCSymbolRefExpr>(Imm.Val);
+ assert(SR && "Unknown value type!");
+ Inst.addOperand(MCOperand::CreateExpr(SR));
+ }
+
+ void addThumbMemPCOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ if (isImm()) {
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ if (CE) {
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
+ return;
+ }
+
+ const MCSymbolRefExpr *SR = dyn_cast<MCSymbolRefExpr>(Imm.Val);
+ assert(SR && "Unknown value type!");
+ Inst.addOperand(MCOperand::CreateExpr(SR));
+ return;
+ }
+
+ assert(isMem() && "Unknown value type!");
+ assert(isa<MCConstantExpr>(Memory.OffsetImm) && "Unknown value type!");
+ Inst.addOperand(MCOperand::CreateImm(Memory.OffsetImm->getValue()));
+ }
+
void addARMSOImmNotOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
// The operand is actually a so_imm, but we have its bitwise
Inst.addOperand(MCOperand::CreateImm(unsigned(getMemBarrierOpt())));
}
+ void addInstSyncBarrierOptOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateImm(unsigned(getInstSyncBarrierOpt())));
+ }
+
void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum));
void addMemPCRelImm12Operands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
int32_t Imm = Memory.OffsetImm->getValue();
- // FIXME: Handle #-0
- if (Imm == INT32_MIN) Imm = 0;
Inst.addOperand(MCOperand::CreateImm(Imm));
}
}
static ARMOperand *
- CreateRegList(const SmallVectorImpl<std::pair<unsigned, SMLoc> > &Regs,
+ CreateRegList(SmallVectorImpl<std::pair<unsigned, unsigned> > &Regs,
SMLoc StartLoc, SMLoc EndLoc) {
+ assert (Regs.size() > 0 && "RegList contains no registers?");
KindTy Kind = k_RegisterList;
- if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().first))
+ if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().second))
Kind = k_DPRRegisterList;
else if (ARMMCRegisterClasses[ARM::SPRRegClassID].
- contains(Regs.front().first))
+ contains(Regs.front().second))
Kind = k_SPRRegisterList;
+ // Sort based on the register encoding values.
+ array_pod_sort(Regs.begin(), Regs.end());
+
ARMOperand *Op = new ARMOperand(Kind);
- for (SmallVectorImpl<std::pair<unsigned, SMLoc> >::const_iterator
+ for (SmallVectorImpl<std::pair<unsigned, unsigned> >::const_iterator
I = Regs.begin(), E = Regs.end(); I != E; ++I)
- Op->Registers.push_back(I->first);
- array_pod_sort(Op->Registers.begin(), Op->Registers.end());
+ Op->Registers.push_back(I->second);
Op->StartLoc = StartLoc;
Op->EndLoc = EndLoc;
return Op;
return Op;
}
+ static ARMOperand *CreateInstSyncBarrierOpt(ARM_ISB::InstSyncBOpt Opt,
+ SMLoc S) {
+ ARMOperand *Op = new ARMOperand(k_InstSyncBarrierOpt);
+ Op->ISBOpt.Val = Opt;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
static ARMOperand *CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_ProcIFlags);
Op->IFlags.Val = IFlags;
getImm()->print(OS);
break;
case k_MemBarrierOpt:
- OS << "<ARM_MB::" << MemBOptToString(getMemBarrierOpt()) << ">";
+ OS << "<ARM_MB::" << MemBOptToString(getMemBarrierOpt(), false) << ">";
+ break;
+ case k_InstSyncBarrierOpt:
+ OS << "<ARM_ISB::" << InstSyncBOptToString(getInstSyncBarrierOpt()) << ">";
break;
case k_Memory:
OS << "<memory "
// The reglist instructions have at most 16 registers, so reserve
// space for that many.
- SmallVector<std::pair<unsigned, SMLoc>, 16> Registers;
+ int EReg = 0;
+ SmallVector<std::pair<unsigned, unsigned>, 16> Registers;
// Allow Q regs and just interpret them as the two D sub-registers.
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
Reg = getDRegFromQReg(Reg);
- Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
+ EReg = MRI->getEncodingValue(Reg);
+ Registers.push_back(std::pair<unsigned, unsigned>(EReg, Reg));
++Reg;
}
const MCRegisterClass *RC;
return Error(RegLoc, "invalid register in register list");
// Store the register.
- Registers.push_back(std::pair<unsigned, SMLoc>(Reg, RegLoc));
+ EReg = MRI->getEncodingValue(Reg);
+ Registers.push_back(std::pair<unsigned, unsigned>(EReg, Reg));
// 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
// 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));
+ EReg = MRI->getEncodingValue(Reg);
+ Registers.push_back(std::pair<unsigned, unsigned>(EReg, Reg));
}
continue;
}
continue;
}
// 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));
- if (isQReg)
- Registers.push_back(std::pair<unsigned, SMLoc>(++Reg, RegLoc));
+ EReg = MRI->getEncodingValue(Reg);
+ Registers.push_back(std::pair<unsigned, unsigned>(EReg, Reg));
+ if (isQReg) {
+ EReg = MRI->getEncodingValue(++Reg);
+ Registers.push_back(std::pair<unsigned, unsigned>(EReg, Reg));
+ }
}
if (Parser.getTok().isNot(AsmToken::RCurly))
// There's an optional '#' token here. Normally there wouldn't be, but
// inline assemble puts one in, and it's friendly to accept that.
if (Parser.getTok().is(AsmToken::Hash))
- Parser.Lex(); // Eat the '#'
+ Parser.Lex(); // Eat '#' or '$'.
const MCExpr *LaneIndex;
SMLoc Loc = Parser.getTok().getLoc();
Opt = StringSwitch<unsigned>(OptStr.slice(0, OptStr.size()).lower())
.Case("sy", ARM_MB::SY)
.Case("st", ARM_MB::ST)
+ .Case("ld", ARM_MB::LD)
.Case("sh", ARM_MB::ISH)
.Case("ish", ARM_MB::ISH)
.Case("shst", ARM_MB::ISHST)
.Case("ishst", ARM_MB::ISHST)
+ .Case("ishld", ARM_MB::ISHLD)
.Case("nsh", ARM_MB::NSH)
.Case("un", ARM_MB::NSH)
.Case("nshst", ARM_MB::NSHST)
+ .Case("nshld", ARM_MB::NSHLD)
.Case("unst", ARM_MB::NSHST)
.Case("osh", ARM_MB::OSH)
.Case("oshst", ARM_MB::OSHST)
+ .Case("oshld", ARM_MB::OSHLD)
.Default(~0U);
+ // ishld, oshld, nshld and ld are only available from ARMv8.
+ if (!hasV8Ops() && (Opt == ARM_MB::ISHLD || Opt == ARM_MB::OSHLD ||
+ Opt == ARM_MB::NSHLD || Opt == ARM_MB::LD))
+ Opt = ~0U;
+
if (Opt == ~0U)
return MatchOperand_NoMatch;
Tok.is(AsmToken::Dollar) ||
Tok.is(AsmToken::Integer)) {
if (Parser.getTok().isNot(AsmToken::Integer))
- Parser.Lex(); // Eat the '#'.
+ Parser.Lex(); // Eat '#' or '$'.
SMLoc Loc = Parser.getTok().getLoc();
const MCExpr *MemBarrierID;
return MatchOperand_Success;
}
+/// parseInstSyncBarrierOptOperand - Try to parse ISB inst sync barrier options.
+ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+parseInstSyncBarrierOptOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ SMLoc S = Parser.getTok().getLoc();
+ const AsmToken &Tok = Parser.getTok();
+ unsigned Opt;
+
+ if (Tok.is(AsmToken::Identifier)) {
+ StringRef OptStr = Tok.getString();
+
+ if (OptStr.lower() == "sy")
+ Opt = ARM_ISB::SY;
+ else
+ return MatchOperand_NoMatch;
+
+ Parser.Lex(); // Eat identifier token.
+ } else if (Tok.is(AsmToken::Hash) ||
+ Tok.is(AsmToken::Dollar) ||
+ Tok.is(AsmToken::Integer)) {
+ if (Parser.getTok().isNot(AsmToken::Integer))
+ Parser.Lex(); // Eat '#' or '$'.
+ SMLoc Loc = Parser.getTok().getLoc();
+
+ const MCExpr *ISBarrierID;
+ if (getParser().parseExpression(ISBarrierID)) {
+ Error(Loc, "illegal expression");
+ return MatchOperand_ParseFail;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ISBarrierID);
+ if (!CE) {
+ Error(Loc, "constant expression expected");
+ return MatchOperand_ParseFail;
+ }
+
+ int Val = CE->getValue();
+ if (Val & ~0xf) {
+ Error(Loc, "immediate value out of range");
+ return MatchOperand_ParseFail;
+ }
+
+ Opt = ARM_ISB::RESERVED_0 + Val;
+ } else
+ return MatchOperand_ParseFail;
+
+ Operands.push_back(ARMOperand::CreateInstSyncBarrierOpt(
+ (ARM_ISB::InstSyncBOpt)Opt, S));
+ return MatchOperand_Success;
+}
+
+
/// parseProcIFlagsOperand - Try to parse iflags from CPS instruction.
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
parseProcIFlagsOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
Error(S, "'be' or 'le' operand expected");
return MatchOperand_ParseFail;
}
- int Val = StringSwitch<int>(Tok.getString())
+ int Val = StringSwitch<int>(Tok.getString().lower())
.Case("be", 1)
.Case("le", 0)
.Default(-1);
// Do immediates first, as we always parse those if we have a '#'.
if (Parser.getTok().is(AsmToken::Hash) ||
Parser.getTok().is(AsmToken::Dollar)) {
- Parser.Lex(); // Eat the '#'.
+ Parser.Lex(); // Eat '#' or '$'.
// Explicitly look for a '-', as we need to encode negative zero
// differently.
bool isNegative = Parser.getTok().is(AsmToken::Minus);
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.
-void ARMAsmParser::
-cvtT2LdrdPre(MCInst &Inst,
- 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);
-}
-
-/// 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.
-void ARMAsmParser::
-cvtT2StrdPre(MCInst &Inst,
- 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);
-}
-
-/// 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.
-void ARMAsmParser::
-cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
-
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
-
- ((ARMOperand*)Operands[3])->addMemImm8OffsetOperands(Inst, 2);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// 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.
-void ARMAsmParser::
-cvtStWriteBackRegT2AddrModeImm8(MCInst &Inst,
- 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);
-}
-
-/// 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.
-void ARMAsmParser::
-cvtLdWriteBackRegAddrMode2(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
-
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
-
- ((ARMOperand*)Operands[3])->addAddrMode2Operands(Inst, 3);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtLdWriteBackRegAddrModeImm12 - 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.
-void ARMAsmParser::
-cvtLdWriteBackRegAddrModeImm12(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
-
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
-
- ((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-
-/// cvtStWriteBackRegAddrModeImm12 - 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.
-void ARMAsmParser::
-cvtStWriteBackRegAddrModeImm12(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- ((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtStWriteBackRegAddrMode2 - 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.
-void ARMAsmParser::
-cvtStWriteBackRegAddrMode2(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- ((ARMOperand*)Operands[3])->addAddrMode2Operands(Inst, 3);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtStWriteBackRegAddrMode3 - 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.
-void ARMAsmParser::
-cvtStWriteBackRegAddrMode3(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- ((ARMOperand*)Operands[3])->addAddrMode3Operands(Inst, 3);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtLdExtTWriteBackImm - 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.
-void ARMAsmParser::
-cvtLdExtTWriteBackImm(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Rt
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // addr
- ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
- // offset
- ((ARMOperand*)Operands[4])->addPostIdxImm8Operands(Inst, 1);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtLdExtTWriteBackReg - 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.
-void ARMAsmParser::
-cvtLdExtTWriteBackReg(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Rt
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // addr
- ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
- // offset
- ((ARMOperand*)Operands[4])->addPostIdxRegOperands(Inst, 2);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtStExtTWriteBackImm - 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.
-void ARMAsmParser::
-cvtStExtTWriteBackImm(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Rt
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- // addr
- ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
- // offset
- ((ARMOperand*)Operands[4])->addPostIdxImm8Operands(Inst, 1);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtStExtTWriteBackReg - 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.
-void ARMAsmParser::
-cvtStExtTWriteBackReg(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Rt
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- // addr
- ((ARMOperand*)Operands[3])->addMemNoOffsetOperands(Inst, 1);
- // offset
- ((ARMOperand*)Operands[4])->addPostIdxRegOperands(Inst, 2);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtLdrdPre - 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.
-void ARMAsmParser::
-cvtLdrdPre(MCInst &Inst,
- 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::CreateImm(0));
- // addr
- ((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtStrdPre - 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.
-void ARMAsmParser::
-cvtStrdPre(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Rt, Rt2
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
- // addr
- ((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtLdWriteBackRegAddrMode3 - 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.
-void ARMAsmParser::
-cvtLdWriteBackRegAddrMode3(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- ((ARMOperand*)Operands[3])->addAddrMode3Operands(Inst, 3);
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-/// cvtThumbMultiply - 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.
+/// Convert parsed operands to MCInst. Needed here because this instruction
+/// only has two register operands, but multiplication is commutative so
+/// assemblers should accept both "mul rD, rN, rD" and "mul rD, rD, rN".
void ARMAsmParser::
cvtThumbMultiply(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
}
void ARMAsmParser::
-cvtVLDwbFixed(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Vd
- ((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Vn
- ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
+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;
-void ARMAsmParser::
-cvtVLDwbRegister(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Vd
- ((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Vn
- ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
- // Vm
- ((ARMOperand*)Operands[5])->addRegOperands(Inst, 1);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
+ case ARM::t2B:
+ case ARM::t2Bcc: CondOp = 1; ImmOp = 3; break;
-void ARMAsmParser::
-cvtVSTwbFixed(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Vn
- ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
- // Vt
- ((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
-}
-
-void ARMAsmParser::
-cvtVSTwbRegister(MCInst &Inst,
- const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- // Create a writeback register dummy placeholder.
- Inst.addOperand(MCOperand::CreateImm(0));
- // Vn
- ((ARMOperand*)Operands[4])->addAlignedMemoryOperands(Inst, 2);
- // Vm
- ((ARMOperand*)Operands[5])->addRegOperands(Inst, 1);
- // Vt
- ((ARMOperand*)Operands[3])->addVecListOperands(Inst, 1);
- // pred
- ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
+ 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
Parser.getTok().is(AsmToken::Dollar) ||
Parser.getTok().is(AsmToken::Integer)) {
if (Parser.getTok().isNot(AsmToken::Integer))
- Parser.Lex(); // Eat the '#'.
+ Parser.Lex(); // Eat '#' or '$'.
E = Parser.getTok().getLoc();
bool isNegative = getParser().getTok().is(AsmToken::Minus);
TyOp->getToken() != ".f64"))
return MatchOperand_NoMatch;
- Parser.Lex(); // Eat the '#'.
+ Parser.Lex(); // Eat '#' or '$'.
// Handle negation, as that still comes through as a separate token.
bool isNegative = false;
Mnemonic == "mls" || Mnemonic == "smmls" || Mnemonic == "vcls" ||
Mnemonic == "vmls" || Mnemonic == "vnmls" || Mnemonic == "vacge" ||
Mnemonic == "vcge" || Mnemonic == "vclt" || Mnemonic == "vacgt" ||
- Mnemonic == "vaclt" || Mnemonic == "vacle" ||
+ Mnemonic == "vaclt" || Mnemonic == "vacle" || Mnemonic == "hlt" ||
Mnemonic == "vcgt" || Mnemonic == "vcle" || Mnemonic == "smlal" ||
Mnemonic == "umaal" || Mnemonic == "umlal" || Mnemonic == "vabal" ||
Mnemonic == "vmlal" || Mnemonic == "vpadal" || Mnemonic == "vqdmlal" ||
- Mnemonic == "fmuls")
+ Mnemonic == "fmuls" || Mnemonic == "vmaxnm" || Mnemonic == "vminnm" ||
+ Mnemonic == "vcvta" || Mnemonic == "vcvtn" || Mnemonic == "vcvtp" ||
+ Mnemonic == "vcvtm" || Mnemonic == "vrinta" || Mnemonic == "vrintn" ||
+ Mnemonic == "vrintp" || Mnemonic == "vrintm" || Mnemonic.startswith("vsel"))
return Mnemonic;
// First, split out any predication code. Ignore mnemonics we know aren't
//
// FIXME: It would be nice to autogen this.
void ARMAsmParser::
-getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet,
- bool &CanAcceptPredicationCode) {
+getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst,
+ bool &CanAcceptCarrySet, bool &CanAcceptPredicationCode) {
if (Mnemonic == "and" || Mnemonic == "lsl" || Mnemonic == "lsr" ||
Mnemonic == "rrx" || Mnemonic == "ror" || Mnemonic == "sub" ||
Mnemonic == "add" || Mnemonic == "adc" ||
} else
CanAcceptCarrySet = false;
- if (Mnemonic == "cbnz" || Mnemonic == "setend" || Mnemonic == "dmb" ||
- Mnemonic == "cps" || Mnemonic == "mcr2" || Mnemonic == "it" ||
- Mnemonic == "mcrr2" || Mnemonic == "cbz" || Mnemonic == "cdp2" ||
- Mnemonic == "trap" || Mnemonic == "mrc2" || Mnemonic == "mrrc2" ||
- Mnemonic == "dsb" || Mnemonic == "isb" || Mnemonic == "setend" ||
- (Mnemonic == "clrex" && !isThumb()) ||
- (Mnemonic == "nop" && isThumbOne()) ||
- ((Mnemonic == "pld" || Mnemonic == "pli" || Mnemonic == "pldw" ||
- Mnemonic == "ldc2" || Mnemonic == "ldc2l" ||
- Mnemonic == "stc2" || Mnemonic == "stc2l") && !isThumb()) ||
- ((Mnemonic.startswith("rfe") || Mnemonic.startswith("srs")) &&
- !isThumb()) ||
- Mnemonic.startswith("cps") || (Mnemonic == "movs" && isThumbOne())) {
+ if (Mnemonic == "bkpt" || Mnemonic == "cbnz" || Mnemonic == "setend" ||
+ Mnemonic == "cps" || Mnemonic == "it" || Mnemonic == "cbz" ||
+ Mnemonic == "trap" || Mnemonic == "hlt" || Mnemonic.startswith("crc32") ||
+ Mnemonic.startswith("cps") || Mnemonic.startswith("vsel") ||
+ Mnemonic == "vmaxnm" || Mnemonic == "vminnm" || Mnemonic == "vcvta" ||
+ Mnemonic == "vcvtn" || Mnemonic == "vcvtp" || Mnemonic == "vcvtm" ||
+ Mnemonic == "vrinta" || Mnemonic == "vrintn" || Mnemonic == "vrintp" ||
+ Mnemonic == "vrintm" || Mnemonic.startswith("aes") ||
+ Mnemonic.startswith("sha1") || Mnemonic.startswith("sha256") ||
+ (FullInst.startswith("vmull") && FullInst.endswith(".p64"))) {
+ // These mnemonics are never predicable
CanAcceptPredicationCode = false;
+ } else if (!isThumb()) {
+ // Some instructions are only predicable in Thumb mode
+ CanAcceptPredicationCode
+ = Mnemonic != "cdp2" && Mnemonic != "clrex" && Mnemonic != "mcr2" &&
+ Mnemonic != "mcrr2" && Mnemonic != "mrc2" && Mnemonic != "mrrc2" &&
+ Mnemonic != "dmb" && Mnemonic != "dsb" && Mnemonic != "isb" &&
+ Mnemonic != "pld" && Mnemonic != "pli" && Mnemonic != "pldw" &&
+ Mnemonic != "ldc2" && Mnemonic != "ldc2l" &&
+ Mnemonic != "stc2" && Mnemonic != "stc2l" &&
+ !Mnemonic.startswith("rfe") && !Mnemonic.startswith("srs");
+ } else if (isThumbOne()) {
+ CanAcceptPredicationCode = Mnemonic != "nop" && Mnemonic != "movs";
} else
CanAcceptPredicationCode = true;
-
- if (isThumb()) {
- if (Mnemonic == "bkpt" || Mnemonic == "mcr" || Mnemonic == "mcrr" ||
- Mnemonic == "mrc" || Mnemonic == "mrrc" || Mnemonic == "cdp")
- CanAcceptPredicationCode = false;
- }
}
bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
static_cast<ARMOperand*>(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 the second register is the PC, this is an
- // alternate form of ADR, which uses encoding T4, so check for that too.
- if ((!isARMLowRegister(static_cast<ARMOperand*>(Operands[3])->getReg()) ||
- !isARMLowRegister(static_cast<ARMOperand*>(Operands[4])->getReg())) &&
- static_cast<ARMOperand*>(Operands[4])->getReg() != ARM::PC &&
- static_cast<ARMOperand*>(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<ARMOperand*>(Operands[4])->getReg()) &&
static_cast<ARMOperand*>(Operands[5])->isImm0_7())
return false;
+ // 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())
+ return false;
// Otherwise, we use encoding T4, which does not have a cc_out
// operand.
return false;
}
+bool ARMAsmParser::shouldOmitPredicateOperand(
+ StringRef Mnemonic, SmallVectorImpl<MCParsedAsmOperand *> &Operands) {
+ // VRINT{Z, R, X} have a predicate operand in VFP, but not in NEON
+ unsigned RegIdx = 3;
+ if ((Mnemonic == "vrintz" || Mnemonic == "vrintx" || Mnemonic == "vrintr") &&
+ static_cast<ARMOperand *>(Operands[2])->getToken() == ".f32") {
+ if (static_cast<ARMOperand *>(Operands[3])->isToken() &&
+ static_cast<ARMOperand *>(Operands[3])->getToken() == ".f32")
+ RegIdx = 4;
+
+ if (static_cast<ARMOperand *>(Operands[RegIdx])->isReg() &&
+ (ARMMCRegisterClasses[ARM::DPRRegClassID]
+ .contains(static_cast<ARMOperand *>(Operands[RegIdx])->getReg()) ||
+ ARMMCRegisterClasses[ARM::QPRRegClassID]
+ .contains(static_cast<ARMOperand *>(Operands[RegIdx])->getReg())))
+ return true;
+ }
+ return false;
+}
+
static bool isDataTypeToken(StringRef Tok) {
return Tok == ".8" || Tok == ".16" || Tok == ".32" || Tok == ".64" ||
Tok == ".i8" || Tok == ".i16" || Tok == ".i32" || Tok == ".i64" ||
// the matcher deal with finding the right instruction or generating an
// appropriate error.
bool CanAcceptCarrySet, CanAcceptPredicationCode;
- getMnemonicAcceptInfo(Mnemonic, CanAcceptCarrySet, CanAcceptPredicationCode);
+ getMnemonicAcceptInfo(Mnemonic, Name, CanAcceptCarrySet, CanAcceptPredicationCode);
// If we had a carry-set on an instruction that can't do that, issue an
// error.
doesIgnoreDataTypeSuffix(Mnemonic, ExtraToken))
continue;
- if (ExtraToken != ".n") {
+ // For for ARM mode generate an error if the .n qualifier is used.
+ if (ExtraToken == ".n" && !isThumb()) {
+ SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Start);
+ return Error(Loc, "instruction with .n (narrow) qualifier not allowed in "
+ "arm mode");
+ }
+
+ // The .n qualifier is always discarded as that is what the tables
+ // and matcher expect. In ARM mode the .w qualifier has no effect,
+ // so discard it to avoid errors that can be caused by the matcher.
+ if (ExtraToken != ".n" && (isThumb() || ExtraToken != ".w")) {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Start);
Operands.push_back(ARMOperand::CreateToken(ExtraToken, Loc));
}
delete Op;
}
+ // Some instructions have the same mnemonic, but don't always
+ // have a predicate. Distinguish them here and delete the
+ // predicate if needed.
+ if (shouldOmitPredicateOperand(Mnemonic, Operands)) {
+ ARMOperand *Op = static_cast<ARMOperand*>(Operands[1]);
+ Operands.erase(Operands.begin() + 1);
+ delete Op;
+ }
+
// 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
// expressed as a GPRPair, so we have to manually merge them.
// FIXME: We would really like to be able to tablegen'erate this.
if (!isThumb() && Operands.size() > 4 &&
- (Mnemonic == "ldrexd" || Mnemonic == "strexd")) {
- bool isLoad = (Mnemonic == "ldrexd");
+ (Mnemonic == "ldrexd" || Mnemonic == "strexd" || Mnemonic == "ldaexd" ||
+ Mnemonic == "stlexd")) {
+ bool isLoad = (Mnemonic == "ldrexd" || Mnemonic == "ldaexd");
unsigned Idx = isLoad ? 2 : 3;
ARMOperand* Op1 = static_cast<ARMOperand*>(Operands[Idx]);
ARMOperand* Op2 = static_cast<ARMOperand*>(Operands[Idx+1]);
}
}
+ // FIXME: As said above, this is all a pretty gross hack. This instruction
+ // does not fit with other "subs" and tblgen.
+ // Adjust operands of B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction
+ // so the Mnemonic is the original name "subs" and delete the predicate
+ // operand so it will match the table entry.
+ if (isThumbTwo() && Mnemonic == "sub" && Operands.size() == 6 &&
+ static_cast<ARMOperand*>(Operands[3])->isReg() &&
+ static_cast<ARMOperand*>(Operands[3])->getReg() == ARM::PC &&
+ static_cast<ARMOperand*>(Operands[4])->isReg() &&
+ static_cast<ARMOperand*>(Operands[4])->getReg() == ARM::LR &&
+ static_cast<ARMOperand*>(Operands[5])->isImm()) {
+ ARMOperand *Op0 = static_cast<ARMOperand*>(Operands[0]);
+ Operands.erase(Operands.begin());
+ delete Op0;
+ Operands.insert(Operands.begin(), ARMOperand::CreateToken(Name, NameLoc));
+
+ ARMOperand *Op1 = static_cast<ARMOperand*>(Operands[1]);
+ Operands.erase(Operands.begin() + 1);
+ delete Op1;
+ }
return false;
}
return false;
}
-// FIXME: We would really prefer to have MCInstrInfo (the wrapper around
-// the ARMInsts array) instead. Getting that here requires awkward
-// API changes, though. Better way?
-namespace llvm {
-extern const MCInstrDesc ARMInsts[];
-}
-static const MCInstrDesc &getInstDesc(unsigned Opcode) {
- return ARMInsts[Opcode];
+// Return true if instruction has the interesting property of being
+// allowed in IT blocks, but not being predicable.
+static bool instIsBreakpoint(const MCInst &Inst) {
+ return Inst.getOpcode() == ARM::tBKPT ||
+ Inst.getOpcode() == ARM::BKPT ||
+ Inst.getOpcode() == ARM::tHLT ||
+ Inst.getOpcode() == ARM::HLT;
+
}
// FIXME: We would really like to be able to tablegen'erate this.
bool ARMAsmParser::
validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
- const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+ const MCInstrDesc &MCID = MII.get(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
- // executes.
- if (inITBlock() && Inst.getOpcode() != ARM::tBKPT &&
- Inst.getOpcode() != ARM::BKPT) {
+ // NOTE: BKPT and HLT instructions have the interesting property of being
+ // allowed in IT blocks, but not being predicable. They just always
+ // execute.
+ if (inITBlock() && !instIsBreakpoint(Inst)) {
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::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()) {
+ const unsigned Opcode = Inst.getOpcode();
+ switch (Opcode) {
case ARM::LDRD:
case ARM::LDRD_PRE:
case ARM::LDRD_POST: {
+ const unsigned RtReg = Inst.getOperand(0).getReg();
+
+ // Rt can't be R14.
+ if (RtReg == ARM::LR)
+ return Error(Operands[3]->getStartLoc(),
+ "Rt can't be R14");
+
+ const unsigned Rt = MRI->getEncodingValue(RtReg);
+ // Rt must be even-numbered.
+ if ((Rt & 1) == 1)
+ return Error(Operands[3]->getStartLoc(),
+ "Rt must be even-numbered");
+
// Rt2 must be Rt + 1.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
+ const unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
if (Rt2 != Rt + 1)
return Error(Operands[3]->getStartLoc(),
"destination operands must be sequential");
+
+ if (Opcode == ARM::LDRD_PRE || Opcode == ARM::LDRD_POST) {
+ const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg());
+ // For addressing modes with writeback, the base register needs to be
+ // different from the destination registers.
+ if (Rn == Rt || Rn == Rt2)
+ return Error(Operands[3]->getStartLoc(),
+ "base register needs to be different from destination "
+ "registers");
+ }
+
+ return false;
+ }
+ case ARM::t2LDRDi8:
+ case ARM::t2LDRD_PRE:
+ case ARM::t2LDRD_POST: {
+ // Rt2 must be different from Rt.
+ unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
+ unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
+ if (Rt2 == Rt)
+ return Error(Operands[3]->getStartLoc(),
+ "destination operands can't be identical");
return false;
}
case ARM::STRD: {
}
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;
+ }
}
return false;
case ARM::t2LDRpcrel:
// Select the narrow version if the immediate will fit.
if (Inst.getOperand(1).getImm() > 0 &&
- Inst.getOperand(1).getImm() <= 0xff)
+ Inst.getOperand(1).getImm() <= 0xff &&
+ !(static_cast<ARMOperand*>(Operands[2])->isToken() &&
+ static_cast<ARMOperand*>(Operands[2])->getToken() == ".w"))
Inst.setOpcode(ARM::tLDRpci);
else
Inst.setOpcode(ARM::t2LDRpci);
MCOperand &MO = Inst.getOperand(1);
unsigned Mask = MO.getImm();
unsigned OrigMask = Mask;
- unsigned TZ = CountTrailingZeros_32(Mask);
+ unsigned TZ = countTrailingZeros(Mask);
if ((Inst.getOperand(0).getImm() & 1) == 0) {
assert(Mask && TZ <= 3 && "illegal IT mask value!");
Mask ^= (0xE << TZ) & 0xF;
// 16-bit thumb arithmetic instructions either require or preclude the 'S'
// suffix depending on whether they're in an IT block or not.
unsigned Opc = Inst.getOpcode();
- const MCInstrDesc &MCID = getInstDesc(Opc);
+ const MCInstrDesc &MCID = MII.get(Opc);
if (MCID.TSFlags & ARMII::ThumbArithFlagSetting) {
assert(MCID.hasOptionalDef() &&
"optionally flag setting instruction missing optional def operand");
return Error(L, "unexpected token in directive");
Parser.Lex();
+ if (!hasThumb())
+ return Error(L, "target does not support Thumb mode");
+
if (!isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
return Error(L, "unexpected token in directive");
Parser.Lex();
+ if (!hasARM())
+ return Error(L, "target does not support ARM mode");
+
if (isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
/// parseDirectiveThumbFunc
/// ::= .thumbfunc symbol_name
bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) {
- const MCAsmInfo &MAI = getParser().getStreamer().getContext().getAsmInfo();
- bool isMachO = MAI.hasSubsectionsViaSymbols();
+ const MCAsmInfo *MAI = getParser().getStreamer().getContext().getAsmInfo();
+ bool isMachO = MAI->hasSubsectionsViaSymbols();
StringRef Name;
bool needFuncName = true;
Parser.Lex();
if (Val == 16) {
+ if (!hasThumb())
+ return Error(L, "target does not support Thumb mode");
+
if (!isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
} else {
+ if (!hasARM())
+ return Error(L, "target does not support ARM mode");
+
if (isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
if (HandlerDataLoc.isValid())
return Error(L, ".save or .vsave must precede .handlerdata directive");
+ // RAII object to make sure parsed operands are deleted.
+ struct CleanupObject {
+ SmallVector<MCParsedAsmOperand *, 1> Operands;
+ ~CleanupObject() {
+ for (unsigned I = 0, E = Operands.size(); I != E; ++I)
+ delete Operands[I];
+ }
+ } CO;
+
// Parse the register list
- SmallVector<MCParsedAsmOperand*, 1> Operands;
- if (parseRegisterList(Operands))
+ if (parseRegisterList(CO.Operands))
return true;
- ARMOperand *Op = (ARMOperand*)Operands[0];
+ ARMOperand *Op = (ARMOperand*)CO.Operands[0];
if (!IsVector && !Op->isRegList())
return Error(L, ".save expects GPR registers");
if (IsVector && !Op->isDPRRegList())