Skip to content

Commit 7005517

Browse files
author
Dan Gohman
committed
[WebAssembly] Support bitcasted function addresses with varargs.
Generalize FixFunctionBitcasts to handle varargs functions. This in particular fixes the case where clang bitcasts away a varargs when calling a K&R-style function. This avoids interacting with tricky ABI details because it operates at the LLVM IR level before varargs ABI details are exposed. This fixes PR35385. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319186 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 46f8d8c commit 7005517

File tree

5 files changed

+58
-17
lines changed

5 files changed

+58
-17
lines changed

lib/MC/WasmObjectWriter.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -1040,12 +1040,15 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
10401040
for (const MCSymbol &S : Asm.symbols()) {
10411041
const auto &WS = static_cast<const MCSymbolWasm &>(S);
10421042

1043-
if (WS.isTemporary())
1044-
continue;
1045-
1043+
// Register types for all functions, including those with private linkage
1044+
// (making them
1045+
// because wasm always needs a type signature.
10461046
if (WS.isFunction())
10471047
registerFunctionType(WS);
10481048

1049+
if (WS.isTemporary())
1050+
continue;
1051+
10491052
// If the symbol is not defined in this translation unit, import it.
10501053
if (!WS.isDefined(/*SetUsed=*/false)) {
10511054
WasmImport Import;

lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,10 @@ static Function *CreateWrapper(Function *F, FunctionType *Ty) {
107107
// Determine what arguments to pass.
108108
SmallVector<Value *, 4> Args;
109109
Function::arg_iterator AI = Wrapper->arg_begin();
110+
Function::arg_iterator AE = Wrapper->arg_end();
110111
FunctionType::param_iterator PI = F->getFunctionType()->param_begin();
111112
FunctionType::param_iterator PE = F->getFunctionType()->param_end();
112-
for (; AI != Wrapper->arg_end() && PI != PE; ++AI, ++PI) {
113+
for (; AI != AE && PI != PE; ++AI, ++PI) {
113114
if (AI->getType() != *PI) {
114115
Wrapper->eraseFromParent();
115116
return nullptr;
@@ -118,6 +119,9 @@ static Function *CreateWrapper(Function *F, FunctionType *Ty) {
118119
}
119120
for (; PI != PE; ++PI)
120121
Args.push_back(UndefValue::get(*PI));
122+
if (F->isVarArg())
123+
for (; AI != AE; ++AI)
124+
Args.push_back(&*AI);
121125

122126
CallInst *Call = CallInst::Create(F, Args, "", BB);
123127

@@ -158,11 +162,6 @@ bool FixFunctionBitcasts::runOnModule(Module &M) {
158162
if (!Ty)
159163
continue;
160164

161-
// Wasm varargs are not ABI-compatible with non-varargs. Just ignore
162-
// such casts for now.
163-
if (Ty->isVarArg() || F->isVarArg())
164-
continue;
165-
166165
auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr));
167166
if (Pair.second)
168167
Pair.first->second = CreateWrapper(F, Ty);

test/CodeGen/WebAssembly/call.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ define void @coldcc_tail_call_void_nullary() {
153153
; CHECK-LABEL: call_constexpr:
154154
; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 2{{$}}
155155
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 3{{$}}
156-
; CHECK-NEXT: call vararg_func@FUNCTION, $pop[[L0]], $pop[[L1]]{{$}}
156+
; CHECK-NEXT: call .Lbitcast@FUNCTION, $pop[[L0]], $pop[[L1]]{{$}}
157157
; CHECK-NEXT: call other_void_nullary@FUNCTION{{$}}
158158
; CHECK-NEXT: call void_nullary@FUNCTION{{$}}
159159
; CHECK-NEXT: return{{$}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: llc < %s -asm-verbose=false | FileCheck %s
2+
3+
; Test that function pointer casts casting away varargs are replaced with
4+
; wrappers.
5+
6+
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
7+
target triple = "wasm32-unknown-unknown-wasm"
8+
9+
define void @callWithArgs() {
10+
entry:
11+
call void bitcast (void (...)* @underspecified to void (i32, i32)*)(i32 0, i32 1)
12+
call void(...) bitcast (void (i32, i32)* @specified to void (...)*)(i32 0, i32 1)
13+
ret void
14+
}
15+
16+
declare void @underspecified(...)
17+
declare void @specified(i32, i32)
18+
19+
; CHECK: callWithArgs:
20+
; CHECK: i32.const $push1=, 0
21+
; CHECK-NEXT: i32.const $push0=, 1
22+
; CHECK-NEXT: call .Lbitcast@FUNCTION, $pop1, $pop0
23+
; CHECK: call .Lbitcast.1@FUNCTION, $pop{{[0-9]+$}}
24+
25+
; CHECK: .Lbitcast:
26+
; CHECK-NEXT: .param i32, i32{{$}}
27+
; CHECK: call underspecified@FUNCTION, $pop{{[0-9]+$}}
28+
29+
; CHECK: .Lbitcast.1:
30+
; CHECK-NEXT: .param i32{{$}}
31+
; CHECK: call specified@FUNCTION, $pop{{[0-9]+}}, $pop{{[0-9]+$}}

test/CodeGen/WebAssembly/function-bitcasts.ll

+15-7
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ declare void @foo3()
2020
; CHECK-NEXT: call .Lbitcast@FUNCTION{{$}}
2121
; CHECK-NEXT: call .Lbitcast.1@FUNCTION{{$}}
2222
; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 0
23-
; CHECK-NEXT: call .Lbitcast.2@FUNCTION, $pop[[L0]]{{$}}
23+
; CHECK-NEXT: call .Lbitcast.4@FUNCTION, $pop[[L0]]{{$}}
2424
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 0
25-
; CHECK-NEXT: call .Lbitcast.2@FUNCTION, $pop[[L1]]{{$}}
25+
; CHECK-NEXT: call .Lbitcast.4@FUNCTION, $pop[[L1]]{{$}}
2626
; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, 0
27-
; CHECK-NEXT: call .Lbitcast.2@FUNCTION, $pop[[L2]]{{$}}
27+
; CHECK-NEXT: call .Lbitcast.4@FUNCTION, $pop[[L2]]{{$}}
2828
; CHECK-NEXT: call foo0@FUNCTION
29-
; CHECK-NEXT: i32.call $drop=, .Lbitcast.3@FUNCTION{{$}}
29+
; CHECK-NEXT: i32.call $drop=, .Lbitcast.5@FUNCTION{{$}}
3030
; CHECK-NEXT: call foo2@FUNCTION{{$}}
3131
; CHECK-NEXT: call foo1@FUNCTION{{$}}
3232
; CHECK-NEXT: call foo3@FUNCTION{{$}}
@@ -54,10 +54,10 @@ entry:
5454
; CHECK-LABEL: test_varargs:
5555
; CHECK: set_global
5656
; CHECK: i32.const $push[[L3:[0-9]+]]=, 0{{$}}
57-
; CHECK-NEXT: call vararg@FUNCTION, $pop[[L3]]{{$}}
57+
; CHECK-NEXT: call .Lbitcast.2@FUNCTION, $pop[[L3]]{{$}}
5858
; CHECK-NEXT: i32.const $push[[L4:[0-9]+]]=, 0{{$}}
5959
; CHECK-NEXT: i32.store 0($[[L5:[0-9]+]]), $pop[[L4]]{{$}}
60-
; CHECK-NEXT: call plain@FUNCTION, $[[L5]]{{$}}
60+
; CHECK-NEXT: call .Lbitcast.3@FUNCTION, $[[L5]]{{$}}
6161
define void @test_varargs() {
6262
call void bitcast (void (...)* @vararg to void (i32)*)(i32 0)
6363
call void (...) bitcast (void (i32)* @plain to void (...)*)(i32 0)
@@ -147,11 +147,19 @@ end:
147147
; CHECK-NEXT: end_function
148148

149149
; CHECK-LABEL: .Lbitcast.2:
150+
; CHECK: call vararg@FUNCTION, $1{{$}}
151+
; CHECK: end_function
152+
153+
; CHECK-LABEL: .Lbitcast.3:
154+
; CHECK: call plain@FUNCTION, $1{{$}}
155+
; CHECK: end_function
156+
157+
; CHECK-LABEL: .Lbitcast.4:
150158
; CHECK-NEXT: .param i32
151159
; CHECK-NEXT: call foo0@FUNCTION{{$}}
152160
; CHECK-NEXT: end_function
153161

154-
; CHECK-LABEL: .Lbitcast.3:
162+
; CHECK-LABEL: .Lbitcast.5:
155163
; CHECK-NEXT: .result i32
156164
; CHECK-NEXT: call foo1@FUNCTION{{$}}
157165
; CHECK-NEXT: copy_local $push0=, $0

0 commit comments

Comments
 (0)