mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-21 16:04:12 +00:00
[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
This commit is contained in:
parent
350b78e5ea
commit
f643231163
@ -448,13 +448,19 @@ def logical_imm64_XFORM : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant(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<i32>, PatLeaf<(imm), [{
|
||||
return AArch64_AM::isLogicalImmediate(N->getZExtValue(), 32);
|
||||
@ -468,6 +474,12 @@ def logical_imm64 : Operand<i64>, PatLeaf<(imm), [{
|
||||
let PrintMethod = "printLogicalImm64";
|
||||
let ParserMatchClass = LogicalImm64Operand;
|
||||
}
|
||||
def logical_imm32_not : Operand<i32> {
|
||||
let ParserMatchClass = LogicalImm32NotOperand;
|
||||
}
|
||||
def logical_imm64_not : Operand<i64> {
|
||||
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<string asm, Instruction inst, RegisterClass regtype>
|
||||
: InstAlias<asm#" $dst, $src1, $src2",
|
||||
(inst regtype:$dst, regtype:$src1, regtype:$src2, 0)>;
|
||||
|
||||
let AddedComplexity = 6 in
|
||||
multiclass LogicalImm<bits<2> opc, string mnemonic, SDNode OpNode> {
|
||||
multiclass LogicalImm<bits<2> opc, string mnemonic, SDNode OpNode,
|
||||
string Alias> {
|
||||
let AddedComplexity = 6 in
|
||||
def Wri : BaseLogicalImm<opc, GPR32sp, GPR32, logical_imm32, mnemonic,
|
||||
[(set GPR32sp:$Rd, (OpNode GPR32:$Rn,
|
||||
logical_imm32:$imm))]> {
|
||||
let Inst{31} = 0;
|
||||
let Inst{22} = 0; // 64-bit version has an additional bit of immediate.
|
||||
}
|
||||
let AddedComplexity = 6 in
|
||||
def Xri : BaseLogicalImm<opc, GPR64sp, GPR64, logical_imm64, mnemonic,
|
||||
[(set GPR64sp:$Rd, (OpNode GPR64:$Rn,
|
||||
logical_imm64:$imm))]> {
|
||||
let Inst{31} = 1;
|
||||
}
|
||||
|
||||
def : InstAlias<Alias # " $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Wri") GPR32sp:$Rd, GPR32:$Rn,
|
||||
logical_imm32_not:$imm), 0>;
|
||||
def : InstAlias<Alias # " $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Xri") GPR64sp:$Rd, GPR64:$Rn,
|
||||
logical_imm64_not:$imm), 0>;
|
||||
}
|
||||
|
||||
multiclass LogicalImmS<bits<2> opc, string mnemonic, SDNode OpNode> {
|
||||
multiclass LogicalImmS<bits<2> opc, string mnemonic, SDNode OpNode,
|
||||
string Alias> {
|
||||
let isCompare = 1, Defs = [NZCV] in {
|
||||
def Wri : BaseLogicalImm<opc, GPR32, GPR32, logical_imm32, mnemonic,
|
||||
[(set GPR32:$Rd, (OpNode GPR32:$Rn, logical_imm32:$imm))]> {
|
||||
@ -1962,6 +1984,13 @@ multiclass LogicalImmS<bits<2> opc, string mnemonic, SDNode OpNode> {
|
||||
let Inst{31} = 1;
|
||||
}
|
||||
} // end Defs = [NZCV]
|
||||
|
||||
def : InstAlias<Alias # " $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Wri") GPR32:$Rd, GPR32:$Rn,
|
||||
logical_imm32_not:$imm), 0>;
|
||||
def : InstAlias<Alias # " $Rd, $Rn, $imm",
|
||||
(!cast<Instruction>(NAME # "Xri") GPR64:$Rd, GPR64:$Rn,
|
||||
logical_imm64_not:$imm), 0>;
|
||||
}
|
||||
|
||||
class BaseLogicalRegPseudo<RegisterClass regtype, SDPatternOperator OpNode>
|
||||
|
@ -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
|
||||
|
@ -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<MCConstantExpr>(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<MCConstantExpr>(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<MCConstantExpr>(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<MCConstantExpr>(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<MCConstantExpr>(getImm());
|
||||
|
41
llvm/test/MC/AArch64/alias-logicalimm.s
Normal file
41
llvm/test/MC/AArch64/alias-logicalimm.s
Normal file
@ -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
|
@ -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: ^
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user