mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
[AArch64] Implement add/adds/sub/subs/cmp/cmn with negative immediate aliases
This patch teaches the AsmParser to accept add/adds/sub/subs/cmp/cmn with a negative immediate operand and convert them as shown: add Rd, Rn, -imm -> sub Rd, Rn, imm sub Rd, Rn, -imm -> add Rd, Rn, imm adds Rd, Rn, -imm -> subs Rd, Rn, imm subs Rd, Rn, -imm -> adds Rd, Rn, imm cmp Rn, -imm -> cmn Rn, imm cmn Rn, -imm -> cmp Rn, imm Those instructions are an alternate syntax available to assembly coders, and are needed in order to support code already compiling with some other assemblers (gas). They are documented in the "ARMv8 Instruction Set Overview", in the "Arithmetic (immediate)" section. This makes llvm-mc a programmer-friendly assembler ! This also fixes PR20978: "Assembly handling of adding negative numbers not as smart as gas". llvm-svn: 241166
This commit is contained in:
parent
8ac96a89b0
commit
9f66584696
@ -614,10 +614,15 @@ def move_vec_shift : Operand<i32> {
|
||||
let ParserMatchClass = MoveVecShifterOperand;
|
||||
}
|
||||
|
||||
def AddSubImmOperand : AsmOperandClass {
|
||||
let Name = "AddSubImm";
|
||||
let ParserMethod = "tryParseAddSubImm";
|
||||
let DiagnosticType = "AddSubSecondSource";
|
||||
let DiagnosticType = "AddSubSecondSource" in {
|
||||
def AddSubImmOperand : AsmOperandClass {
|
||||
let Name = "AddSubImm";
|
||||
let ParserMethod = "tryParseAddSubImm";
|
||||
}
|
||||
def AddSubImmNegOperand : AsmOperandClass {
|
||||
let Name = "AddSubImmNeg";
|
||||
let ParserMethod = "tryParseAddSubImm";
|
||||
}
|
||||
}
|
||||
// An ADD/SUB immediate shifter operand:
|
||||
// second operand:
|
||||
@ -631,8 +636,17 @@ class addsub_shifted_imm<ValueType Ty>
|
||||
let MIOperandInfo = (ops i32imm, i32imm);
|
||||
}
|
||||
|
||||
class addsub_shifted_imm_neg<ValueType Ty>
|
||||
: Operand<Ty> {
|
||||
let EncoderMethod = "getAddSubImmOpValue";
|
||||
let ParserMatchClass = AddSubImmNegOperand;
|
||||
let MIOperandInfo = (ops i32imm, i32imm);
|
||||
}
|
||||
|
||||
def addsub_shifted_imm32 : addsub_shifted_imm<i32>;
|
||||
def addsub_shifted_imm64 : addsub_shifted_imm<i64>;
|
||||
def addsub_shifted_imm32_neg : addsub_shifted_imm_neg<i32>;
|
||||
def addsub_shifted_imm64_neg : addsub_shifted_imm_neg<i64>;
|
||||
|
||||
class neg_addsub_shifted_imm<ValueType Ty>
|
||||
: Operand<Ty>, ComplexPattern<Ty, 2, "SelectNegArithImmed", [imm]> {
|
||||
@ -1633,7 +1647,7 @@ class AddSubRegAlias<string asm, Instruction inst, RegisterClass dstRegtype,
|
||||
(inst dstRegtype:$dst, src1Regtype:$src1, src2Regtype:$src2,
|
||||
shiftExt)>;
|
||||
|
||||
multiclass AddSub<bit isSub, string mnemonic,
|
||||
multiclass AddSub<bit isSub, string mnemonic, string alias,
|
||||
SDPatternOperator OpNode = null_frag> {
|
||||
let hasSideEffects = 0, isReMaterializable = 1, isAsCheapAsAMove = 1 in {
|
||||
// Add/Subtract immediate
|
||||
@ -1686,6 +1700,14 @@ multiclass AddSub<bit isSub, string mnemonic,
|
||||
let Inst{31} = 1;
|
||||
}
|
||||
|
||||
// add Rd, Rb, -imm -> sub Rd, Rn, imm
|
||||
def : InstAlias<alias#" $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Wri") GPR32sp:$Rd, GPR32sp:$Rn,
|
||||
addsub_shifted_imm32_neg:$imm), 0>;
|
||||
def : InstAlias<alias#" $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Xri") GPR64sp:$Rd, GPR64sp:$Rn,
|
||||
addsub_shifted_imm64_neg:$imm), 0>;
|
||||
|
||||
// Register/register aliases with no shift when SP is not used.
|
||||
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
|
||||
GPR32, GPR32, GPR32, 0>;
|
||||
@ -1706,7 +1728,8 @@ multiclass AddSub<bit isSub, string mnemonic,
|
||||
GPR64sp, GPR64sponly, GPR64, 24>; // UXTX #0
|
||||
}
|
||||
|
||||
multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp> {
|
||||
multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp,
|
||||
string alias, string cmpAlias> {
|
||||
let isCompare = 1, Defs = [NZCV] in {
|
||||
// Add/Subtract immediate
|
||||
def Wri : BaseAddSubImm<isSub, 1, GPR32, GPR32sp, addsub_shifted_imm32,
|
||||
@ -1752,6 +1775,14 @@ multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp> {
|
||||
}
|
||||
} // Defs = [NZCV]
|
||||
|
||||
// Support negative immediates, e.g. adds Rd, Rn, -imm -> subs Rd, Rn, imm
|
||||
def : InstAlias<alias#" $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Wri") GPR32:$Rd, GPR32sp:$Rn,
|
||||
addsub_shifted_imm32_neg:$imm), 0>;
|
||||
def : InstAlias<alias#" $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Xri") GPR64:$Rd, GPR64sp:$Rn,
|
||||
addsub_shifted_imm64_neg:$imm), 0>;
|
||||
|
||||
// Compare aliases
|
||||
def : InstAlias<cmp#" $src, $imm", (!cast<Instruction>(NAME#"Wri")
|
||||
WZR, GPR32sp:$src, addsub_shifted_imm32:$imm), 5>;
|
||||
@ -1768,6 +1799,12 @@ multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp> {
|
||||
def : InstAlias<cmp#" $src1, $src2$sh", (!cast<Instruction>(NAME#"Xrs")
|
||||
XZR, GPR64:$src1, GPR64:$src2, arith_shift64:$sh), 4>;
|
||||
|
||||
// Support negative immediates, e.g. cmp Rn, -imm -> cmn Rn, imm
|
||||
def : InstAlias<cmpAlias#" $src, $imm", (!cast<Instruction>(NAME#"Wri")
|
||||
WZR, GPR32sp:$src, addsub_shifted_imm32_neg:$imm), 0>;
|
||||
def : InstAlias<cmpAlias#" $src, $imm", (!cast<Instruction>(NAME#"Xri")
|
||||
XZR, GPR64sp:$src, addsub_shifted_imm64_neg:$imm), 0>;
|
||||
|
||||
// Compare shorthands
|
||||
def : InstAlias<cmp#" $src1, $src2", (!cast<Instruction>(NAME#"Wrs")
|
||||
WZR, GPR32:$src1, GPR32:$src2, 0), 5>;
|
||||
|
@ -567,8 +567,8 @@ def : InstAlias<"ngcs $dst, $src", (SBCSWr GPR32:$dst, WZR, GPR32:$src)>;
|
||||
def : InstAlias<"ngcs $dst, $src", (SBCSXr GPR64:$dst, XZR, GPR64:$src)>;
|
||||
|
||||
// Add/subtract
|
||||
defm ADD : AddSub<0, "add", add>;
|
||||
defm SUB : AddSub<1, "sub">;
|
||||
defm ADD : AddSub<0, "add", "sub", add>;
|
||||
defm SUB : AddSub<1, "sub", "add">;
|
||||
|
||||
def : InstAlias<"mov $dst, $src",
|
||||
(ADDWri GPR32sponly:$dst, GPR32sp:$src, 0, 0)>;
|
||||
@ -579,8 +579,8 @@ def : InstAlias<"mov $dst, $src",
|
||||
def : InstAlias<"mov $dst, $src",
|
||||
(ADDXri GPR64sp:$dst, GPR64sponly:$src, 0, 0)>;
|
||||
|
||||
defm ADDS : AddSubS<0, "adds", AArch64add_flag, "cmn">;
|
||||
defm SUBS : AddSubS<1, "subs", AArch64sub_flag, "cmp">;
|
||||
defm ADDS : AddSubS<0, "adds", AArch64add_flag, "cmn", "subs", "cmp">;
|
||||
defm SUBS : AddSubS<1, "subs", AArch64sub_flag, "cmp", "adds", "cmn">;
|
||||
|
||||
// Use SUBS instead of SUB to enable CSE between SUBS and SUB.
|
||||
def : Pat<(sub GPR32sp:$Rn, addsub_shifted_imm32:$imm),
|
||||
|
@ -699,6 +699,25 @@ public:
|
||||
const MCConstantExpr *CE = cast<MCConstantExpr>(Expr);
|
||||
return CE->getValue() >= 0 && CE->getValue() <= 0xfff;
|
||||
}
|
||||
bool isAddSubImmNeg() 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();
|
||||
|
||||
// Otherwise it should be a real negative immediate in range:
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr);
|
||||
return CE != nullptr && CE->getValue() < 0 && -CE->getValue() <= 0xfff;
|
||||
}
|
||||
bool isCondCode() const { return Kind == k_CondCode; }
|
||||
bool isSIMDImmType10() const {
|
||||
if (!isImm())
|
||||
@ -1219,6 +1238,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void addAddSubImmNegOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 2 && "Invalid number of operands!");
|
||||
|
||||
const MCExpr *MCE = isShiftedImm() ? getShiftedImmVal() : getImm();
|
||||
const MCConstantExpr *CE = cast<MCConstantExpr>(MCE);
|
||||
int64_t Val = -CE->getValue();
|
||||
unsigned ShiftAmt = isShiftedImm() ? ShiftedImm.ShiftAmount : 0;
|
||||
|
||||
Inst.addOperand(MCOperand::createImm(Val));
|
||||
Inst.addOperand(MCOperand::createImm(ShiftAmt));
|
||||
}
|
||||
|
||||
void addCondCodeOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
Inst.addOperand(MCOperand::createImm(getCondCode()));
|
||||
|
94
test/MC/AArch64/alias-addsubimm.s
Normal file
94
test/MC/AArch64/alias-addsubimm.s
Normal file
@ -0,0 +1,94 @@
|
||||
// RUN: llvm-mc -triple=aarch64-none-linux-gnu < %s | FileCheck %s
|
||||
|
||||
// CHECK: sub w0, w2, #2, lsl #12
|
||||
// CHECK: sub w0, w2, #2, lsl #12
|
||||
sub w0, w2, #2, lsl 12
|
||||
add w0, w2, #-2, lsl 12
|
||||
// CHECK: sub x1, x3, #2, lsl #12
|
||||
// CHECK: sub x1, x3, #2, lsl #12
|
||||
sub x1, x3, #2, lsl 12
|
||||
add x1, x3, #-2, lsl 12
|
||||
// CHECK: sub x1, x3, #4
|
||||
// CHECK: sub x1, x3, #4
|
||||
sub x1, x3, #4
|
||||
add x1, x3, #-4
|
||||
// CHECK: sub x1, x3, #4095
|
||||
// CHECK: sub x1, x3, #4095
|
||||
sub x1, x3, #4095, lsl 0
|
||||
add x1, x3, #-4095, lsl 0
|
||||
// CHECK: sub x3, x4, #0
|
||||
sub x3, x4, #0
|
||||
|
||||
// CHECK: add w0, w2, #2, lsl #12
|
||||
// CHECK: add w0, w2, #2, lsl #12
|
||||
add w0, w2, #2, lsl 12
|
||||
sub w0, w2, #-2, lsl 12
|
||||
// CHECK: add x1, x3, #2, lsl #12
|
||||
// CHECK: add x1, x3, #2, lsl #12
|
||||
add x1, x3, #2, lsl 12
|
||||
sub x1, x3, #-2, lsl 12
|
||||
// CHECK: add x1, x3, #4
|
||||
// CHECK: add x1, x3, #4
|
||||
add x1, x3, #4
|
||||
sub x1, x3, #-4
|
||||
// CHECK: add x1, x3, #4095
|
||||
// CHECK: add x1, x3, #4095
|
||||
add x1, x3, #4095, lsl 0
|
||||
sub x1, x3, #-4095, lsl 0
|
||||
// CHECK: add x2, x5, #0
|
||||
add x2, x5, #0
|
||||
|
||||
// CHECK: subs w0, w2, #2, lsl #12
|
||||
// CHECK: subs w0, w2, #2, lsl #12
|
||||
subs w0, w2, #2, lsl 12
|
||||
adds w0, w2, #-2, lsl 12
|
||||
// CHECK: subs x1, x3, #2, lsl #12
|
||||
// CHECK: subs x1, x3, #2, lsl #12
|
||||
subs x1, x3, #2, lsl 12
|
||||
adds x1, x3, #-2, lsl 12
|
||||
// CHECK: subs x1, x3, #4
|
||||
// CHECK: subs x1, x3, #4
|
||||
subs x1, x3, #4
|
||||
adds x1, x3, #-4
|
||||
// CHECK: subs x1, x3, #4095
|
||||
// CHECK: subs x1, x3, #4095
|
||||
subs x1, x3, #4095, lsl 0
|
||||
adds x1, x3, #-4095, lsl 0
|
||||
// CHECK: subs x3, x4, #0
|
||||
subs x3, x4, #0
|
||||
|
||||
// CHECK: adds w0, w2, #2, lsl #12
|
||||
// CHECK: adds w0, w2, #2, lsl #12
|
||||
adds w0, w2, #2, lsl 12
|
||||
subs w0, w2, #-2, lsl 12
|
||||
// CHECK: adds x1, x3, #2, lsl #12
|
||||
// CHECK: adds x1, x3, #2, lsl #12
|
||||
adds x1, x3, #2, lsl 12
|
||||
subs x1, x3, #-2, lsl 12
|
||||
// CHECK: adds x1, x3, #4
|
||||
// CHECK: adds x1, x3, #4
|
||||
adds x1, x3, #4
|
||||
subs x1, x3, #-4
|
||||
// CHECK: adds x1, x3, #4095
|
||||
// CHECK: adds x1, x3, #4095
|
||||
adds x1, x3, #4095, lsl 0
|
||||
subs x1, x3, #-4095, lsl 0
|
||||
// CHECK: adds x2, x5, #0
|
||||
adds x2, x5, #0
|
||||
|
||||
// CHECK: {{adds xzr,|cmn}} x5, #5
|
||||
// CHECK: {{adds xzr,|cmn}} x5, #5
|
||||
cmn x5, #5
|
||||
cmp x5, #-5
|
||||
// CHECK: {{subs xzr,|cmp}} x6, #4095
|
||||
// CHECK: {{subs xzr,|cmp}} x6, #4095
|
||||
cmp x6, #4095
|
||||
cmn x6, #-4095
|
||||
// CHECK: {{adds wzr,|cmn}} w7, #5
|
||||
// CHECK: {{adds wzr,|cmn}} w7, #5
|
||||
cmn w7, #5
|
||||
cmp w7, #-5
|
||||
// CHECK: {{subs wzr,|cmp}} w8, #4095
|
||||
// CHECK: {{subs wzr,|cmp}} w8, #4095
|
||||
cmp w8, #4095
|
||||
cmn w8, #-4095
|
@ -75,19 +75,19 @@
|
||||
// Add/sub (immediate)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Out of range immediates: < 0 or more than 12 bits
|
||||
add w4, w5, #-1
|
||||
// Out of range immediates: more than 12 bits
|
||||
add w4, w5, #-4096
|
||||
add w5, w6, #0x1000
|
||||
add w4, w5, #-1, lsl #12
|
||||
add w4, w5, #-4096, lsl #12
|
||||
add w5, w6, #0x1000, lsl #12
|
||||
// CHECK-ERROR: error: expected compatible register, symbol or integer in range [0, 4095]
|
||||
// CHECK-ERROR-NEXT: add w4, w5, #-1
|
||||
// CHECK-ERROR-NEXT: add w4, w5, #-4096
|
||||
// CHECK-ERROR-NEXT: ^
|
||||
// CHECK-ERROR-AARCH64-NEXT: error: expected compatible register, symbol or integer in range [0, 4095]
|
||||
// CHECK-ERROR-AARCH64-NEXT: add w5, w6, #0x1000
|
||||
// CHECK-ERROR-AARCH64-NEXT: ^
|
||||
// CHECK-ERROR-NEXT: error: expected compatible register, symbol or integer in range [0, 4095]
|
||||
// CHECK-ERROR-NEXT: add w4, w5, #-1, lsl #12
|
||||
// CHECK-ERROR-NEXT: add w4, w5, #-4096, lsl #12
|
||||
// CHECK-ERROR-NEXT: ^
|
||||
// CHECK-ERROR-NEXT: error: expected compatible register, symbol or integer in range [0, 4095]
|
||||
// CHECK-ERROR-NEXT: add w5, w6, #0x1000, lsl #12
|
||||
|
Loading…
Reference in New Issue
Block a user