Skip to content

Commit 4791a66

Browse files
committedNov 20, 2018
[WebAssembly] WebAssemblyLowerEmscriptenEHSjLj: use getter/setter for accessing tempRet0
Rather than assuming that `tempRet0` exists in linear memory only assume the getter/setter functions exist. This avoids conflicting with binaryen which declares a wasm global for this purpose and defines it's own getter and setter for that. The other advantage of doing things this way is that it leaving it up to the linker/finalizer to decide how to actually store this temporary. As it happens binaryen uses a wasm global which is more appropriate since it is thread safe. This also allows us to change the way this is stored in the future (memory, TLS memory, wasm global) without modifying LLVM. This is part of a 4 part change: LLVM: https://reviews.llvm.org/D53240 fastcomp: emscripten-core/emscripten-fastcomp#237 emscripten: emscripten-core/emscripten#7358 binaryen: WebAssembly/binaryen#1709 Differential Revision: https://reviews.llvm.org/D53240 llvm-svn: 347340
1 parent 377748f commit 4791a66

File tree

3 files changed

+55
-48
lines changed

3 files changed

+55
-48
lines changed
 

Diff for: ‎llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp

+45-40
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,19 @@
5050
///
5151
/// In detail, this pass does following things:
5252
///
53-
/// 1) Assumes the existence of global variables: __THREW__, __threwValue, and
54-
/// __tempRet0.
55-
/// __tempRet0 will be set within __cxa_find_matching_catch() function in
56-
/// JS library, and __THREW__ and __threwValue will be set in invoke wrappers
53+
/// 1) Assumes the existence of global variables: __THREW__, __threwValue
54+
/// __THREW__ and __threwValue will be set in invoke wrappers
5755
/// in JS glue code. For what invoke wrappers are, refer to 3). These
5856
/// variables are used for both exceptions and setjmp/longjmps.
5957
/// __THREW__ indicates whether an exception or a longjmp occurred or not. 0
6058
/// means nothing occurred, 1 means an exception occurred, and other numbers
6159
/// mean a longjmp occurred. In the case of longjmp, __threwValue variable
6260
/// indicates the corresponding setjmp buffer the longjmp corresponds to.
63-
/// In exception handling, __tempRet0 indicates the type of an exception
64-
/// caught, and in setjmp/longjmp, it means the second argument to longjmp
65-
/// function.
6661
///
6762
/// * Exception handling
6863
///
69-
/// 2) We assume the existence of setThrew and setTempRet0 functions at link
70-
/// time.
64+
/// 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
65+
/// at link time.
7166
/// The global variables in 1) will exist in wasm address space,
7267
/// but their values should be set in JS code, so these functions
7368
/// as interfaces to JS glue code. These functions are equivalent to the
@@ -80,10 +75,12 @@
8075
/// __threwValue = value;
8176
/// }
8277
/// }
78+
//
79+
/// setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
8380
///
84-
/// function setTempRet0(value) {
85-
/// __tempRet0 = value;
86-
/// }
81+
/// In exception handling, getTempRet0 indicates the type of an exception
82+
/// caught, and in setjmp/longjmp, it means the second argument to longjmp
83+
/// function.
8784
///
8885
/// 3) Lower
8986
/// invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
@@ -120,11 +117,10 @@
120117
/// ... use %val ...
121118
/// into
122119
/// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
123-
/// %val = {%fmc, __tempRet0}
120+
/// %val = {%fmc, getTempRet0()}
124121
/// ... use %val ...
125122
/// Here N is a number calculated based on the number of clauses.
126-
/// Global variable __tempRet0 is set within __cxa_find_matching_catch() in
127-
/// JS glue code.
123+
/// setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
128124
///
129125
/// 5) Lower
130126
/// resume {%a, %b}
@@ -162,15 +158,15 @@
162158
/// setjmp(buf)
163159
/// into
164160
/// setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
165-
/// setjmpTableSize = __tempRet0;
161+
/// setjmpTableSize = getTempRet0();
166162
/// For each dynamic setjmp call, setjmpTable stores its ID (a number which
167163
/// is incrementally assigned from 0) and its label (a unique number that
168164
/// represents each callsite of setjmp). When we need more entries in
169165
/// setjmpTable, it is reallocated in saveSetjmp() in JS code and it will
170166
/// return the new table address, and assign the new table size in
171-
/// __tempRet0. saveSetjmp also stores the setjmp's ID into the buffer buf.
172-
/// A BB with setjmp is split into two after setjmp call in order to make the
173-
/// post-setjmp BB the possible destination of longjmp BB.
167+
/// setTempRet0(). saveSetjmp also stores the setjmp's ID into the buffer
168+
/// buf. A BB with setjmp is split into two after setjmp call in order to
169+
/// make the post-setjmp BB the possible destination of longjmp BB.
174170
///
175171
///
176172
/// 4) Lower every call that might longjmp into
@@ -183,11 +179,11 @@
183179
/// setjmpTableSize);
184180
/// if (%label == 0)
185181
/// emscripten_longjmp(%__THREW__.val, __threwValue);
186-
/// __tempRet0 = __threwValue;
182+
/// setTempRet0(__threwValue);
187183
/// } else {
188184
/// %label = -1;
189185
/// }
190-
/// longjmp_result = __tempRet0;
186+
/// longjmp_result = getTempRet0();
191187
/// switch label {
192188
/// label 1: goto post-setjmp BB 1
193189
/// label 2: goto post-setjmp BB 2
@@ -246,7 +242,8 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
246242

247243
GlobalVariable *ThrewGV;
248244
GlobalVariable *ThrewValueGV;
249-
GlobalVariable *TempRet0GV;
245+
Function *GetTempRet0Func;
246+
Function *SetTempRet0Func;
250247
Function *ResumeF;
251248
Function *EHTypeIDF;
252249
Function *EmLongjmpF;
@@ -286,9 +283,10 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
286283

287284
WebAssemblyLowerEmscriptenEHSjLj(bool EnableEH = true, bool EnableSjLj = true)
288285
: ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
289-
ThrewGV(nullptr), ThrewValueGV(nullptr), TempRet0GV(nullptr),
290-
ResumeF(nullptr), EHTypeIDF(nullptr), EmLongjmpF(nullptr),
291-
EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr), TestSetjmpF(nullptr) {
286+
ThrewGV(nullptr), ThrewValueGV(nullptr), GetTempRet0Func(nullptr),
287+
SetTempRet0Func(nullptr), ResumeF(nullptr), EHTypeIDF(nullptr),
288+
EmLongjmpF(nullptr), EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr),
289+
TestSetjmpF(nullptr) {
292290
EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end());
293291
}
294292
bool runOnModule(Module &M) override;
@@ -514,7 +512,8 @@ bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
514512
Function *ThrowF = M.getFunction("__cxa_throw");
515513
Function *TerminateF = M.getFunction("__clang_call_terminate");
516514
if (Callee == BeginCatchF || Callee == EndCatchF ||
517-
Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF)
515+
Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF ||
516+
Callee == GetTempRet0Func || Callee == SetTempRet0Func)
518517
return false;
519518

520519
// Otherwise we don't know
@@ -527,11 +526,11 @@ bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
527526
// %label = _testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
528527
// if (%label == 0)
529528
// emscripten_longjmp(%__THREW__.val, threwValue);
530-
// __tempRet0 = threwValue;
529+
// setTempRet0(threwValue);
531530
// } else {
532531
// %label = -1;
533532
// }
534-
// %longjmp_result = __tempRet0;
533+
// %longjmp_result = getTempRet0();
535534
//
536535
// As output parameters. returns %label, %longjmp_result, and the BB the last
537536
// instruction (%longjmp_result = ...) is in.
@@ -575,15 +574,15 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
575574
IRB.CreateCall(EmLongjmpF, {Threw, ThrewValue});
576575
IRB.CreateUnreachable();
577576

578-
// __tempRet0 = threwValue;
577+
// setTempRet0(threwValue);
579578
IRB.SetInsertPoint(EndBB2);
580-
IRB.CreateStore(ThrewValue, TempRet0GV);
579+
IRB.CreateCall(SetTempRet0Func, ThrewValue);
581580
IRB.CreateBr(EndBB1);
582581

583582
IRB.SetInsertPoint(ElseBB1);
584583
IRB.CreateBr(EndBB1);
585584

586-
// longjmp_result = __tempRet0;
585+
// longjmp_result = getTempRet0();
587586
IRB.SetInsertPoint(EndBB1);
588587
PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
589588
LabelPHI->addIncoming(ThenLabel, EndBB2);
@@ -593,7 +592,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
593592
// Output parameter assignment
594593
Label = LabelPHI;
595594
EndBB = EndBB1;
596-
LongjmpResult = IRB.CreateLoad(TempRet0GV, "longjmp_result");
595+
LongjmpResult = IRB.CreateCall(GetTempRet0Func, None, "longjmp_result");
597596
}
598597

599598
void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
@@ -633,12 +632,19 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
633632
bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
634633
bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
635634

636-
// Declare (or get) global variables __THREW__, __threwValue, and __tempRet0,
637-
// which are used in common for both exception handling and setjmp/longjmp
638-
// handling
635+
// Declare (or get) global variables __THREW__, __threwValue, and
636+
// getTempRet0/setTempRet0 function which are used in common for both
637+
// exception handling and setjmp/longjmp handling
639638
ThrewGV = getGlobalVariableI32(M, IRB, "__THREW__");
640639
ThrewValueGV = getGlobalVariableI32(M, IRB, "__threwValue");
641-
TempRet0GV = getGlobalVariableI32(M, IRB, "__tempRet0");
640+
GetTempRet0Func =
641+
Function::Create(FunctionType::get(IRB.getInt32Ty(), false),
642+
GlobalValue::ExternalLinkage, "getTempRet0", &M);
643+
SetTempRet0Func = Function::Create(
644+
FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(), false),
645+
GlobalValue::ExternalLinkage, "setTempRet0", &M);
646+
GetTempRet0Func->setDoesNotThrow();
647+
SetTempRet0Func->setDoesNotThrow();
642648

643649
bool Changed = false;
644650

@@ -848,8 +854,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
848854
CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
849855
Value *Undef = UndefValue::get(LPI->getType());
850856
Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
851-
Value *TempRet0 =
852-
IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + ".val");
857+
Value *TempRet0 = IRB.CreateCall(GetTempRet0Func, None, "tempret0");
853858
Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
854859

855860
LPI->replaceAllUsesWith(Pair1);
@@ -930,7 +935,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
930935
Instruction *NewSetjmpTable =
931936
IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
932937
Instruction *NewSetjmpTableSize =
933-
IRB.CreateLoad(TempRet0GV, "setjmpTableSize");
938+
IRB.CreateCall(GetTempRet0Func, None, "setjmpTableSize");
934939
SetjmpTableInsts.push_back(NewSetjmpTable);
935940
SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
936941
ToErase.push_back(CI);
@@ -1052,7 +1057,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
10521057
// ...
10531058
// somebb:
10541059
// setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
1055-
// setjmpTableSize = __tempRet0;
1060+
// setjmpTableSize = getTempRet0();
10561061
// So we need to make sure the SSA for these variables is valid so that every
10571062
// saveSetjmp and testSetjmp calls have the correct arguments.
10581063
SSAUpdater SetjmpTableSSA;

Diff for: ‎llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ target triple = "wasm32-unknown-unknown"
77
@_ZTIc = external constant i8*
88
; CHECK-DAG: __THREW__ = external global i32
99
; CHECK-DAG: __threwValue = external global i32
10-
; CHECK-DAG: __tempRet0 = external global i32
1110

1211
; Test invoke instruction with clauses (try-catch block)
1312
define void @clause() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
@@ -36,7 +35,7 @@ lpad: ; preds = %entry
3635
; CHECK: lpad:
3736
; CHECK-NEXT: %[[FMC:.*]] = call i8* @__cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* null)
3837
; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0
39-
; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @__tempRet0
38+
; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = call i32 @getTempRet0()
4039
; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1
4140
; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0
4241
; CHECK-NEXT: %[[CDR:.*]] = extractvalue { i8*, i32 } %[[IVI2]], 1
@@ -91,7 +90,7 @@ lpad: ; preds = %entry
9190
; CHECK: lpad:
9291
; CHECK-NEXT: %[[FMC:.*]] = call i8* @__cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIc to i8*))
9392
; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0
94-
; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @__tempRet0
93+
; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = call i32 @getTempRet0()
9594
; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1
9695
; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0
9796
; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 1
@@ -168,6 +167,8 @@ declare void @__cxa_end_catch()
168167
declare void @__cxa_call_unexpected(i8*)
169168

170169
; JS glue functions and invoke wrappers declaration
170+
; CHECK-DAG: declare i32 @getTempRet0()
171+
; CHECK-DAG: declare void @setTempRet0(i32)
171172
; CHECK-DAG: declare void @__resumeException(i8*)
172173
; CHECK-DAG: declare void @__invoke_void_i32(void (i32)*, i32)
173174
; CHECK-DAG: declare i8* @__cxa_find_matching_catch_4(i8*, i8*)

Diff for: ‎llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll

+6-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ target triple = "wasm32-unknown-unknown"
88
@global_var = hidden global i32 0, align 4
99
; CHECK-DAG: __THREW__ = external global i32
1010
; CHECK-DAG: __threwValue = external global i32
11-
; CHECK-DAG: __tempRet0 = external global i32
1211

1312
; Test a simple setjmp - longjmp sequence
1413
define hidden void @setjmp_longjmp() {
@@ -28,7 +27,7 @@ entry:
2827
; CHECK-NEXT: %[[BUF:.*]] = alloca [1 x %struct.__jmp_buf_tag]
2928
; CHECK-NEXT: %[[ARRAYDECAY:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0
3029
; CHECK-NEXT: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(%struct.__jmp_buf_tag* %[[ARRAYDECAY]], i32 1, i32* %[[SETJMP_TABLE]], i32 %[[SETJMP_TABLE_SIZE]])
31-
; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @__tempRet0
30+
; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = call i32 @getTempRet0()
3231
; CHECK-NEXT: br label %entry.split
3332

3433
; CHECK: entry.split:
@@ -59,7 +58,7 @@ entry:
5958

6059
; CHECK: if.end:
6160
; CHECK-NEXT: %[[LABEL_PHI:.*]] = phi i32 [ %[[LABEL:.*]], %if.end2 ], [ -1, %if.else1 ]
62-
; CHECK-NEXT: %[[LONGJMP_RESULT]] = load i32, i32* @__tempRet0
61+
; CHECK-NEXT: %[[LONGJMP_RESULT]] = call i32 @getTempRet0()
6362
; CHECK-NEXT: switch i32 %[[LABEL_PHI]], label %entry.split.split [
6463
; CHECK-NEXT: i32 1, label %entry.split
6564
; CHECK-NEXT: ]
@@ -69,7 +68,7 @@ entry:
6968
; CHECK-NEXT: unreachable
7069

7170
; CHECK: if.end2:
72-
; CHECK-NEXT: store i32 %[[THREWVALUE_VAL]], i32* @__tempRet0
71+
; CHECK-NEXT: call void @setTempRet0(i32 %[[THREWVALUE_VAL]])
7372
; CHECK-NEXT: br label %if.end
7473
}
7574

@@ -152,7 +151,7 @@ if.then: ; preds = %entry
152151
; CHECK: if.then:
153152
; CHECK: %[[VAR0:.*]] = load i32, i32* @global_var, align 4
154153
; CHECK: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(
155-
; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @__tempRet0
154+
; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = call i32 @getTempRet0()
156155

157156
; CHECK: if.then.split:
158157
; CHECK: %[[VAR1:.*]] = phi i32 [ %[[VAR0]], %if.then ], [ %[[VAR2:.*]], %if.end3 ]
@@ -201,6 +200,8 @@ declare i8* @malloc(i32)
201200
declare void @free(i8*)
202201

203202
; JS glue functions and invoke wrappers declaration
203+
; CHECK-DAG: declare i32 @getTempRet0()
204+
; CHECK-DAG: declare void @setTempRet0(i32)
204205
; CHECK-DAG: declare i32* @saveSetjmp(%struct.__jmp_buf_tag*, i32, i32*, i32)
205206
; CHECK-DAG: declare i32 @testSetjmp(i32, i32*, i32)
206207
; CHECK-DAG: declare void @emscripten_longjmp_jmpbuf(%struct.__jmp_buf_tag*, i32)

0 commit comments

Comments
 (0)
Please sign in to comment.