]> granicus.if.org Git - llvm/commitdiff
GlobalISel: Enable the legalization of G_MERGE_VALUES and G_UNMERGE_VALUES
authorVolkan Keles <vkeles@apple.com>
Fri, 1 Dec 2017 08:19:10 +0000 (08:19 +0000)
committerVolkan Keles <vkeles@apple.com>
Fri, 1 Dec 2017 08:19:10 +0000 (08:19 +0000)
Summary: LegalizerInfo assumes all G_MERGE_VALUES and G_UNMERGE_VALUES instructions are legal, so it is not possible to legalize vector operations on illegal vector types. This patch fixes the problem by removing the related check and adding default actions for G_MERGE_VALUES and G_UNMERGE_VALUES.

Reviewers: qcolombet, ab, dsanders, aditya_nandakumar, t.p.northover, kristof.beyls

Reviewed By: dsanders

Subscribers: rovka, javed.absar, igorb, llvm-commits

Differential Revision: https://reviews.llvm.org/D39823

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319524 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Target/GenericOpcodes.td
lib/CodeGen/GlobalISel/LegalizerInfo.cpp
lib/Target/AArch64/AArch64LegalizerInfo.cpp
lib/Target/ARM/ARMLegalizerInfo.cpp
lib/Target/X86/X86LegalizerInfo.cpp
test/CodeGen/AArch64/GlobalISel/legalize-combines.mir
test/CodeGen/AArch64/GlobalISel/legalize-merge-values.mir [new file with mode: 0644]
test/CodeGen/AArch64/GlobalISel/legalize-nonpowerof2eltsvec.mir
test/CodeGen/AArch64/GlobalISel/legalize-unmerge-values.mir [new file with mode: 0644]
test/CodeGen/AArch64/GlobalISel/no-regclass.mir

index 96244d852784d3a0a5635362ff740815f2b456e1..489b569d990ab7bb822b454433d93164bef85737 100644 (file)
@@ -607,8 +607,8 @@ def G_EXTRACT : Instruction {
 // indexes. This will almost certainly be mapped to sub-register COPYs after
 // register banks have been selected.
 def G_UNMERGE_VALUES : Instruction {
-  let OutOperandList = (outs);
-  let InOperandList = (ins variable_ops);
+  let OutOperandList = (outs type0:$dst0, variable_ops);
+  let InOperandList = (ins type1:$src);
   let hasSideEffects = 0;
 }
 
@@ -619,10 +619,10 @@ def G_INSERT : Instruction {
   let hasSideEffects = 0;
 }
 
-/// Concatenante multiple registers of the same size into a wider register.
+/// Concatenate multiple registers of the same size into a wider register.
 def G_MERGE_VALUES : Instruction {
   let OutOperandList = (outs type0:$dst);
-  let InOperandList = (ins variable_ops);
+  let InOperandList = (ins type1:$src0, variable_ops);
   let hasSideEffects = 0;
 }
 
index 1a23b26e7ce11d3904c38ddabb4c267c00f10576..9c27c59a065494520421c6289af123a50168d496 100644 (file)
@@ -167,19 +167,25 @@ LegalizerInfo::getAction(const InstrAspect &Aspect) const {
   assert(TablesInitialized && "backend forgot to call computeTables");
   // These *have* to be implemented for now, they're the fundamental basis of
   // how everything else is transformed.
-
-  // FIXME: the long-term plan calls for expansion in terms of load/store (if
-  // they're not legal).
-  if (Aspect.Opcode == TargetOpcode::G_MERGE_VALUES ||
-      Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES)
-    return std::make_pair(Legal, Aspect.Type);
-
   if (Aspect.Type.isScalar() || Aspect.Type.isPointer())
     return findScalarLegalAction(Aspect);
   assert(Aspect.Type.isVector());
   return findVectorLegalAction(Aspect);
 }
 
+/// Helper function to get LLT for the given type index.
+static LLT getTypeFromTypeIdx(const MachineInstr &MI,
+                              const MachineRegisterInfo &MRI, unsigned OpIdx,
+                              unsigned TypeIdx) {
+  assert(TypeIdx < MI.getNumOperands() && "Unexpected TypeIdx");
+  // G_UNMERGE_VALUES has variable number of operands, but there is only
+  // one source type and one destination type as all destinations must be the
+  // same type. So, get the last operand if TypeIdx == 1.
+  if (MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES && TypeIdx == 1)
+    return MRI.getType(MI.getOperand(MI.getNumOperands() - 1).getReg());
+  return MRI.getType(MI.getOperand(OpIdx).getReg());
+}
+
 std::tuple<LegalizerInfo::LegalizeAction, unsigned, LLT>
 LegalizerInfo::getAction(const MachineInstr &MI,
                          const MachineRegisterInfo &MRI) const {
@@ -198,7 +204,7 @@ LegalizerInfo::getAction(const MachineInstr &MI,
 
     SeenTypes.set(TypeIdx);
 
-    LLT Ty = MRI.getType(MI.getOperand(i).getReg());
+    LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx);
     auto Action = getAction({MI.getOpcode(), TypeIdx, Ty});
     if (Action.first != Legal)
       return std::make_tuple(Action.first, TypeIdx, Action.second);
index c7a42629c96ce6186477195c5c6ea7df8084b765..05df5120222985e98669b39e93d6244a6a676f56 100644 (file)
@@ -368,6 +368,23 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
     }
   }
 
+  // Merge/Unmerge
+  for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES})
+    for (int Sz : {8, 16, 32, 64, 128, 192, 256, 384, 512}) {
+      LLT ScalarTy = LLT::scalar(Sz);
+      setAction({Op, ScalarTy}, Legal);
+      setAction({Op, 1, ScalarTy}, Legal);
+      if (Sz < 32)
+        continue;
+      for (int EltSize = 8; EltSize <= 64; EltSize *= 2) {
+        if (EltSize >= Sz)
+          continue;
+        LLT VecTy = LLT::vector(Sz / EltSize, EltSize);
+        setAction({Op, VecTy}, Legal);
+        setAction({Op, 1, VecTy}, Legal);
+      }
+    }
+
   computeTables();
 }
 
index 51eae325c952e4b27b8c91b86c151794484ef8a3..6a541991adb47e79abb88950290f827d07f6706b 100644 (file)
@@ -177,6 +177,15 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
     for (auto Ty : {s32, s64})
       setAction({Op, Ty}, Libcall);
 
+  // Merge/Unmerge
+  for (const auto &Ty : {s32, s64}) {
+    setAction({G_MERGE_VALUES, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);
+  }
+  for (const auto &Ty : {s16, s32}) {
+    setAction({G_MERGE_VALUES, 1, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, Ty}, Legal);
+  }
   computeTables();
 }
 
index 4c86373f6f81c5699ae64ebc66c1c63343132b9e..4108a58fa7a508279b28de76c2bec7841d77c063 100644 (file)
@@ -90,6 +90,7 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
   const LLT s8 = LLT::scalar(8);
   const LLT s16 = LLT::scalar(16);
   const LLT s32 = LLT::scalar(32);
+  const LLT s64 = LLT::scalar(64);
 
   for (auto Ty : {p0, s1, s8, s16, s32})
     setAction({G_IMPLICIT_DEF, Ty}, Legal);
@@ -140,6 +141,16 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
 
   for (auto Ty : {s8, s16, s32, p0})
     setAction({G_ICMP, 1, Ty}, Legal);
+
+  // Merge/Unmerge
+  for (const auto &Ty : {s16, s32, s64}) {
+    setAction({G_MERGE_VALUES, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);
+  }
+  for (const auto &Ty : {s8, s16, s32}) {
+    setAction({G_MERGE_VALUES, 1, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, Ty}, Legal);
+  }
 }
 
 void X86LegalizerInfo::setLegalizerInfo64bit() {
@@ -148,6 +159,7 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
     return;
 
   const LLT s64 = LLT::scalar(64);
+  const LLT s128 = LLT::scalar(128);
 
   setAction({G_IMPLICIT_DEF, s64}, Legal);
 
@@ -172,6 +184,12 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
 
   // Comparison
   setAction({G_ICMP, 1, s64}, Legal);
+
+  // Merge/Unmerge
+  setAction({G_MERGE_VALUES, s128}, Legal);
+  setAction({G_UNMERGE_VALUES, 1, s128}, Legal);
+  setAction({G_MERGE_VALUES, 1, s128}, Legal);
+  setAction({G_UNMERGE_VALUES, s128}, Legal);
 }
 
 void X86LegalizerInfo::setLegalizerInfoSSE1() {
@@ -179,6 +197,7 @@ void X86LegalizerInfo::setLegalizerInfoSSE1() {
     return;
 
   const LLT s32 = LLT::scalar(32);
+  const LLT s64 = LLT::scalar(64);
   const LLT v4s32 = LLT::vector(4, 32);
   const LLT v2s64 = LLT::vector(2, 64);
 
@@ -192,6 +211,14 @@ void X86LegalizerInfo::setLegalizerInfoSSE1() {
 
   // Constants
   setAction({TargetOpcode::G_FCONSTANT, s32}, Legal);
+
+  // Merge/Unmerge
+  for (const auto &Ty : {v4s32, v2s64}) {
+    setAction({G_MERGE_VALUES, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);
+  }
+  setAction({G_MERGE_VALUES, 1, s64}, Legal);
+  setAction({G_UNMERGE_VALUES, s64}, Legal);
 }
 
 void X86LegalizerInfo::setLegalizerInfoSSE2() {
@@ -205,6 +232,11 @@ void X86LegalizerInfo::setLegalizerInfoSSE2() {
   const LLT v4s32 = LLT::vector(4, 32);
   const LLT v2s64 = LLT::vector(2, 64);
 
+  const LLT v32s8 = LLT::vector(32, 8);
+  const LLT v16s16 = LLT::vector(16, 16);
+  const LLT v8s32 = LLT::vector(8, 32);
+  const LLT v4s64 = LLT::vector(4, 64);
+
   for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
     for (auto Ty : {s64, v2s64})
       setAction({BinOp, Ty}, Legal);
@@ -220,6 +252,17 @@ void X86LegalizerInfo::setLegalizerInfoSSE2() {
 
   // Constants
   setAction({TargetOpcode::G_FCONSTANT, s64}, Legal);
+
+  // Merge/Unmerge
+  for (const auto &Ty :
+       {v16s8, v32s8, v8s16, v16s16, v4s32, v8s32, v2s64, v4s64}) {
+    setAction({G_MERGE_VALUES, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);
+  }
+  for (const auto &Ty : {v16s8, v8s16, v4s32, v2s64}) {
+    setAction({G_MERGE_VALUES, 1, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, Ty}, Legal);
+  }
 }
 
 void X86LegalizerInfo::setLegalizerInfoSSE41() {
@@ -241,9 +284,13 @@ void X86LegalizerInfo::setLegalizerInfoAVX() {
   const LLT v2s64 = LLT::vector(2, 64);
 
   const LLT v32s8 = LLT::vector(32, 8);
+  const LLT v64s8 = LLT::vector(64, 8);
   const LLT v16s16 = LLT::vector(16, 16);
+  const LLT v32s16 = LLT::vector(32, 16);
   const LLT v8s32 = LLT::vector(8, 32);
+  const LLT v16s32 = LLT::vector(16, 32);
   const LLT v4s64 = LLT::vector(4, 64);
+  const LLT v8s64 = LLT::vector(8, 64);
 
   for (unsigned MemOp : {G_LOAD, G_STORE})
     for (auto Ty : {v8s32, v4s64})
@@ -257,6 +304,17 @@ void X86LegalizerInfo::setLegalizerInfoAVX() {
     setAction({G_INSERT, 1, Ty}, Legal);
     setAction({G_EXTRACT, Ty}, Legal);
   }
+  // Merge/Unmerge
+  for (const auto &Ty :
+       {v32s8, v64s8, v16s16, v32s16, v8s32, v16s32, v4s64, v8s64}) {
+    setAction({G_MERGE_VALUES, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);
+  }
+  for (const auto &Ty :
+       {v16s8, v32s8, v8s16, v16s16, v4s32, v8s32, v2s64, v4s64}) {
+    setAction({G_MERGE_VALUES, 1, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, Ty}, Legal);
+  }
 }
 
 void X86LegalizerInfo::setLegalizerInfoAVX2() {
@@ -268,12 +326,27 @@ void X86LegalizerInfo::setLegalizerInfoAVX2() {
   const LLT v8s32 = LLT::vector(8, 32);
   const LLT v4s64 = LLT::vector(4, 64);
 
+  const LLT v64s8 = LLT::vector(64, 8);
+  const LLT v32s16 = LLT::vector(32, 16);
+  const LLT v16s32 = LLT::vector(16, 32);
+  const LLT v8s64 = LLT::vector(8, 64);
+
   for (unsigned BinOp : {G_ADD, G_SUB})
     for (auto Ty : {v32s8, v16s16, v8s32, v4s64})
       setAction({BinOp, Ty}, Legal);
 
   for (auto Ty : {v16s16, v8s32})
     setAction({G_MUL, Ty}, Legal);
+
+  // Merge/Unmerge
+  for (const auto &Ty : {v64s8, v32s16, v16s32, v8s64}) {
+    setAction({G_MERGE_VALUES, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);
+  }
+  for (const auto &Ty : {v32s8, v16s16, v8s32, v4s64}) {
+    setAction({G_MERGE_VALUES, 1, Ty}, Legal);
+    setAction({G_UNMERGE_VALUES, Ty}, Legal);
+  }
 }
 
 void X86LegalizerInfo::setLegalizerInfoAVX512() {
index 82594b8c476a1259f3bacf5ec367780d1a515a0c..9cf0f8fd0e7168c1e70b54ebf9d3c58d022d8d9c 100644 (file)
@@ -8,7 +8,6 @@
   define void @test_combines_3() { ret void }
   define void @test_combines_4() { ret void }
   define void @test_combines_5() { ret void }
-  define void @test_combines_6() { ret void }
 ...
 
 ---
@@ -90,23 +89,3 @@ body: |
     %5:_(s32) = G_ADD %3, %4
     %w0 = COPY %5
 ...
-
----
-name:            test_combines_6
-body: |
-  bb.0:
-    liveins: %w0
-
-    ; Check that we replace all the uses of a G_EXTRACT.
-    ; CHECK-LABEL: name: test_combines_6
-    ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY %w0
-    ; CHECK: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[COPY]], [[COPY]]
-    ; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[MUL]]
-    %0:_(s32) = COPY %w0
-
-    %1:_(s32) = G_MERGE_VALUES %0
-    %2:_(s32) = G_UNMERGE_VALUES %1
-    %3:_(s32) = G_MUL %2, %2
-    %4:_(s32) = G_ADD %2, %3
-    %w0 = COPY %4
-...
diff --git a/test/CodeGen/AArch64/GlobalISel/legalize-merge-values.mir b/test/CodeGen/AArch64/GlobalISel/legalize-merge-values.mir
new file mode 100644 (file)
index 0000000..e617138
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: llc -O0 -run-pass=legalizer -global-isel -global-isel-abort=0 -pass-remarks-missed='gisel*' %s -o - 2>&1 | FileCheck %s
+
+--- |
+  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+  target triple = "aarch64--"
+  define void @test_merge_s4() {
+    ret void
+  }
+...
+
+---
+name:            test_merge_s4
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+  - { id: 3, class: _ }
+  - { id: 4, class: _ }
+body: |
+  bb.0:
+    %0(s64) = G_CONSTANT i64 0
+    %1(s4) = G_TRUNC %0(s64)
+    ; Previously, LegalizerInfo was assuming all G_MERGE_VALUES and G_UNMERGE_VALUES
+    ; instructions are legal. Make sure that is no longer happening.
+    ; CHECK: unable to legalize instruction: {{.*}} G_MERGE_VALUES
+    %2(s8) = G_MERGE_VALUES %1(s4), %1(s4)
+    %3(s8) = COPY %2(s8)
+    %4(s64) = G_ANYEXT %3(s8)
+    %x0 = COPY %4(s64)
+...
index a586e69c855cbe3e4299d10f1de6131ba6dcca88..168e1df02775e855720d8c3213397ad214d9fd5c 100644 (file)
@@ -4,33 +4,31 @@
 --- |
   target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
   target triple = "aarch64--"
-  define void @test_legalize_merge_v3s32() {
+  define void @test_legalize_merge_v3s64() {
     ret void
   }
 ...
 ---
-name:            test_legalize_merge_v3s32
+name:            test_legalize_merge_v3s64
 registers:
   - { id: 0, class: _ }
   - { id: 1, class: _ }
   - { id: 2, class: _ }
   - { id: 3, class: _ }
+  - { id: 4, class: _ }
+  - { id: 5, class: _ }
 body: |
   bb.0:
-    liveins: %w0, %w1, %w2
-    ; CHECK-LABEL: name: test_legalize_merge_v3s32
-    ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY %w0
-    ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY %w1
-    ; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY %w2
-    ; CHECK: %w0 = COPY [[COPY]](s32)
-    ; CHECK: %w1 = COPY [[COPY1]](s32)
-    ; CHECK: %w2 = COPY [[COPY2]](s32)
-    %0(s32) = COPY %w0
-    %1(s32) = COPY %w1
-    %2(s32) = COPY %w2
-    %3(<3 x s32>) = G_MERGE_VALUES %0(s32), %1(s32), %2(s32)
-    %4:_(s32), %5:_(s32), %6:_(s32) = G_UNMERGE_VALUES %3
-    %w0 = COPY %4
-    %w1 = COPY %5
-    %w2 = COPY %6
+    liveins: %w0
+    ; CHECK-LABEL: name: test_legalize_merge_v3s64
+    ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY %x0
+    ; CHECK: [[MV:%[0-9]+]]:_(<3 x s64>) = G_MERGE_VALUES [[COPY]](s64), [[COPY]](s64), [[COPY]](s64)
+    ; CHECK: [[COPY1:%[0-9]+]]:_(<3 x s64>) = COPY [[MV]](<3 x s64>)
+    ; CHECK: [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64), [[UV2:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[COPY1]](<3 x s64>)
+    ; CHECK: %x0 = COPY [[UV]](s64)
+    %0(s64) = COPY %x0
+    %1(<3 x s64>) = G_MERGE_VALUES %0(s64), %0(s64), %0(s64)
+    %2(<3 x s64>) = COPY %1(<3 x s64>)
+    %3(s64), %4(s64), %5(s64) = G_UNMERGE_VALUES %2(<3 x s64>)
+    %x0 = COPY %3(s64)
 ...
diff --git a/test/CodeGen/AArch64/GlobalISel/legalize-unmerge-values.mir b/test/CodeGen/AArch64/GlobalISel/legalize-unmerge-values.mir
new file mode 100644 (file)
index 0000000..85b65e9
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: llc -O0 -run-pass=legalizer -global-isel -global-isel-abort=0 -pass-remarks-missed='gisel*' %s -o - 2>&1 | FileCheck %s
+
+--- |
+  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+  target triple = "aarch64--"
+  define void @test_unmerge_s4() {
+    ret void
+  }
+...
+
+---
+name:            test_unmerge_s4
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+  - { id: 3, class: _ }
+body: |
+  bb.0:
+    %0(s8) = G_CONSTANT i8 0
+    ; Previously, LegalizerInfo was assuming all G_MERGE_VALUES and G_UNMERGE_VALUES
+    ; instructions are legal. Make sure that is no longer happening.
+    ; CHECK: unable to legalize instruction: {{.*}} G_UNMERGE_VALUES
+    %1(s4), %2(s4)= G_UNMERGE_VALUES %0(s8)
+    %3(s64) = G_ANYEXT %1(s4)
+    %x0 = COPY %3(s64)
+
+...
index d4d23142ab9c117fb7de4ad63ae6d375922f15c8..8732274fe034e1c94eb25e674fe44737b67e0f02 100644 (file)
@@ -25,7 +25,7 @@ body:             |
     ; CHECK: [[COPY:%[0-9]+]]:gpr32all = COPY %w0
     ; CHECK: %w0 = COPY [[COPY]]
     %0:gpr(s32) = COPY %w0
-    %1:gpr(s32) = G_MERGE_VALUES %0(s32)
-    %2:gpr(s32) = G_UNMERGE_VALUES %1(s32)
+    %1:gpr(s64) = G_MERGE_VALUES %0(s32), %0(s32)
+    %2:gpr(s32), %3:gpr(s32) = G_UNMERGE_VALUES %1(s64)
     %w0 = COPY %2(s32)
 ...