[GVN] Store source element type for GEP expressions
authorNikita Popov <npopov@redhat.com>
Fri, 11 Feb 2022 12:01:17 +0000 (13:01 +0100)
committerNikita Popov <npopov@redhat.com>
Fri, 11 Feb 2022 12:03:30 +0000 (13:03 +0100)
To avoid incorrectly merging GEPs with different source types
under opaque pointers.

To avoid increasing the Expression structure size, this reuses the
existing type member. The code does not rely on this to be the
expression result type, it's only used as a disambiguator.

llvm/lib/Transforms/Scalar/GVN.cpp
llvm/test/Transforms/GVN/opaque-ptr.ll [new file with mode: 0644]

index c3008a6..ddfaf9c 100644 (file)
@@ -129,6 +129,8 @@ static cl::opt<uint32_t> MaxBBSpeculations(
 struct llvm::GVNPass::Expression {
   uint32_t opcode;
   bool commutative = false;
+  // The type is not necessarily the result type of the expression, it may be
+  // any additional type needed to disambiguate the expression.
   Type *type = nullptr;
   SmallVector<uint32_t, 4> varargs;
 
@@ -310,7 +312,13 @@ struct llvm::gvn::AvailableValueInBlock {
 
 GVNPass::Expression GVNPass::ValueTable::createExpr(Instruction *I) {
   Expression e;
-  e.type = I->getType();
+  // For GEPs, disambiguate based on the source element type, which is not
+  // implied by the result type with opaque pointers. (Conversely, the source
+  // element type together with the operand types does imply the result type.)
+  if (const auto *GEP = dyn_cast<GetElementPtrInst>(I))
+    e.type = GEP->getSourceElementType();
+  else
+    e.type = I->getType();
   e.opcode = I->getOpcode();
   if (const GCRelocateInst *GCR = dyn_cast<GCRelocateInst>(I)) {
     // gc.relocate is 'special' call: its second and third operands are
diff --git a/llvm/test/Transforms/GVN/opaque-ptr.ll b/llvm/test/Transforms/GVN/opaque-ptr.ll
new file mode 100644 (file)
index 0000000..f382b79
--- /dev/null
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -gvn -opaque-pointers < %s | FileCheck %s
+
+declare void @use(ptr)
+
+define void @test(ptr %p) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 1
+; CHECK-NEXT:    [[GEP3:%.*]] = getelementptr i64, ptr [[P]], i64 1
+; CHECK-NEXT:    call void @use(ptr [[GEP1]])
+; CHECK-NEXT:    call void @use(ptr [[GEP1]])
+; CHECK-NEXT:    call void @use(ptr [[GEP3]])
+; CHECK-NEXT:    ret void
+;
+  %gep1 = getelementptr i32, ptr %p, i64 1
+  %gep2 = getelementptr i32, ptr %p, i64 1
+  %gep3 = getelementptr i64, ptr %p, i64 1
+  call void @use(ptr %gep1)
+  call void @use(ptr %gep2)
+  call void @use(ptr %gep3)
+  ret void
+}