forked from OSchip/llvm-project
ARM assembly parsing for MOV (immediate).
Add range checking for the immediate operand and handle the "mov" mnemonic choosing between encodings based on the value of the immediate. Add tests for fixups, encoding choice and values, and diagnostic for out of range values. llvm-svn: 135500
This commit is contained in:
parent
20dd6e9fae
commit
7c09e3c3f3
|
@ -494,11 +494,16 @@ def imm0_31_m1 : Operand<i32>, ImmLeaf<i32, [{
|
||||||
let EncoderMethod = "getImmMinusOneOpValue";
|
let EncoderMethod = "getImmMinusOneOpValue";
|
||||||
}
|
}
|
||||||
|
|
||||||
// i32imm_hilo16 - For movt/movw - sets the MC Encoder method.
|
// imm0_65535_expr - For movt/movw - 16-bit immediate that can also reference
|
||||||
// The imm is split into imm{15-12}, imm{11-0}
|
// a relocatable expression.
|
||||||
//
|
//
|
||||||
def i32imm_hilo16 : Operand<i32> {
|
// FIXME: This really needs a Thumb version separate from the ARM version.
|
||||||
|
// While the range is the same, and can thus use the same match class,
|
||||||
|
// the encoding is different so it should have a different encoder method.
|
||||||
|
def Imm0_65535ExprAsmOperand: AsmOperandClass { let Name = "Imm0_65535Expr"; }
|
||||||
|
def imm0_65535_expr : Operand<i32> {
|
||||||
let EncoderMethod = "getHiLo16ImmOpValue";
|
let EncoderMethod = "getHiLo16ImmOpValue";
|
||||||
|
let ParserMatchClass = Imm0_65535ExprAsmOperand;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
|
/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
|
||||||
|
@ -2123,7 +2128,7 @@ def MOVi : AsI1<0b1101, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, IIC_iMOVi,
|
||||||
}
|
}
|
||||||
|
|
||||||
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
|
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
|
||||||
def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins i32imm_hilo16:$imm),
|
def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins imm0_65535_expr:$imm),
|
||||||
DPFrm, IIC_iMOVi,
|
DPFrm, IIC_iMOVi,
|
||||||
"movw", "\t$Rd, $imm",
|
"movw", "\t$Rd, $imm",
|
||||||
[(set GPR:$Rd, imm0_65535:$imm)]>,
|
[(set GPR:$Rd, imm0_65535:$imm)]>,
|
||||||
|
@ -2137,11 +2142,15 @@ def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins i32imm_hilo16:$imm),
|
||||||
let Inst{25} = 1;
|
let Inst{25} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def : InstAlias<"mov${p} $Rd, $imm",
|
||||||
|
(MOVi16 GPR:$Rd, imm0_65535_expr:$imm, pred:$p)>,
|
||||||
|
Requires<[IsARM]>;
|
||||||
|
|
||||||
def MOVi16_ga_pcrel : PseudoInst<(outs GPR:$Rd),
|
def MOVi16_ga_pcrel : PseudoInst<(outs GPR:$Rd),
|
||||||
(ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>;
|
(ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>;
|
||||||
|
|
||||||
let Constraints = "$src = $Rd" in {
|
let Constraints = "$src = $Rd" in {
|
||||||
def MOVTi16 : AI1<0b1010, (outs GPR:$Rd), (ins GPR:$src, i32imm_hilo16:$imm),
|
def MOVTi16 : AI1<0b1010, (outs GPR:$Rd), (ins GPR:$src, imm0_65535_expr:$imm),
|
||||||
DPFrm, IIC_iMOVi,
|
DPFrm, IIC_iMOVi,
|
||||||
"movt", "\t$Rd, $imm",
|
"movt", "\t$Rd, $imm",
|
||||||
[(set GPR:$Rd,
|
[(set GPR:$Rd,
|
||||||
|
@ -3260,7 +3269,7 @@ def MOVCCs : ARMPseudoInst<(outs GPR:$Rd),
|
||||||
|
|
||||||
let isMoveImm = 1 in
|
let isMoveImm = 1 in
|
||||||
def MOVCCi16 : ARMPseudoInst<(outs GPR:$Rd),
|
def MOVCCi16 : ARMPseudoInst<(outs GPR:$Rd),
|
||||||
(ins GPR:$false, i32imm_hilo16:$imm, pred:$p),
|
(ins GPR:$false, imm0_65535_expr:$imm, pred:$p),
|
||||||
4, IIC_iMOVi,
|
4, IIC_iMOVi,
|
||||||
[]>,
|
[]>,
|
||||||
RegConstraint<"$false = $Rd">, Requires<[IsARM, HasV6T2]>;
|
RegConstraint<"$false = $Rd">, Requires<[IsARM, HasV6T2]>;
|
||||||
|
|
|
@ -1615,7 +1615,7 @@ def : InstAlias<"mov${s}${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm,
|
||||||
Requires<[IsThumb2]>;
|
Requires<[IsThumb2]>;
|
||||||
|
|
||||||
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
|
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
|
||||||
def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins i32imm_hilo16:$imm), IIC_iMOVi,
|
def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins imm0_65535_expr:$imm), IIC_iMOVi,
|
||||||
"movw", "\t$Rd, $imm",
|
"movw", "\t$Rd, $imm",
|
||||||
[(set rGPR:$Rd, imm0_65535:$imm)]> {
|
[(set rGPR:$Rd, imm0_65535:$imm)]> {
|
||||||
let Inst{31-27} = 0b11110;
|
let Inst{31-27} = 0b11110;
|
||||||
|
@ -1639,7 +1639,7 @@ def t2MOVi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd),
|
||||||
|
|
||||||
let Constraints = "$src = $Rd" in {
|
let Constraints = "$src = $Rd" in {
|
||||||
def t2MOVTi16 : T2I<(outs rGPR:$Rd),
|
def t2MOVTi16 : T2I<(outs rGPR:$Rd),
|
||||||
(ins rGPR:$src, i32imm_hilo16:$imm), IIC_iMOVi,
|
(ins rGPR:$src, imm0_65535_expr:$imm), IIC_iMOVi,
|
||||||
"movt", "\t$Rd, $imm",
|
"movt", "\t$Rd, $imm",
|
||||||
[(set rGPR:$Rd,
|
[(set rGPR:$Rd,
|
||||||
(or (and rGPR:$src, 0xffff), lo16AllZero:$imm))]> {
|
(or (and rGPR:$src, 0xffff), lo16AllZero:$imm))]> {
|
||||||
|
@ -2723,7 +2723,7 @@ def t2MOVCCi : t2PseudoInst<(outs rGPR:$Rd),
|
||||||
// FIXME: Pseudo-ize these. For now, just mark codegen only.
|
// FIXME: Pseudo-ize these. For now, just mark codegen only.
|
||||||
let isCodeGenOnly = 1 in {
|
let isCodeGenOnly = 1 in {
|
||||||
let isMoveImm = 1 in
|
let isMoveImm = 1 in
|
||||||
def t2MOVCCi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$false, i32imm_hilo16:$imm),
|
def t2MOVCCi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$false, imm0_65535_expr:$imm),
|
||||||
IIC_iCMOVi,
|
IIC_iCMOVi,
|
||||||
"movw", "\t$Rd, $imm", []>,
|
"movw", "\t$Rd, $imm", []>,
|
||||||
RegConstraint<"$false = $Rd"> {
|
RegConstraint<"$false = $Rd"> {
|
||||||
|
|
|
@ -407,6 +407,16 @@ public:
|
||||||
int64_t Value = CE->getValue();
|
int64_t Value = CE->getValue();
|
||||||
return Value >= 0 && Value < 65536;
|
return Value >= 0 && Value < 65536;
|
||||||
}
|
}
|
||||||
|
bool isImm0_65535Expr() const {
|
||||||
|
if (Kind != Immediate)
|
||||||
|
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 >= 0 && Value < 65536;
|
||||||
|
}
|
||||||
bool isARMSOImm() const {
|
bool isARMSOImm() const {
|
||||||
if (Kind != Immediate)
|
if (Kind != Immediate)
|
||||||
return false;
|
return false;
|
||||||
|
@ -621,6 +631,11 @@ public:
|
||||||
addExpr(Inst, getImm());
|
addExpr(Inst, getImm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addImm0_65535ExprOperands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(N == 1 && "Invalid number of operands!");
|
||||||
|
addExpr(Inst, getImm());
|
||||||
|
}
|
||||||
|
|
||||||
void addARMSOImmOperands(MCInst &Inst, unsigned N) const {
|
void addARMSOImmOperands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 1 && "Invalid number of operands!");
|
assert(N == 1 && "Invalid number of operands!");
|
||||||
addExpr(Inst, getImm());
|
addExpr(Inst, getImm());
|
||||||
|
@ -2063,16 +2078,19 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||||
// Create the leading tokens for the mnemonic, split by '.' characters.
|
// Create the leading tokens for the mnemonic, split by '.' characters.
|
||||||
size_t Start = 0, Next = Name.find('.');
|
size_t Start = 0, Next = Name.find('.');
|
||||||
StringRef Head = Name.slice(Start, Next);
|
StringRef Mnemonic = Name.slice(Start, Next);
|
||||||
|
|
||||||
// Split out the predication code and carry setting flag from the mnemonic.
|
// Split out the predication code and carry setting flag from the mnemonic.
|
||||||
unsigned PredicationCode;
|
unsigned PredicationCode;
|
||||||
unsigned ProcessorIMod;
|
unsigned ProcessorIMod;
|
||||||
bool CarrySetting;
|
bool CarrySetting;
|
||||||
Head = SplitMnemonic(Head, PredicationCode, CarrySetting,
|
Mnemonic = SplitMnemonic(Mnemonic, PredicationCode, CarrySetting,
|
||||||
ProcessorIMod);
|
ProcessorIMod);
|
||||||
|
|
||||||
Operands.push_back(ARMOperand::CreateToken(Head, NameLoc));
|
Operands.push_back(ARMOperand::CreateToken(Mnemonic, NameLoc));
|
||||||
|
|
||||||
|
// FIXME: This is all a pretty gross hack. We should automatically handle
|
||||||
|
// optional operands like this via tblgen.
|
||||||
|
|
||||||
// Next, add the CCOut and ConditionCode operands, if needed.
|
// Next, add the CCOut and ConditionCode operands, if needed.
|
||||||
//
|
//
|
||||||
|
@ -2082,13 +2100,13 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||||
// the matcher deal with finding the right instruction or generating an
|
// the matcher deal with finding the right instruction or generating an
|
||||||
// appropriate error.
|
// appropriate error.
|
||||||
bool CanAcceptCarrySet, CanAcceptPredicationCode;
|
bool CanAcceptCarrySet, CanAcceptPredicationCode;
|
||||||
GetMnemonicAcceptInfo(Head, CanAcceptCarrySet, CanAcceptPredicationCode);
|
GetMnemonicAcceptInfo(Mnemonic, CanAcceptCarrySet, CanAcceptPredicationCode);
|
||||||
|
|
||||||
// If we had a carry-set on an instruction that can't do that, issue an
|
// If we had a carry-set on an instruction that can't do that, issue an
|
||||||
// error.
|
// error.
|
||||||
if (!CanAcceptCarrySet && CarrySetting) {
|
if (!CanAcceptCarrySet && CarrySetting) {
|
||||||
Parser.EatToEndOfStatement();
|
Parser.EatToEndOfStatement();
|
||||||
return Error(NameLoc, "instruction '" + Head +
|
return Error(NameLoc, "instruction '" + Mnemonic +
|
||||||
"' can not set flags, but 's' suffix specified");
|
"' can not set flags, but 's' suffix specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2136,7 +2154,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||||
// Read the remaining operands.
|
// Read the remaining operands.
|
||||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||||
// Read the first operand.
|
// Read the first operand.
|
||||||
if (ParseOperand(Operands, Head)) {
|
if (ParseOperand(Operands, Mnemonic)) {
|
||||||
Parser.EatToEndOfStatement();
|
Parser.EatToEndOfStatement();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2145,7 +2163,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||||
Parser.Lex(); // Eat the comma.
|
Parser.Lex(); // Eat the comma.
|
||||||
|
|
||||||
// Parse and remember the operand.
|
// Parse and remember the operand.
|
||||||
if (ParseOperand(Operands, Head)) {
|
if (ParseOperand(Operands, Mnemonic)) {
|
||||||
Parser.EatToEndOfStatement();
|
Parser.EatToEndOfStatement();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2158,6 +2176,26 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser.Lex(); // Consume the EndOfStatement
|
Parser.Lex(); // Consume the EndOfStatement
|
||||||
|
|
||||||
|
|
||||||
|
// The 'mov' mnemonic is special. One variant has a cc_out operand, while
|
||||||
|
// another does not. Specifically, the MOVW instruction does not. So we
|
||||||
|
// special case it here and remove the defaulted (non-setting) cc_out
|
||||||
|
// operand if that's the instruction we're trying to match.
|
||||||
|
//
|
||||||
|
// We do this 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 &&
|
||||||
|
!static_cast<ARMOperand*>(Operands[4])->isARMSOImm() &&
|
||||||
|
static_cast<ARMOperand*>(Operands[4])->isImm0_65535Expr()) {
|
||||||
|
ARMOperand *Op = static_cast<ARMOperand*>(Operands[1]);
|
||||||
|
Operands.erase(Operands.begin() + 1);
|
||||||
|
delete Op;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
// RUN: llvm-mc -triple arm-unknown-unknown %s --show-encoding > %t
|
@ RUN: llvm-mc -triple armv7-unknown-unknown %s --show-encoding > %t
|
||||||
// RUN: FileCheck < %t %s
|
@ RUN: FileCheck < %t %s
|
||||||
|
|
||||||
// CHECK: bl _printf @ encoding: [A,A,A,0xeb]
|
bl _printf
|
||||||
// CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_uncondbranch
|
@ CHECK: bl _printf @ encoding: [A,A,A,0xeb]
|
||||||
bl _printf
|
@ CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_uncondbranch
|
||||||
|
|
||||||
|
mov r9, :lower16:(_foo)
|
||||||
|
movw r9, :lower16:(_foo)
|
||||||
|
movt r9, :upper16:(_foo)
|
||||||
|
|
||||||
|
@ CHECK: movw r9, :lower16:_foo @ encoding: [A,0x90'A',0b0000AAAA,0xe3]
|
||||||
|
@ CHECK: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movw_lo16
|
||||||
|
@ CHECK: movw r9, :lower16:_foo @ encoding: [A,0x90'A',0b0000AAAA,0xe3]
|
||||||
|
@ CHECK: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movw_lo16
|
||||||
|
@ CHECK: movt r9, :upper16:_foo @ encoding: [A,0x90'A',0b0100AAAA,0xe3]
|
||||||
|
@ CHECK: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_movt_hi16
|
||||||
|
|
|
@ -670,6 +670,21 @@ _func:
|
||||||
@ CHECK: mls r2, r5, r6, r3 @ encoding: [0x95,0x36,0x62,0xe0]
|
@ CHECK: mls r2, r5, r6, r3 @ encoding: [0x95,0x36,0x62,0xe0]
|
||||||
@ CHECK: mlsne r2, r5, r6, r3 @ encoding: [0x95,0x36,0x62,0x10]
|
@ CHECK: mlsne r2, r5, r6, r3 @ encoding: [0x95,0x36,0x62,0x10]
|
||||||
|
|
||||||
|
@------------------------------------------------------------------------------
|
||||||
|
@ MOV (immediate)
|
||||||
|
@------------------------------------------------------------------------------
|
||||||
|
mov r3, #7
|
||||||
|
mov r4, #0xff0
|
||||||
|
mov r5, #0xff0000
|
||||||
|
mov r6, #0xffff
|
||||||
|
movw r9, #0xffff
|
||||||
|
|
||||||
|
@ CHECK: mov r3, #7 @ encoding: [0x07,0x30,0xa0,0xe3]
|
||||||
|
@ CHECK: mov r4, #4080 @ encoding: [0xff,0x4e,0xa0,0xe3]
|
||||||
|
@ CHECK: mov r5, #16711680 @ encoding: [0xff,0x58,0xa0,0xe3]
|
||||||
|
@ CHECK: movw r6, #65535 @ encoding: [0xff,0x6f,0x0f,0xe3]
|
||||||
|
@ CHECK: movw r9, #65535 @ encoding: [0xff,0x9f,0x0f,0xe3]
|
||||||
|
|
||||||
@------------------------------------------------------------------------------
|
@------------------------------------------------------------------------------
|
||||||
@ STM*
|
@ STM*
|
||||||
@------------------------------------------------------------------------------
|
@------------------------------------------------------------------------------
|
||||||
|
|
|
@ -88,3 +88,8 @@
|
||||||
@ CHECK-ERRORS: error: invalid operand for instruction
|
@ CHECK-ERRORS: error: invalid operand for instruction
|
||||||
@ CHECK-ERRORS: error: invalid operand for instruction
|
@ CHECK-ERRORS: error: invalid operand for instruction
|
||||||
@ CHECK-ERRORS: error: invalid operand for instruction
|
@ CHECK-ERRORS: error: invalid operand for instruction
|
||||||
|
|
||||||
|
|
||||||
|
@ Out of range immediate for MOV
|
||||||
|
movw r9, 0x10000
|
||||||
|
@ CHECK-ERRORS: error: invalid operand for instruction
|
||||||
|
|
|
@ -593,6 +593,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
|
||||||
IMM("imm0_255");
|
IMM("imm0_255");
|
||||||
IMM("imm0_4095");
|
IMM("imm0_4095");
|
||||||
IMM("imm0_65535");
|
IMM("imm0_65535");
|
||||||
|
IMM("imm0_65535_expr");
|
||||||
IMM("jt2block_operand");
|
IMM("jt2block_operand");
|
||||||
IMM("t_imm_s4");
|
IMM("t_imm_s4");
|
||||||
IMM("pclabel");
|
IMM("pclabel");
|
||||||
|
|
Loading…
Reference in New Issue