From f643231163d2e897139b7dc1e1b53da4242b32b2 Mon Sep 17 00:00:00 2001 From: "Arnaud A. de Grandmaison" Date: Thu, 10 Jul 2014 15:12:26 +0000 Subject: [PATCH] [AArch64] Add logical alias instructions to MC AsmParser This patch teaches the AsmParser to accept some logical+immediate instructions and convert them as shown: bic Rd, Rn, #imm -> and Rd, Rn, #~imm bics Rd, Rn, #imm -> ands Rd, Rn, #~imm orn Rd, Rn, #imm -> orr Rd, Rn, #~imm eon Rd, Rn, #imm -> eor Rd, 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. For example, the bic construct is used by the linux kernel. llvm-svn: 212722 --- llvm/lib/Target/AArch64/AArch64InstrFormats.td | 49 +++++++++++++++++----- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 8 ++-- .../Target/AArch64/AsmParser/AArch64AsmParser.cpp | 33 +++++++++++++++ llvm/test/MC/AArch64/alias-logicalimm.s | 41 ++++++++++++++++++ llvm/test/MC/AArch64/basic-a64-diagnostics.s | 10 +++-- 5 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 llvm/test/MC/AArch64/alias-logicalimm.s diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index 446149b..5007172 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -448,13 +448,19 @@ def logical_imm64_XFORM : SDNodeXFormgetTargetConstant(enc, MVT::i32); }]>; -def LogicalImm32Operand : AsmOperandClass { - let Name = "LogicalImm32"; - let DiagnosticType = "LogicalSecondSource"; -} -def LogicalImm64Operand : AsmOperandClass { - let Name = "LogicalImm64"; - let DiagnosticType = "LogicalSecondSource"; +let DiagnosticType = "LogicalSecondSource" in { + def LogicalImm32Operand : AsmOperandClass { + let Name = "LogicalImm32"; + } + def LogicalImm64Operand : AsmOperandClass { + let Name = "LogicalImm64"; + } + def LogicalImm32NotOperand : AsmOperandClass { + let Name = "LogicalImm32Not"; + } + def LogicalImm64NotOperand : AsmOperandClass { + let Name = "LogicalImm64Not"; + } } def logical_imm32 : Operand, PatLeaf<(imm), [{ return AArch64_AM::isLogicalImmediate(N->getZExtValue(), 32); @@ -468,6 +474,12 @@ def logical_imm64 : Operand, PatLeaf<(imm), [{ let PrintMethod = "printLogicalImm64"; let ParserMatchClass = LogicalImm64Operand; } +def logical_imm32_not : Operand { + let ParserMatchClass = LogicalImm32NotOperand; +} +def logical_imm64_not : Operand { + let ParserMatchClass = LogicalImm64NotOperand; +} // imm0_65535 predicate - True if the immediate is in the range [0,65535]. def Imm0_65535Operand : AsmImmRange<0, 65535>; @@ -1935,22 +1947,32 @@ class LogicalRegAlias : InstAlias; -let AddedComplexity = 6 in -multiclass LogicalImm opc, string mnemonic, SDNode OpNode> { +multiclass LogicalImm opc, string mnemonic, SDNode OpNode, + string Alias> { + let AddedComplexity = 6 in def Wri : BaseLogicalImm { let Inst{31} = 0; let Inst{22} = 0; // 64-bit version has an additional bit of immediate. } + let AddedComplexity = 6 in def Xri : BaseLogicalImm { let Inst{31} = 1; } + + def : InstAlias(NAME # "Wri") GPR32sp:$Rd, GPR32:$Rn, + logical_imm32_not:$imm), 0>; + def : InstAlias(NAME # "Xri") GPR64sp:$Rd, GPR64:$Rn, + logical_imm64_not:$imm), 0>; } -multiclass LogicalImmS opc, string mnemonic, SDNode OpNode> { +multiclass LogicalImmS opc, string mnemonic, SDNode OpNode, + string Alias> { let isCompare = 1, Defs = [NZCV] in { def Wri : BaseLogicalImm { @@ -1962,6 +1984,13 @@ multiclass LogicalImmS opc, string mnemonic, SDNode OpNode> { let Inst{31} = 1; } } // end Defs = [NZCV] + + def : InstAlias(NAME # "Wri") GPR32:$Rd, GPR32:$Rn, + logical_imm32_not:$imm), 0>; + def : InstAlias(NAME # "Xri") GPR64:$Rd, GPR64:$Rn, + logical_imm64_not:$imm), 0>; } class BaseLogicalRegPseudo diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index d7c6d78..1211fba 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -671,10 +671,10 @@ def CRC32CXrr : BaseCRC32<1, 0b11, 1, GPR64, int_aarch64_crc32cx, "crc32cx">; //===----------------------------------------------------------------------===// // (immediate) -defm ANDS : LogicalImmS<0b11, "ands", AArch64and_flag>; -defm AND : LogicalImm<0b00, "and", and>; -defm EOR : LogicalImm<0b10, "eor", xor>; -defm ORR : LogicalImm<0b01, "orr", or>; +defm ANDS : LogicalImmS<0b11, "ands", AArch64and_flag, "bics">; +defm AND : LogicalImm<0b00, "and", and, "bic">; +defm EOR : LogicalImm<0b10, "eor", xor, "eon">; +defm ORR : LogicalImm<0b01, "orr", or, "orn">; // FIXME: these aliases *are* canonical sometimes (when movz can't be // used). Actually, it seems to be working right now, but putting logical_immXX diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 69f51da..c42d11e 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -633,6 +633,23 @@ public: return false; return AArch64_AM::isLogicalImmediate(MCE->getValue(), 64); } + bool isLogicalImm32Not() const { + if (!isImm()) + return false; + const MCConstantExpr *MCE = dyn_cast(getImm()); + if (!MCE) + return false; + int64_t Val = ~MCE->getValue() & 0xFFFFFFFF; + return AArch64_AM::isLogicalImmediate(Val, 32); + } + bool isLogicalImm64Not() const { + if (!isImm()) + return false; + const MCConstantExpr *MCE = dyn_cast(getImm()); + if (!MCE) + return false; + return AArch64_AM::isLogicalImmediate(~MCE->getValue(), 64); + } bool isShiftedImm() const { return Kind == k_ShiftedImm; } bool isAddSubImm() const { if (!isShiftedImm() && !isImm()) @@ -1377,6 +1394,22 @@ public: Inst.addOperand(MCOperand::CreateImm(encoding)); } + void addLogicalImm32NotOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *MCE = cast(getImm()); + int64_t Val = ~MCE->getValue() & 0xFFFFFFFF; + uint64_t encoding = AArch64_AM::encodeLogicalImmediate(Val, 32); + Inst.addOperand(MCOperand::CreateImm(encoding)); + } + + void addLogicalImm64NotOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *MCE = cast(getImm()); + uint64_t encoding = + AArch64_AM::encodeLogicalImmediate(~MCE->getValue(), 64); + Inst.addOperand(MCOperand::CreateImm(encoding)); + } + void addSIMDImmType10Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *MCE = dyn_cast(getImm()); diff --git a/llvm/test/MC/AArch64/alias-logicalimm.s b/llvm/test/MC/AArch64/alias-logicalimm.s new file mode 100644 index 0000000..28ec40b --- /dev/null +++ b/llvm/test/MC/AArch64/alias-logicalimm.s @@ -0,0 +1,41 @@ +// RUN: llvm-mc -triple=aarch64-none-linux-gnu < %s | FileCheck %s + +// CHECK: and x0, x1, #0xfffffffffffffffd +// CHECK: and x0, x1, #0xfffffffffffffffd + and x0, x1, #~2 + bic x0, x1, #2 + +// CHECK: and w0, w1, #0xfffffffd +// CHECK: and w0, w1, #0xfffffffd + and w0, w1, #~2 + bic w0, w1, #2 + +// CHECK: ands x0, x1, #0xfffffffffffffffd +// CHECK: ands x0, x1, #0xfffffffffffffffd + ands x0, x1, #~2 + bics x0, x1, #2 + +// CHECK: ands w0, w1, #0xfffffffd +// CHECK: ands w0, w1, #0xfffffffd + ands w0, w1, #~2 + bics w0, w1, #2 + +// CHECK: orr x0, x1, #0xfffffffffffffffd +// CHECK: orr x0, x1, #0xfffffffffffffffd + orr x0, x1, #~2 + orn x0, x1, #2 + +// CHECK: orr w2, w1, #0xfffffffc +// CHECK: orr w2, w1, #0xfffffffc + orr w2, w1, #~3 + orn w2, w1, #3 + +// CHECK: eor x0, x1, #0xfffffffffffffffd +// CHECK: eor x0, x1, #0xfffffffffffffffd + eor x0, x1, #~2 + eon x0, x1, #2 + +// CHECK: eor w2, w1, #0xfffffffc +// CHECK: eor w2, w1, #0xfffffffc + eor w2, w1, #~3 + eon w2, w1, #3 diff --git a/llvm/test/MC/AArch64/basic-a64-diagnostics.s b/llvm/test/MC/AArch64/basic-a64-diagnostics.s index 2726d00..5293131 100644 --- a/llvm/test/MC/AArch64/basic-a64-diagnostics.s +++ b/llvm/test/MC/AArch64/basic-a64-diagnostics.s @@ -2985,13 +2985,17 @@ orn wsp, w3, w5 bics x20, sp, x9, lsr #0 orn x2, x6, sp, lsl #3 -// CHECK-ERROR: error: invalid operand for instruction +// FIXME: the diagnostic we get for 'orn wsp, w3, w5' is from the orn alias, +// which is a better match than the genuine ORNWri, whereas it would be better +// to get the ORNWri diagnostic when the alias did not match, i.e. the +// alias' diagnostics should have a lower priority. +// CHECK-ERROR: error: expected compatible register or logical immediate // CHECK-ERROR-NEXT: orn wsp, w3, w5 -// CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: ^ // CHECK-ERROR-NEXT: error: invalid operand for instruction // CHECK-ERROR-NEXT: bics x20, sp, x9, lsr #0 // CHECK-ERROR-NEXT: ^ -// CHECK-ERROR-NEXT: error: invalid operand for instruction +// CHECK-ERROR-NEXT: error: expected compatible register or logical immediate // CHECK-ERROR-NEXT: orn x2, x6, sp, lsl #3 // CHECK-ERROR-NEXT: ^ -- 2.7.4