mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-15 06:18:50 +00:00
[ARM64] Re-work parsing of ADD/SUB shifted immediate operands
The parsing of ADD/SUB shifted immediates needs to be done explicitly so that better diagnostics can be emitted, as a side effect this also removes some of the hacks in the current method of handling this operand type. Additionally remove manual CMP aliasing to ADD/SUB and use InstAlias instead. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208329 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4f83e2ca5d
commit
0d2a5d26f2
@ -102,12 +102,6 @@ def ArithmeticShifterOperand : AsmOperandClass {
|
|||||||
let Name = "ArithmeticShifter";
|
let Name = "ArithmeticShifter";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shifter operand for arithmetic shifted encodings for ADD/SUB instructions.
|
|
||||||
def AddSubShifterOperand : AsmOperandClass {
|
|
||||||
let SuperClasses = [ArithmeticShifterOperand];
|
|
||||||
let Name = "AddSubShifter";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shifter operand for logical vector 128/64-bit shifted encodings.
|
// Shifter operand for logical vector 128/64-bit shifted encodings.
|
||||||
def LogicalVecShifterOperand : AsmOperandClass {
|
def LogicalVecShifterOperand : AsmOperandClass {
|
||||||
let SuperClasses = [ShifterOperand];
|
let SuperClasses = [ShifterOperand];
|
||||||
@ -556,18 +550,21 @@ def move_vec_shift : Operand<i32> {
|
|||||||
let ParserMatchClass = MoveVecShifterOperand;
|
let ParserMatchClass = MoveVecShifterOperand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def AddSubImmOperand : AsmOperandClass {
|
||||||
|
let Name = "AddSubImm";
|
||||||
|
let ParserMethod = "tryParseAddSubImm";
|
||||||
|
let DiagnosticType = "AddSubSecondSource";
|
||||||
|
}
|
||||||
// An ADD/SUB immediate shifter operand:
|
// An ADD/SUB immediate shifter operand:
|
||||||
|
// second operand:
|
||||||
// {7-6} - shift type: 00 = lsl
|
// {7-6} - shift type: 00 = lsl
|
||||||
// {5-0} - imm6: #0 or #12
|
// {5-0} - imm6: #0 or #12
|
||||||
def addsub_shift : Operand<i32> {
|
|
||||||
let ParserMatchClass = AddSubShifterOperand;
|
|
||||||
}
|
|
||||||
|
|
||||||
class addsub_shifted_imm<ValueType Ty>
|
class addsub_shifted_imm<ValueType Ty>
|
||||||
: Operand<Ty>, ComplexPattern<Ty, 2, "SelectArithImmed", [imm]> {
|
: Operand<Ty>, ComplexPattern<Ty, 2, "SelectArithImmed", [imm]> {
|
||||||
let PrintMethod = "printAddSubImm";
|
let PrintMethod = "printAddSubImm";
|
||||||
let EncoderMethod = "getAddSubImmOpValue";
|
let EncoderMethod = "getAddSubImmOpValue";
|
||||||
let MIOperandInfo = (ops i32imm, addsub_shift);
|
let ParserMatchClass = AddSubImmOperand;
|
||||||
|
let MIOperandInfo = (ops i32imm, i32imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
def addsub_shifted_imm32 : addsub_shifted_imm<i32>;
|
def addsub_shifted_imm32 : addsub_shifted_imm<i32>;
|
||||||
@ -577,7 +574,8 @@ class neg_addsub_shifted_imm<ValueType Ty>
|
|||||||
: Operand<Ty>, ComplexPattern<Ty, 2, "SelectNegArithImmed", [imm]> {
|
: Operand<Ty>, ComplexPattern<Ty, 2, "SelectNegArithImmed", [imm]> {
|
||||||
let PrintMethod = "printAddSubImm";
|
let PrintMethod = "printAddSubImm";
|
||||||
let EncoderMethod = "getAddSubImmOpValue";
|
let EncoderMethod = "getAddSubImmOpValue";
|
||||||
let MIOperandInfo = (ops i32imm, addsub_shift);
|
let ParserMatchClass = AddSubImmOperand;
|
||||||
|
let MIOperandInfo = (ops i32imm, i32imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
def neg_addsub_shifted_imm32 : neg_addsub_shifted_imm<i32>;
|
def neg_addsub_shifted_imm32 : neg_addsub_shifted_imm<i32>;
|
||||||
@ -1522,7 +1520,7 @@ multiclass AddSub<bit isSub, string mnemonic,
|
|||||||
GPR64sp, GPR64sp, GPR64, 24>; // UXTX #0
|
GPR64sp, GPR64sp, GPR64, 24>; // UXTX #0
|
||||||
}
|
}
|
||||||
|
|
||||||
multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode> {
|
multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp> {
|
||||||
let isCompare = 1, Defs = [NZCV] in {
|
let isCompare = 1, Defs = [NZCV] in {
|
||||||
// Add/Subtract immediate
|
// Add/Subtract immediate
|
||||||
def Wri : BaseAddSubImm<isSub, 1, GPR32, GPR32sp, addsub_shifted_imm32,
|
def Wri : BaseAddSubImm<isSub, 1, GPR32, GPR32sp, addsub_shifted_imm32,
|
||||||
@ -1568,6 +1566,28 @@ multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode> {
|
|||||||
}
|
}
|
||||||
} // Defs = [NZCV]
|
} // Defs = [NZCV]
|
||||||
|
|
||||||
|
// Compare aliases
|
||||||
|
def : InstAlias<cmp#" $src, $imm", (!cast<Instruction>(NAME#"Wri")
|
||||||
|
WZR, GPR32sp:$src, addsub_shifted_imm32:$imm)>;
|
||||||
|
def : InstAlias<cmp#" $src, $imm", (!cast<Instruction>(NAME#"Xri")
|
||||||
|
XZR, GPR64sp:$src, addsub_shifted_imm64:$imm)>;
|
||||||
|
def : InstAlias<cmp#" $src1, $src2, $sh", (!cast<Instruction>(NAME#"Wrx")
|
||||||
|
WZR, GPR32sp:$src1, GPR32:$src2, arith_extend:$sh)>;
|
||||||
|
def : InstAlias<cmp#" $src1, $src2, $sh", (!cast<Instruction>(NAME#"Xrx")
|
||||||
|
XZR, GPR64sp:$src1, GPR32:$src2, arith_extend:$sh)>;
|
||||||
|
def : InstAlias<cmp#" $src1, $src2, $sh", (!cast<Instruction>(NAME#"Xrx64")
|
||||||
|
XZR, GPR64sp:$src1, GPR64:$src2, arith_extendlsl64:$sh)>;
|
||||||
|
def : InstAlias<cmp#" $src1, $src2, $sh", (!cast<Instruction>(NAME#"Wrs")
|
||||||
|
WZR, GPR32:$src1, GPR32:$src2, arith_shift:$sh)>;
|
||||||
|
def : InstAlias<cmp#" $src1, $src2, $sh", (!cast<Instruction>(NAME#"Xrs")
|
||||||
|
XZR, GPR64:$src1, GPR64:$src2, arith_shift:$sh)>;
|
||||||
|
|
||||||
|
// Compare shorthands
|
||||||
|
def : InstAlias<cmp#" $src1, $src2", (!cast<Instruction>(NAME#"Wrs")
|
||||||
|
WZR, GPR32:$src1, GPR32:$src2, 0)>;
|
||||||
|
def : InstAlias<cmp#" $src1, $src2", (!cast<Instruction>(NAME#"Xrs")
|
||||||
|
XZR, GPR64:$src1, GPR64:$src2, 0)>;
|
||||||
|
|
||||||
// Register/register aliases with no shift when SP is not used.
|
// Register/register aliases with no shift when SP is not used.
|
||||||
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
|
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
|
||||||
GPR32, GPR32, GPR32, 0>;
|
GPR32, GPR32, GPR32, 0>;
|
||||||
|
@ -474,8 +474,8 @@ def : InstAlias<"ngcs $dst, $src", (SBCSXr GPR64:$dst, XZR, GPR64:$src)>;
|
|||||||
defm ADD : AddSub<0, "add", add>;
|
defm ADD : AddSub<0, "add", add>;
|
||||||
defm SUB : AddSub<1, "sub">;
|
defm SUB : AddSub<1, "sub">;
|
||||||
|
|
||||||
defm ADDS : AddSubS<0, "adds", ARM64add_flag>;
|
defm ADDS : AddSubS<0, "adds", ARM64add_flag, "cmn">;
|
||||||
defm SUBS : AddSubS<1, "subs", ARM64sub_flag>;
|
defm SUBS : AddSubS<1, "subs", ARM64sub_flag, "cmp">;
|
||||||
|
|
||||||
// Use SUBS instead of SUB to enable CSE between SUBS and SUB.
|
// Use SUBS instead of SUB to enable CSE between SUBS and SUB.
|
||||||
def : Pat<(sub GPR32sp:$Rn, addsub_shifted_imm32:$imm),
|
def : Pat<(sub GPR32sp:$Rn, addsub_shifted_imm32:$imm),
|
||||||
|
@ -96,6 +96,7 @@ private:
|
|||||||
OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands);
|
OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands);
|
||||||
OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands);
|
OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands);
|
||||||
OperandMatchResultTy tryParseFPImm(OperandVector &Operands);
|
OperandMatchResultTy tryParseFPImm(OperandVector &Operands);
|
||||||
|
OperandMatchResultTy tryParseAddSubImm(OperandVector &Operands);
|
||||||
bool tryParseVectorRegister(OperandVector &Operands);
|
bool tryParseVectorRegister(OperandVector &Operands);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -142,6 +143,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
enum KindTy {
|
enum KindTy {
|
||||||
k_Immediate,
|
k_Immediate,
|
||||||
|
k_ShiftedImm,
|
||||||
k_Memory,
|
k_Memory,
|
||||||
k_Register,
|
k_Register,
|
||||||
k_VectorList,
|
k_VectorList,
|
||||||
@ -184,6 +186,11 @@ private:
|
|||||||
const MCExpr *Val;
|
const MCExpr *Val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ShiftedImmOp {
|
||||||
|
const MCExpr *Val;
|
||||||
|
unsigned ShiftAmount;
|
||||||
|
};
|
||||||
|
|
||||||
struct FPImmOp {
|
struct FPImmOp {
|
||||||
unsigned Val; // Encoded 8-bit representation.
|
unsigned Val; // Encoded 8-bit representation.
|
||||||
};
|
};
|
||||||
@ -232,6 +239,7 @@ private:
|
|||||||
struct VectorListOp VectorList;
|
struct VectorListOp VectorList;
|
||||||
struct VectorIndexOp VectorIndex;
|
struct VectorIndexOp VectorIndex;
|
||||||
struct ImmOp Imm;
|
struct ImmOp Imm;
|
||||||
|
struct ShiftedImmOp ShiftedImm;
|
||||||
struct FPImmOp FPImm;
|
struct FPImmOp FPImm;
|
||||||
struct BarrierOp Barrier;
|
struct BarrierOp Barrier;
|
||||||
struct SysRegOp SysReg;
|
struct SysRegOp SysReg;
|
||||||
@ -261,6 +269,9 @@ public:
|
|||||||
case k_Immediate:
|
case k_Immediate:
|
||||||
Imm = o.Imm;
|
Imm = o.Imm;
|
||||||
break;
|
break;
|
||||||
|
case k_ShiftedImm:
|
||||||
|
ShiftedImm = o.ShiftedImm;
|
||||||
|
break;
|
||||||
case k_FPImm:
|
case k_FPImm:
|
||||||
FPImm = o.FPImm;
|
FPImm = o.FPImm;
|
||||||
break;
|
break;
|
||||||
@ -319,6 +330,16 @@ public:
|
|||||||
return Imm.Val;
|
return Imm.Val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MCExpr *getShiftedImmVal() const {
|
||||||
|
assert(Kind == k_ShiftedImm && "Invalid access!");
|
||||||
|
return ShiftedImm.Val;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getShiftedImmShift() const {
|
||||||
|
assert(Kind == k_ShiftedImm && "Invalid access!");
|
||||||
|
return ShiftedImm.ShiftAmount;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned getFPImm() const {
|
unsigned getFPImm() const {
|
||||||
assert(Kind == k_FPImm && "Invalid access!");
|
assert(Kind == k_FPImm && "Invalid access!");
|
||||||
return FPImm.Val;
|
return FPImm.Val;
|
||||||
@ -549,6 +570,45 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
return ARM64_AM::isLogicalImmediate(MCE->getValue(), 64);
|
return ARM64_AM::isLogicalImmediate(MCE->getValue(), 64);
|
||||||
}
|
}
|
||||||
|
bool isShiftedImm() const { return Kind == k_ShiftedImm; }
|
||||||
|
bool isAddSubImm() const {
|
||||||
|
if (!isShiftedImm() && !isImm())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const MCExpr *Expr;
|
||||||
|
|
||||||
|
// An ADD/SUB shifter is either 'lsl #0' or 'lsl #12'.
|
||||||
|
if (isShiftedImm()) {
|
||||||
|
unsigned Shift = ShiftedImm.ShiftAmount;
|
||||||
|
Expr = ShiftedImm.Val;
|
||||||
|
if (Shift != 0 && Shift != 12)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Expr = getImm();
|
||||||
|
}
|
||||||
|
|
||||||
|
ARM64MCExpr::VariantKind ELFRefKind;
|
||||||
|
MCSymbolRefExpr::VariantKind DarwinRefKind;
|
||||||
|
int64_t Addend;
|
||||||
|
if (ARM64AsmParser::classifySymbolRef(Expr, ELFRefKind,
|
||||||
|
DarwinRefKind, Addend)) {
|
||||||
|
return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF
|
||||||
|
|| DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF
|
||||||
|
|| (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0)
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_LO12
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_DTPREL_HI12
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12_NC
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_TPREL_HI12
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_TPREL_LO12
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_TPREL_LO12_NC
|
||||||
|
|| ELFRefKind == ARM64MCExpr::VK_TLSDESC_LO12;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise it should be a real immediate in range:
|
||||||
|
const MCConstantExpr *CE = cast<MCConstantExpr>(Expr);
|
||||||
|
return CE->getValue() >= 0 && CE->getValue() <= 0xfff;
|
||||||
|
}
|
||||||
bool isSIMDImmType10() const {
|
bool isSIMDImmType10() const {
|
||||||
if (!isImm())
|
if (!isImm())
|
||||||
return false;
|
return false;
|
||||||
@ -805,17 +865,6 @@ public:
|
|||||||
return (Val == 0 || Val == 16 || Val == 32 || Val == 48);
|
return (Val == 0 || Val == 16 || Val == 32 || Val == 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAddSubShifter() const {
|
|
||||||
if (!isShifter())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// An ADD/SUB shifter is either 'lsl #0' or 'lsl #12'.
|
|
||||||
unsigned Val = Shifter.Val;
|
|
||||||
return ARM64_AM::getShiftType(Val) == ARM64_AM::LSL &&
|
|
||||||
(ARM64_AM::getShiftValue(Val) == 0 ||
|
|
||||||
ARM64_AM::getShiftValue(Val) == 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLogicalVecShifter() const {
|
bool isLogicalVecShifter() const {
|
||||||
if (!isShifter())
|
if (!isShifter())
|
||||||
return false;
|
return false;
|
||||||
@ -1132,6 +1181,17 @@ public:
|
|||||||
addExpr(Inst, getImm());
|
addExpr(Inst, getImm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addAddSubImmOperands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(N == 2 && "Invalid number of operands!");
|
||||||
|
if (isShiftedImm()) {
|
||||||
|
addExpr(Inst, getShiftedImmVal());
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(getShiftedImmShift()));
|
||||||
|
} else {
|
||||||
|
addExpr(Inst, getImm());
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addAdrpLabelOperands(MCInst &Inst, unsigned N) const {
|
void addAdrpLabelOperands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 1 && "Invalid number of operands!");
|
assert(N == 1 && "Invalid number of operands!");
|
||||||
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
|
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
|
||||||
@ -1399,11 +1459,6 @@ public:
|
|||||||
Inst.addOperand(MCOperand::CreateImm(getShifter()));
|
Inst.addOperand(MCOperand::CreateImm(getShifter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addAddSubShifterOperands(MCInst &Inst, unsigned N) const {
|
|
||||||
assert(N == 1 && "Invalid number of operands!");
|
|
||||||
Inst.addOperand(MCOperand::CreateImm(getShifter()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void addLogicalVecShifterOperands(MCInst &Inst, unsigned N) const {
|
void addLogicalVecShifterOperands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 1 && "Invalid number of operands!");
|
assert(N == 1 && "Invalid number of operands!");
|
||||||
Inst.addOperand(MCOperand::CreateImm(getShifter()));
|
Inst.addOperand(MCOperand::CreateImm(getShifter()));
|
||||||
@ -1664,6 +1719,16 @@ public:
|
|||||||
return Op;
|
return Op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ARM64Operand *CreateShiftedImm(const MCExpr *Val, unsigned ShiftAmount,
|
||||||
|
SMLoc S, SMLoc E, MCContext &Ctx) {
|
||||||
|
ARM64Operand *Op = new ARM64Operand(k_ShiftedImm, Ctx);
|
||||||
|
Op->ShiftedImm .Val = Val;
|
||||||
|
Op->ShiftedImm.ShiftAmount = ShiftAmount;
|
||||||
|
Op->StartLoc = S;
|
||||||
|
Op->EndLoc = E;
|
||||||
|
return Op;
|
||||||
|
}
|
||||||
|
|
||||||
static ARM64Operand *CreateFPImm(unsigned Val, SMLoc S, MCContext &Ctx) {
|
static ARM64Operand *CreateFPImm(unsigned Val, SMLoc S, MCContext &Ctx) {
|
||||||
ARM64Operand *Op = new ARM64Operand(k_FPImm, Ctx);
|
ARM64Operand *Op = new ARM64Operand(k_FPImm, Ctx);
|
||||||
Op->FPImm.Val = Val;
|
Op->FPImm.Val = Val;
|
||||||
@ -1781,6 +1846,14 @@ void ARM64Operand::print(raw_ostream &OS) const {
|
|||||||
case k_Immediate:
|
case k_Immediate:
|
||||||
getImm()->print(OS);
|
getImm()->print(OS);
|
||||||
break;
|
break;
|
||||||
|
case k_ShiftedImm: {
|
||||||
|
unsigned Shift = getShiftedImmShift();
|
||||||
|
OS << "<shiftedimm ";
|
||||||
|
getShiftedImmVal()->print(OS);
|
||||||
|
OS << ", " << ARM64_AM::getShiftName(ARM64_AM::getShiftType(Shift)) << " #"
|
||||||
|
<< ARM64_AM::getShiftValue(Shift) << ">";
|
||||||
|
break;
|
||||||
|
}
|
||||||
case k_Memory:
|
case k_Memory:
|
||||||
OS << "<memory>";
|
OS << "<memory>";
|
||||||
break;
|
break;
|
||||||
@ -2232,6 +2305,72 @@ ARM64AsmParser::tryParseFPImm(OperandVector &Operands) {
|
|||||||
return MatchOperand_ParseFail;
|
return MatchOperand_ParseFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// tryParseAddSubImm - Parse ADD/SUB shifted immediate operand
|
||||||
|
ARM64AsmParser::OperandMatchResultTy
|
||||||
|
ARM64AsmParser::tryParseAddSubImm(OperandVector &Operands) {
|
||||||
|
SMLoc S = getLoc();
|
||||||
|
|
||||||
|
if (Parser.getTok().is(AsmToken::Hash))
|
||||||
|
Parser.Lex(); // Eat '#'
|
||||||
|
else if (Parser.getTok().isNot(AsmToken::Integer))
|
||||||
|
// Operand should start from # or should be integer, emit error otherwise.
|
||||||
|
return MatchOperand_NoMatch;
|
||||||
|
|
||||||
|
const MCExpr *Imm;
|
||||||
|
if (parseSymbolicImmVal(Imm))
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
else if (Parser.getTok().isNot(AsmToken::Comma)) {
|
||||||
|
uint64_t ShiftAmount = 0;
|
||||||
|
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Imm);
|
||||||
|
if (MCE) {
|
||||||
|
int64_t Val = MCE->getValue();
|
||||||
|
if (Val > 0xfff && (Val & 0xfff) == 0) {
|
||||||
|
Imm = MCConstantExpr::Create(Val >> 12, getContext());
|
||||||
|
ShiftAmount = 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SMLoc E = Parser.getTok().getLoc();
|
||||||
|
Operands.push_back(ARM64Operand::CreateShiftedImm(Imm, ShiftAmount, S, E,
|
||||||
|
getContext()));
|
||||||
|
return MatchOperand_Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat ','
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
// The optional operand must be "lsl #N" where N is non-negative.
|
||||||
|
if (!Parser.getTok().is(AsmToken::Identifier) ||
|
||||||
|
!Parser.getTok().getIdentifier().equals_lower("lsl")) {
|
||||||
|
Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat 'lsl'
|
||||||
|
Parser.Lex();
|
||||||
|
|
||||||
|
if (Parser.getTok().is(AsmToken::Hash)) {
|
||||||
|
Parser.Lex();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parser.getTok().isNot(AsmToken::Integer)) {
|
||||||
|
Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ShiftAmount = Parser.getTok().getIntVal();
|
||||||
|
|
||||||
|
if (ShiftAmount < 0) {
|
||||||
|
Error(Parser.getTok().getLoc(), "positive shift amount required");
|
||||||
|
return MatchOperand_ParseFail;
|
||||||
|
}
|
||||||
|
Parser.Lex(); // Eat the number
|
||||||
|
|
||||||
|
SMLoc E = Parser.getTok().getLoc();
|
||||||
|
Operands.push_back(ARM64Operand::CreateShiftedImm(Imm, ShiftAmount,
|
||||||
|
S, E, getContext()));
|
||||||
|
return MatchOperand_Success;
|
||||||
|
}
|
||||||
|
|
||||||
/// parseCondCodeString - Parse a Condition Code string.
|
/// parseCondCodeString - Parse a Condition Code string.
|
||||||
unsigned ARM64AsmParser::parseCondCodeString(StringRef Cond) {
|
unsigned ARM64AsmParser::parseCondCodeString(StringRef Cond) {
|
||||||
unsigned CC = StringSwitch<unsigned>(Cond.lower())
|
unsigned CC = StringSwitch<unsigned>(Cond.lower())
|
||||||
@ -2301,7 +2440,7 @@ ARM64AsmParser::tryParseOptionalShift(OperandVector &Operands) {
|
|||||||
// We expect a number here.
|
// We expect a number here.
|
||||||
bool Hash = getLexer().is(AsmToken::Hash);
|
bool Hash = getLexer().is(AsmToken::Hash);
|
||||||
if (!Hash && getLexer().isNot(AsmToken::Integer)) {
|
if (!Hash && getLexer().isNot(AsmToken::Integer)) {
|
||||||
TokError("immediate value expected for shifter operand");
|
TokError("expected #imm after shift specifier");
|
||||||
return MatchOperand_ParseFail;
|
return MatchOperand_ParseFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2322,7 +2461,7 @@ ARM64AsmParser::tryParseOptionalShift(OperandVector &Operands) {
|
|||||||
|
|
||||||
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
|
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
|
||||||
if (!MCE) {
|
if (!MCE) {
|
||||||
TokError("immediate value expected for shifter operand");
|
TokError("expected #imm after shift specifier");
|
||||||
return MatchOperand_ParseFail;
|
return MatchOperand_ParseFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3550,19 +3689,9 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
|
|||||||
case ARM64::SUBSXri:
|
case ARM64::SUBSXri:
|
||||||
case ARM64::SUBWri:
|
case ARM64::SUBWri:
|
||||||
case ARM64::SUBXri: {
|
case ARM64::SUBXri: {
|
||||||
if (!Inst.getOperand(3).isImm())
|
// Annoyingly we can't do this in the isAddSubImm predicate, so there is
|
||||||
return Error(Loc[3], "immediate value expected");
|
// some slight duplication here.
|
||||||
int64_t shifter = Inst.getOperand(3).getImm();
|
if (Inst.getOperand(2).isExpr()) {
|
||||||
if (shifter != 0 && shifter != 12)
|
|
||||||
return Error(Loc[3], "shift value out of range");
|
|
||||||
// The imm12 operand can be an expression. Validate that it's legit.
|
|
||||||
// FIXME: We really, really want to allow arbitrary expressions here
|
|
||||||
// and resolve the value and validate the result at fixup time, but
|
|
||||||
// that's hard as we have long since lost any source information we
|
|
||||||
// need to generate good diagnostics by that point.
|
|
||||||
if ((Inst.getOpcode() == ARM64::ADDXri ||
|
|
||||||
Inst.getOpcode() == ARM64::ADDWri) &&
|
|
||||||
Inst.getOperand(2).isExpr()) {
|
|
||||||
const MCExpr *Expr = Inst.getOperand(2).getExpr();
|
const MCExpr *Expr = Inst.getOperand(2).getExpr();
|
||||||
ARM64MCExpr::VariantKind ELFRefKind;
|
ARM64MCExpr::VariantKind ELFRefKind;
|
||||||
MCSymbolRefExpr::VariantKind DarwinRefKind;
|
MCSymbolRefExpr::VariantKind DarwinRefKind;
|
||||||
@ -3571,38 +3700,28 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
|
|||||||
return Error(Loc[2], "invalid immediate expression");
|
return Error(Loc[2], "invalid immediate expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we don't range-check the addend. It's adjusted modulo page
|
// Only allow these with ADDXri.
|
||||||
// size when converted, so there is no "out of range" condition when using
|
|
||||||
// @pageoff. Any validity checking for the value was done in the is*()
|
|
||||||
// predicate function.
|
|
||||||
if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
|
if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
|
||||||
DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
|
DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
|
||||||
Inst.getOpcode() == ARM64::ADDXri)
|
Inst.getOpcode() == ARM64::ADDXri)
|
||||||
return false;
|
return false;
|
||||||
if (ELFRefKind == ARM64MCExpr::VK_LO12 ||
|
|
||||||
|
// Only allow these with ADDXri/ADDWri
|
||||||
|
if ((ELFRefKind == ARM64MCExpr::VK_LO12 ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_DTPREL_HI12 ||
|
ELFRefKind == ARM64MCExpr::VK_DTPREL_HI12 ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12 ||
|
ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12 ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12_NC ||
|
ELFRefKind == ARM64MCExpr::VK_DTPREL_LO12_NC ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_TPREL_HI12 ||
|
ELFRefKind == ARM64MCExpr::VK_TPREL_HI12 ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_TPREL_LO12 ||
|
ELFRefKind == ARM64MCExpr::VK_TPREL_LO12 ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_TPREL_LO12_NC ||
|
ELFRefKind == ARM64MCExpr::VK_TPREL_LO12_NC ||
|
||||||
ELFRefKind == ARM64MCExpr::VK_TLSDESC_LO12) {
|
ELFRefKind == ARM64MCExpr::VK_TLSDESC_LO12) &&
|
||||||
|
(Inst.getOpcode() == ARM64::ADDXri ||
|
||||||
|
Inst.getOpcode() == ARM64::ADDWri))
|
||||||
return false;
|
return false;
|
||||||
} else if (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF) {
|
|
||||||
// @gotpageoff can only be used directly, not with an addend.
|
|
||||||
return Addend != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we're not sure, so don't allow it for now.
|
// Don't allow expressions in the immediate field otherwise
|
||||||
return Error(Loc[2], "invalid immediate expression");
|
return Error(Loc[2], "invalid immediate expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's anything but an immediate, it's not legit.
|
|
||||||
if (!Inst.getOperand(2).isImm())
|
|
||||||
return Error(Loc[2], "invalid immediate expression");
|
|
||||||
int64_t imm = Inst.getOperand(2).getImm();
|
|
||||||
if (imm > 4095 || imm < 0)
|
|
||||||
return Error(Loc[2], "immediate value out of range");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case ARM64::LDRBpre:
|
case ARM64::LDRBpre:
|
||||||
@ -3834,10 +3953,8 @@ static void rewriteMOVRSP(ARM64AsmParser::OperandVector &Operands,
|
|||||||
ARM64Operand::CreateToken("add", false, Op->getStartLoc(), Context);
|
ARM64Operand::CreateToken("add", false, Op->getStartLoc(), Context);
|
||||||
|
|
||||||
const MCExpr *Imm = MCConstantExpr::Create(0, Context);
|
const MCExpr *Imm = MCConstantExpr::Create(0, Context);
|
||||||
Operands.push_back(ARM64Operand::CreateImm(Imm, Op2->getStartLoc(),
|
Operands.push_back(ARM64Operand::CreateShiftedImm(Imm, 0, Op2->getStartLoc(),
|
||||||
Op2->getEndLoc(), Context));
|
Op2->getEndLoc(), Context));
|
||||||
Operands.push_back(ARM64Operand::CreateShifter(
|
|
||||||
ARM64_AM::LSL, 0, Op2->getStartLoc(), Op2->getEndLoc(), Context));
|
|
||||||
|
|
||||||
delete Op;
|
delete Op;
|
||||||
}
|
}
|
||||||
@ -3879,6 +3996,9 @@ bool ARM64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode) {
|
|||||||
case Match_AddSubRegExtendLarge:
|
case Match_AddSubRegExtendLarge:
|
||||||
return Error(Loc,
|
return Error(Loc,
|
||||||
"expected 'sxtx' 'uxtx' or 'lsl' with optional integer in range [0, 4]");
|
"expected 'sxtx' 'uxtx' or 'lsl' with optional integer in range [0, 4]");
|
||||||
|
case Match_AddSubSecondSource:
|
||||||
|
return Error(Loc,
|
||||||
|
"expected compatible register, symbol or integer in range [0, 4095]");
|
||||||
case Match_InvalidMemoryIndexedSImm9:
|
case Match_InvalidMemoryIndexedSImm9:
|
||||||
return Error(Loc, "index must be an integer in range [-256, 255].");
|
return Error(Loc, "index must be an integer in range [-256, 255].");
|
||||||
case Match_InvalidMemoryIndexed32SImm7:
|
case Match_InvalidMemoryIndexed32SImm7:
|
||||||
@ -3947,35 +4067,6 @@ bool ARM64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|||||||
assert(Op->isToken() && "Leading operand should always be a mnemonic!");
|
assert(Op->isToken() && "Leading operand should always be a mnemonic!");
|
||||||
|
|
||||||
StringRef Tok = Op->getToken();
|
StringRef Tok = Op->getToken();
|
||||||
// Translate CMN/CMP pseudos to ADDS/SUBS with zero register destination.
|
|
||||||
// This needs to be done before the special handling of ADD/SUB immediates.
|
|
||||||
if (Tok == "cmp" || Tok == "cmn") {
|
|
||||||
// Replace the opcode with either ADDS or SUBS.
|
|
||||||
const char *Repl = StringSwitch<const char *>(Tok)
|
|
||||||
.Case("cmp", "subs")
|
|
||||||
.Case("cmn", "adds")
|
|
||||||
.Default(nullptr);
|
|
||||||
assert(Repl && "Unknown compare instruction");
|
|
||||||
delete Operands[0];
|
|
||||||
Operands[0] = ARM64Operand::CreateToken(Repl, false, IDLoc, getContext());
|
|
||||||
|
|
||||||
// Insert WZR or XZR as destination operand.
|
|
||||||
ARM64Operand *RegOp = static_cast<ARM64Operand *>(Operands[1]);
|
|
||||||
unsigned ZeroReg;
|
|
||||||
if (RegOp->isReg() &&
|
|
||||||
ARM64MCRegisterClasses[ARM64::GPR32allRegClassID].contains(
|
|
||||||
RegOp->getReg()))
|
|
||||||
ZeroReg = ARM64::WZR;
|
|
||||||
else
|
|
||||||
ZeroReg = ARM64::XZR;
|
|
||||||
Operands.insert(
|
|
||||||
Operands.begin() + 1,
|
|
||||||
ARM64Operand::CreateReg(ZeroReg, false, IDLoc, IDLoc, getContext()));
|
|
||||||
// Update since we modified it above.
|
|
||||||
ARM64Operand *Op = static_cast<ARM64Operand *>(Operands[0]);
|
|
||||||
Tok = Op->getToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned NumOperands = Operands.size();
|
unsigned NumOperands = Operands.size();
|
||||||
|
|
||||||
if (Tok == "mov" && NumOperands == 3) {
|
if (Tok == "mov" && NumOperands == 3) {
|
||||||
@ -4050,39 +4141,7 @@ bool ARM64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|||||||
rewriteMOVR(Operands, getContext());
|
rewriteMOVR(Operands, getContext());
|
||||||
}
|
}
|
||||||
} else if (NumOperands == 4) {
|
} else if (NumOperands == 4) {
|
||||||
if (Tok == "add" || Tok == "adds" || Tok == "sub" || Tok == "subs") {
|
if (NumOperands == 4 && Tok == "lsl") {
|
||||||
// Handle the uimm24 immediate form, where the shift is not specified.
|
|
||||||
ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]);
|
|
||||||
if (Op3->isImm()) {
|
|
||||||
if (const MCConstantExpr *CE =
|
|
||||||
dyn_cast<MCConstantExpr>(Op3->getImm())) {
|
|
||||||
uint64_t Val = CE->getValue();
|
|
||||||
if (Val >= (1 << 24)) {
|
|
||||||
Error(IDLoc, "immediate value is too large");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Val < (1 << 12)) {
|
|
||||||
Operands.push_back(ARM64Operand::CreateShifter(
|
|
||||||
ARM64_AM::LSL, 0, IDLoc, IDLoc, getContext()));
|
|
||||||
} else if ((Val & 0xfff) == 0) {
|
|
||||||
delete Operands[3];
|
|
||||||
CE = MCConstantExpr::Create(Val >> 12, getContext());
|
|
||||||
Operands[3] =
|
|
||||||
ARM64Operand::CreateImm(CE, IDLoc, IDLoc, getContext());
|
|
||||||
Operands.push_back(ARM64Operand::CreateShifter(
|
|
||||||
ARM64_AM::LSL, 12, IDLoc, IDLoc, getContext()));
|
|
||||||
} else {
|
|
||||||
Error(IDLoc, "immediate value is too large");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Operands.push_back(ARM64Operand::CreateShifter(
|
|
||||||
ARM64_AM::LSL, 0, IDLoc, IDLoc, getContext()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Horible hack to handle the LSL -> UBFM alias.
|
|
||||||
} else if (NumOperands == 4 && Tok == "lsl") {
|
|
||||||
ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]);
|
ARM64Operand *Op2 = static_cast<ARM64Operand *>(Operands[2]);
|
||||||
ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]);
|
ARM64Operand *Op3 = static_cast<ARM64Operand *>(Operands[3]);
|
||||||
if (Op2->isReg() && Op3->isImm()) {
|
if (Op2->isReg() && Op3->isImm()) {
|
||||||
@ -4457,6 +4516,7 @@ bool ARM64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|||||||
// FALL THROUGH
|
// FALL THROUGH
|
||||||
case Match_AddSubRegExtendSmall:
|
case Match_AddSubRegExtendSmall:
|
||||||
case Match_AddSubRegExtendLarge:
|
case Match_AddSubRegExtendLarge:
|
||||||
|
case Match_AddSubSecondSource:
|
||||||
case Match_InvalidMemoryIndexed8:
|
case Match_InvalidMemoryIndexed8:
|
||||||
case Match_InvalidMemoryIndexed16:
|
case Match_InvalidMemoryIndexed16:
|
||||||
case Match_InvalidMemoryIndexed32SImm7:
|
case Match_InvalidMemoryIndexed32SImm7:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user