diff options
author | Jan Voung <jvoung@chromium.org> | 2013-10-11 15:27:57 -0700 |
---|---|---|
committer | Jan Voung <jvoung@chromium.org> | 2013-10-11 15:27:57 -0700 |
commit | c036ceaa8225a23a795b50144b1da4b883e984a3 (patch) | |
tree | 9b1db86c6393dab9c34c52726a54eb757205dbc6 /test | |
parent | e87e8cd648035ac8e2cda19ce0cfd9d9a6e309fb (diff) |
Cherry-pick LLVM 187787 to prevent tail calls on x86-32 when not appropriate.
See:
http://llvm.org/viewvc/llvm-project?view=revision&revision=187787
The newer version of newlib tickles this x86-32 bug
when building the exception handling tests, which don't
strip the "tail" attribute.
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3702
Waiting on trybots, but it seems to have fixed the minimal
reproducer I have:
http://chromegw.corp.google.com/i/tryserver.nacl/builders/nacl-toolchain-linux-pnacl-x86_64/builds/922
http://chromegw.corp.google.com/i/tryserver.nacl/builders/nacl-toolchain-linux-pnacl-x86_32/builds/870
http://chromegw.corp.google.com/i/tryserver.nacl/builders/nacl-toolchain-mac-pnacl-x86_32/builds/875
R=jfb@chromium.org
Review URL: https://codereview.chromium.org/26538008
Diffstat (limited to 'test')
-rw-r--r-- | test/CodeGen/Hexagon/tail-call-trunc.ll | 28 | ||||
-rw-r--r-- | test/CodeGen/X86/returned-trunc-tail-calls.ll | 97 | ||||
-rw-r--r-- | test/CodeGen/X86/tail-call-legality.ll | 32 |
3 files changed, 157 insertions, 0 deletions
diff --git a/test/CodeGen/Hexagon/tail-call-trunc.ll b/test/CodeGen/Hexagon/tail-call-trunc.ll new file mode 100644 index 0000000000..98214c7b1e --- /dev/null +++ b/test/CodeGen/Hexagon/tail-call-trunc.ll @@ -0,0 +1,28 @@ +; RUN: llc -march=hexagon < %s | FileCheck %s + +declare i32 @ret_i32() + +define i8 @test_i8() { +; CHECK-LABEL: test_i8: +; CHECK: jump ret_i32 + %res = tail call i32 @ret_i32() + %val = trunc i32 %res to i8 + ret i8 %val +} + +define i16 @test_i16() { +; CHECK-LABEL: test_i16: +; CHECK: jump ret_i32 + %res = tail call i32 @ret_i32() + %val = trunc i32 %res to i16 + ret i16 %val +} + +declare i64 @ret_i64() +define i32 @test_i32() { +; CHECK-LABEL: test_i32: +; CHECK: call ret_i64 + %res = tail call i64 @ret_i64() + %val = trunc i64 %res to i32 + ret i32 42 +} diff --git a/test/CodeGen/X86/returned-trunc-tail-calls.ll b/test/CodeGen/X86/returned-trunc-tail-calls.ll new file mode 100644 index 0000000000..10bd3b673b --- /dev/null +++ b/test/CodeGen/X86/returned-trunc-tail-calls.ll @@ -0,0 +1,97 @@ +; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s + +declare i32 @ret32(i32 returned) +declare i64 @ret64(i64 returned) + +define i64 @test1(i64 %val) { +; CHECK-LABEL: test1: +; CHECK-NOT: jmp +; CHECK: callq + %in = trunc i64 %val to i32 + tail call i32 @ret32(i32 returned %in) + ret i64 %val +} + +define i32 @test2(i64 %val) { +; CHECK-LABEL: test2: +; CHECK: jmp +; CHECK-NOT: callq + %in = trunc i64 %val to i32 + tail call i64 @ret64(i64 returned %val) + ret i32 %in +} + +define i32 @test3(i64 %in) { +; CHECK-LABEL: test3: +; CHECK: jmp +; CHECK-NOT: callq + %small = trunc i64 %in to i32 + tail call i32 @ret32(i32 returned %small) + ret i32 %small +} + +declare {i32, i8} @take_i32_i8({i32, i8} returned) +define { i8, i8 } @test_nocommon_value({i32, i32} %in) { +; CHECK-LABEL: test_nocommon_value +; CHECK: jmp + + %first = extractvalue {i32, i32} %in, 0 + %first.trunc = trunc i32 %first to i8 + + %second = extractvalue {i32, i32} %in, 1 + %second.trunc = trunc i32 %second to i8 + + %tmp = insertvalue {i32, i8} undef, i32 %first, 0 + %callval = insertvalue {i32, i8} %tmp, i8 %second.trunc, 1 + tail call {i32, i8} @take_i32_i8({i32, i8} returned %callval) + + %restmp = insertvalue {i8, i8} undef, i8 %first.trunc, 0 + %res = insertvalue {i8, i8} %restmp, i8 %second.trunc, 1 + ret {i8, i8} %res +} + +declare {i32, {i32, i32}} @give_i32_i32_i32() +define {{i32, i32}, i32} @test_structs_different_shape() { +; CHECK-LABEL: test_structs_different_shape +; CHECK: jmp + %val = tail call {i32, {i32, i32}} @give_i32_i32_i32() + + %first = extractvalue {i32, {i32, i32}} %val, 0 + %second = extractvalue {i32, {i32, i32}} %val, 1, 0 + %third = extractvalue {i32, {i32, i32}} %val, 1, 1 + + %restmp = insertvalue {{i32, i32}, i32} undef, i32 %first, 0, 0 + %reseventmper = insertvalue {{i32, i32}, i32} %restmp, i32 %second, 0, 1 + %res = insertvalue {{i32, i32}, i32} %reseventmper, i32 %third, 1 + + ret {{i32, i32}, i32} %res +} + +define i64 @test_undef_asymmetry() { +; CHECK: test_undef_asymmetry +; CHECK-NOT: jmp + tail call i64 @ret64(i64 returned undef) + ret i64 2 +} + +define {{}, {{}, i32, {}}, [1 x i32]} @evil_empty_aggregates() { +; CHECK-LABEL: evil_empty_aggregates +; CHECK: jmp + %agg = tail call {i32, {i32, i32}} @give_i32_i32_i32() + + %first = extractvalue {i32, {i32, i32}} %agg, 0 + %second = extractvalue {i32, {i32, i32}} %agg, 1, 0 + + %restmp = insertvalue {{}, {{}, i32, {}}, [1 x i32]} undef, i32 %first, 1, 1 + %res = insertvalue {{}, {{}, i32, {}}, [1 x i32]} %restmp, i32 %second, 2, 0 + ret {{}, {{}, i32, {}}, [1 x i32]} %res +} + +define i32 @structure_is_unimportant() { +; CHECK-LABEL: structure_is_unimportant +; CHECK: jmp + %val = tail call {i32, {i32, i32}} @give_i32_i32_i32() + + %res = extractvalue {i32, {i32, i32}} %val, 0 + ret i32 %res +} diff --git a/test/CodeGen/X86/tail-call-legality.ll b/test/CodeGen/X86/tail-call-legality.ll new file mode 100644 index 0000000000..119610430b --- /dev/null +++ b/test/CodeGen/X86/tail-call-legality.ll @@ -0,0 +1,32 @@ +; RUN: llc -march=x86 -o - < %s | FileCheck %s + +; This used to be classified as a tail call because of a mismatch in the +; arguments seen by Analysis.cpp and ISelLowering. As seen by ISelLowering, they +; both return {i32, i32, i32} (since i64 is illegal) which is fine for a tail +; call. + +; As seen by Analysis.cpp: i64 -> i32 is a valid trunc, second i32 passes +; straight through and the third is undef, also OK for a tail call. + +; Analysis.cpp was wrong. + +; FIXME: in principle we *could* support some tail calls involving truncations +; of illegal types: a single "trunc i64 %whatever to i32" is probably valid +; because of how the extra registers are laid out. + +declare {i64, i32} @test() + +define {i32, i32, i32} @test_pair_notail(i64 %in) { +; CHECK-LABEL: test_pair_notail +; CHECK-NOT: jmp + + %whole = tail call {i64, i32} @test() + %first = extractvalue {i64, i32} %whole, 0 + %first.trunc = trunc i64 %first to i32 + + %second = extractvalue {i64, i32} %whole, 1 + + %tmp = insertvalue {i32, i32, i32} undef, i32 %first.trunc, 0 + %res = insertvalue {i32, i32, i32} %tmp, i32 %second, 1 + ret {i32, i32, i32} %res +} |