[llvm] 66a54af - [WebAssembly] Support opaque pointers in AddMissingPrototypes

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 4 02:32:26 PDT 2021


Author: Nikita Popov
Date: 2021-09-04T11:25:42+02:00
New Revision: 66a54af96766ab635bc1a9fdaf2d568e3c46eb11

URL: https://github.com/llvm/llvm-project/commit/66a54af96766ab635bc1a9fdaf2d568e3c46eb11
DIFF: https://github.com/llvm/llvm-project/commit/66a54af96766ab635bc1a9fdaf2d568e3c46eb11.diff

LOG: [WebAssembly] Support opaque pointers in AddMissingPrototypes

The change here is basically the same as in D108880: Rather than
looking at bitcasts, look at calls and their function type. We
still need to look through bitcasts to find those calls.

The change in llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll
is due to different visitation order. add-prototypes-opaque-ptrs.ll
is a copy of add-prototypes.ll with -force-opaque-pointers.

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

Added: 
    llvm/test/CodeGen/WebAssembly/add-prototypes-opaque-ptrs.ll

Modified: 
    llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
    llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
index 530a55cda0e5a..90e8199128471 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAddMissingPrototypes.cpp
@@ -86,27 +86,37 @@ bool WebAssemblyAddMissingPrototypes::runOnModule(Module &M) {
                            F.getName());
     }
 
-    // Create a function prototype based on the first call site (first bitcast)
-    // that we find.
+    // Find calls of this function, looking through bitcasts.
+    SmallVector<CallBase *> Calls;
+    SmallVector<Value *> Worklist;
+    Worklist.push_back(&F);
+    while (!Worklist.empty()) {
+      Value *V = Worklist.pop_back_val();
+      for (User *U : V->users()) {
+        if (auto *BC = dyn_cast<BitCastOperator>(U))
+          Worklist.push_back(BC);
+        else if (auto *CB = dyn_cast<CallBase>(U))
+          if (CB->getCalledOperand() == V)
+            Calls.push_back(CB);
+      }
+    }
+
+    // Create a function prototype based on the first call site that we find.
     FunctionType *NewType = nullptr;
-    for (Use &U : F.uses()) {
-      LLVM_DEBUG(dbgs() << "prototype-less use: " << F.getName() << "\n");
-      LLVM_DEBUG(dbgs() << *U.getUser() << "\n");
-      if (auto *BC = dyn_cast<BitCastOperator>(U.getUser())) {
-        if (auto *DestType = dyn_cast<FunctionType>(
-                BC->getDestTy()->getPointerElementType())) {
-          if (!NewType) {
-            // Create a new function with the correct type
-            NewType = DestType;
-            LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
-          } else if (NewType != DestType) {
-            errs() << "warning: prototype-less function used with "
-                      "conflicting signatures: "
-                   << F.getName() << "\n";
-            LLVM_DEBUG(dbgs() << "  " << *DestType << "\n");
-            LLVM_DEBUG(dbgs() << "  "<<  *NewType << "\n");
-          }
-        }
+    for (CallBase *CB : Calls) {
+      LLVM_DEBUG(dbgs() << "prototype-less call of " << F.getName() << ":\n");
+      LLVM_DEBUG(dbgs() << *CB << "\n");
+      FunctionType *DestType = CB->getFunctionType();
+      if (!NewType) {
+        // Create a new function with the correct type
+        NewType = DestType;
+        LLVM_DEBUG(dbgs() << "found function type: " << *NewType << "\n");
+      } else if (NewType != DestType) {
+        errs() << "warning: prototype-less function used with "
+                  "conflicting signatures: "
+               << F.getName() << "\n";
+        LLVM_DEBUG(dbgs() << "  " << *DestType << "\n");
+        LLVM_DEBUG(dbgs() << "  " << *NewType << "\n");
       }
     }
 

diff  --git a/llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll b/llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll
index 914ac0c89cebe..3b84797d8fdbb 100644
--- a/llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll
+++ b/llvm/test/CodeGen/WebAssembly/add-prototypes-conflict.ll
@@ -7,15 +7,15 @@ target triple = "wasm32-unknown-unknown"
 ; WARNING: warning: prototype-less function used with conflicting signatures: foo
 
 ; CHECK-LABEL: @call_with_conflicting_prototypes
-; CHECK: %call1 = call i64 @foo(i32 42)
-; CHECK: %call2 = call i64 bitcast (i64 (i32)* @foo to i64 (i32, i32)*)(i32 42, i32 43)
+; CHECK: %call1 = call i64 bitcast (i64 (i32, i32)* @foo to i64 (i32)*)(i32 42)
+; CHECK: %call2 = call i64 @foo(i32 42, i32 43)
 define void @call_with_conflicting_prototypes() {
   %call1 = call i64 bitcast (i64 (...)* @foo to i64 (i32)*)(i32 42)
   %call2 = call i64 bitcast (i64 (...)* @foo to i64 (i32, i32)*)(i32 42, i32 43)
   ret void
 }
 
-; CHECK: declare extern_weak i64 @foo(i32)
+; CHECK: declare extern_weak i64 @foo(i32, i32)
 declare extern_weak i64 @foo(...) #1
 
 ; CHECK-NOT: attributes {{.*}} = { {{.*}}"no-prototype"{{.*}} }

diff  --git a/llvm/test/CodeGen/WebAssembly/add-prototypes-opaque-ptrs.ll b/llvm/test/CodeGen/WebAssembly/add-prototypes-opaque-ptrs.ll
new file mode 100644
index 0000000000000..67233a17c91a0
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/add-prototypes-opaque-ptrs.ll
@@ -0,0 +1,79 @@
+; RUN: opt -S -wasm-add-missing-prototypes -force-opaque-pointers %s | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; CHECK: @foo_addr = global ptr @foo, align 8
+ at foo_addr = global i64 (i32)* bitcast (i64 (...)* @foo to i64 (i32)*), align 8
+
+; CHECK: @foo_addr_i8 = global ptr @foo, align 8
+ at foo_addr_i8 = global i8* bitcast (i64 (...)* @foo to i8*), align 8
+
+; CHECK-LABEL: @call_foo
+; CHECK: %call = call i64 @foo(i32 42)
+define void @call_foo(i32 %a) {
+  %call = call i64 bitcast (i64 (...)* @foo to i64 (i32)*)(i32 42)
+  ret void
+}
+
+; CHECK-LABEL: @call_foo_ptr
+; CHECK: %1 = bitcast ptr @foo to ptr
+; CHECK-NEXT: %call = call i64 %1(i32 43)
+define i64 @call_foo_ptr(i32 %a) {
+  %1 = bitcast i64 (...)* @foo to i64 (i32)*
+  %call = call i64 (i32) %1(i32 43)
+  ret i64 %call
+}
+
+; CHECK-LABEL: @to_intptr_inst
+; CHECK: %1 = bitcast ptr @foo to ptr
+; CHECK-NEXT: ret ptr %1
+define i8* @to_intptr_inst() {
+  %1 = bitcast i64 (...)* @foo to i8*
+  ret i8* %1
+}
+
+; CHECK-LABEL: @to_intptr_constexpr
+; CHECK: ret ptr @foo
+define i8* @to_intptr_constexpr() {
+  ret i8* bitcast (i64 (...)* @foo to i8*)
+}
+
+; CHECK-LABEL: @null_compare
+; CHECK: br i1 icmp eq (ptr @foo, ptr null), label %if.then, label %if.end
+define i8 @null_compare() {
+  br i1 icmp eq (i64 (...)* @foo, i64 (...)* null), label %if.then, label %if.end
+if.then:
+  ret i8 0
+if.end:
+  ret i8 1
+}
+
+; CHECK-LABEL: @as_paramater
+; CHECK: call void @func_param(ptr @foo)
+define void @as_paramater() {
+  call void @func_param(i64 (...)* @foo)
+  ret void
+}
+
+; Check if a sret parameter works in a no-prototype function.
+; CHECK-LABEL: @sret_param
+; CHECK: call void @make_struct_foo(ptr sret(%struct.foo) %foo)
+%struct.foo = type { i32, i32 }
+declare void @make_struct_foo(%struct.foo* sret(%struct.foo), ...) #1
+define void @sret_param() {
+  %foo = alloca %struct.foo, align 4
+  call void bitcast (void (%struct.foo*, ...)* @make_struct_foo to void (%struct.foo*)*)(%struct.foo* sret(%struct.foo) %foo)
+  ret void
+}
+
+declare void @func_param(i64 (...)*)
+
+; CHECK: declare void @func_not_called()
+declare void @func_not_called(...) #1
+
+; CHECK: declare extern_weak i64 @foo(i32)
+declare extern_weak i64 @foo(...) #1
+
+; CHECK-NOT: attributes {{.*}} = { {{.*}}"no-prototype"{{.*}} }
+attributes #1 = { "no-prototype" }


        


More information about the llvm-commits mailing list