1# RUN: llc -mtriple=wasm32-unknown-unknown -exception-model=wasm -run-pass wasm-cfg-stackify %s -o - | FileCheck %s 2 3--- | 4 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 5 target triple = "wasm32-unknown-unknown" 6 7 @__wasm_lpad_context = external global { i32, i8*, i32 } 8 9 declare void @may_throw() 10 ; Function Attrs: nounwind 11 declare void @dont_throw() #0 12 declare i8* @__cxa_begin_catch(i8*) 13 declare void @__cxa_end_catch() 14 declare void @__cxa_rethrow() 15 ; Function Attrs: nounwind 16 declare i32 @__gxx_wasm_personality_v0(...) 17 declare i32 @_Unwind_CallPersonality(i8*) #0 18 19 define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 20 unreachable 21 } 22 define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 23 unreachable 24 } 25 define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 26 unreachable 27 } 28 define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 29 unreachable 30 } 31 32 attributes #0 = { nounwind } 33 34--- 35# Simplest try-catch 36# try { 37# may_throw(); 38# } catch (...) { 39# } 40name: test0 41# CHECK-LABEL: name: test0 42liveins: 43 - { reg: '$arguments', reg: '$value_stack' } 44body: | 45 bb.0: 46 successors: %bb.2, %bb.1 47 48 CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64 49 BR %bb.2, implicit-def $arguments 50 ; CHECK-LABEL: bb.0: 51 ; CHECK: TRY 52 ; CHECK-NEXT: CALL_VOID @may_throw 53 54 bb.1 (landing-pad): 55 ; predecessors: %bb.0 56 successors: %bb.2 57 58 %2:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 59 %3:i32 = CALL_I32 @__cxa_begin_catch, %2:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack 60 DROP_I32 killed %3:i32, implicit-def $arguments 61 CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64 62 63 bb.2: 64 ; predecessors: %bb.0, %bb.1 65 66 RETURN_VOID implicit-def dead $arguments 67 ; CHECK-LABEL: bb.2: 68 ; CHECK-NEXT: END_TRY 69 ; CHECK: RETURN_VOID 70... 71--- 72 73# Nested try-catch inside another catch 74# try { 75# may_throw(); 76# } catch (int n) { 77# try { 78# may_throw(); 79# } catch (int n) { 80# } 81# } 82name: test1 83# CHECK-LABEL: name: test1 84liveins: 85 - { reg: '$arguments', reg: '$value_stack' } 86body: | 87 bb.0: 88 successors: %bb.9, %bb.1 89 90 CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64 91 BR %bb.9, implicit-def $arguments 92 ; CHECK-LABEL: bb.0: 93 ; CHECK: TRY 94 ; CHECK-NEXT: CALL_VOID @may_throw 95 96 bb.1 (landing-pad): 97 ; predecessors: %bb.0 98 successors: %bb.2, %bb.7 99 100 %30:i32 = CATCH_I32 0, implicit-def dead $arguments 101 SET_LOCAL_I32 0, %30:i32, implicit-def $arguments 102 %16:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 103 %27:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 104 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)`) 105 %26:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 106 %25:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 107 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)`) 108 %32:i32 = GET_LOCAL_I32 0, implicit-def $arguments 109 %31:i32 = CALL_I32 @_Unwind_CallPersonality, %32:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 110 DROP_I32 killed %31:i32, implicit-def $arguments 111 %24:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 112 %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)`) 113 %18:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 114 %19:i32 = NE_I32 %17:i32, %18:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 115 BR_IF %bb.7, %19:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack 116 117 bb.2: 118 ; predecessors: %bb.1 119 successors: %bb.8, %bb.3, %bb.6 120 121 %34:i32 = GET_LOCAL_I32 0, implicit-def $arguments 122 %33:i32 = CALL_I32 @__cxa_begin_catch, %34:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 123 DROP_I32 killed %33:i32, implicit-def $arguments 124 CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64 125 BR %bb.8, implicit-def $arguments 126 ; CHECK-LABEL: bb.2: 127 ; CHECK: DROP_I32 128 ; CHECK-NEXT: TRY 129 ; CHECK-NEXT: TRY 130 ; CHECK-NEXT: CALL_VOID @may_throw 131 132 bb.3 (landing-pad): 133 ; predecessors: %bb.2 134 successors: %bb.4, %bb.5 135 136 %35:i32 = CATCH_I32 0, implicit-def dead $arguments 137 SET_LOCAL_I32 0, %35:i32, implicit-def $arguments 138 %21:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 139 %20:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 140 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)`) 141 %37:i32 = GET_LOCAL_I32 0, implicit-def $arguments 142 %36:i32 = CALL_I32 @_Unwind_CallPersonality, %37:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 143 DROP_I32 killed %36:i32, implicit-def $arguments 144 %29:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 145 %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)`) 146 %28:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 147 %23:i32 = NE_I32 %22:i32, %28:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 148 BR_IF %bb.5, %23:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack 149 150 bb.4: 151 ; predecessors: %bb.3 152 successors: %bb.8 153 154 %39:i32 = GET_LOCAL_I32 0, implicit-def $arguments 155 %38:i32 = CALL_I32 @__cxa_begin_catch, %39:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 156 DROP_I32 killed %38:i32, implicit-def $arguments 157 CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64 158 BR %bb.8, implicit-def $arguments 159 160 bb.5: 161 ; predecessors: %bb.3 162 successors: %bb.6 163 164 CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64 165 RETHROW %bb.6, implicit-def $arguments 166 167 bb.6 (landing-pad): 168 ; predecessors: %bb.2, %bb.5 169 170 CATCH_ALL implicit-def $arguments 171 CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64 172 RETHROW_TO_CALLER implicit-def $arguments 173 ; CHECK-LABEL: bb.6 (landing-pad): 174 ; CHECK-NEXT: END_TRY 175 176 bb.7: 177 ; predecessors: %bb.1 178 179 CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64 180 RETHROW_TO_CALLER implicit-def $arguments 181 ; CHECK-LABEL: bb.7: 182 ; CHECK-NEXT: END_TRY 183 ; CHECK: RETHROW 0 184 185 bb.8: 186 ; predecessors: %bb.2, %bb.4 187 successors: %bb.9 188 189 CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64 190 191 bb.9: 192 ; predecessors: %bb.0, %bb.8 193 194 RETURN_VOID implicit-def dead $arguments 195 ; CHECK-LABEL: bb.9: 196 ; CHECK-NEXT: END_TRY 197... 198--- 199 200# A loop within a try. 201# try { 202# for (int i = 0; i < n; ++i) 203# may_throw(); 204# } catch (...) { 205# } 206name: test2 207# CHECK-LABEL: name: test2 208liveins: 209 - { reg: '$arguments', reg: '$value_stack' } 210body: | 211 bb.0: 212 successors: %bb.1, %bb.4 213 214 %18:i32 = CONST_I32 0, implicit-def dead $arguments 215 SET_LOCAL_I32 1, %18:i32, implicit-def $arguments 216 %14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 217 %19:i32 = GET_LOCAL_I32 0, implicit-def $arguments 218 %9:i32 = GE_S_I32 %14:i32, %19:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 219 BR_IF %bb.4, %9:i32, implicit-def $arguments 220 221 bb.1: 222 ; predecessors: %bb.0, %bb.3 223 successors: %bb.3, %bb.2 224 225 CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64 226 BR %bb.3, implicit-def $arguments 227 ; CHECK-LABEL: bb.1: 228 ; CHECK: LOOP 229 ; CHECK: TRY 230 ; CHECK-NEXT: CALL_VOID @may_throw 231 232 bb.2 (landing-pad): 233 ; predecessors: %bb.1 234 successors: %bb.4 235 236 %11:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 237 %22:i32 = CALL_I32 @__cxa_begin_catch, %11:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack 238 DROP_I32 killed %22:i32, implicit-def $arguments 239 CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64 240 BR %bb.4, implicit-def $arguments 241 242 bb.3: 243 ; predecessors: %bb.1 244 successors: %bb.1, %bb.4 245 246 %20:i32 = GET_LOCAL_I32 1, implicit-def $arguments 247 %17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 248 %16:i32 = ADD_I32 %20:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 249 %15:i32 = TEE_LOCAL_I32 1, %16:i32, implicit-def $arguments 250 %21:i32 = GET_LOCAL_I32 0, implicit-def $arguments 251 %10:i32 = GE_S_I32 %15:i32, %21:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 252 BR_UNLESS %bb.1, %10:i32, implicit-def $arguments 253 ; CHECK-LABEL: bb.3: 254 ; CHECK: END_TRY 255 256 bb.4: 257 ; predecessors: %bb.2, %bb.0, %bb.3 258 259 RETURN_VOID implicit-def dead $arguments 260... 261--- 262 263# A loop within a catch 264# try { 265# may_throw(); 266# } catch (...) { 267# for (int i = 0; i < n; ++i) 268# dont_throw(); 269# } 270name: test3 271# CHECK-LABEL: name: test3 272liveins: 273 - { reg: '$arguments', reg: '$value_stack' } 274body: | 275 bb.0: 276 successors: %bb.4, %bb.1 277 278 CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64 279 BR %bb.4, implicit-def $arguments 280 ; CHECK-LABEL: bb.0: 281 ; CHECK: TRY 282 ; CHECK-NEXT: CALL_VOID @may_throw 283 284 bb.1 (landing-pad): 285 ; predecessors: %bb.0 286 successors: %bb.2, %bb.3 287 288 %9:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 289 %18:i32 = CALL_I32 @__cxa_begin_catch, %9:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack 290 DROP_I32 killed %18:i32, implicit-def $arguments 291 %19:i32 = CONST_I32 0, implicit-def dead $arguments 292 SET_LOCAL_I32 1, %19:i32, implicit-def $arguments 293 %14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 294 %20:i32 = GET_LOCAL_I32 0, implicit-def $arguments 295 %10:i32 = GE_S_I32 %14:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 296 BR_IF %bb.3, %10:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack 297 298 bb.2: 299 ; predecessors: %bb.1, %bb.2 300 successors: %bb.2, %bb.3 301 302 CALL_VOID @dont_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64 303 %21:i32 = GET_LOCAL_I32 1, implicit-def $arguments 304 %17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 305 %16:i32 = ADD_I32 %21:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 306 %15:i32 = TEE_LOCAL_I32 1, %16:i32, implicit-def $arguments 307 %22:i32 = GET_LOCAL_I32 0, implicit-def $arguments 308 %11:i32 = GE_S_I32 %15:i32, %22:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack 309 BR_UNLESS %bb.2, %11:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack 310 311 bb.3: 312 ; predecessors: %bb.1, %bb.2 313 successors: %bb.4 314 315 CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64 316 317 bb.4: 318 ; predecessors: %bb.0, %bb.3 319 320 RETURN_VOID implicit-def dead $arguments 321 ; CHECK-LABEL: bb.4: 322 ; CHECK: END_TRY 323