[llvm] 7f058ce - [WebAssembly] Support opaque pointers in FixFunctionBitcasts
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 1 13:17:34 PDT 2021
Author: Nikita Popov
Date: 2021-09-01T22:17:24+02:00
New Revision: 7f058ce8c2cb433bec71445c770fb3f7a401b3e4
URL: https://github.com/llvm/llvm-project/commit/7f058ce8c2cb433bec71445c770fb3f7a401b3e4
DIFF: https://github.com/llvm/llvm-project/commit/7f058ce8c2cb433bec71445c770fb3f7a401b3e4.diff
LOG: [WebAssembly] Support opaque pointers in FixFunctionBitcasts
With opaque pointers, no actual bitcasts will be present. Instead,
there will be a mismatch between the call FunctionType and the
function ValueType. Change the code to collect CallBases
specifically (rather than general Uses) and compare these types.
RAUW is no longer performed, as there would no longer be any
bitcasts that can be RAUWd.
Differential Revision: https://reviews.llvm.org/D108880
Added:
Modified:
llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
llvm/test/CodeGen/WebAssembly/main-declaration.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
index 7abb6fa8905cc..2a4349e02f1b7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
@@ -64,29 +64,21 @@ ModulePass *llvm::createWebAssemblyFixFunctionBitcasts() {
// Recursively descend the def-use lists from V to find non-bitcast users of
// bitcasts of V.
static void findUses(Value *V, Function &F,
- SmallVectorImpl<std::pair<Use *, Function *>> &Uses,
- SmallPtrSetImpl<Constant *> &ConstantBCs) {
- for (Use &U : V->uses()) {
- if (auto *BC = dyn_cast<BitCastOperator>(U.getUser()))
- findUses(BC, F, Uses, ConstantBCs);
- else if (auto *A = dyn_cast<GlobalAlias>(U.getUser()))
- findUses(A, F, Uses, ConstantBCs);
- else if (U.get()->getType() != F.getType()) {
- CallBase *CB = dyn_cast<CallBase>(U.getUser());
- if (!CB)
- // Skip uses that aren't immediately called
- continue;
+ SmallVectorImpl<std::pair<CallBase *, Function *>> &Uses) {
+ for (User *U : V->users()) {
+ if (auto *BC = dyn_cast<BitCastOperator>(U))
+ findUses(BC, F, Uses);
+ else if (auto *A = dyn_cast<GlobalAlias>(U))
+ findUses(A, F, Uses);
+ else if (auto *CB = dyn_cast<CallBase>(U)) {
Value *Callee = CB->getCalledOperand();
if (Callee != V)
// Skip calls where the function isn't the callee
continue;
- if (isa<Constant>(U.get())) {
- // Only add constant bitcasts to the list once; they get RAUW'd
- auto C = ConstantBCs.insert(cast<Constant>(U.get()));
- if (!C.second)
- continue;
- }
- Uses.push_back(std::make_pair(&U, &F));
+ if (CB->getFunctionType() == F.getValueType())
+ // Skip uses that are immediately called
+ continue;
+ Uses.push_back(std::make_pair(CB, &F));
}
}
}
@@ -238,8 +230,7 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
Function *Main = nullptr;
CallInst *CallMain = nullptr;
- SmallVector<std::pair<Use *, Function *>, 0> Uses;
- SmallPtrSet<Constant *, 2> ConstantBCs;
+ SmallVector<std::pair<CallBase *, Function *>, 0> Uses;
// Collect all the places that need wrappers.
for (Function &F : M) {
@@ -247,7 +238,7 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
// bitcast type
diff erence for swiftself and swifterror.
if (F.getCallingConv() == CallingConv::Swift)
continue;
- findUses(&F, F, Uses, ConstantBCs);
+ findUses(&F, F, Uses);
// If we have a "main" function, and its type isn't
// "int main(int argc, char *argv[])", create an artificial call with it
@@ -268,8 +259,7 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
Value *Casted =
ConstantExpr::getBitCast(Main, PointerType::get(MainTy, 0));
CallMain = CallInst::Create(MainTy, Casted, Args, "call_main");
- Use *UseMain = &CallMain->getOperandUse(2);
- Uses.push_back(std::make_pair(UseMain, &F));
+ Uses.push_back(std::make_pair(CallMain, &F));
}
}
}
@@ -277,16 +267,9 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
DenseMap<std::pair<Function *, FunctionType *>, Function *> Wrappers;
for (auto &UseFunc : Uses) {
- Use *U = UseFunc.first;
+ CallBase *CB = UseFunc.first;
Function *F = UseFunc.second;
- auto *PTy = cast<PointerType>(U->get()->getType());
- auto *Ty = dyn_cast<FunctionType>(PTy->getElementType());
-
- // If the function is casted to something like i8* as a "generic pointer"
- // to be later casted to something else, we can't generate a wrapper for it.
- // Just ignore such casts for now.
- if (!Ty)
- continue;
+ FunctionType *Ty = CB->getFunctionType();
auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr));
if (Pair.second)
@@ -296,10 +279,7 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
if (!Wrapper)
continue;
- if (isa<Constant>(U->get()))
- U->get()->replaceAllUsesWith(Wrapper);
- else
- U->set(Wrapper);
+ CB->setCalledOperand(Wrapper);
}
// If we created a wrapper for main, rename the wrapper so that it's the
diff --git a/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll b/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
index 36cd5d8094e61..5ebf2bc119764 100644
--- a/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
+++ b/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
@@ -1,7 +1,10 @@
-; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefixes=CHECK,TYPED
+; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -enable-emscripten-cxx-exceptions -force-opaque-pointers | FileCheck %s --check-prefixes=CHECK,OPAQUE
; Test that function pointer casts are replaced with wrappers.
+; The TYPED and OPAQUE prefixes only
diff er in function ordering.
+
target triple = "wasm32-unknown-unknown"
define void @has_i32_arg(i32) {
@@ -20,8 +23,10 @@ declare void @foo2()
declare void @foo3()
; CHECK-LABEL: test:
-; CHECK: call .Lhas_i32_arg_bitcast.2{{$}}
-; CHECK-NEXT: call .Lhas_i32_arg_bitcast.2{{$}}
+; TYPED: call .Lhas_i32_arg_bitcast.2{{$}}
+; TYPED-NEXT: call .Lhas_i32_arg_bitcast.2{{$}}
+; OPAQUE: call .Lhas_i32_arg_bitcast{{$}}
+; OPAQUE-NEXT: call .Lhas_i32_arg_bitcast{{$}}
; CHECK-NEXT: call .Lhas_i32_ret_bitcast{{$}}
; CHECK-NEXT: call $drop=, has_i32_ret
; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0
@@ -62,7 +67,8 @@ entry:
@alias_i32_arg = weak hidden alias void (i32), void (i32)* @has_i32_arg
; CHECK-LABEL: test_alias:
-; CHECK: call .Lhas_i32_arg_bitcast.2
+; TYPED: call .Lhas_i32_arg_bitcast.2
+; OPAQUE: call .Lhas_i32_arg_bitcast
define void @test_alias() {
entry:
call void bitcast (void (i32)* @alias_i32_arg to void ()*)()
@@ -71,8 +77,10 @@ entry:
; CHECK-LABEL: test_structs:
-; CHECK: call .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
-; CHECK: call .Lhas_i32_arg_bitcast, $0, $pop2
+; TYPED: call .Lhas_i32_arg_bitcast.1, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
+; TYPED: call .Lhas_i32_arg_bitcast, $0, $pop2
+; OPAQUE: call .Lhas_i32_arg_bitcast.2, $pop{{[0-9]+}}, $pop{{[0-9]+$}}
+; OPAQUE: call .Lhas_i32_arg_bitcast.1, $0, $pop2
; CHECK: call .Lhas_struct_arg_bitcast{{$}}
define void @test_structs() {
entry:
@@ -156,7 +164,8 @@ define void @test_argument() {
; CHECK: i32.const $push[[L3:[0-9]+]]=, call_func{{$}}
; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, has_i32_arg{{$}}
; CHECK-NEXT: call invoke_vi, $pop[[L3]], $pop[[L2]]{{$}}
-; CHECK: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}}
+; TYPED: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast.2{{$}}
+; OPAQUE: i32.const $push[[L4:[0-9]+]]=, .Lhas_i32_arg_bitcast{{$}}
; CHECK-NEXT: call invoke_v, $pop[[L4]]{{$}}
declare i32 @personality(...)
define void @test_invoke() personality i32 (...)* @personality {
@@ -181,19 +190,35 @@ end:
ret void
}
-; CHECK-LABEL: .Lhas_i32_arg_bitcast:
-; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> ()
-; CHECK-NEXT: call has_i32_arg, $1{{$}}
-; CHECK-NEXT: end_function
-
-; CHECK-LABEL: .Lhas_i32_arg_bitcast.1:
-; CHECK-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
-; CHECK-NEXT: call has_i32_arg, $0{{$}}
-; CHECK-NEXT: end_function
-
-; CHECK-LABEL: .Lhas_i32_arg_bitcast.2:
-; CHECK: call has_i32_arg, $0{{$}}
-; CHECK-NEXT: end_function
+; TYPED-LABEL: .Lhas_i32_arg_bitcast:
+; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast (i32, i32) -> ()
+; TYPED-NEXT: call has_i32_arg, $1{{$}}
+; TYPED-NEXT: end_function
+
+; TYPED-LABEL: .Lhas_i32_arg_bitcast.1:
+; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
+; TYPED-NEXT: call has_i32_arg, $0{{$}}
+; TYPED-NEXT: end_function
+
+; TYPED-LABEL: .Lhas_i32_arg_bitcast.2:
+; TYPED-NEXT: .functype .Lhas_i32_arg_bitcast.2 () -> ()
+; TYPED-NEXT: call has_i32_arg, $0{{$}}
+; TYPED-NEXT: end_function
+
+; OPAQUE-LABEL: .Lhas_i32_arg_bitcast:
+; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast () -> ()
+; OPAQUE-NEXT: call has_i32_arg, $0{{$}}
+; OPAQUE-NEXT: end_function
+
+; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.1:
+; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.1 (i32, i32) -> ()
+; OPAQUE-NEXT: call has_i32_arg, $1{{$}}
+; OPAQUE-NEXT: end_function
+
+; OPAQUE-LABEL: .Lhas_i32_arg_bitcast.2:
+; OPAQUE-NEXT: .functype .Lhas_i32_arg_bitcast.2 (i32, i32) -> ()
+; OPAQUE-NEXT: call has_i32_arg, $0{{$}}
+; OPAQUE-NEXT: end_function
; CHECK-LABEL: .Lhas_i32_ret_bitcast:
; CHECK: call $drop=, has_i32_ret{{$}}
diff --git a/llvm/test/CodeGen/WebAssembly/main-declaration.ll b/llvm/test/CodeGen/WebAssembly/main-declaration.ll
index 445300f73fd14..81b5b1bc81df6 100644
--- a/llvm/test/CodeGen/WebAssembly/main-declaration.ll
+++ b/llvm/test/CodeGen/WebAssembly/main-declaration.ll
@@ -1,4 +1,5 @@
; RUN: llc < %s -asm-verbose=false | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -force-opaque-pointers | FileCheck %s
; Test main functions with alternate signatures.
More information about the llvm-commits
mailing list