mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-22 04:22:57 +02:00
0b69bb0689
Summary: Currently when assigning depths 'rethrow' does not take the whole control flow stack into accounts but only considers EH pad stacks. When assigning depth immmediates to rethrows, in normal cases it is done correctly but when a rethrow instruction throws up to a caller, i.e., we convert a pseudo RETHROW_TO_CALLER instruction to a rethrow, it mistakenly compute the whole stack depth. Reviewers: dschuff Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D53619 llvm-svn: 345223
323 lines
13 KiB
YAML
323 lines
13 KiB
YAML
# RUN: llc -mtriple=wasm32-unknown-unknown -exception-model=wasm -run-pass wasm-cfg-stackify %s -o - | FileCheck %s
|
|
|
|
--- |
|
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
|
target triple = "wasm32-unknown-unknown"
|
|
|
|
@__wasm_lpad_context = external global { i32, i8*, i32 }
|
|
|
|
declare void @may_throw()
|
|
; Function Attrs: nounwind
|
|
declare void @dont_throw() #0
|
|
declare i8* @__cxa_begin_catch(i8*)
|
|
declare void @__cxa_end_catch()
|
|
declare void @__cxa_rethrow()
|
|
; Function Attrs: nounwind
|
|
declare i32 @__gxx_wasm_personality_v0(...)
|
|
declare i32 @_Unwind_CallPersonality(i8*) #0
|
|
|
|
define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
|
unreachable
|
|
}
|
|
define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
|
unreachable
|
|
}
|
|
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
|
unreachable
|
|
}
|
|
define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
|
unreachable
|
|
}
|
|
|
|
attributes #0 = { nounwind }
|
|
|
|
---
|
|
# Simplest try-catch
|
|
# try {
|
|
# may_throw();
|
|
# } catch (...) {
|
|
# }
|
|
name: test0
|
|
# CHECK-LABEL: name: test0
|
|
liveins:
|
|
- { reg: '$arguments', reg: '$value_stack' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.2, %bb.1
|
|
|
|
CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.2, implicit-def $arguments
|
|
; CHECK-LABEL: bb.0:
|
|
; CHECK: TRY
|
|
; CHECK-NEXT: CALL_VOID @may_throw
|
|
|
|
bb.1 (landing-pad):
|
|
; predecessors: %bb.0
|
|
successors: %bb.2
|
|
|
|
%2:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%3:i32 = CALL_I32 @__cxa_begin_catch, %2:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
|
|
DROP_I32 killed %3:i32, implicit-def $arguments
|
|
CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
|
|
bb.2:
|
|
; predecessors: %bb.0, %bb.1
|
|
|
|
RETURN_VOID implicit-def dead $arguments
|
|
; CHECK-LABEL: bb.2:
|
|
; CHECK-NEXT: END_TRY
|
|
; CHECK: RETURN_VOID
|
|
...
|
|
---
|
|
|
|
# Nested try-catch inside another catch
|
|
# try {
|
|
# may_throw();
|
|
# } catch (int n) {
|
|
# try {
|
|
# may_throw();
|
|
# } catch (int n) {
|
|
# }
|
|
# }
|
|
name: test1
|
|
# CHECK-LABEL: name: test1
|
|
liveins:
|
|
- { reg: '$arguments', reg: '$value_stack' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.9, %bb.1
|
|
|
|
CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.9, implicit-def $arguments
|
|
; CHECK-LABEL: bb.0:
|
|
; CHECK: TRY
|
|
; CHECK-NEXT: CALL_VOID @may_throw
|
|
|
|
bb.1 (landing-pad):
|
|
; predecessors: %bb.0
|
|
successors: %bb.2, %bb.7
|
|
|
|
%30:i32 = CATCH_I32 0, implicit-def dead $arguments
|
|
SET_LOCAL_I32 0, %30:i32, implicit-def $arguments
|
|
%16:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%27:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
STORE_I32 2, @__wasm_lpad_context + 4, %16:i32, %27:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i8** getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 1)`)
|
|
%26:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%25:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
STORE_I32 2, @__wasm_lpad_context, %26:i32, %25:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)`)
|
|
%32:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%31:i32 = CALL_I32 @_Unwind_CallPersonality, %32:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
DROP_I32 killed %31:i32, implicit-def $arguments
|
|
%24:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%17:i32 = LOAD_I32 2, @__wasm_lpad_context + 8, %24:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (dereferenceable load 4 from `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2)`)
|
|
%18:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%19:i32 = NE_I32 %17:i32, %18:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
BR_IF %bb.7, %19:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
|
|
|
|
bb.2:
|
|
; predecessors: %bb.1
|
|
successors: %bb.8, %bb.3, %bb.6
|
|
|
|
%34:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%33:i32 = CALL_I32 @__cxa_begin_catch, %34:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
DROP_I32 killed %33:i32, implicit-def $arguments
|
|
CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.8, implicit-def $arguments
|
|
; CHECK-LABEL: bb.2:
|
|
; CHECK: DROP_I32
|
|
; CHECK-NEXT: TRY
|
|
; CHECK-NEXT: TRY
|
|
; CHECK-NEXT: CALL_VOID @may_throw
|
|
|
|
bb.3 (landing-pad):
|
|
; predecessors: %bb.2
|
|
successors: %bb.4, %bb.5
|
|
|
|
%35:i32 = CATCH_I32 0, implicit-def dead $arguments
|
|
SET_LOCAL_I32 0, %35:i32, implicit-def $arguments
|
|
%21:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%20:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
STORE_I32 2, @__wasm_lpad_context, %21:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)`)
|
|
%37:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%36:i32 = CALL_I32 @_Unwind_CallPersonality, %37:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
DROP_I32 killed %36:i32, implicit-def $arguments
|
|
%29:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%22:i32 = LOAD_I32 2, @__wasm_lpad_context + 8, %29:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (dereferenceable load 4 from `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2)`)
|
|
%28:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%23:i32 = NE_I32 %22:i32, %28:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
BR_IF %bb.5, %23:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
|
|
|
|
bb.4:
|
|
; predecessors: %bb.3
|
|
successors: %bb.8
|
|
|
|
%39:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%38:i32 = CALL_I32 @__cxa_begin_catch, %39:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
DROP_I32 killed %38:i32, implicit-def $arguments
|
|
CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.8, implicit-def $arguments
|
|
|
|
bb.5:
|
|
; predecessors: %bb.3
|
|
successors: %bb.6
|
|
|
|
CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
RETHROW %bb.6, implicit-def $arguments
|
|
|
|
bb.6 (landing-pad):
|
|
; predecessors: %bb.2, %bb.5
|
|
|
|
CATCH_ALL implicit-def $arguments
|
|
CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
RETHROW_TO_CALLER implicit-def $arguments
|
|
; CHECK-LABEL: bb.6 (landing-pad):
|
|
; CHECK-NEXT: END_TRY
|
|
|
|
bb.7:
|
|
; predecessors: %bb.1
|
|
|
|
CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
RETHROW_TO_CALLER implicit-def $arguments
|
|
; CHECK-LABEL: bb.7:
|
|
; CHECK-NEXT: END_TRY
|
|
; CHECK: RETHROW 0
|
|
|
|
bb.8:
|
|
; predecessors: %bb.2, %bb.4
|
|
successors: %bb.9
|
|
|
|
CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
|
|
bb.9:
|
|
; predecessors: %bb.0, %bb.8
|
|
|
|
RETURN_VOID implicit-def dead $arguments
|
|
; CHECK-LABEL: bb.9:
|
|
; CHECK-NEXT: END_TRY
|
|
...
|
|
---
|
|
|
|
# A loop within a try.
|
|
# try {
|
|
# for (int i = 0; i < n; ++i)
|
|
# may_throw();
|
|
# } catch (...) {
|
|
# }
|
|
name: test2
|
|
# CHECK-LABEL: name: test2
|
|
liveins:
|
|
- { reg: '$arguments', reg: '$value_stack' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.4
|
|
|
|
%18:i32 = CONST_I32 0, implicit-def dead $arguments
|
|
SET_LOCAL_I32 1, %18:i32, implicit-def $arguments
|
|
%14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%19:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%9:i32 = GE_S_I32 %14:i32, %19:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
BR_IF %bb.4, %9:i32, implicit-def $arguments
|
|
|
|
bb.1:
|
|
; predecessors: %bb.0, %bb.3
|
|
successors: %bb.3, %bb.2
|
|
|
|
CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.3, implicit-def $arguments
|
|
; CHECK-LABEL: bb.1:
|
|
; CHECK: LOOP
|
|
; CHECK: TRY
|
|
; CHECK-NEXT: CALL_VOID @may_throw
|
|
|
|
bb.2 (landing-pad):
|
|
; predecessors: %bb.1
|
|
successors: %bb.4
|
|
|
|
%11:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%22:i32 = CALL_I32 @__cxa_begin_catch, %11:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
|
|
DROP_I32 killed %22:i32, implicit-def $arguments
|
|
CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.4, implicit-def $arguments
|
|
|
|
bb.3:
|
|
; predecessors: %bb.1
|
|
successors: %bb.1, %bb.4
|
|
|
|
%20:i32 = GET_LOCAL_I32 1, implicit-def $arguments
|
|
%17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%16:i32 = ADD_I32 %20:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%15:i32 = TEE_LOCAL_I32 1, %16:i32, implicit-def $arguments
|
|
%21:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%10:i32 = GE_S_I32 %15:i32, %21:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
BR_UNLESS %bb.1, %10:i32, implicit-def $arguments
|
|
; CHECK-LABEL: bb.3:
|
|
; CHECK: END_TRY
|
|
|
|
bb.4:
|
|
; predecessors: %bb.2, %bb.0, %bb.3
|
|
|
|
RETURN_VOID implicit-def dead $arguments
|
|
...
|
|
---
|
|
|
|
# A loop within a catch
|
|
# try {
|
|
# may_throw();
|
|
# } catch (...) {
|
|
# for (int i = 0; i < n; ++i)
|
|
# dont_throw();
|
|
# }
|
|
name: test3
|
|
# CHECK-LABEL: name: test3
|
|
liveins:
|
|
- { reg: '$arguments', reg: '$value_stack' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.4, %bb.1
|
|
|
|
CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
BR %bb.4, implicit-def $arguments
|
|
; CHECK-LABEL: bb.0:
|
|
; CHECK: TRY
|
|
; CHECK-NEXT: CALL_VOID @may_throw
|
|
|
|
bb.1 (landing-pad):
|
|
; predecessors: %bb.0
|
|
successors: %bb.2, %bb.3
|
|
|
|
%9:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%18:i32 = CALL_I32 @__cxa_begin_catch, %9:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
|
|
DROP_I32 killed %18:i32, implicit-def $arguments
|
|
%19:i32 = CONST_I32 0, implicit-def dead $arguments
|
|
SET_LOCAL_I32 1, %19:i32, implicit-def $arguments
|
|
%14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%20:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%10:i32 = GE_S_I32 %14:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
BR_IF %bb.3, %10:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
|
|
|
|
bb.2:
|
|
; predecessors: %bb.1, %bb.2
|
|
successors: %bb.2, %bb.3
|
|
|
|
CALL_VOID @dont_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
%21:i32 = GET_LOCAL_I32 1, implicit-def $arguments
|
|
%17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%16:i32 = ADD_I32 %21:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
%15:i32 = TEE_LOCAL_I32 1, %16:i32, implicit-def $arguments
|
|
%22:i32 = GET_LOCAL_I32 0, implicit-def $arguments
|
|
%11:i32 = GE_S_I32 %15:i32, %22:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
|
|
BR_UNLESS %bb.2, %11:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
|
|
|
|
bb.3:
|
|
; predecessors: %bb.1, %bb.2
|
|
successors: %bb.4
|
|
|
|
CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
|
|
|
|
bb.4:
|
|
; predecessors: %bb.0, %bb.3
|
|
|
|
RETURN_VOID implicit-def dead $arguments
|
|
; CHECK-LABEL: bb.4:
|
|
; CHECK: END_TRY
|