[GlobalIsel][X86] Update legalization of G_MUL
authorSimon Pilgrim <llvm-dev@redking.me.uk>
Sat, 3 Jun 2023 17:19:46 +0000 (18:19 +0100)
committerSimon Pilgrim <llvm-dev@redking.me.uk>
Sat, 3 Jun 2023 17:22:02 +0000 (18:22 +0100)
Replace the legacy G_MUL legalizer, this handles all scalar promotion and vector clamping, however we still need to add custom legalization for many vector multiplies.

llvm/lib/Target/X86/X86LegalizerInfo.cpp
llvm/test/CodeGen/X86/GlobalISel/legalize-mul-scalar.mir

index 4fbcd00..7a4c2a2 100644 (file)
@@ -63,8 +63,11 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
 
   bool Is64Bit = Subtarget.is64Bit();
   bool HasSSE2 = Subtarget.hasSSE2();
+  bool HasSSE41 = Subtarget.hasSSE41();
   bool HasAVX2 = Subtarget.hasAVX2();
   bool HasAVX512 = Subtarget.hasAVX512();
+  bool HasVLX = Subtarget.hasVLX();
+  bool HasDQI = Subtarget.hasAVX512() && Subtarget.hasDQI();
   bool HasBWI = Subtarget.hasAVX512() && Subtarget.hasBWI();
 
   const LLT s8 = LLT::scalar(8);
@@ -117,6 +120,39 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
       .clampScalar(0, s8, sMaxScalar)
       .scalarize(0);
 
+  // integer multiply
+  getActionDefinitionsBuilder(G_MUL)
+      .legalIf([=](const LegalityQuery &Query) -> bool {
+        if (typeInSet(0, {s8, s16, s32})(Query))
+          return true;
+        if (Is64Bit && typeInSet(0, {s64})(Query))
+          return true;
+        if (HasSSE2 && typeInSet(0, {v8s16})(Query))
+          return true;
+        if (HasSSE41 && typeInSet(0, {v4s32})(Query))
+          return true;
+        if (HasAVX2 && typeInSet(0, {v16s16, v8s32})(Query))
+          return true;
+        if (HasAVX512 && typeInSet(0, {v16s32})(Query))
+          return true;
+        if (HasDQI && typeInSet(0, {v8s64})(Query))
+          return true;
+        if (HasDQI && HasVLX && typeInSet(0, {v2s64, v4s64})(Query))
+          return true;
+        if (HasBWI && typeInSet(0, {v32s16})(Query))
+          return true;
+        return false;
+      })
+      .clampMinNumElements(0, s16, 8)
+      .clampMinNumElements(0, s32, 4)
+      .clampMinNumElements(0, s64, HasVLX ? 2 : 8)
+      .clampMaxNumElements(0, s16, HasBWI ? 32 : (HasAVX2 ? 16 : 8))
+      .clampMaxNumElements(0, s32, HasAVX512 ? 16 : (HasAVX2 ? 8 : 4))
+      .clampMaxNumElements(0, s64, 8)
+      .widenScalarToNextPow2(0, /*Min=*/32)
+      .clampScalar(0, s8, sMaxScalar)
+      .scalarize(0);
+
   // integer divisions
   getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
       .legalIf([=](const LegalityQuery &Query) -> bool {
@@ -182,7 +218,7 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
 
   auto &LegacyInfo = getLegacyLegalizerInfo();
   LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(G_PHI, 0, widen_1);
-  for (unsigned BinOp : {G_MUL, G_AND, G_OR, G_XOR})
+  for (unsigned BinOp : {G_AND, G_OR, G_XOR})
     LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, widen_1);
   for (unsigned MemOp : {G_LOAD, G_STORE})
     LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(
@@ -223,7 +259,7 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
   for (auto Ty : {s8, s16, s32, p0})
     LegacyInfo.setAction({G_PHI, Ty}, LegacyLegalizeActions::Legal);
 
-  for (unsigned BinOp : {G_MUL, G_AND, G_OR, G_XOR})
+  for (unsigned BinOp : {G_AND, G_OR, G_XOR})
     for (auto Ty : {s8, s16, s32})
       LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal);
 
@@ -311,7 +347,7 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
 
   LegacyInfo.setAction({G_PHI, s64}, LegacyLegalizeActions::Legal);
 
-  for (unsigned BinOp : {G_MUL, G_AND, G_OR, G_XOR})
+  for (unsigned BinOp : {G_AND, G_OR, G_XOR})
     LegacyInfo.setAction({BinOp, s64}, LegacyLegalizeActions::Legal);
 
   for (unsigned MemOp : {G_LOAD, G_STORE})
@@ -423,8 +459,6 @@ void X86LegalizerInfo::setLegalizerInfoSSE2() {
     for (auto Ty : {s64, v2s64})
       LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal);
 
-  LegacyInfo.setAction({G_MUL, v8s16}, LegacyLegalizeActions::Legal);
-
   LegacyInfo.setAction({G_FPEXT, s64}, LegacyLegalizeActions::Legal);
   LegacyInfo.setAction({G_FPEXT, 1, s32}, LegacyLegalizeActions::Legal);
 
@@ -452,18 +486,11 @@ void X86LegalizerInfo::setLegalizerInfoSSE2() {
 void X86LegalizerInfo::setLegalizerInfoSSE41() {
   if (!Subtarget.hasSSE41())
     return;
-
-  const LLT v4s32 = LLT::fixed_vector(4, 32);
-
-  auto &LegacyInfo = getLegacyLegalizerInfo();
-
-  LegacyInfo.setAction({G_MUL, v4s32}, LegacyLegalizeActions::Legal);
 }
 
 void X86LegalizerInfo::setLegalizerInfoSSE42() {
   if (!Subtarget.hasSSE42())
     return;
-
 }
 
 void X86LegalizerInfo::setLegalizerInfoAVX() {
@@ -529,9 +556,6 @@ void X86LegalizerInfo::setLegalizerInfoAVX2() {
 
   auto &LegacyInfo = getLegacyLegalizerInfo();
 
-  for (auto Ty : {v16s16, v8s32})
-    LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
-
   // Merge/Unmerge
   for (const auto &Ty : {v64s8, v32s16, v16s32, v8s64}) {
     LegacyInfo.setAction({G_CONCAT_VECTORS, Ty}, LegacyLegalizeActions::Legal);
@@ -569,9 +593,6 @@ void X86LegalizerInfo::setLegalizerInfoAVX512() {
 
   auto &LegacyInfo = getLegacyLegalizerInfo();
 
-
-  LegacyInfo.setAction({G_MUL, v16s32}, LegacyLegalizeActions::Legal);
-
   for (unsigned MemOp : {G_LOAD, G_STORE})
     for (auto Ty : {v16s32, v8s64})
       LegacyInfo.setAction({MemOp, Ty}, LegacyLegalizeActions::Legal);
@@ -584,53 +605,14 @@ void X86LegalizerInfo::setLegalizerInfoAVX512() {
     LegacyInfo.setAction({G_INSERT, 1, Ty}, LegacyLegalizeActions::Legal);
     LegacyInfo.setAction({G_EXTRACT, Ty}, LegacyLegalizeActions::Legal);
   }
-
-  /************ VLX *******************/
-  if (!Subtarget.hasVLX())
-    return;
-
-  for (auto Ty : {v4s32, v8s32})
-    LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
 }
 
 void X86LegalizerInfo::setLegalizerInfoAVX512DQ() {
   if (!(Subtarget.hasAVX512() && Subtarget.hasDQI()))
     return;
-
-  const LLT v8s64 = LLT::fixed_vector(8, 64);
-
-  auto &LegacyInfo = getLegacyLegalizerInfo();
-
-  LegacyInfo.setAction({G_MUL, v8s64}, LegacyLegalizeActions::Legal);
-
-  /************ VLX *******************/
-  if (!Subtarget.hasVLX())
-    return;
-
-  const LLT v2s64 = LLT::fixed_vector(2, 64);
-  const LLT v4s64 = LLT::fixed_vector(4, 64);
-
-  for (auto Ty : {v2s64, v4s64})
-    LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
 }
 
 void X86LegalizerInfo::setLegalizerInfoAVX512BW() {
   if (!(Subtarget.hasAVX512() && Subtarget.hasBWI()))
     return;
-
-  const LLT v32s16 = LLT::fixed_vector(32, 16);
-
-  auto &LegacyInfo = getLegacyLegalizerInfo();
-
-  LegacyInfo.setAction({G_MUL, v32s16}, LegacyLegalizeActions::Legal);
-
-  /************ VLX *******************/
-  if (!Subtarget.hasVLX())
-    return;
-
-  const LLT v8s16 = LLT::fixed_vector(8, 16);
-  const LLT v16s16 = LLT::fixed_vector(16, 16);
-
-  for (auto Ty : {v8s16, v16s16})
-    LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
 }
index 2483a45..d064d6c 100644 (file)
@@ -1,5 +1,10 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -O0 -mtriple=x86_64-linux-gnu -run-pass=legalizer %s -o - | FileCheck %s
+# RUN: llc -O0 -mtriple=x86_64-linux-gnu -run-pass=legalizer %s -o - | FileCheck %s --check-prefixes=CHECK,X64
+# RUN: llc -O0 -mtriple=i386-linux-gnu  -run-pass=legalizer -global-isel-abort=2 -pass-remarks-missed='gisel*'  %s 2>%t -o - | FileCheck %s --check-prefixes=CHECK,X86
+# RUN: FileCheck -check-prefix=ERR32  %s < %t
+
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %14:_(s32) = G_UMULH %7:_, %9:_ (in function: test_mul_i42)
+# ERR32: remark: <unknown>:0:0: unable to legalize instruction: %10:_(s32) = G_UMULH %3:_, %5:_ (in function: test_mul_i64)
 
 --- |
   define void @test_mul_i1() { ret void }
     ret i16 %ret
   }
 
+  define i27 @test_mul_i27(i27 %arg1, i27 %arg2) {
+    %ret = mul i27 %arg1, %arg2
+    ret i27 %ret
+  }
+
   define i32 @test_mul_i32(i32 %arg1, i32 %arg2) {
     %ret = mul i32 %arg1, %arg2
     ret i32 %ret
   }
 
+  define i42 @test_mul_i42(i42 %arg1, i42 %arg2) {
+    %ret = mul i42 %arg1, %arg2
+    ret i42 %ret
+  }
+
   define i64 @test_mul_i64(i64 %arg1, i64 %arg2) {
     %ret = mul i64 %arg1, %arg2
     ret i64 %ret
@@ -108,6 +123,33 @@ body:             |
     RET 0, implicit $ax
 ...
 ---
+name:            test_mul_i27
+alignment:       16
+legalized:       false
+regBankSelected: false
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body:             |
+  bb.1 (%ir-block.0):
+
+    ;
+    ;
+    ; CHECK-LABEL: name: test_mul_i27
+    ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edx
+    ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY]], [[COPY]]
+    ; CHECK-NEXT: $eax = COPY [[MUL]](s32)
+    ; CHECK-NEXT: RET 0
+    %0(s32) = COPY $edx
+    %1(s27) = G_TRUNC %0(s32)
+    %2(s27) = G_MUL %1, %1
+    %3:_(s32) = G_ANYEXT %2
+    $eax = COPY %3
+    RET 0
+...
+---
+
 name:            test_mul_i32
 alignment:       16
 legalized:       false
@@ -135,6 +177,53 @@ body:             |
     RET 0, implicit $eax
 ...
 ---
+name:            test_mul_i42
+alignment:       16
+legalized:       false
+regBankSelected: false
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body:             |
+  bb.1 (%ir-block.0):
+    liveins: $rdi, $rsi
+
+    ; X64-LABEL: name: test_mul_i42
+    ; X64: liveins: $rdi, $rsi
+    ; X64-NEXT: {{  $}}
+    ; X64-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdx
+    ; X64-NEXT: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY]]
+    ; X64-NEXT: $rax = COPY [[MUL]](s64)
+    ; X64-NEXT: RET 0
+    ; X86-LABEL: name: test_mul_i42
+    ; X86: liveins: $rdi, $rsi
+    ; X86-NEXT: {{  $}}
+    ; X86-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdx
+    ; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s42) = G_TRUNC [[COPY]](s64)
+    ; X86-NEXT: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC]](s42)
+    ; X86-NEXT: [[ANYEXT1:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC]](s42)
+    ; X86-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ANYEXT]](s64)
+    ; X86-NEXT: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ANYEXT1]](s64)
+    ; X86-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV2]]
+    ; X86-NEXT: [[MUL1:%[0-9]+]]:_(s32) = G_MUL [[UV1]], [[UV2]]
+    ; X86-NEXT: [[MUL2:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV3]]
+    ; X86-NEXT: [[UMULH:%[0-9]+]]:_(s32) = G_UMULH [[UV]], [[UV2]]
+    ; X86-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[MUL1]], [[MUL2]]
+    ; X86-NEXT: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[UMULH]]
+    ; X86-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[MUL]](s32), [[ADD1]](s32)
+    ; X86-NEXT: [[TRUNC1:%[0-9]+]]:_(s42) = G_TRUNC [[MV]](s64)
+    ; X86-NEXT: [[ANYEXT2:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC1]](s42)
+    ; X86-NEXT: $rax = COPY [[ANYEXT2]](s64)
+    ; X86-NEXT: RET 0
+    %0(s64) = COPY $rdx
+    %1(s42) = G_TRUNC %0(s64)
+    %2(s42) = G_MUL %1, %1
+    %3:_(s64) = G_ANYEXT %2
+    $rax = COPY %3
+    RET 0
+...
+---
 name:            test_mul_i64
 alignment:       16
 legalized:       false
@@ -147,14 +236,30 @@ body:             |
   bb.1 (%ir-block.0):
     liveins: $rdi, $rsi
 
-    ; CHECK-LABEL: name: test_mul_i64
-    ; CHECK: liveins: $rdi, $rsi
-    ; CHECK-NEXT: {{  $}}
-    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
-    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $rsi
-    ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]]
-    ; CHECK-NEXT: $rax = COPY [[MUL]](s64)
-    ; CHECK-NEXT: RET 0, implicit $rax
+    ; X64-LABEL: name: test_mul_i64
+    ; X64: liveins: $rdi, $rsi
+    ; X64-NEXT: {{  $}}
+    ; X64-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
+    ; X64-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $rsi
+    ; X64-NEXT: [[MUL:%[0-9]+]]:_(s64) = G_MUL [[COPY]], [[COPY1]]
+    ; X64-NEXT: $rax = COPY [[MUL]](s64)
+    ; X64-NEXT: RET 0, implicit $rax
+    ; X86-LABEL: name: test_mul_i64
+    ; X86: liveins: $rdi, $rsi
+    ; X86-NEXT: {{  $}}
+    ; X86-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
+    ; X86-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $rsi
+    ; X86-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]](s64)
+    ; X86-NEXT: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY1]](s64)
+    ; X86-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV2]]
+    ; X86-NEXT: [[MUL1:%[0-9]+]]:_(s32) = G_MUL [[UV1]], [[UV2]]
+    ; X86-NEXT: [[MUL2:%[0-9]+]]:_(s32) = G_MUL [[UV]], [[UV3]]
+    ; X86-NEXT: [[UMULH:%[0-9]+]]:_(s32) = G_UMULH [[UV]], [[UV2]]
+    ; X86-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[MUL1]], [[MUL2]]
+    ; X86-NEXT: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[UMULH]]
+    ; X86-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[MUL]](s32), [[ADD1]](s32)
+    ; X86-NEXT: $rax = COPY [[MV]](s64)
+    ; X86-NEXT: RET 0, implicit $rax
     %0(s64) = COPY $rdi
     %1(s64) = COPY $rsi
     %2(s64) = G_MUL %0, %1