[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