[MergeFuncs] Don't merge shufflevectors with different masks
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 1 May 2020 20:28:59 +0000 (22:28 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Sat, 2 May 2020 08:21:14 +0000 (10:21 +0200)
When the shufflevector mask operand was converted into special
instruction data, the FunctionComparator was not updated to
account for this. As such, MergeFuncs will happily merge
shufflevectors with different masks.

This fixes https://bugs.llvm.org/show_bug.cgi?id=45773.

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

llvm/lib/Transforms/Utils/FunctionComparator.cpp
llvm/test/Transforms/MergeFunc/shufflevector.ll [new file with mode: 0644]

index 8a9ff13..713ae41 100644 (file)
@@ -656,6 +656,16 @@ int FunctionComparator::cmpOperations(const Instruction *L,
     return cmpNumbers(RMWI->getSyncScopeID(),
                       cast<AtomicRMWInst>(R)->getSyncScopeID());
   }
+  if (const ShuffleVectorInst *SVI = dyn_cast<ShuffleVectorInst>(L)) {
+    ArrayRef<int> LMask = SVI->getShuffleMask();
+    ArrayRef<int> RMask = cast<ShuffleVectorInst>(R)->getShuffleMask();
+    if (int Res = cmpNumbers(LMask.size(), RMask.size()))
+      return Res;
+    for (size_t i = 0, e = LMask.size(); i != e; ++i) {
+      if (int Res = cmpNumbers(LMask[i], RMask[i]))
+        return Res;
+    }
+  }
   if (const PHINode *PNL = dyn_cast<PHINode>(L)) {
     const PHINode *PNR = cast<PHINode>(R);
     // Ensure that in addition to the incoming values being identical
diff --git a/llvm/test/Transforms/MergeFunc/shufflevector.ll b/llvm/test/Transforms/MergeFunc/shufflevector.ll
new file mode 100644 (file)
index 0000000..244fd5c
--- /dev/null
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -mergefunc < %s | FileCheck %s
+
+define internal <2 x i32> @test1(<2 x i32> %v1, <2 x i32> %v2) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[X:%.*]] = shufflevector <2 x i32> [[V1:%.*]], <2 x i32> [[V2:%.*]], <2 x i32> <i32 0, i32 1>
+; CHECK-NEXT:    ret <2 x i32> [[X]]
+;
+  %x = shufflevector <2 x i32> %v1, <2 x i32> %v2, <2 x i32> <i32 0, i32 1>
+  ret <2 x i32> %x
+}
+
+; Same mask as test1.
+define internal <2 x i32> @test2(<2 x i32> %v1, <2 x i32> %v2) {
+  %x = shufflevector <2 x i32> %v1, <2 x i32> %v2, <2 x i32> <i32 0, i32 1>
+  ret <2 x i32> %x
+}
+
+; Different mask than test1, don't merge.
+define internal <2 x i32> @test3(<2 x i32> %v1, <2 x i32> %v2) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[X:%.*]] = shufflevector <2 x i32> [[V1:%.*]], <2 x i32> [[V2:%.*]], <2 x i32> <i32 1, i32 0>
+; CHECK-NEXT:    ret <2 x i32> [[X]]
+;
+  %x = shufflevector <2 x i32> %v1, <2 x i32> %v2, <2 x i32> <i32 1, i32 0>
+  ret <2 x i32> %x
+}
+
+define void @caller(<2 x i32> %v1, <2 x i32> %v2) {
+; CHECK-LABEL: @caller(
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i32> @test1(<2 x i32> [[V1:%.*]], <2 x i32> [[V2:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @test1(<2 x i32> [[V1]], <2 x i32> [[V2]])
+; CHECK-NEXT:    [[TMP3:%.*]] = call <2 x i32> @test3(<2 x i32> [[V1]], <2 x i32> [[V2]])
+; CHECK-NEXT:    ret void
+;
+  call <2 x i32> @test1(<2 x i32> %v1, <2 x i32> %v2)
+  call <2 x i32> @test2(<2 x i32> %v1, <2 x i32> %v2)
+  call <2 x i32> @test3(<2 x i32> %v1, <2 x i32> %v2)
+  ret void
+}