[llvm] [RFC][TableGen] Require DAG argument for complex operands in InstAlias (PR #136411)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 23 10:14:40 PDT 2025
https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/136411
>From 8d4c44b54da6b7cf8e015f2cc9d0eb11c040b553 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Mon, 25 Mar 2024 23:32:10 +0300
Subject: [PATCH 1/2] [RFC][TableGen] Require DAG argument for complex operands
in InstAlias
---
.../lib/Target/AArch64/AArch64InstrFormats.td | 109 +++---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 78 ++--
llvm/lib/Target/AArch64/SVEInstrFormats.td | 18 +-
llvm/lib/Target/ARM/ARMInstrFormats.td | 2 +-
llvm/lib/Target/ARM/ARMInstrInfo.td | 2 +-
llvm/lib/Target/ARM/ARMInstrNEON.td | 4 -
llvm/lib/Target/ARM/ARMInstrThumb.td | 8 +-
llvm/lib/Target/ARM/ARMInstrThumb2.td | 23 +-
llvm/lib/Target/Lanai/LanaiInstrInfo.td | 2 +-
llvm/lib/Target/PowerPC/PPCInstrInfo.td | 32 +-
.../TableGen/Common/CodeGenInstAlias.cpp | 337 ++++++++----------
llvm/utils/TableGen/Common/CodeGenInstAlias.h | 28 +-
12 files changed, 327 insertions(+), 316 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 9bbcb6f3aedf5..5901bd8184c67 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -3028,8 +3028,12 @@ class BaseAddSubEReg64<bit isSub, bit setFlags, RegisterClass dstRegtype,
// Aliases for register+register add/subtract.
class AddSubRegAlias<string asm, Instruction inst, RegisterClass dstRegtype,
- RegisterClass src1Regtype, RegisterClass src2Regtype,
- int shiftExt>
+ RegisterClass src1Regtype, dag src2>
+ : InstAlias<asm#"\t$dst, $src1, $src2",
+ (inst dstRegtype:$dst, src1Regtype:$src1, src2)>;
+class AddSubRegAlias64<string asm, Instruction inst, RegisterClass dstRegtype,
+ RegisterClass src1Regtype, RegisterClass src2Regtype,
+ int shiftExt>
: InstAlias<asm#"\t$dst, $src1, $src2",
(inst dstRegtype:$dst, src1Regtype:$src1, src2Regtype:$src2,
shiftExt)>;
@@ -3097,22 +3101,22 @@ multiclass AddSub<bit isSub, string mnemonic, string alias,
// Register/register aliases with no shift when SP is not used.
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
- GPR32, GPR32, GPR32, 0>;
+ GPR32, GPR32, (arith_shifted_reg32 GPR32:$src2, 0)>;
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Xrs"),
- GPR64, GPR64, GPR64, 0>;
+ GPR64, GPR64, (arith_shifted_reg64 GPR64:$src2, 0)>;
// Register/register aliases with no shift when either the destination or
// first source register is SP.
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrx"),
- GPR32sponly, GPR32sp, GPR32, 16>; // UXTW #0
+ GPR32sponly, GPR32sp,
+ (arith_extended_reg32_i32 GPR32:$src2, 16)>; // UXTW #0
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrx"),
- GPR32sp, GPR32sponly, GPR32, 16>; // UXTW #0
- def : AddSubRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Xrx64"),
- GPR64sponly, GPR64sp, GPR64, 24>; // UXTX #0
- def : AddSubRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Xrx64"),
- GPR64sp, GPR64sponly, GPR64, 24>; // UXTX #0
+ GPR32sp, GPR32sponly,
+ (arith_extended_reg32_i32 GPR32:$src2, 16)>; // UXTW #0
+ def : AddSubRegAlias64<mnemonic, !cast<Instruction>(NAME#"Xrx64"),
+ GPR64sponly, GPR64sp, GPR64, 24>; // UXTX #0
+ def : AddSubRegAlias64<mnemonic, !cast<Instruction>(NAME#"Xrx64"),
+ GPR64sp, GPR64sponly, GPR64, 24>; // UXTX #0
}
multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp,
@@ -3176,15 +3180,19 @@ multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp,
def : InstAlias<cmp#"\t$src, $imm", (!cast<Instruction>(NAME#"Xri")
XZR, GPR64sp:$src, addsub_shifted_imm64:$imm), 5>;
def : InstAlias<cmp#"\t$src1, $src2$sh", (!cast<Instruction>(NAME#"Wrx")
- WZR, GPR32sp:$src1, GPR32:$src2, arith_extend:$sh), 4>;
+ WZR, GPR32sp:$src1,
+ (arith_extended_reg32_i32 GPR32:$src2, arith_extend:$sh)), 4>;
def : InstAlias<cmp#"\t$src1, $src2$sh", (!cast<Instruction>(NAME#"Xrx")
- XZR, GPR64sp:$src1, GPR32:$src2, arith_extend:$sh), 4>;
+ XZR, GPR64sp:$src1,
+ (arith_extended_reg32_i64 GPR32:$src2, arith_extend:$sh)), 4>;
def : InstAlias<cmp#"\t$src1, $src2$sh", (!cast<Instruction>(NAME#"Xrx64")
XZR, GPR64sp:$src1, GPR64:$src2, arith_extendlsl64:$sh), 4>;
def : InstAlias<cmp#"\t$src1, $src2$sh", (!cast<Instruction>(NAME#"Wrs")
- WZR, GPR32:$src1, GPR32:$src2, arith_shift32:$sh), 4>;
+ WZR, GPR32:$src1,
+ (arith_shifted_reg32 GPR32:$src2, arith_shift32:$sh)), 4>;
def : InstAlias<cmp#"\t$src1, $src2$sh", (!cast<Instruction>(NAME#"Xrs")
- XZR, GPR64:$src1, GPR64:$src2, arith_shift64:$sh), 4>;
+ XZR, GPR64:$src1,
+ (arith_shifted_reg64 GPR64:$src2, arith_shift64:$sh)), 4>;
// Support negative immediates, e.g. cmp Rn, -imm -> cmn Rn, imm
def : InstSubst<cmpAlias#"\t$src, $imm", (!cast<Instruction>(NAME#"Wri")
@@ -3194,27 +3202,28 @@ multiclass AddSubS<bit isSub, string mnemonic, SDNode OpNode, string cmp,
// Compare shorthands
def : InstAlias<cmp#"\t$src1, $src2", (!cast<Instruction>(NAME#"Wrs")
- WZR, GPR32:$src1, GPR32:$src2, 0), 5>;
+ WZR, GPR32:$src1, (arith_shifted_reg32 GPR32:$src2, 0)), 5>;
def : InstAlias<cmp#"\t$src1, $src2", (!cast<Instruction>(NAME#"Xrs")
- XZR, GPR64:$src1, GPR64:$src2, 0), 5>;
+ XZR, GPR64:$src1, (arith_shifted_reg64 GPR64:$src2, 0)), 5>;
def : InstAlias<cmp#"\t$src1, $src2", (!cast<Instruction>(NAME#"Wrx")
- WZR, GPR32sponly:$src1, GPR32:$src2, 16), 5>;
+ WZR, GPR32sponly:$src1,
+ (arith_extended_reg32_i32 GPR32:$src2, 16)), 5>;
def : InstAlias<cmp#"\t$src1, $src2", (!cast<Instruction>(NAME#"Xrx64")
XZR, GPR64sponly:$src1, GPR64:$src2, 24), 5>;
// Register/register aliases with no shift when SP is not used.
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
- GPR32, GPR32, GPR32, 0>;
+ GPR32, GPR32, (arith_shifted_reg32 GPR32:$src2, 0)>;
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Xrs"),
- GPR64, GPR64, GPR64, 0>;
+ GPR64, GPR64, (arith_shifted_reg64 GPR64:$src2, 0)>;
// Register/register aliases with no shift when the first source register
// is SP.
def : AddSubRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrx"),
- GPR32, GPR32sponly, GPR32, 16>; // UXTW #0
- def : AddSubRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Xrx64"),
- GPR64, GPR64sponly, GPR64, 24>; // UXTX #0
+ GPR32, GPR32sponly,
+ (arith_extended_reg32_i32 GPR32:$src2, 16)>; // UXTW #0
+ def : AddSubRegAlias64<mnemonic, !cast<Instruction>(NAME#"Xrx64"),
+ GPR64, GPR64sponly, GPR64, 24>; // UXTX #0
}
class AddSubG<bit isSub, string asm_inst, SDPatternOperator OpNode>
@@ -3399,9 +3408,10 @@ class BaseLogicalSReg<bits<2> opc, bit N, RegisterClass regtype,
}
// Aliases for register+register logical instructions.
-class LogicalRegAlias<string asm, Instruction inst, RegisterClass regtype>
+class LogicalRegAlias<string asm, Instruction inst, RegisterClass regtype,
+ dag op2>
: InstAlias<asm#"\t$dst, $src1, $src2",
- (inst regtype:$dst, regtype:$src1, regtype:$src2, 0)>;
+ (inst regtype:$dst, regtype:$src1, op2)>;
multiclass LogicalImm<bits<2> opc, string mnemonic, SDNode OpNode,
string Alias> {
@@ -3473,10 +3483,10 @@ multiclass LogicalReg<bits<2> opc, bit N, string mnemonic,
let Inst{31} = 1;
}
- def : LogicalRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Wrs"), GPR32>;
- def : LogicalRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Xrs"), GPR64>;
+ def : LogicalRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
+ GPR32, (logical_shifted_reg32 GPR32:$src2, 0)>;
+ def : LogicalRegAlias<mnemonic, !cast<Instruction>(NAME#"Xrs"),
+ GPR64, (logical_shifted_reg64 GPR64:$src2, 0)>;
}
// Split from LogicalReg to allow setting NZCV Defs
@@ -3496,10 +3506,10 @@ multiclass LogicalRegS<bits<2> opc, bit N, string mnemonic,
}
} // Defs = [NZCV]
- def : LogicalRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Wrs"), GPR32>;
- def : LogicalRegAlias<mnemonic,
- !cast<Instruction>(NAME#"Xrs"), GPR64>;
+ def : LogicalRegAlias<mnemonic, !cast<Instruction>(NAME#"Wrs"),
+ GPR32, (logical_shifted_reg32 GPR32:$src2, 0)>;
+ def : LogicalRegAlias<mnemonic, !cast<Instruction>(NAME#"Xrs"),
+ GPR64, (logical_shifted_reg64 GPR64:$src2, 0)>;
}
//---
@@ -3987,9 +3997,10 @@ class LoadStore8RO<bits<2> sz, bit V, bits<2> opc, string asm, dag ins,
let Inst{4-0} = Rt;
}
-class ROInstAlias<string asm, DAGOperand regtype, Instruction INST>
+class ROInstAlias<string asm, DAGOperand regtype, Instruction INST,
+ ro_extend ext>
: InstAlias<asm # "\t$Rt, [$Rn, $Rm]",
- (INST regtype:$Rt, GPR64sp:$Rn, GPR64:$Rm, 0, 0)>;
+ (INST regtype:$Rt, GPR64sp:$Rn, GPR64:$Rm, (ext 0, 0))>;
multiclass Load8RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
string asm, ValueType Ty, SDPatternOperator loadop> {
@@ -4015,7 +4026,7 @@ multiclass Load8RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend8>;
}
multiclass Store8RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
@@ -4040,7 +4051,7 @@ multiclass Store8RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend8>;
}
class LoadStore16RO<bits<2> sz, bit V, bits<2> opc, string asm, dag ins,
@@ -4087,7 +4098,7 @@ multiclass Load16RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend16>;
}
multiclass Store16RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
@@ -4112,7 +4123,7 @@ multiclass Store16RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend16>;
}
class LoadStore32RO<bits<2> sz, bit V, bits<2> opc, string asm, dag ins,
@@ -4159,7 +4170,7 @@ multiclass Load32RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend32>;
}
multiclass Store32RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
@@ -4184,7 +4195,7 @@ multiclass Store32RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend32>;
}
class LoadStore64RO<bits<2> sz, bit V, bits<2> opc, string asm, dag ins,
@@ -4231,7 +4242,7 @@ multiclass Load64RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend64>;
}
multiclass Store64RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
@@ -4256,7 +4267,7 @@ multiclass Store64RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend64>;
}
class LoadStore128RO<bits<2> sz, bit V, bits<2> opc, string asm, dag ins,
@@ -4303,7 +4314,7 @@ multiclass Load128RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend128>;
}
multiclass Store128RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
@@ -4324,7 +4335,7 @@ multiclass Store128RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
let Inst{13} = 0b1;
}
- def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
+ def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX"), ro_Xextend128>;
}
let mayLoad = 0, mayStore = 0, hasSideEffects = 1 in
@@ -4373,9 +4384,7 @@ multiclass PrefetchRO<bits<2> sz, bit V, bits<2> opc, string asm> {
let Inst{13} = 0b1;
}
- def : InstAlias<"prfm $Rt, [$Rn, $Rm]",
- (!cast<Instruction>(NAME # "roX") prfop:$Rt,
- GPR64sp:$Rn, GPR64:$Rm, 0, 0)>;
+ def : ROInstAlias<"prfm", prfop, !cast<Instruction>(NAME # "roX"), ro_Xextend64>;
}
//---
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index a060a2f597ccd..01c1d4b54ffbc 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2416,13 +2416,17 @@ 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)>;
+ (ADDWri GPR32sponly:$dst, GPR32sp:$src,
+ (addsub_shifted_imm32 0, 0))>;
def : InstAlias<"mov $dst, $src",
- (ADDWri GPR32sp:$dst, GPR32sponly:$src, 0, 0)>;
+ (ADDWri GPR32sp:$dst, GPR32sponly:$src,
+ (addsub_shifted_imm32 0, 0))>;
def : InstAlias<"mov $dst, $src",
- (ADDXri GPR64sponly:$dst, GPR64sp:$src, 0, 0)>;
+ (ADDXri GPR64sponly:$dst, GPR64sp:$src,
+ (addsub_shifted_imm64 0, 0))>;
def : InstAlias<"mov $dst, $src",
- (ADDXri GPR64sp:$dst, GPR64sponly:$src, 0, 0)>;
+ (ADDXri GPR64sp:$dst, GPR64sponly:$src,
+ (addsub_shifted_imm64 0, 0))>;
defm ADDS : AddSubS<0, "adds", AArch64add_flag, "cmn", "subs", "cmp">;
defm SUBS : AddSubS<1, "subs", AArch64sub_flag, "cmp", "adds", "cmn">;
@@ -2482,19 +2486,31 @@ def : Pat<(AArch64sub_flag GPR64:$Rn, neg_addsub_shifted_imm64:$imm),
(ADDSXri GPR64:$Rn, neg_addsub_shifted_imm64:$imm)>;
}
-def : InstAlias<"neg $dst, $src", (SUBWrs GPR32:$dst, WZR, GPR32:$src, 0), 3>;
-def : InstAlias<"neg $dst, $src", (SUBXrs GPR64:$dst, XZR, GPR64:$src, 0), 3>;
+def : InstAlias<"neg $dst, $src",
+ (SUBWrs GPR32:$dst, WZR,
+ (arith_shifted_reg32 GPR32:$src, 0)), 3>;
+def : InstAlias<"neg $dst, $src",
+ (SUBXrs GPR64:$dst, XZR,
+ (arith_shifted_reg64 GPR64:$src, 0)), 3>;
def : InstAlias<"neg $dst, $src$shift",
- (SUBWrs GPR32:$dst, WZR, GPR32:$src, arith_shift32:$shift), 2>;
+ (SUBWrs GPR32:$dst, WZR,
+ (arith_shifted_reg32 GPR32:$src, arith_shift32:$shift)), 2>;
def : InstAlias<"neg $dst, $src$shift",
- (SUBXrs GPR64:$dst, XZR, GPR64:$src, arith_shift64:$shift), 2>;
-
-def : InstAlias<"negs $dst, $src", (SUBSWrs GPR32:$dst, WZR, GPR32:$src, 0), 3>;
-def : InstAlias<"negs $dst, $src", (SUBSXrs GPR64:$dst, XZR, GPR64:$src, 0), 3>;
+ (SUBXrs GPR64:$dst, XZR,
+ (arith_shifted_reg64 GPR64:$src, arith_shift64:$shift)), 2>;
+
+def : InstAlias<"negs $dst, $src",
+ (SUBSWrs GPR32:$dst, WZR,
+ (arith_shifted_reg32 GPR32:$src, 0)), 3>;
+def : InstAlias<"negs $dst, $src",
+ (SUBSXrs GPR64:$dst, XZR,
+ (arith_shifted_reg64 GPR64:$src, 0)), 3>;
def : InstAlias<"negs $dst, $src$shift",
- (SUBSWrs GPR32:$dst, WZR, GPR32:$src, arith_shift32:$shift), 2>;
+ (SUBSWrs GPR32:$dst, WZR,
+ (arith_shifted_reg32 GPR32:$src, arith_shift32:$shift)), 2>;
def : InstAlias<"negs $dst, $src$shift",
- (SUBSXrs GPR64:$dst, XZR, GPR64:$src, arith_shift64:$shift), 2>;
+ (SUBSXrs GPR64:$dst, XZR,
+ (arith_shifted_reg64 GPR64:$src, arith_shift64:$shift)), 2>;
// Unsigned/Signed divide
@@ -2921,16 +2937,26 @@ defm ORN : LogicalReg<0b01, 1, "orn",
BinOpFrag<(or node:$LHS, (not node:$RHS))>>;
defm ORR : LogicalReg<0b01, 0, "orr", or>;
-def : InstAlias<"mov $dst, $src", (ORRWrs GPR32:$dst, WZR, GPR32:$src, 0), 2>;
-def : InstAlias<"mov $dst, $src", (ORRXrs GPR64:$dst, XZR, GPR64:$src, 0), 2>;
-
-def : InstAlias<"mvn $Wd, $Wm", (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, 0), 3>;
-def : InstAlias<"mvn $Xd, $Xm", (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, 0), 3>;
+def : InstAlias<"mov $dst, $src",
+ (ORRWrs GPR32:$dst, WZR,
+ (logical_shifted_reg32 GPR32:$src, 0)), 2>;
+def : InstAlias<"mov $dst, $src",
+ (ORRXrs GPR64:$dst, XZR,
+ (logical_shifted_reg64 GPR64:$src, 0)), 2>;
+
+def : InstAlias<"mvn $Wd, $Wm",
+ (ORNWrs GPR32:$Wd, WZR,
+ (logical_shifted_reg32 GPR32:$Wm, 0)), 3>;
+def : InstAlias<"mvn $Xd, $Xm",
+ (ORNXrs GPR64:$Xd, XZR,
+ (logical_shifted_reg64 GPR64:$Xm, 0)), 3>;
def : InstAlias<"mvn $Wd, $Wm$sh",
- (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, logical_shift32:$sh), 2>;
+ (ORNWrs GPR32:$Wd, WZR,
+ (logical_shifted_reg32 GPR32:$Wm, logical_shift32:$sh)), 2>;
def : InstAlias<"mvn $Xd, $Xm$sh",
- (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, logical_shift64:$sh), 2>;
+ (ORNXrs GPR64:$Xd, XZR,
+ (logical_shifted_reg64 GPR64:$Xm, logical_shift64:$sh)), 2>;
def : InstAlias<"tst $src1, $src2",
(ANDSWri WZR, GPR32:$src1, logical_imm32:$src2), 2>;
@@ -2938,14 +2964,18 @@ def : InstAlias<"tst $src1, $src2",
(ANDSXri XZR, GPR64:$src1, logical_imm64:$src2), 2>;
def : InstAlias<"tst $src1, $src2",
- (ANDSWrs WZR, GPR32:$src1, GPR32:$src2, 0), 3>;
+ (ANDSWrs WZR, GPR32:$src1,
+ (logical_shifted_reg32 GPR32:$src2, 0)), 3>;
def : InstAlias<"tst $src1, $src2",
- (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, 0), 3>;
+ (ANDSXrs XZR, GPR64:$src1,
+ (logical_shifted_reg64 GPR64:$src2, 0)), 3>;
def : InstAlias<"tst $src1, $src2$sh",
- (ANDSWrs WZR, GPR32:$src1, GPR32:$src2, logical_shift32:$sh), 2>;
+ (ANDSWrs WZR, GPR32:$src1,
+ (logical_shifted_reg32 GPR32:$src2, logical_shift32:$sh)), 2>;
def : InstAlias<"tst $src1, $src2$sh",
- (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, logical_shift64:$sh), 2>;
+ (ANDSXrs XZR, GPR64:$src1,
+ (logical_shifted_reg64 GPR64:$src2, logical_shift64:$sh)), 2>;
def : Pat<(not GPR32:$Wm), (ORNWrr WZR, GPR32:$Wm)>;
diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td
index c56713783289e..3e5ad17d9b5a9 100644
--- a/llvm/lib/Target/AArch64/SVEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td
@@ -5140,11 +5140,14 @@ multiclass sve_int_dup_imm<string asm> {
(!cast<Instruction>(NAME # _D) ZPR64:$Zd, cpy_imm8_opt_lsl_i64:$imm), 1>;
def : InstAlias<"fmov $Zd, #0.0",
- (!cast<Instruction>(NAME # _H) ZPR16:$Zd, 0, 0), 1>;
+ (!cast<Instruction>(NAME # _H) ZPR16:$Zd,
+ (cpy_imm8_opt_lsl_i16 0, 0)), 1>;
def : InstAlias<"fmov $Zd, #0.0",
- (!cast<Instruction>(NAME # _S) ZPR32:$Zd, 0, 0), 1>;
+ (!cast<Instruction>(NAME # _S) ZPR32:$Zd,
+ (cpy_imm8_opt_lsl_i32 0, 0)), 1>;
def : InstAlias<"fmov $Zd, #0.0",
- (!cast<Instruction>(NAME # _D) ZPR64:$Zd, 0, 0), 1>;
+ (!cast<Instruction>(NAME # _D) ZPR64:$Zd,
+ (cpy_imm8_opt_lsl_i64 0, 0)), 1>;
}
class sve_int_dup_fpimm<bits<2> sz8_64, Operand fpimmtype,
@@ -5522,11 +5525,14 @@ multiclass sve_int_dup_imm_pred_merge<string asm, SDPatternOperator op> {
nxv2i64, nxv2i1, i64, SVECpyDupImm64Pat>;
def : InstAlias<"fmov $Zd, $Pg/m, #0.0",
- (!cast<Instruction>(NAME # _H) ZPR16:$Zd, PPRAny:$Pg, 0, 0), 0>;
+ (!cast<Instruction>(NAME # _H) ZPR16:$Zd, PPRAny:$Pg,
+ (cpy_imm8_opt_lsl_i16 0, 0)), 0>;
def : InstAlias<"fmov $Zd, $Pg/m, #0.0",
- (!cast<Instruction>(NAME # _S) ZPR32:$Zd, PPRAny:$Pg, 0, 0), 0>;
+ (!cast<Instruction>(NAME # _S) ZPR32:$Zd, PPRAny:$Pg,
+ (cpy_imm8_opt_lsl_i32 0, 0)), 0>;
def : InstAlias<"fmov $Zd, $Pg/m, #0.0",
- (!cast<Instruction>(NAME # _D) ZPR64:$Zd, PPRAny:$Pg, 0, 0), 0>;
+ (!cast<Instruction>(NAME # _D) ZPR64:$Zd, PPRAny:$Pg,
+ (cpy_imm8_opt_lsl_i64 0, 0)), 0>;
def : Pat<(vselect PPRAny:$Pg, (SVEDup0), (nxv8f16 ZPR:$Zd)),
(!cast<Instruction>(NAME # _H) $Zd, $Pg, 0, 0)>;
diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td
index 9eb9114069143..e50740f7d57c5 100644
--- a/llvm/lib/Target/ARM/ARMInstrFormats.td
+++ b/llvm/lib/Target/ARM/ARMInstrFormats.td
@@ -160,7 +160,7 @@ def CondCodeOperand : AsmOperandClass {
let DefaultMethod = "defaultCondCodeOp";
let IsOptional = true;
}
-def pred : PredicateOperand<OtherVT, (ops i32imm, i32imm),
+def pred : PredicateOperand<OtherVT, (ops i32imm, CCR),
(ops (i32 14), (i32 zero_reg))> {
let PrintMethod = "printPredicateOperand";
let ParserMatchClass = CondCodeOperand;
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index d6387ff848593..356aba914e221 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -6469,7 +6469,7 @@ def : ARMInstAlias<"neg${s}${p} $Rd, $Rm",
(RSBri GPR:$Rd, GPR:$Rm, 0, pred:$p, cc_out:$s)>;
// Pre-v6, 'mov r0, r0' was used as a NOP encoding.
-def : InstAlias<"nop${p}", (MOVr R0, R0, pred:$p, zero_reg), 0>,
+def : InstAlias<"nop${p}", (MOVr R0, R0, pred:$p, (cc_out zero_reg)), 0>,
Requires<[IsARM, NoV6]>;
// MUL/UMLAL/SMLAL/UMULL/SMULL are available on all arches, but
diff --git a/llvm/lib/Target/ARM/ARMInstrNEON.td b/llvm/lib/Target/ARM/ARMInstrNEON.td
index 3335f52f15555..63d2e4e0a535e 100644
--- a/llvm/lib/Target/ARM/ARMInstrNEON.td
+++ b/llvm/lib/Target/ARM/ARMInstrNEON.td
@@ -95,28 +95,24 @@ def VectorIndex8 : Operand<i32>, ImmLeaf<i32, [{
}]> {
let ParserMatchClass = VectorIndex8Operand;
let PrintMethod = "printVectorIndex";
- let MIOperandInfo = (ops i32imm);
}
def VectorIndex16 : Operand<i32>, ImmLeaf<i32, [{
return ((uint64_t)Imm) < 4;
}]> {
let ParserMatchClass = VectorIndex16Operand;
let PrintMethod = "printVectorIndex";
- let MIOperandInfo = (ops i32imm);
}
def VectorIndex32 : Operand<i32>, ImmLeaf<i32, [{
return ((uint64_t)Imm) < 2;
}]> {
let ParserMatchClass = VectorIndex32Operand;
let PrintMethod = "printVectorIndex";
- let MIOperandInfo = (ops i32imm);
}
def VectorIndex64 : Operand<i32>, ImmLeaf<i32, [{
return ((uint64_t)Imm) < 1;
}]> {
let ParserMatchClass = VectorIndex64Operand;
let PrintMethod = "printVectorIndex";
- let MIOperandInfo = (ops i32imm);
}
// Register list of one D register.
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td
index b69bc601a0cdc..46746dde384af 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb.td
@@ -1209,8 +1209,9 @@ def tMOVi8 : T1sI<(outs tGPR:$Rd), (ins imm0_255_expr:$imm8), IIC_iMOVi,
}
// Because we have an explicit tMOVSr below, we need an alias to handle
// the immediate "movs" form here. Blech.
-def : tInstAlias <"movs $Rdn, $imm8",
- (tMOVi8 tGPR:$Rdn, CPSR, imm0_255_expr:$imm8, 14, zero_reg)>;
+def : tInstAlias<"movs $Rdn, $imm8",
+ (tMOVi8 tGPR:$Rdn, (s_cc_out CPSR),
+ imm0_255_expr:$imm8, (pred 14, zero_reg))>;
// A7-73: MOV(2) - mov setting flag.
@@ -1764,7 +1765,8 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
// In Thumb1, "nop" is encoded as a "mov r8, r8". Technically, the bf00
// encoding is available on ARMv6K, but we don't differentiate that finely.
-def : InstAlias<"nop", (tMOVr R8, R8, 14, zero_reg), 0>, Requires<[IsThumb, IsThumb1Only]>;
+def : InstAlias<"nop", (tMOVr R8, R8, (pred 14, zero_reg)), 0>,
+ Requires<[IsThumb, IsThumb1Only]>;
// "neg" is and alias for "rsb rd, rn, #0"
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
index 9f80af07df0fc..ed24e9ddd8f4e 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -2222,11 +2222,11 @@ def t2MOVr : T2sTwoReg<(outs GPRnopc:$Rd), (ins GPRnopc:$Rm), IIC_iMOVr,
let Inst{7-4} = 0b0000;
}
def : t2InstAlias<"mov${p}.w $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPRnopc:$Rm,
- pred:$p, zero_reg)>;
+ pred:$p, (cc_out zero_reg))>;
def : t2InstAlias<"movs${p}.w $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPRnopc:$Rm,
- pred:$p, CPSR)>;
+ pred:$p, (cc_out CPSR))>;
def : t2InstAlias<"movs${p} $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPRnopc:$Rm,
- pred:$p, CPSR)>;
+ pred:$p, (cc_out CPSR))>;
// AddedComplexity to ensure isel tries t2MOVi before t2MOVi16.
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1,
@@ -2244,14 +2244,14 @@ def t2MOVi : T2sOneRegImm<(outs rGPR:$Rd), (ins t2_so_imm:$imm), IIC_iMOVi,
// cc_out is handled as part of the explicit mnemonic in the parser for 'mov'.
// Use aliases to get that to play nice here.
def : t2InstAlias<"movs${p}.w $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm,
- pred:$p, CPSR)>;
+ pred:$p, (cc_out CPSR))>;
def : t2InstAlias<"movs${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm,
- pred:$p, CPSR)>;
+ pred:$p, (cc_out CPSR))>;
def : t2InstAlias<"mov${p}.w $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm,
- pred:$p, zero_reg)>;
+ pred:$p, (cc_out zero_reg))>;
def : t2InstAlias<"mov${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm,
- pred:$p, zero_reg)>;
+ pred:$p, (cc_out zero_reg))>;
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins imm0_65535_expr:$imm), IIC_iMOVi,
@@ -5122,8 +5122,10 @@ def : InstAlias<"isb${p}.w", (t2ISB 0xf, pred:$p), 0>, Requires<[HasDB]>;
// Non-predicable aliases of a predicable DSB: the predicate is (14, zero_reg) where
// 14 = AL (always execute) and zero_reg = "instruction doesn't read the CPSR".
-def : InstAlias<"ssbb", (t2DSB 0x0, 14, zero_reg), 1>, Requires<[HasDB, IsThumb2]>;
-def : InstAlias<"pssbb", (t2DSB 0x4, 14, zero_reg), 1>, Requires<[HasDB, IsThumb2]>;
+def : InstAlias<"ssbb", (t2DSB 0x0, (pred 14, zero_reg)), 1>,
+ Requires<[HasDB, IsThumb2]>;
+def : InstAlias<"pssbb", (t2DSB 0x4, (pred 14, zero_reg)), 1>,
+ Requires<[HasDB, IsThumb2]>;
// Armv8-R 'Data Full Barrier'
def : InstAlias<"dfb${p}", (t2DSB 0xc, pred:$p), 1>, Requires<[HasDFB]>;
@@ -5340,7 +5342,8 @@ def : t2InstAlias<"sxth${p} $Rd, $Rm$rot",
// "mov Rd, t2_so_imm_not" can be handled via "mvn" in assembly, just like
// for isel.
def : t2InstSubst<"mov${p} $Rd, $imm",
- (t2MVNi rGPR:$Rd, t2_so_imm_not:$imm, pred:$p, zero_reg)>;
+ (t2MVNi rGPR:$Rd, t2_so_imm_not:$imm, pred:$p,
+ (cc_out zero_reg))>;
def : t2InstSubst<"mvn${s}${p} $Rd, $imm",
(t2MOVi rGPR:$Rd, t2_so_imm_not:$imm, pred:$p, s_cc_out:$s)>;
// Same for AND <--> BIC
diff --git a/llvm/lib/Target/Lanai/LanaiInstrInfo.td b/llvm/lib/Target/Lanai/LanaiInstrInfo.td
index 6feed27b7047b..8950cb85715d9 100644
--- a/llvm/lib/Target/Lanai/LanaiInstrInfo.td
+++ b/llvm/lib/Target/Lanai/LanaiInstrInfo.td
@@ -402,7 +402,7 @@ def : Pat<(LanaiSubbF GPR:$Rs1, i32lo16z:$imm),
def : Pat<(LanaiSubbF GPR:$Rs1, i32hi16:$imm),
(SUBB_F_I_HI GPR:$Rs1, i32hi16:$imm)>;
-def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0, 0)>;
+def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0, (pred 0))>;
let isAsCheapAsAMove = 1, Rs1 = R0.Num, isCodeGenOnly = 1, H = 1, F = 0,
isReMaterializable = 1 in
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
index e2864c2405967..d4853d5f61b6a 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
@@ -4984,44 +4984,44 @@ defm : BranchSimpleMnemonic1<"dzf", "", 2>;
multiclass BranchExtendedMnemonicPM<string name, string pm, int bibo> {
def : InstAlias<"b"#name#pm#" $cc, $dst",
- (BCC bibo, crrc:$cc, condbrtarget:$dst)>;
+ (BCC (pred bibo, crrc:$cc), condbrtarget:$dst)>;
def : InstAlias<"b"#name#pm#" $dst",
- (BCC bibo, CR0, condbrtarget:$dst)>;
+ (BCC (pred bibo, CR0), condbrtarget:$dst)>;
def : InstAlias<"b"#name#"a"#pm#" $cc, $dst",
- (BCCA bibo, crrc:$cc, abscondbrtarget:$dst)>;
+ (BCCA (pred bibo, crrc:$cc), abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"a"#pm#" $dst",
- (BCCA bibo, CR0, abscondbrtarget:$dst)>;
+ (BCCA (pred bibo, CR0), abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"lr"#pm#" $cc",
- (BCCLR bibo, crrc:$cc)>;
+ (BCCLR (pred bibo, crrc:$cc))>;
def : InstAlias<"b"#name#"lr"#pm,
- (BCCLR bibo, CR0)>;
+ (BCCLR (pred bibo, CR0))>;
def : InstAlias<"b"#name#"ctr"#pm#" $cc",
- (BCCCTR bibo, crrc:$cc)>;
+ (BCCCTR (pred bibo, crrc:$cc))>;
def : InstAlias<"b"#name#"ctr"#pm,
- (BCCCTR bibo, CR0)>;
+ (BCCCTR (pred bibo, CR0))>;
def : InstAlias<"b"#name#"l"#pm#" $cc, $dst",
- (BCCL bibo, crrc:$cc, condbrtarget:$dst)>;
+ (BCCL (pred bibo, crrc:$cc), condbrtarget:$dst)>;
def : InstAlias<"b"#name#"l"#pm#" $dst",
- (BCCL bibo, CR0, condbrtarget:$dst)>;
+ (BCCL (pred bibo, CR0), condbrtarget:$dst)>;
def : InstAlias<"b"#name#"la"#pm#" $cc, $dst",
- (BCCLA bibo, crrc:$cc, abscondbrtarget:$dst)>;
+ (BCCLA (pred bibo, crrc:$cc), abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"la"#pm#" $dst",
- (BCCLA bibo, CR0, abscondbrtarget:$dst)>;
+ (BCCLA (pred bibo, CR0), abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"lrl"#pm#" $cc",
- (BCCLRL bibo, crrc:$cc)>;
+ (BCCLRL (pred bibo, crrc:$cc))>;
def : InstAlias<"b"#name#"lrl"#pm,
- (BCCLRL bibo, CR0)>;
+ (BCCLRL (pred bibo, CR0))>;
def : InstAlias<"b"#name#"ctrl"#pm#" $cc",
- (BCCCTRL bibo, crrc:$cc)>;
+ (BCCCTRL (pred bibo, crrc:$cc))>;
def : InstAlias<"b"#name#"ctrl"#pm,
- (BCCCTRL bibo, CR0)>;
+ (BCCCTRL (pred bibo, CR0))>;
}
multiclass BranchExtendedMnemonic<string name, int bibo> {
defm : BranchExtendedMnemonicPM<name, "", bibo>;
diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp
index 94c0d51faf2e9..ad5dbbf91743b 100644
--- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp
@@ -15,155 +15,125 @@
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Error.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
-/// tryAliasOpMatch - This is a helper function for the CodeGenInstAlias
-/// constructor. It checks if an argument in an InstAlias pattern matches
-/// the corresponding operand of the instruction. It returns true on a
-/// successful match, with ResOp set to the result operand to be used.
-bool CodeGenInstAlias::tryAliasOpMatch(const DagInit *Result,
- unsigned AliasOpNo,
- const Record *InstOpRec, bool hasSubOps,
- ArrayRef<SMLoc> Loc,
- const CodeGenTarget &T,
- ResultOperand &ResOp) {
- const Init *Arg = Result->getArg(AliasOpNo);
- const DefInit *ADI = dyn_cast<DefInit>(Arg);
- const Record *ResultRecord = ADI ? ADI->getDef() : nullptr;
-
- if (ADI && ADI->getDef() == InstOpRec) {
- // If the operand is a record, it must have a name, and the record type
- // must match up with the instruction's argument type.
- if (!Result->getArgName(AliasOpNo))
- PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) +
- " must have a name!");
- ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
- ResultRecord);
- return true;
- }
-
- // For register operands, the source register class can be a subclass
- // of the instruction register class, not just an exact match.
- if (InstOpRec->isSubClassOf("RegisterOperand"))
- InstOpRec = InstOpRec->getValueAsDef("RegClass");
+unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const {
+ if (!isRecord())
+ return 1;
- if (ADI && ADI->getDef()->isSubClassOf("RegisterOperand"))
- ADI = ADI->getDef()->getValueAsDef("RegClass")->getDefInit();
+ const Record *Rec = getRecord();
+ if (!Rec->isSubClassOf("Operand"))
+ return 1;
- if (ADI && ADI->getDef()->isSubClassOf("RegisterClass")) {
- if (!InstOpRec->isSubClassOf("RegisterClass"))
- return false;
- if (!T.getRegisterClass(InstOpRec).hasSubClass(
- &T.getRegisterClass(ADI->getDef())))
- return false;
- ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
- ResultRecord);
- return true;
+ const DagInit *MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
+ if (MIOpInfo->getNumArgs() == 0) {
+ // Unspecified, so it defaults to 1
+ return 1;
}
- // Handle explicit registers.
- if (ADI && ADI->getDef()->isSubClassOf("Register")) {
- if (InstOpRec->isSubClassOf("OptionalDefOperand")) {
- const DagInit *DI = InstOpRec->getValueAsDag("MIOperandInfo");
- // The operand info should only have a single (register) entry. We
- // want the register class of it.
- InstOpRec = cast<DefInit>(DI->getArg(0))->getDef();
- }
-
- if (!InstOpRec->isSubClassOf("RegisterClass"))
- return false;
-
- if (!T.getRegisterClass(InstOpRec).contains(
- T.getRegBank().getReg(ADI->getDef())))
- PrintFatalError(Loc, "fixed register " + ADI->getDef()->getName() +
- " is not a member of the " +
- InstOpRec->getName() + " register class!");
-
- if (Result->getArgName(AliasOpNo))
- PrintFatalError(Loc, "result fixed register argument must "
- "not have a name!");
+ return MIOpInfo->getNumArgs();
+}
- ResOp = ResultOperand(ResultRecord);
- return true;
+static const Record *getInitValueAsRegClass(const Init *V) {
+ if (const DefInit *VDefInit = dyn_cast<DefInit>(V)) {
+ const Record *R = VDefInit->getDef();
+ if (R->isSubClassOf("RegisterClass"))
+ return R;
+ if (R->isSubClassOf("RegisterOperand"))
+ return R->getValueAsDef("RegClass");
}
+ return nullptr;
+}
+
+using ResultOperand = CodeGenInstAlias::ResultOperand;
+
+static Expected<ResultOperand> matchSimpleOperand(const Init *Arg,
+ const StringInit *ArgName,
+ const Record *Op,
+ const CodeGenTarget &T) {
+ if (Op->isSubClassOf("RegisterClass") ||
+ Op->isSubClassOf("RegisterOperand")) {
+ const Record *OpRC =
+ Op->isSubClassOf("RegisterClass") ? Op : Op->getValueAsDef("RegClass");
+
+ if (const auto *ArgDef = dyn_cast<DefInit>(Arg)) {
+ const Record *ArgRec = ArgDef->getDef();
+
+ // Match 'RegClass:$name' or 'RegOp:$name'.
+ if (const Record *ArgRC = getInitValueAsRegClass(Arg)) {
+ if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC)))
+ return createStringError(
+ "argument register class" + ArgRC->getName() +
+ " is not a subclass of operand register class " +
+ OpRC->getName());
+ if (!ArgName)
+ return createStringError("register class argument must have a name");
+ return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
+ cast<DefInit>(Arg)->getDef());
+ }
- // Handle "zero_reg" for optional def operands.
- if (ADI && ADI->getDef()->getName() == "zero_reg") {
+ // Match 'Reg'.
+ if (ArgRec->isSubClassOf("Register")) {
+ if (!T.getRegisterClass(OpRC).contains(T.getRegBank().getReg(ArgRec)))
+ return createStringError(
+ "register argument " + ArgRec->getName() +
+ " is not a member of operand register class " + OpRC->getName());
+ if (ArgName)
+ return createStringError("register argument must not have a name");
+ return ResultOperand::createRegister(ArgRec);
+ }
- // Check if this is an optional def.
- // Tied operands where the source is a sub-operand of a complex operand
- // need to represent both operands in the alias destination instruction.
- // Allow zero_reg for the tied portion. This can and should go away once
- // the MC representation of things doesn't use tied operands at all.
- // if (!InstOpRec->isSubClassOf("OptionalDefOperand"))
- // throw TGError(Loc, "reg0 used for result that is not an "
- // "OptionalDefOperand!");
+ // Match 'zero_reg'.
+ if (ArgRec->getName() == "zero_reg") {
+ if (ArgName)
+ return createStringError("register argument must not have a name");
+ return ResultOperand::createRegister(nullptr);
+ }
+ }
- ResOp = ResultOperand(nullptr);
- return true;
+ return createStringError("argument must be a subclass of RegisterClass, "
+ "RegisterOperand, or zero_reg");
}
- // Literal integers.
- if (const IntInit *II = dyn_cast<IntInit>(Arg)) {
- if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
- return false;
- // Integer arguments can't have names.
- if (Result->getArgName(AliasOpNo))
- PrintFatalError(Loc, "result argument #" + Twine(AliasOpNo) +
- " must not have a name!");
- ResOp = ResultOperand(II->getValue());
- return true;
- }
+ if (Op->isSubClassOf("Operand")) {
+ // Match integer or bits.
+ if (const IntInit *ArgInt = dyn_cast_or_null<IntInit>(
+ Arg->convertInitializerTo(IntRecTy::get(Arg->getRecordKeeper())))) {
+ if (ArgName)
+ return createStringError("integer argument must not have a name");
+ return ResultOperand::createImmediate(ArgInt->getValue());
+ }
- // Bits<n> (also used for 0bxx literals)
- if (const BitsInit *BI = dyn_cast<BitsInit>(Arg)) {
- if (hasSubOps || !InstOpRec->isSubClassOf("Operand"))
- return false;
- if (!BI->isComplete())
- return false;
- // Convert the bits init to an integer and use that for the result.
- std::optional<int64_t> Value = BI->convertInitializerToInt();
- if (!Value)
- return false;
- ResOp = ResultOperand(*Value);
- return true;
- }
+ // Match a subclass of Operand.
+ if (const auto *ArgDef = dyn_cast<DefInit>(Arg);
+ ArgDef && ArgDef->getDef()->isSubClassOf("Operand")) {
+ if (!ArgName)
+ return createStringError("argument must have a name");
+ return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
+ ArgDef->getDef());
+ }
- // If both are Operands with the same MVT, allow the conversion. It's
- // up to the user to make sure the values are appropriate, just like
- // for isel Pat's.
- if (InstOpRec->isSubClassOf("Operand") && ADI &&
- ADI->getDef()->isSubClassOf("Operand")) {
- // FIXME: What other attributes should we check here? Identical
- // MIOperandInfo perhaps?
- if (InstOpRec->getValueInit("Type") != ADI->getDef()->getValueInit("Type"))
- return false;
- ResOp = ResultOperand(std::string(Result->getArgNameStr(AliasOpNo)),
- ADI->getDef());
- return true;
+ return createStringError("argument must be a subclass of Operand");
}
- return false;
+ llvm_unreachable("Unknown operand kind");
}
-unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const {
- if (!isRecord())
- return 1;
-
- const Record *Rec = getRecord();
- if (!Rec->isSubClassOf("Operand"))
- return 1;
-
- const DagInit *MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
- if (MIOpInfo->getNumArgs() == 0) {
- // Unspecified, so it defaults to 1
- return 1;
- }
-
- return MIOpInfo->getNumArgs();
+static Expected<ResultOperand> matchComplexOperand(const Init *Arg,
+ const StringInit *ArgName,
+ const Record *Op) {
+ assert(Op->isSubClassOf("Operand"));
+ const auto *ArgDef = dyn_cast<DefInit>(Arg);
+ if (!ArgDef || !ArgDef->getDef()->isSubClassOf("Operand"))
+ return createStringError("argument must be a subclass of Operand");
+ if (!ArgName)
+ return createStringError("argument must have a name");
+ return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
+ ArgDef->getDef());
}
CodeGenInstAlias::CodeGenInstAlias(const Record *R, const CodeGenTarget &T)
@@ -199,7 +169,7 @@ CodeGenInstAlias::CodeGenInstAlias(const Record *R, const CodeGenTarget &T)
}
// Decode and validate the arguments of the result.
- unsigned AliasOpNo = 0;
+ unsigned ArgIdx = 0;
for (auto [OpIdx, OpInfo] : enumerate(ResultInst->Operands)) {
// Tied registers don't have an entry in the result dag unless they're part
// of a complex operand, in which case we include them anyways, as we
@@ -213,71 +183,64 @@ CodeGenInstAlias::CodeGenInstAlias(const Record *R, const CodeGenTarget &T)
continue;
}
- if (AliasOpNo >= Result->getNumArgs())
+ if (ArgIdx >= Result->getNumArgs())
PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
- const Record *InstOpRec = OpInfo.Rec;
- unsigned NumSubOps = OpInfo.MINumOperands;
- ResultOperand ResOp(static_cast<int64_t>(0));
- if (tryAliasOpMatch(Result, AliasOpNo, InstOpRec, (NumSubOps > 1),
- R->getLoc(), T, ResOp)) {
- // If this is a simple operand, or a complex operand with a custom match
- // class, then we can match is verbatim.
- if (NumSubOps == 1 || (InstOpRec->getValue("ParserMatchClass") &&
- InstOpRec->getValueAsDef("ParserMatchClass")
- ->getValueAsString("Name") != "Imm")) {
- ResultOperands.push_back(std::move(ResOp));
- ResultInstOperandIndex.emplace_back(OpIdx, -1);
- ++AliasOpNo;
-
- // Otherwise, we need to match each of the suboperands individually.
- } else {
- const DagInit *MIOI = OpInfo.MIOperandInfo;
- for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
- const Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef();
-
- // Take care to instantiate each of the suboperands with the correct
- // nomenclature: $foo.bar
- ResultOperands.emplace_back(
- Result->getArgName(AliasOpNo)->getAsUnquotedString() + "." +
- MIOI->getArgName(SubOp)->getAsUnquotedString(),
- SubRec);
- ResultInstOperandIndex.emplace_back(OpIdx, SubOp);
- }
- ++AliasOpNo;
- }
- continue;
- }
-
- // If the argument did not match the instruction operand, and the operand
- // is composed of multiple suboperands, try matching the suboperands.
- if (NumSubOps > 1) {
- const DagInit *MIOI = OpInfo.MIOperandInfo;
- for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
- if (AliasOpNo >= Result->getNumArgs())
- PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
- const Record *SubRec = cast<DefInit>(MIOI->getArg(SubOp))->getDef();
- if (tryAliasOpMatch(Result, AliasOpNo, SubRec, false, R->getLoc(), T,
- ResOp)) {
- ResultOperands.push_back(ResOp);
- ResultInstOperandIndex.emplace_back(OpIdx, SubOp);
- ++AliasOpNo;
- } else {
- PrintFatalError(
- R->getLoc(),
- "result argument #" + Twine(AliasOpNo) +
- " does not match instruction operand class " +
- (SubOp == 0 ? InstOpRec->getName() : SubRec->getName()));
+ const Record *Op = OpInfo.Rec;
+ if (Op->isSubClassOf("Operand") && !OpInfo.MIOperandInfo->arg_empty()) {
+ // Complex operand (a subclass of Operand with non-empty MIOperandInfo).
+ // The argument can be a DAG or a subclass of Operand.
+ if (auto *ArgDag = dyn_cast<DagInit>(Result->getArg(ArgIdx))) {
+ // The argument is a DAG. The operator must be the name of the operand.
+ if (auto *Operator = dyn_cast<DefInit>(ArgDag->getOperator());
+ !Operator || Operator->getDef()->getName() != Op->getName())
+ PrintFatalError(R, "argument #" + Twine(ArgIdx) +
+ " operator must be " + Op->getName());
+ // The number of sub-arguments and the number of sub-operands
+ // must match exactly.
+ unsigned NumSubOps = OpInfo.MIOperandInfo->getNumArgs();
+ unsigned NumSubArgs = ArgDag->getNumArgs();
+ if (NumSubArgs != NumSubOps)
+ PrintFatalError(R, "argument #" + Twine(ArgIdx) +
+ " must have exactly " + Twine(NumSubOps) +
+ " sub-arguments");
+ // Match sub-operands individually.
+ for (unsigned SubOpIdx = 0; SubOpIdx != NumSubOps; ++SubOpIdx) {
+ const Record *SubOp =
+ cast<DefInit>(OpInfo.MIOperandInfo->getArg(SubOpIdx))->getDef();
+ Expected<ResultOperand> ResOpOrErr = matchSimpleOperand(
+ ArgDag->getArg(SubOpIdx), ArgDag->getArgName(SubOpIdx), SubOp, T);
+ if (!ResOpOrErr)
+ PrintFatalError(R, "in argument #" + Twine(ArgIdx) + "." +
+ Twine(SubOpIdx) + ": " +
+ toString(ResOpOrErr.takeError()));
+ ResultOperands.push_back(*ResOpOrErr);
+ ResultInstOperandIndex.emplace_back(OpIdx, SubOpIdx);
}
+ } else {
+ // Match complex operand as a whole.
+ Expected<ResultOperand> ResOpOrErr = matchComplexOperand(
+ Result->getArg(ArgIdx), Result->getArgName(ArgIdx), Op);
+ if (!ResOpOrErr)
+ PrintFatalError(R, "in argument #" + Twine(ArgIdx) + ": " +
+ toString(ResOpOrErr.takeError()));
+ ResultOperands.push_back(*ResOpOrErr);
+ ResultInstOperandIndex.emplace_back(OpIdx, -1);
}
- continue;
+ } else {
+ // Simple operand (RegisterClass, RegisterOperand or Operand with empty
+ // MIOperandInfo).
+ Expected<ResultOperand> ResOpOrErr = matchSimpleOperand(
+ Result->getArg(ArgIdx), Result->getArgName(ArgIdx), Op, T);
+ if (!ResOpOrErr)
+ PrintFatalError(R, "in argument #" + Twine(ArgIdx) + ": " +
+ toString(ResOpOrErr.takeError()));
+ ResultOperands.push_back(*ResOpOrErr);
+ ResultInstOperandIndex.emplace_back(OpIdx, -1);
}
- PrintFatalError(R->getLoc(),
- "result argument #" + Twine(AliasOpNo) +
- " does not match instruction operand class " +
- InstOpRec->getName());
+ ArgIdx++;
}
- if (AliasOpNo != Result->getNumArgs())
+ if (ArgIdx != Result->getNumArgs())
PrintFatalError(R->getLoc(), "too many operands for instruction!");
}
diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.h b/llvm/utils/TableGen/Common/CodeGenInstAlias.h
index f045b9f6c1990..e9f603125d678 100644
--- a/llvm/utils/TableGen/Common/CodeGenInstAlias.h
+++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.h
@@ -22,11 +22,9 @@
namespace llvm {
-template <typename T> class ArrayRef;
class CodeGenInstruction;
class CodeGenTarget;
class DagInit;
-class SMLoc;
class Record;
/// CodeGenInstAlias - This represents an InstAlias definition.
@@ -45,20 +43,29 @@ class CodeGenInstAlias {
/// Result).
CodeGenInstruction *ResultInst;
- struct ResultOperand {
- private:
+ class ResultOperand {
std::string Name;
const Record *R = nullptr;
int64_t Imm = 0;
- public:
- enum { K_Record, K_Imm, K_Reg } Kind;
-
ResultOperand(std::string N, const Record *R)
: Name(std::move(N)), R(R), Kind(K_Record) {}
- ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
+ ResultOperand(int64_t Imm) : Imm(Imm), Kind(K_Imm) {}
ResultOperand(const Record *R) : R(R), Kind(K_Reg) {}
+ public:
+ enum { K_Record, K_Imm, K_Reg } Kind;
+
+ static ResultOperand createRecord(std::string N, const Record *R) {
+ return ResultOperand(std::move(N), R);
+ }
+ static ResultOperand createImmediate(int64_t Imm) {
+ return ResultOperand(Imm);
+ }
+ static ResultOperand createRegister(const Record *R) {
+ return ResultOperand(R);
+ }
+
bool isRecord() const { return Kind == K_Record; }
bool isImm() const { return Kind == K_Imm; }
bool isReg() const { return Kind == K_Reg; }
@@ -94,11 +101,6 @@ class CodeGenInstAlias {
std::vector<std::pair<unsigned, int>> ResultInstOperandIndex;
CodeGenInstAlias(const Record *R, const CodeGenTarget &T);
-
- bool tryAliasOpMatch(const DagInit *Result, unsigned AliasOpNo,
- const Record *InstOpRec, bool hasSubOps,
- ArrayRef<SMLoc> Loc, const CodeGenTarget &T,
- ResultOperand &ResOp);
};
} // namespace llvm
>From 8836fe9d7dbedaceacda50a37826bb39e742bb7b Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Wed, 23 Apr 2025 20:08:04 +0300
Subject: [PATCH 2/2] Reuse existing variable; fix indentation
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 8 ++++----
llvm/utils/TableGen/Common/CodeGenInstAlias.cpp | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 01c1d4b54ffbc..6a4c14cf76f8c 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2971,11 +2971,11 @@ def : InstAlias<"tst $src1, $src2",
(logical_shifted_reg64 GPR64:$src2, 0)), 3>;
def : InstAlias<"tst $src1, $src2$sh",
- (ANDSWrs WZR, GPR32:$src1,
- (logical_shifted_reg32 GPR32:$src2, logical_shift32:$sh)), 2>;
+ (ANDSWrs WZR, GPR32:$src1,
+ (logical_shifted_reg32 GPR32:$src2, logical_shift32:$sh)), 2>;
def : InstAlias<"tst $src1, $src2$sh",
- (ANDSXrs XZR, GPR64:$src1,
- (logical_shifted_reg64 GPR64:$src2, logical_shift64:$sh)), 2>;
+ (ANDSXrs XZR, GPR64:$src1,
+ (logical_shifted_reg64 GPR64:$src2, logical_shift64:$sh)), 2>;
def : Pat<(not GPR32:$Wm), (ORNWrr WZR, GPR32:$Wm)>;
diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp
index ad5dbbf91743b..366ba69037c77 100644
--- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp
@@ -73,7 +73,7 @@ static Expected<ResultOperand> matchSimpleOperand(const Init *Arg,
if (!ArgName)
return createStringError("register class argument must have a name");
return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
- cast<DefInit>(Arg)->getDef());
+ ArgRec);
}
// Match 'Reg'.
More information about the llvm-commits
mailing list