diff --git a/lib/Target/AArch64/AArch64InstrFormats.td b/lib/Target/AArch64/AArch64InstrFormats.td index 2c52f340d6d..3f2e772a90c 100644 --- a/lib/Target/AArch64/AArch64InstrFormats.td +++ b/lib/Target/AArch64/AArch64InstrFormats.td @@ -614,10 +614,15 @@ def move_vec_shift : Operand { 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 let MIOperandInfo = (ops i32imm, i32imm); } +class addsub_shifted_imm_neg + : Operand { + let EncoderMethod = "getAddSubImmOpValue"; + let ParserMatchClass = AddSubImmNegOperand; + let MIOperandInfo = (ops i32imm, i32imm); +} + def addsub_shifted_imm32 : addsub_shifted_imm; def addsub_shifted_imm64 : addsub_shifted_imm; +def addsub_shifted_imm32_neg : addsub_shifted_imm_neg; +def addsub_shifted_imm64_neg : addsub_shifted_imm_neg; class neg_addsub_shifted_imm : Operand, ComplexPattern { @@ -1633,7 +1647,7 @@ class AddSubRegAlias; -multiclass AddSub { let hasSideEffects = 0, isReMaterializable = 1, isAsCheapAsAMove = 1 in { // Add/Subtract immediate @@ -1686,6 +1700,14 @@ multiclass AddSub sub Rd, Rn, imm + def : InstAlias(NAME # "Wri") GPR32sp:$Rd, GPR32sp:$Rn, + addsub_shifted_imm32_neg:$imm), 0>; + def : InstAlias(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(NAME#"Wrs"), GPR32, GPR32, GPR32, 0>; @@ -1706,7 +1728,8 @@ multiclass AddSub; // UXTX #0 } -multiclass AddSubS { +multiclass AddSubS { let isCompare = 1, Defs = [NZCV] in { // Add/Subtract immediate def Wri : BaseAddSubImm { } } // Defs = [NZCV] + // Support negative immediates, e.g. adds Rd, Rn, -imm -> subs Rd, Rn, imm + def : InstAlias(NAME # "Wri") GPR32:$Rd, GPR32sp:$Rn, + addsub_shifted_imm32_neg:$imm), 0>; + def : InstAlias(NAME # "Xri") GPR64:$Rd, GPR64sp:$Rn, + addsub_shifted_imm64_neg:$imm), 0>; + // Compare aliases def : InstAlias(NAME#"Wri") WZR, GPR32sp:$src, addsub_shifted_imm32:$imm), 5>; @@ -1768,6 +1799,12 @@ multiclass AddSubS { def : InstAlias(NAME#"Xrs") XZR, GPR64:$src1, GPR64:$src2, arith_shift64:$sh), 4>; + // Support negative immediates, e.g. cmp Rn, -imm -> cmn Rn, imm + def : InstAlias(NAME#"Wri") + WZR, GPR32sp:$src, addsub_shifted_imm32_neg:$imm), 0>; + def : InstAlias(NAME#"Xri") + XZR, GPR64sp:$src, addsub_shifted_imm64_neg:$imm), 0>; + // Compare shorthands def : InstAlias(NAME#"Wrs") WZR, GPR32:$src1, GPR32:$src2, 0), 5>; diff --git a/lib/Target/AArch64/AArch64InstrInfo.td b/lib/Target/AArch64/AArch64InstrInfo.td index 653f80286b2..b73e0958df9 100644 --- a/lib/Target/AArch64/AArch64InstrInfo.td +++ b/lib/Target/AArch64/AArch64InstrInfo.td @@ -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), diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 063c053ffe8..38e8b4d9a93 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -699,6 +699,25 @@ public: const MCConstantExpr *CE = cast(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(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(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())); diff --git a/test/MC/AArch64/alias-addsubimm.s b/test/MC/AArch64/alias-addsubimm.s new file mode 100644 index 00000000000..75e0a185572 --- /dev/null +++ b/test/MC/AArch64/alias-addsubimm.s @@ -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 diff --git a/test/MC/AArch64/basic-a64-diagnostics.s b/test/MC/AArch64/basic-a64-diagnostics.s index bf7db132b44..0c2bc689663 100644 --- a/test/MC/AArch64/basic-a64-diagnostics.s +++ b/test/MC/AArch64/basic-a64-diagnostics.s @@ -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