brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.1 KiB · f243f37 Raw
429 lines · cpp
1// REQUIRES: webassembly-registered-target2 3// RUN: %clang -E -dM %s -target wasm32-unknown-unknown -fwasm-exceptions | FileCheck %s -check-prefix PREPROCESSOR4// PREPROCESSOR: #define __WASM_EXCEPTIONS__ 15 6// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s7// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s8 9// Test code generation for Wasm EH using WebAssembly EH proposal.10// (https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md)11 12void may_throw();13void dont_throw() noexcept;14 15struct Cleanup {16  ~Cleanup() { dont_throw(); }17};18 19// Multiple catch clauses w/o catch-all20void multiple_catches_wo_catch_all() {21  try {22    may_throw();23  } catch (int) {24    dont_throw();25  } catch (double) {26    dont_throw();27  }28}29 30// CHECK-LABEL: define void @_Z29multiple_catches_wo_catch_allv() {{.*}} personality ptr @__gxx_wasm_personality_v031 32// CHECK:   %[[INT_ALLOCA:.*]] = alloca i3233// CHECK:   invoke void @_Z9may_throwv()34// CHECK-NEXT:           to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]35 36// CHECK: [[CATCHDISPATCH_BB]]:37// CHECK-NEXT:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller38 39// CHECK: [[CATCHSTART_BB]]:40// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi, ptr @_ZTId]41// CHECK-NEXT:   %[[EXN:.*]] = call ptr @llvm.wasm.get.exception(token %[[CATCHPAD]])42// CHECK-NEXT:   store ptr %[[EXN]], ptr %exn.slot43// CHECK-NEXT:   %[[SELECTOR:.*]] = call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]])44// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) #745// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]46// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]47 48// CHECK: [[CATCH_INT_BB]]:49// CHECK-NEXT:   %[[EXN:.*]] = load ptr, ptr %exn.slot50// CHECK-NEXT:   %[[ADDR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]51// CHECK-NEXT:   %[[INT_VAL:.*]] = load i32, ptr %[[ADDR]]52// CHECK-NEXT:   store i32 %[[INT_VAL]], ptr %[[INT_ALLOCA]]53// CHECK-NEXT:   call void @_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]54// CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]55// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]]56 57// CHECK: [[CATCHRET_DEST_BB0]]:58// CHECK-NEXT:   br label %[[TRY_CONT_BB:.*]]59 60// CHECK: [[CATCH_FALLTHROUGH_BB]]61// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTId) #762// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]63// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]64 65// CHECK: [[CATCH_FLOAT_BB]]:66// CHECK:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]67 68// CHECK: [[CATCHRET_DEST_BB1]]:69// CHECK-NEXT:   br label %[[TRY_CONT_BB]]70 71// CHECK: [[RETHROW_BB]]:72// CHECK-NEXT:   call void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]73// CHECK-NEXT:   unreachable74 75// Single catch-all76void single_catch_all() {77  try {78    may_throw();79  } catch (...) {80    dont_throw();81  }82}83 84// CATCH-LABEL: @_Z16single_catch_allv()85 86// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller87 88// CHECK: [[CATCHSTART_BB]]:89// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr null]90// CHECK:   br label %[[CATCH_ALL_BB:.*]]91 92// CHECK: [[CATCH_ALL_BB]]:93// CHECK:   catchret from %[[CATCHPAD]] to label94 95// Multiple catch clauses w/ catch-all96void multiple_catches_w_catch_all() {97  try {98    may_throw();99  } catch (int) {100    dont_throw();101  } catch (...) {102    dont_throw();103  }104}105 106// CHECK-LABEL: @_Z28multiple_catches_w_catch_allv()107 108// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller109 110// CHECK: [[CATCHSTART_BB]]:111// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi, ptr null]112// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]113 114// CHECK: [[CATCH_INT_BB]]:115// CHECK:   catchret from %[[CATCHPAD]] to label116 117// CHECK: [[CATCH_ALL_BB]]:118// CHECK:   catchret from %[[CATCHPAD]] to label119 120// Cleanup121void cleanup() {122  Cleanup c;123  may_throw();124}125 126// CHECK-LABEL: @_Z7cleanupv()127 128// CHECK:   invoke void @_Z9may_throwv()129// CHECK-NEXT:           to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]130 131// CHECK: [[EHCLEANUP_BB]]:132// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within none []133// CHECK-NEXT:   call noundef ptr @_ZN7CleanupD1Ev(ptr {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]134// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller135 136// Possibly throwing function call within a catch137void catch_int() {138  try {139    may_throw();140  } catch (int) {141    may_throw();142  }143}144 145// CHECK-LABEL: @_Z9catch_intv()146 147// CHECK:   %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller148 149// CHECK: [[CATCHSTART_BB]]:150// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi]151 152// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]153// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]154 155// CHECK: [[INVOKE_CONT_BB]]:156// CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]157// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label158 159// CHECK: [[EHCLEANUP_BB]]:160// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] []161// CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]162// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller163 164// Possibly throwing function call within a catch-all165void catch_all() {166  try {167    may_throw();168  } catch (...) {169    may_throw();170  }171}172 173// CHECK-LABEL: @_Z9catch_allv()174 175// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller176 177// CHECK: [[CATCHSTART_BB]]:178// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr null]179 180// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]181// CHECK-NEXT:           to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]182 183// CHECK: [[INVOKE_CONT_BB0]]:184// CHECK-NEXT:   call void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]185// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label186 187// CHECK: [[EHCLEANUP_BB]]:188// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] []189// CHECK-NEXT:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ]190// CHECK-NEXT:           to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]]191 192// CHECK: [[INVOKE_CONT_BB1]]:193// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind to caller194 195// CHECK: [[TERMINATE_BB]]:196// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []197// CHECK-NEXT:   call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]198// CHECK-NEXT:   unreachable199 200// Try-catch with cleanups201void try_catch_w_cleanups() {202  Cleanup c1;203  try {204    Cleanup c2;205    may_throw();206  } catch (int) {207    Cleanup c3;208    may_throw();209  }210}211 212// CHECK-LABEL: @_Z20try_catch_w_cleanupsv()213// CHECK:   invoke void @_Z9may_throwv()214// CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]215 216// CHECK: [[EHCLEANUP_BB0]]:217// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []218// CHECK-NEXT:   call noundef ptr @_ZN7CleanupD1Ev(ptr {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]219// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]220 221// CHECK: [[CATCH_DISPATCH_BB]]:222// CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]223 224// CHECK: [[CATCHSTART_BB]]:225// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi]226// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]227 228// CHECK: [[CATCH_INT_BB]]:229// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]230// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]231 232// CHECK: [[INVOKE_CONT_BB]]:233// CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}234 235// CHECK: [[RETHROW_BB]]:236// CHECK-NEXT:   invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]237// CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]238 239// CHECK: [[EHCLEANUP_BB2]]:240// CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []241// CHECK-NEXT:   call noundef ptr @_ZN7CleanupD1Ev(ptr {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]242// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]243 244// CHECK: [[EHCLEANUP_BB3]]:245// CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []246// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]247 248// CHECK: [[EHCLEANUP_BB1]]:249// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []250// CHECK-NEXT:   call noundef ptr @_ZN7CleanupD1Ev(ptr {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]251// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller252 253// CHECK: [[UNREACHABLE_BB]]:254// CHECK-NEXT:   unreachable255 256// Nested try-catches within a try with cleanups257void nested_try_catches_with_cleanups() {258  Cleanup c1;259  may_throw();260  try {261    Cleanup c2;262    may_throw();263    try {264      Cleanup c3;265      may_throw();266    } catch (int) {267      may_throw();268    } catch (double) {269      may_throw();270    }271  } catch (int) {272    may_throw();273  } catch (...) {274    may_throw();275  }276}277 278// CHECK-LABEL: @_Z32nested_try_catches_with_cleanupsv()279// CHECK:   invoke void @_Z9may_throwv()280 281// CHECK:   invoke void @_Z9may_throwv()282 283// CHECK:   invoke void @_Z9may_throwv()284 285// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []286// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label287 288// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none289 290// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [ptr @_ZTIi, ptr @_ZTId]291 292// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]293 294// CHECK:   catchret from %[[CATCHPAD0]] to label295 296// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]297 298// CHECK:   catchret from %[[CATCHPAD0]] to label299 300// CHECK:   invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]301 302// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []303// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label304 305// CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []306// CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label307 308// CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []309// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label310 311// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none312 313// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [ptr @_ZTIi, ptr null]314 315// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]316 317// CHECK:   catchret from %[[CATCHPAD1]] to label318 319// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]320 321// CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]322 323// CHECK:   catchret from %[[CATCHPAD1]] to label324 325// CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []326// CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]327 328// CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label329 330// CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []331// CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label332 333// CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []334// CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller335 336// CHECK:   unreachable337 338// CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []339// CHECK:   call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]340// CHECK:   unreachable341 342// Nested try-catches within a catch343void nested_try_catch_within_catch() {344  try {345    may_throw();346  } catch (int) {347    try {348      may_throw();349    } catch (int) {350      may_throw();351    }352  }353}354 355// CHECK-LABEL: @_Z29nested_try_catch_within_catchv()356// CHECK:   invoke void @_Z9may_throwv()357 358// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none359 360// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [ptr @_ZTIi]361 362// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]363 364// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]365 366// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [ptr @_ZTIi]367 368// CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]369 370// CHECK:   catchret from %[[CATCHPAD1]] to label371 372// CHECK:   invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]373 374// CHECK:   catchret from %[[CATCHPAD0]] to label375 376// CHECK:   call void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]377// CHECK:   unreachable378 379// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []380// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label381 382// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []383// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller384 385// CHECK:   unreachable386 387void noexcept_throw() noexcept {388  throw 3;389}390 391// CATCH-LABEL: define void @_Z14noexcept_throwv()392// CHECK: %{{.*}} = cleanuppad within none []393// CHECK-NEXT:  call void @_ZSt9terminatev()394 395 396// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-DEFAULT397// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -Wwasm-exception-spec -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-ON398// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -Wno-wasm-exception-spec -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-OFF399// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=EM-EH-WARNING400 401// Wasm EH ignores dynamic exception specifications with types at the moment.402// This is controlled by -Wwasm-exception-spec, which is on by default. This403// warning can be suppressed with -Wno-wasm-exception-spec. Checks if a warning404// message is correctly printed or not printed depending on the options.405void exception_spec_warning() throw(int) {406}407// WARNING-DEFAULT: warning: dynamic exception specifications with types are currently ignored in wasm408// WARNING-ON: warning: dynamic exception specifications with types are currently ignored in wasm409// WARNING-OFF-NOT: warning: dynamic exception specifications with types are currently ignored in wasm410// EM-EH-WARNING: warning: dynamic exception specifications with types are currently ignored in wasm411 412// Wasm currently treats 'throw()' in the same way as 'noexcept'. Check if the413// same warning message is printed as if when a 'noexcept' function throws.414void exception_spec_throw_empty() throw() {415  throw 3;416}417// WARNING-DEFAULT: warning: 'exception_spec_throw_empty' has a non-throwing exception specification but can still throw418// WARNING-DEFAULT: function declared non-throwing here419 420// Here we only check if the command enables wasm exception handling in the421// backend so that exception handling instructions can be generated in .s file.422 423// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -S -o - -std=c++11 | FileCheck %s --check-prefix=ASSEMBLY424 425// ASSEMBLY: try426// ASSEMBLY: catch427// ASSEMBLY: rethrow428// ASSEMBLY: end_try429