342 lines · c
1// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s2 3void g(void);4 5//////////////////////////////////////////////////////////////////////////////6// __leave with __except7 8// Nothing in the __try block can trap, so __try.cont isn't created.9int __leave_with___except_simple(void) {10 int myres = 0;11 __try {12 myres = 15;13 __leave;14 myres = 23;15 } __except (1) {16 return 0;17 }18 return 1;19}20// CHECK-LABEL: define dso_local i32 @__leave_with___except_simple()21// CHECK: store i32 15, ptr %myres22// CHECK-NEXT: br label %[[tryleave:[^ ]*]]23// CHECK-NOT: store i32 2324// CHECK: [[tryleave]]25// CHECK-NEXT: ret i32 126 27 28// The "normal" case.29int __leave_with___except(void) {30 int myres = 0;31 __try {32 g();33 __leave;34 myres = 23;35 } __except (1) {36 return 0;37 }38 return 1;39}40// CHECK-LABEL: define dso_local i32 @__leave_with___except()41// CHECK: invoke void @g()42// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}}43// For __excepts, instead of an explicit __try.__leave label, we could use44// use invoke.cont as __leave jump target instead. However, not doing this45// keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will46// simplify this anyways.47// CHECK: [[cont]]48// CHECK-NEXT: br label %[[tryleave:[^ ]*]]49// CHECK-NOT: store i32 2350// CHECK: [[tryleave]]51// CHECK-NEXT: br label %52 53 54//////////////////////////////////////////////////////////////////////////////55// __leave with __finally56 57void abort(void) __attribute__((noreturn));58 59// Nothing in the __try block can trap, so __finally.cont and friends aren't60// created.61int __leave_with___finally_simple(void) {62 int myres = 0;63 __try {64 myres = 15;65 __leave;66 myres = 23;67 } __finally {68 return 0;69 }70 return 1;71}72// CHECK-LABEL: define dso_local i32 @__leave_with___finally_simple()73// CHECK: store i32 15, ptr %myres74// CHECK-NEXT: br label %[[tryleave:[^ ]*]]75// CHECK-NOT: store i32 2376// CHECK: [[tryleave]]77// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()78// CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally_simple@@"(i8 noundef 0, ptr noundef %[[fp]])79 80// __finally block doesn't return, __finally.cont doesn't exist.81int __leave_with___finally_noreturn(void) {82 int myres = 0;83 __try {84 myres = 15;85 __leave;86 myres = 23;87 } __finally {88 abort();89 }90 return 1;91}92// CHECK-LABEL: define dso_local i32 @__leave_with___finally_noreturn()93// CHECK: store i32 15, ptr %myres94// CHECK-NEXT: br label %[[tryleave:[^ ]*]]95// CHECK-NOT: store i32 2396// CHECK: [[tryleave]]97// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()98// CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally_noreturn@@"(i8 noundef 0, ptr noundef %[[fp]])99 100// The "normal" case.101int __leave_with___finally(void) {102 int myres = 0;103 __try {104 g();105 __leave;106 myres = 23;107 } __finally {108 return 0;109 }110 return 1;111}112// CHECK-LABEL: define dso_local i32 @__leave_with___finally()113// CHECK: invoke void @g()114// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}}115// For __finally, there needs to be an explicit __try.__leave, because116// abnormal.termination.slot needs to be set there.117// CHECK: [[cont]]118// CHECK-NEXT: br label %[[tryleave:[^ ]*]]119// CHECK-NOT: store i32 23120// CHECK: [[tryleave]]121// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()122// CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally@@"(i8 noundef 0, ptr noundef %[[fp]])123 124 125//////////////////////////////////////////////////////////////////////////////126// Mixed, nested cases.127 128int nested___except___finally(void) {129 int myres = 0;130 __try {131 __try {132 g();133 } __finally {134 g();135 __leave; // Refers to the outer __try, not the __finally!136 myres = 23;137 return 0;138 }139 140 myres = 51;141 } __except (1) {142 }143 return 1;144}145// CHECK-LABEL: define dso_local i32 @nested___except___finally()146 147// CHECK-LABEL: invoke void @g()148// CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]]149 150// CHECK: [[g1_cont1]]151// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()152// CHECK-NEXT: invoke void @"?fin$0@0@nested___except___finally@@"(i8 noundef 0, ptr noundef %[[fp]])153// CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]]154 155// CHECK: [[fin_cont]]156// CHECK: store i32 51, ptr %157// CHECK-NEXT: br label %[[trycont:[^ ]*]]158 159// CHECK: [[g1_lpad]]160// CHECK-NEXT: cleanuppad161// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()162// CHECK-NEXT: invoke void @"?fin$0@0@nested___except___finally@@"(i8 noundef 1, ptr noundef %[[fp]])163// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]164// CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]]165 166// CHECK: [[g2_lpad]]167// CHECK: catchpad {{.*}} [ptr null]168// CHECK: catchret169// CHECK: br label %[[trycont]]170 171// CHECK: [[trycont]]172// CHECK-NEXT: ret i32 1173 174// CHECK-LABEL: define internal void @"?fin$0@0@nested___except___finally@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer)175// CHECK: call void @g()176// CHECK: unreachable177 178int nested___except___except(void) {179 int myres = 0;180 __try {181 __try {182 g();183 myres = 16;184 } __except (1) {185 g();186 __leave; // Refers to the outer __try, not the __except we're in!187 myres = 23;188 return 0;189 }190 191 myres = 51;192 } __except (1) {193 }194 return 1;195}196// The order of basic blocks in the below doesn't matter.197// CHECK-LABEL: define dso_local i32 @nested___except___except()198 199// CHECK-LABEL: invoke void @g()200// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]201 202// CHECK: [[g1_lpad]]203// CHECK: catchpad {{.*}} [ptr null]204// CHECK: catchret {{.*}} to label %[[except:[^ ]*]]205// CHECK: [[except]]206// CHECK: invoke void @g()207// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]208 209// CHECK: [[g2_lpad]]210// CHECK: catchpad {{.*}} [ptr null]211// CHECK: catchret212// CHECK: br label %[[trycont4:[^ ]*]]213 214// CHECK: [[trycont4]]215// CHECK-NEXT: ret i32 1216 217// CHECK: [[g2_cont]]218// CHECK-NEXT: br label %[[tryleave:[^ ]*]]219// CHECK-NOT: store i32 23220 221// CHECK: [[g1_cont]]222// CHECK: store i32 16, ptr %myres223// CHECK-NEXT: br label %[[trycont:[^ ]*]]224 225// CHECK: [[trycont]]226// CHECK-NEXT: store i32 51, ptr %myres227// CHECK-NEXT: br label %[[tryleave]]228 229// CHECK: [[tryleave]]230// CHECK-NEXT: br label %[[trycont4]]231 232int nested___finally___except(void) {233 int myres = 0;234 __try {235 __try {236 g();237 } __except (1) {238 g();239 __leave; // Refers to the outer __try, not the __except!240 myres = 23;241 return 0;242 }243 244 myres = 51;245 } __finally {246 }247 return 1;248}249// The order of basic blocks in the below doesn't matter.250// CHECK-LABEL: define dso_local i32 @nested___finally___except()251 252// CHECK-LABEL: invoke void @g()253// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]254 255// CHECK: [[g1_lpad]]256// CHECK: catchpad257// CHECK: catchret258// CHECK: invoke void @g()259// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]260 261// CHECK: [[g2_cont]]262// CHECK: br label %[[tryleave:[^ ]*]]263// CHECK-NOT: 23264 265// CHECK: [[g1_cont]]266// CHECK-NEXT: br label %[[trycont:[^ ]*]]267 268// CHECK: [[trycont]]269// CHECK: store i32 51, ptr %270// CHECK-NEXT: br label %[[tryleave]]271 272// CHECK: [[tryleave]]273// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()274// CHECK-NEXT: call void @"?fin$0@0@nested___finally___except@@"(i8 noundef 0, ptr noundef %[[fp]])275// CHECK-NEXT: ret i32 1276 277// CHECK: [[g2_lpad]]278// CHECK: cleanuppad279// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()280// CHECK-NEXT: call void @"?fin$0@0@nested___finally___except@@"(i8 noundef 1, ptr noundef %[[fp]])281// CHECK: cleanupret {{.*}} unwind to caller282 283// CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___except@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer)284// CHECK: ret void285 286int nested___finally___finally(void) {287 int myres = 0;288 __try {289 __try {290 g();291 myres = 16;292 } __finally {293 g();294 __leave; // Refers to the outer __try, not the __finally we're in!295 myres = 23;296 return 0;297 }298 299 myres = 51;300 } __finally {301 }302 return 1;303}304// The order of basic blocks in the below doesn't matter.305// CHECK-LABEL: define dso_local i32 @nested___finally___finally()306 307// CHECK: invoke void @g()308// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]309 310// CHECK: [[g1_cont]]311// CHECK: store i32 16, ptr %[[myres:[^ ]*]],312// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()313// CHECK-NEXT: invoke void @"?fin$1@0@nested___finally___finally@@"(i8 noundef 0, ptr noundef %[[fp]])314// CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]]315 316// CHECK: [[finally_cont]]317// CHECK: store i32 51, ptr %[[myres]]318// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()319// CHECK-NEXT: call void @"?fin$0@0@nested___finally___finally@@"(i8 noundef 0, ptr noundef %[[fp]])320// CHECK-NEXT: ret i32 1321 322// CHECK: [[g1_lpad]]323// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none []324// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()325// CHECK-NEXT: invoke void @"?fin$1@0@nested___finally___finally@@"(i8 noundef 1, ptr noundef %[[fp]])326// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]327// CHECK: [[finally_cont2]]328// CHECK: cleanupret from %[[padtoken]] unwind label %[[g2_lpad]]329 330// CHECK: [[g2_lpad]]331// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none []332// CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()333// CHECK-NEXT: call void @"?fin$0@0@nested___finally___finally@@"(i8 noundef 1, ptr noundef %[[fp]])334// CHECK: cleanupret from %[[padtoken]] unwind to caller335 336// CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer)337// CHECK: ret void338 339// CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer)340// CHECK: call void @g()341// CHECK: unreachable342