Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -225,13 +225,8 @@ namespace { class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass { - static const char *ThrewGVName; - static const char *ThrewValueGVName; - static const char *TempRet0GVName; static const char *ResumeFName; static const char *EHTypeIDFName; - static const char *SetThrewFName; - static const char *SetTempRet0FName; static const char *EmLongjmpFName; static const char *EmLongjmpJmpbufFName; static const char *SaveSetjmpFName; @@ -300,14 +295,9 @@ }; } // End anonymous namespace -const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewGVName = "__THREW__"; -const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewValueGVName = "__threwValue"; -const char *WebAssemblyLowerEmscriptenEHSjLj::TempRet0GVName = "__tempRet0"; const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException"; const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName = "llvm_eh_typeid_for"; -const char *WebAssemblyLowerEmscriptenEHSjLj::SetThrewFName = "setThrew"; -const char *WebAssemblyLowerEmscriptenEHSjLj::SetTempRet0FName = "setTempRet0"; const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName = "emscripten_longjmp"; const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName = @@ -343,15 +333,13 @@ return true; } -// Returns an available name for a global value. -// If the proposed name already exists in the module, adds '_' at the end of -// the name until the name is available. -static inline std::string createGlobalValueName(const Module &M, - const std::string &Propose) { - std::string Name = Propose; - while (M.getNamedGlobal(Name)) - Name += "_"; - return Name; +static GlobalVariable *createGlobalVariableI32(Module &M, IRBuilder<> &IRB, + const char *Name) { + if (M.getNamedGlobal(Name)) + report_fatal_error(Twine("variable name is reserved: ") + Name); + + return new GlobalVariable(M, IRB.getInt32Ty(), false, + GlobalValue::WeakODRLinkage, IRB.getInt32(0), Name); } // Simple function name mangler. @@ -613,11 +601,13 @@ LLVMContext &C = M.getContext(); IRBuilder<> IRB(C); - assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists"); + if (M.getNamedGlobal("setThrew")) + report_fatal_error("setThrew already exists"); + Type *Params[] = {IRB.getInt32Ty(), IRB.getInt32Ty()}; FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false); Function *F = - Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M); + Function::Create(FTy, GlobalValue::WeakODRLinkage, "setThrew", &M); Argument *Arg1 = &*(F->arg_begin()); Argument *Arg2 = &*std::next(F->arg_begin()); Arg1->setName("threw"); @@ -648,11 +638,12 @@ LLVMContext &C = M.getContext(); IRBuilder<> IRB(C); - assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists"); + if (M.getNamedGlobal("setTempRet0")) + report_fatal_error("setTempRet0 already exists"); Type *Params[] = {IRB.getInt32Ty()}; FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false); Function *F = - Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M); + Function::Create(FTy, GlobalValue::WeakODRLinkage, "setTempRet0", &M); F->arg_begin()->setName("value"); BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F); IRB.SetInsertPoint(EntryBB); @@ -699,15 +690,9 @@ // Create global variables __THREW__, threwValue, and __tempRet0, which are // used in common for both exception handling and setjmp/longjmp handling - ThrewGV = new GlobalVariable(M, IRB.getInt32Ty(), false, - GlobalValue::ExternalLinkage, IRB.getInt32(0), - createGlobalValueName(M, ThrewGVName)); - ThrewValueGV = new GlobalVariable( - M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage, IRB.getInt32(0), - createGlobalValueName(M, ThrewValueGVName)); - TempRet0GV = new GlobalVariable(M, IRB.getInt32Ty(), false, - GlobalValue::ExternalLinkage, IRB.getInt32(0), - createGlobalValueName(M, TempRet0GVName)); + ThrewGV = createGlobalVariableI32(M, IRB, "__THREW__"); + ThrewValueGV = createGlobalVariableI32(M, IRB, "__threwValue"); + TempRet0GV = createGlobalVariableI32(M, IRB, "__tempRet0"); bool Changed = false; @@ -736,12 +721,6 @@ if (DoSjLj) { Changed = true; // We have setjmp or longjmp somewhere - Function *MallocF = M.getFunction("malloc"); - Function *FreeF = M.getFunction("free"); - if (!MallocF || !FreeF) - report_fatal_error( - "malloc and free must be linked into the module if setjmp is used"); - // Register saveSetjmp function FunctionType *SetjmpFTy = SetjmpF->getFunctionType(); SmallVector Params = {SetjmpFTy->getParamType(0), Index: llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll +++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll @@ -5,9 +5,9 @@ @_ZTIi = external constant i8* @_ZTIc = external constant i8* -; CHECK-DAG: @[[__THREW__:__THREW__.*]] = global i32 0 -; CHECK-DAG: @[[THREWVALUE:__threwValue.*]] = global i32 0 -; CHECK-DAG: @[[TEMPRET0:__tempRet0.*]] = global i32 0 +; CHECK-DAG: __THREW__ = weak_odr global i32 0 +; CHECK-DAG: __threwValue = weak_odr global i32 0 +; CHECK-DAG: __tempRet0 = weak_odr global i32 0 ; Test invoke instruction with clauses (try-catch block) define void @clause() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { @@ -16,10 +16,10 @@ invoke void @foo(i32 3) to label %invoke.cont unwind label %lpad ; CHECK: entry: -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3) -; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]] -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__ +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1 ; CHECK-NEXT: br i1 %cmp, label %lpad, label %invoke.cont @@ -36,7 +36,7 @@ ; CHECK: lpad: ; CHECK-NEXT: %[[FMC:.*]] = call i8* @__cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* null) ; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0 -; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @__tempRet0 ; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1 ; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0 ; CHECK-NEXT: %[[CDR:.*]] = extractvalue { i8*, i32 } %[[IVI2]], 1 @@ -72,10 +72,10 @@ invoke void @foo(i32 3) to label %invoke.cont unwind label %lpad ; CHECK: entry: -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3) -; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]] -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__ +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1 ; CHECK-NEXT: br i1 %cmp, label %lpad, label %invoke.cont @@ -91,7 +91,7 @@ ; CHECK: lpad: ; CHECK-NEXT: %[[FMC:.*]] = call i8* @__cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIc to i8*)) ; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0 -; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @__tempRet0 ; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1 ; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0 ; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 1 @@ -123,7 +123,7 @@ %0 = invoke noalias i8* @bar(i8 signext 1, i8 zeroext 2) to label %invoke.cont unwind label %lpad ; CHECK: entry: -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: %0 = call noalias i8* @"__invoke_i8*_i8_i8"(i8* (i8, i8)* @bar, i8 signext 1, i8 zeroext 2) invoke.cont: ; preds = %entry @@ -173,22 +173,22 @@ ; CHECK-DAG: declare i8* @__cxa_find_matching_catch_4(i8*, i8*) ; setThrew function creation -; CHECK-LABEL: define void @setThrew(i32 %threw, i32 %value) { +; CHECK-LABEL: define weak_odr void @setThrew(i32 %threw, i32 %value) { ; CHECK: entry: -; CHECK-NEXT: %[[__THREW__]].val = load i32, i32* @[[__THREW__]] -; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__]].val, 0 +; CHECK-NEXT: %__THREW__.val = load i32, i32* @__THREW__ +; CHECK-NEXT: %cmp = icmp eq i32 %__THREW__.val, 0 ; CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end ; CHECK: if.then: -; CHECK-NEXT: store i32 %threw, i32* @[[__THREW__]] -; CHECK-NEXT: store i32 %value, i32* @[[THREWVALUE]] +; CHECK-NEXT: store i32 %threw, i32* @__THREW__ +; CHECK-NEXT: store i32 %value, i32* @__threwValue ; CHECK-NEXT: br label %if.end ; CHECK: if.end: ; CHECK-NEXT: ret void ; CHECK: } ; setTempRet0 function creation -; CHECK-LABEL: define void @setTempRet0(i32 %value) { +; CHECK-LABEL: define weak_odr void @setTempRet0(i32 %value) { ; CHECK: entry: -; CHECK-NEXT: store i32 %value, i32* @[[TEMPRET0]] +; CHECK-NEXT: store i32 %value, i32* @__tempRet0 ; CHECK-NEXT: ret void ; CHECK: } Index: llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll =================================================================== --- llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -6,9 +6,9 @@ %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] } @global_var = hidden global i32 0, align 4 -; CHECK-DAG: @[[__THREW__:__THREW__.*]] = global i32 0 -; CHECK-DAG: @[[THREWVALUE:__threwValue.*]] = global i32 0 -; CHECK-DAG: @[[TEMPRET0:__tempRet0.*]] = global i32 0 +; CHECK-DAG: __THREW__ = weak_odr global i32 0 +; CHECK-DAG: __threwValue = weak_odr global i32 0 +; CHECK-DAG: __tempRet0 = weak_odr global i32 0 ; Test a simple setjmp - longjmp sequence define hidden void @setjmp_longjmp() { @@ -28,18 +28,18 @@ ; CHECK-NEXT: %[[BUF:.*]] = alloca [1 x %struct.__jmp_buf_tag] ; CHECK-NEXT: %[[ARRAYDECAY:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0 ; CHECK-NEXT: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(%struct.__jmp_buf_tag* %[[ARRAYDECAY]], i32 1, i32* %[[SETJMP_TABLE]], i32 %[[SETJMP_TABLE_SIZE]]) -; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @__tempRet0 ; CHECK-NEXT: br label %entry.split ; CHECK: entry.split: ; CHECK-NEXT: phi i32 [ 0, %entry ], [ %[[LONGJMP_RESULT:.*]], %if.end ] ; CHECK-NEXT: %[[ARRAYDECAY1:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0 -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: call void @"__invoke_void_%struct.__jmp_buf_tag*_i32"(void (%struct.__jmp_buf_tag*, i32)* @emscripten_longjmp_jmpbuf, %struct.__jmp_buf_tag* %[[ARRAYDECAY1]], i32 1) -; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]] -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__ +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %__THREW__.val, 0 -; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @[[THREWVALUE]] +; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @__threwValue ; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0 ; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]] ; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1 @@ -59,7 +59,7 @@ ; CHECK: if.end: ; CHECK-NEXT: %[[LABEL_PHI:.*]] = phi i32 [ %[[LABEL:.*]], %if.end2 ], [ -1, %if.else1 ] -; CHECK-NEXT: %[[LONGJMP_RESULT]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[LONGJMP_RESULT]] = load i32, i32* @__tempRet0 ; CHECK-NEXT: switch i32 %[[LABEL_PHI]], label %entry.split.split [ ; CHECK-NEXT: i32 1, label %entry.split ; CHECK-NEXT: ] @@ -69,7 +69,7 @@ ; CHECK-NEXT: unreachable ; CHECK: if.end2: -; CHECK-NEXT: store i32 %[[THREWVALUE_VAL]], i32* @[[TEMPRET0]] +; CHECK-NEXT: store i32 %[[THREWVALUE_VAL]], i32* @__tempRet0 ; CHECK-NEXT: br label %if.end } @@ -105,12 +105,12 @@ to label %try.cont unwind label %lpad ; CHECK: entry.split: -; CHECK: store i32 0, i32* @[[__THREW__]] +; CHECK: store i32 0, i32* @__THREW__ ; CHECK-NEXT: call void @__invoke_void(void ()* @foo) -; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]] -; CHECK-NEXT: store i32 0, i32* @[[__THREW__]] +; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__ +; CHECK-NEXT: store i32 0, i32* @__THREW__ ; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %[[__THREW__VAL]], 0 -; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @[[THREWVALUE]] +; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @__threwValue ; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0 ; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]] ; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1 @@ -152,7 +152,7 @@ ; CHECK: if.then: ; CHECK: %[[VAR0:.*]] = load i32, i32* @global_var, align 4 ; CHECK: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp( -; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @[[TEMPRET0]] +; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @__tempRet0 ; CHECK: if.then.split: ; CHECK: %[[VAR1:.*]] = phi i32 [ %[[VAR0]], %if.then ], [ %[[VAR2:.*]], %if.end3 ]