[llvm] 41ba39d - [WebAssembly] Don't do SjLj transformation when there's only setjmp
Heejin Ahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 5 15:28:56 PDT 2021
Author: Heejin Ahn
Date: 2021-08-05T15:28:02-07:00
New Revision: 41ba39dfcd0a765f238561ce1b52f843c825ff9a
URL: https://github.com/llvm/llvm-project/commit/41ba39dfcd0a765f238561ce1b52f843c825ff9a
DIFF: https://github.com/llvm/llvm-project/commit/41ba39dfcd0a765f238561ce1b52f843c825ff9a.diff
LOG: [WebAssembly] Don't do SjLj transformation when there's only setjmp
When there is a `setjmp` call in a function, we transform every callsite
of `setjmp` to record its information by calling `saveSetjmp` function,
and we also transform every callsite of a function that can longjmp to
to check if a longjmp occurred and if so jump to the corresponding
post-setjmp BB. Currently we are doing this for every function that
contains a call to `setjmp`, but if there is no other function call
within that function that can longjmp, this transformation of `setjmp`
callsite and all the preparation of `setjmpTable` in the entry of the
function are not necessary.
This checks if a setjmp-calling function has any other calls that can
longjmp, and if not, skips the function for the SjLj transformation.
Reviewed By: dschuff
Differential Revision: https://reviews.llvm.org/D107530
Added:
Modified:
llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll
llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 0ef52edcbd816..aac5dd02922d3 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -253,8 +253,6 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
Function *getInvokeWrapper(CallBase *CI);
bool areAllExceptionsAllowed() const { return EHAllowlistSet.empty(); }
- bool canLongjmp(const Value *Callee) const;
- bool isEmAsmCall(const Value *Callee) const;
bool supportsException(const Function *F) const {
return EnableEmEH && (areAllExceptionsAllowed() ||
EHAllowlistSet.count(std::string(F->getName())));
@@ -505,7 +503,7 @@ Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
return F;
}
-bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(const Value *Callee) const {
+static bool canLongjmp(const Value *Callee) {
if (auto *CalleeF = dyn_cast<Function>(Callee))
if (CalleeF->isIntrinsic())
return false;
@@ -543,7 +541,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(const Value *Callee) const {
return true;
}
-bool WebAssemblyLowerEmscriptenEHSjLj::isEmAsmCall(const Value *Callee) const {
+static bool isEmAsmCall(const Value *Callee) {
StringRef CalleeName = Callee->getName();
// This is an exhaustive list from Emscripten's <emscripten/em_asm.h>.
return CalleeName == "emscripten_asm_const_int" ||
@@ -689,6 +687,15 @@ static void replaceLongjmpWithEmscriptenLongjmp(Function *LongjmpF,
}
}
+static bool containsLongjmpableCalls(const Function *F) {
+ for (const auto &BB : *F)
+ for (const auto &I : BB)
+ if (const auto *CB = dyn_cast<CallBase>(&I))
+ if (canLongjmp(CB->getCalledOperand()))
+ return true;
+ return false;
+}
+
bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
@@ -697,9 +704,6 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
Function *SetjmpF = M.getFunction("setjmp");
Function *LongjmpF = M.getFunction("longjmp");
- bool SetjmpUsed = SetjmpF && !SetjmpF->use_empty();
- bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
- DoSjLj = EnableEmSjLj && (SetjmpUsed || LongjmpUsed);
auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
assert(TPC && "Expected a TargetPassConfig");
@@ -737,6 +741,22 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
EHTypeIDF = getEmscriptenFunction(EHTypeIDTy, "llvm_eh_typeid_for", &M);
}
+ if (EnableEmSjLj && SetjmpF) {
+ // Precompute setjmp users
+ for (User *U : SetjmpF->users()) {
+ Function *UserF = cast<Instruction>(U)->getFunction();
+ // If a function that calls setjmp does not contain any other calls that
+ // can longjmp, we don't need to do any transformation on that function,
+ // so can ignore it
+ if (containsLongjmpableCalls(UserF))
+ SetjmpUsers.insert(UserF);
+ }
+ }
+
+ bool SetjmpUsed = SetjmpF && !SetjmpUsers.empty();
+ bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
+ DoSjLj = EnableEmSjLj && (SetjmpUsed || LongjmpUsed);
+
// Function registration and data pre-gathering for setjmp/longjmp handling
if (DoSjLj) {
// Register emscripten_longjmp function
@@ -759,12 +779,6 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
{getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
false);
TestSetjmpF = getEmscriptenFunction(FTy, "testSetjmp", &M);
-
- // Precompute setjmp users
- for (User *U : SetjmpF->users()) {
- auto *UI = cast<Instruction>(U);
- SetjmpUsers.insert(UI->getFunction());
- }
}
}
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll
index 6cd8e123dcfef..e38b5ae0c84ec 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alias.ll
@@ -23,11 +23,10 @@ entry:
store i32 0, i32* %retval, align 4
%arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %jmp, i32 0, i32 0
%call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ call void @foo()
ret void
; CHECK-LABEL: entry.split
- ; CHECK: call void @free
- ; CHECK: ret void
}
; This is a dummy dlmalloc implemenation only to make compiler pass, because an
@@ -37,6 +36,7 @@ define i8* @dlmalloc(i32) {
ret i8* %p
}
+declare void @foo()
; Function Attrs: returns_twice
declare i32 @setjmp(%struct.__jmp_buf_tag*) #0
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
index bba286999d103..e68c8eb124460 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
@@ -100,6 +100,23 @@ entry:
; CHECK-NEXT: ret void
}
+; Test a case where a function has a setjmp call but no other calls that can
+; longjmp. We don't need to do any transformation in this case.
+define void @setjmp_only(i8* %ptr) {
+; CHECK-LABEL: @setjmp_only
+entry:
+ %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
+ %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
+ %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
+ ; free cannot longjmp
+ call void @free(i8* %ptr)
+ ret void
+; CHECK-NOT: @malloc
+; CHECK-NOT: %setjmpTable
+; CHECK-NOT: @saveSetjmp
+; CHECK-NOT: @testSetjmp
+}
+
; Test SSA validity
define void @ssa(i32 %n) {
; CHECK-LABEL: @ssa
More information about the llvm-commits
mailing list