diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-12-25 11:31:31 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-12-25 11:32:06 -0800 |
commit | fda1fc2a3eb8f8de71d9fbe2d9459cadd4a93501 (patch) | |
tree | 7f481a19fccf1ed95010eb12598ffd7b2a227268 | |
parent | 0caa98e6ccae219815efafe1f7692ac0dce04971 (diff) |
properly handle invoke of setjmp, by lowering to a call, which fixes phis that refer to it. fixes #1942
-rw-r--r-- | src/analyzer.js | 12 | ||||
-rw-r--r-- | tests/cases/longjmp_tiny_invoke_phi.ll | 46 | ||||
-rw-r--r-- | tests/cases/longjmp_tiny_invoke_phi.txt | 4 |
3 files changed, 61 insertions, 1 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 17582ea3..e8ca6cf6 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1570,7 +1570,17 @@ function analyzer(data, sidePass) { for (var j = 0; j < label.lines.length; j++) { var line = label.lines[j]; if ((line.intertype == 'call' || line.intertype == 'invoke') && line.ident == setjmp) { - // Add a new label + if (line.intertype == 'invoke') { + // setjmp cannot trigger unwinding, so just reduce the invoke to a call + branch + line.intertype = 'call'; + label.lines.push({ + intertype: 'branch', + label: line.toLabel, + lineNum: line.lineNum + 0.01, // XXX legalizing might confuse this + }); + line.toLabel = line.unwindLabel = -2; + } + // split this label into up to the setjmp (including), then a new label for the rest. longjmp will reach the rest var oldLabel = label.ident; var newLabel = func.labelIdCounter++; if (!func.setjmpTable) func.setjmpTable = []; diff --git a/tests/cases/longjmp_tiny_invoke_phi.ll b/tests/cases/longjmp_tiny_invoke_phi.ll new file mode 100644 index 00000000..30c43339 --- /dev/null +++ b/tests/cases/longjmp_tiny_invoke_phi.ll @@ -0,0 +1,46 @@ +; ModuleID = '/tmp/emscripten_temp/src.cpp.o' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@_ZL3buf = internal global [20 x i16] zeroinitializer, align 2 +@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1 +@.str1 = private unnamed_addr constant [6 x i8] c"more\0A\00", align 1 +@.str2 = private unnamed_addr constant [6 x i8] c"fair\0A\00", align 1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = invoke i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice + to label %allgood unwind label %awful + +allgood: + %p = phi i32 [0, %entry], [1, %if.else] + %calll = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0)) + %total = add i32 %p, %call + %tobool = icmp ne i32 %total, 10 + br i1 %tobool, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0)) + call void @longjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0), i32 10) + br label %if.end + +if.else: ; preds = %entry + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0)) + %chak = icmp ne i32 %call2, 1337 + br i1 %chak, label %if.end, label %allgood + +if.end: ; preds = %if.else, %if.then + ret i32 0 + +awful: + ret i32 1 +} + +declare i32 @setjmp(i16*) returns_twice + +declare i32 @printf(i8*, ...) + +declare void @longjmp(i16*, i32) + diff --git a/tests/cases/longjmp_tiny_invoke_phi.txt b/tests/cases/longjmp_tiny_invoke_phi.txt new file mode 100644 index 00000000..aaa41d11 --- /dev/null +++ b/tests/cases/longjmp_tiny_invoke_phi.txt @@ -0,0 +1,4 @@ +fair +hello world +fair +more |