1 // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - \ 2 // RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64 3 // RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - \ 4 // RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86 5 // RUN: %clang_cc1 %s -triple aarch64-windows -fms-extensions -emit-llvm -o - \ 6 // RUN: | FileCheck %s --check-prefixes=CHECK,ARM64 7 // RUN: %clang_cc1 %s -triple i686-pc-windows-gnu -fms-extensions -emit-llvm -o - \ 8 // RUN: | FileCheck %s --check-prefix=X86-GNU 9 // RUN: %clang_cc1 %s -triple x86_64-pc-windows-gnu -fms-extensions -emit-llvm -o - \ 10 // RUN: | FileCheck %s --check-prefix=X64-GNU 11 12 void try_body(int numerator, int denominator, int *myres) { 13 *myres = numerator / denominator; 14 } 15 // CHECK-LABEL: define dso_local void @try_body(i32 noundef %numerator, i32 noundef %denominator, ptr noundef %myres) 16 // CHECK: sdiv i32 17 // CHECK: store i32 %{{.*}}, ptr 18 // CHECK: ret void 19 20 int safe_div(int numerator, int denominator, int *res) { 21 int myres = 0; 22 int success = 1; 23 __try { 24 try_body(numerator, denominator, &myres); 25 } __except (1) { 26 success = -42; 27 } 28 *res = myres; 29 return success; 30 } 31 32 // CHECK-LABEL: define dso_local i32 @safe_div(i32 noundef %numerator, i32 noundef %denominator, ptr noundef %res) 33 // X64-SAME: personality ptr @__C_specific_handler 34 // ARM64-SAME: personality ptr @__C_specific_handler 35 // X86-SAME: personality ptr @_except_handler3 36 // CHECK: invoke void @try_body(i32 noundef %{{.*}}, i32 noundef %{{.*}}, ptr noundef %{{.*}}) #[[NOINLINE:[0-9]+]] 37 // CHECK: to label %{{.*}} unwind label %[[catchpad:[^ ]*]] 38 // 39 // CHECK: [[catchpad]] 40 // X64: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [ptr null] 41 // ARM64: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [ptr null] 42 // X86: %[[padtoken:[^ ]*]] = catchpad within %{{[^ ]*}} [ptr @"?filt$0@0@safe_div@@"] 43 // CHECK-NEXT: catchret from %[[padtoken]] to label %[[except:[^ ]*]] 44 // 45 // CHECK: [[except]] 46 // CHECK: store i32 -42, ptr %[[success:[^ ]*]] 47 // 48 // CHECK: %[[res:[^ ]*]] = load i32, ptr %[[success]] 49 // CHECK: ret i32 %[[res]] 50 51 // 32-bit SEH needs this filter to save the exception code. 52 // 53 // X86-LABEL: define internal i32 @"?filt$0@0@safe_div@@"() 54 // X86: %[[ebp:[^ ]*]] = call ptr @llvm.frameaddress.p0(i32 1) 55 // X86: %[[fp:[^ ]*]] = call ptr @llvm.eh.recoverfp(ptr @safe_div, ptr %[[ebp]]) 56 // X86: call ptr @llvm.localrecover(ptr @safe_div, ptr %[[fp]], i32 0) 57 // X86: load ptr, ptr 58 // X86: load ptr, ptr 59 // X86: load i32, ptr 60 // X86: store i32 %{{.*}}, ptr 61 // X86: ret i32 1 62 63 // Mingw uses msvcrt, so it can also use _except_handler3. 64 // X86-GNU-LABEL: define dso_local i32 @safe_div(i32 noundef %numerator, i32 noundef %denominator, ptr noundef %res) 65 // X86-GNU-SAME: personality ptr @_except_handler3 66 // X64-GNU-LABEL: define dso_local i32 @safe_div(i32 noundef %numerator, i32 noundef %denominator, ptr noundef %res) 67 // X64-GNU-SAME: personality ptr @__C_specific_handler 68 69 void j(void); 70 71 int filter_expr_capture(void) { 72 int r = 42; 73 __try { 74 j(); 75 } __except(r = -1) { 76 r = 13; 77 } 78 return r; 79 } 80 81 // CHECK-LABEL: define dso_local i32 @filter_expr_capture() 82 // X64-SAME: personality ptr @__C_specific_handler 83 // ARM64-SAME: personality ptr @__C_specific_handler 84 // X86-SAME: personality ptr @_except_handler3 85 // X64: call void (...) @llvm.localescape(ptr %[[r:[^ ,]*]]) 86 // ARM64: call void (...) @llvm.localescape(ptr %[[r:[^ ,]*]]) 87 // X86: call void (...) @llvm.localescape(ptr %[[r:[^ ,]*]], ptr %[[code:[^ ,]*]]) 88 // CHECK: store i32 42, ptr %[[r]] 89 // CHECK: invoke void @j() #[[NOINLINE]] 90 // 91 // CHECK: catchpad within %{{[^ ]*}} [ptr @"?filt$0@0@filter_expr_capture@@"] 92 // CHECK: store i32 13, ptr %[[r]] 93 // 94 // CHECK: %[[rv:[^ ]*]] = load i32, ptr %[[r]] 95 // CHECK: ret i32 %[[rv]] 96 97 // X64-LABEL: define internal i32 @"?filt$0@0@filter_expr_capture@@"(ptr noundef %exception_pointers, ptr noundef %frame_pointer) 98 // X64: %[[fp:[^ ]*]] = call ptr @llvm.eh.recoverfp(ptr @filter_expr_capture, ptr %frame_pointer) 99 // X64: call ptr @llvm.localrecover(ptr @filter_expr_capture, ptr %[[fp]], i32 0) 100 // 101 // ARM64-LABEL: define internal i32 @"?filt$0@0@filter_expr_capture@@"(ptr noundef %exception_pointers, ptr noundef %frame_pointer) 102 // ARM64: %[[fp:[^ ]*]] = call ptr @llvm.eh.recoverfp(ptr @filter_expr_capture, ptr %frame_pointer) 103 // ARM64: call ptr @llvm.localrecover(ptr @filter_expr_capture, ptr %[[fp]], i32 0) 104 // 105 // X86-LABEL: define internal i32 @"?filt$0@0@filter_expr_capture@@"() 106 // X86: %[[ebp:[^ ]*]] = call ptr @llvm.frameaddress.p0(i32 1) 107 // X86: %[[fp:[^ ]*]] = call ptr @llvm.eh.recoverfp(ptr @filter_expr_capture, ptr %[[ebp]]) 108 // X86: call ptr @llvm.localrecover(ptr @filter_expr_capture, ptr %[[fp]], i32 0) 109 // 110 // CHECK: store i32 -1, ptr %{{.*}} 111 // CHECK: ret i32 -1 112 113 int nested_try(void) { 114 int r = 42; 115 __try { 116 __try { 117 j(); 118 r = 0; 119 } __except(_exception_code() == 123) { 120 r = 123; 121 } 122 } __except(_exception_code() == 456) { 123 r = 456; 124 } 125 return r; 126 } 127 // CHECK-LABEL: define dso_local i32 @nested_try() 128 // X64-SAME: personality ptr @__C_specific_handler 129 // ARM64-SAME: personality ptr @__C_specific_handler 130 // X86-SAME: personality ptr @_except_handler3 131 // CHECK: store i32 42, ptr %[[r:[^ ,]*]] 132 // CHECK: invoke void @j() #[[NOINLINE]] 133 // CHECK: to label %[[cont:[^ ]*]] unwind label %[[cswitch_inner:[^ ]*]] 134 // 135 // CHECK: [[cswitch_inner]] 136 // CHECK: %[[cs_inner:[^ ]*]] = catchswitch within none [label %[[cpad_inner:[^ ]*]]] unwind label %[[cswitch_outer:[^ ]*]] 137 // 138 // CHECK: [[cswitch_outer]] 139 // CHECK: %[[cs_outer:[^ ]*]] = catchswitch within none [label %[[cpad_outer:[^ ]*]]] unwind to caller 140 // 141 // CHECK: [[cpad_outer]] 142 // CHECK: catchpad within %{{[^ ]*}} [ptr @"?filt$0@0@nested_try@@"] 143 // CHECK-NEXT: catchret {{.*}} to label %[[except_outer:[^ ]*]] 144 // 145 // CHECK: [[except_outer]] 146 // CHECK: store i32 456, ptr %[[r]] 147 // CHECK: br label %[[outer_try_cont:[^ ]*]] 148 // 149 // CHECK: [[outer_try_cont]] 150 // CHECK: %[[r_load:[^ ]*]] = load i32, ptr %[[r]] 151 // CHECK: ret i32 %[[r_load]] 152 // 153 // CHECK: [[cpad_inner]] 154 // CHECK: catchpad within %[[cs_inner]] [ptr @"?filt$1@0@nested_try@@"] 155 // CHECK-NEXT: catchret {{.*}} to label %[[except_inner:[^ ]*]] 156 // 157 // CHECK: [[except_inner]] 158 // CHECK: store i32 123, ptr %[[r]] 159 // CHECK: br label %[[inner_try_cont:[^ ]*]] 160 // 161 // CHECK: [[inner_try_cont]] 162 // CHECK: br label %[[outer_try_cont]] 163 // 164 // CHECK: [[cont]] 165 // CHECK: store i32 0, ptr %[[r]] 166 // CHECK: br label %[[inner_try_cont]] 167 // 168 // CHECK-LABEL: define internal i32 @"?filt$0@0@nested_try@@"({{.*}}) 169 // X86: call ptr @llvm.eh.recoverfp({{.*}}) 170 // CHECK: load ptr, ptr 171 // CHECK: load i32, ptr 172 // CHECK: icmp eq i32 %{{.*}}, 456 173 // 174 // CHECK-LABEL: define internal i32 @"?filt$1@0@nested_try@@"({{.*}}) 175 // X86: call ptr @llvm.eh.recoverfp({{.*}}) 176 // CHECK: load ptr, ptr 177 // CHECK: load i32, ptr 178 // CHECK: icmp eq i32 %{{.*}}, 123 179 180 int basic_finally(int g) { 181 __try { 182 j(); 183 } __finally { 184 ++g; 185 } 186 return g; 187 } 188 // CHECK-LABEL: define dso_local i32 @basic_finally(i32 noundef %g) 189 // X64-SAME: personality ptr @__C_specific_handler 190 // ARM64-SAME: personality ptr @__C_specific_handler 191 // X86-SAME: personality ptr @_except_handler3 192 // CHECK: %[[g_addr:[^ ]*]] = alloca i32, align 4 193 // CHECK: call void (...) @llvm.localescape(ptr %[[g_addr]]) 194 // CHECK: store i32 %g, ptr %[[g_addr]] 195 // 196 // CHECK: invoke void @j() 197 // CHECK: to label %[[cont:[^ ]*]] unwind label %[[cleanuppad:[^ ]*]] 198 // 199 // CHECK: [[cont]] 200 // CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() 201 // CHECK: call void @"?fin$0@0@basic_finally@@"({{i8 noundef( zeroext)?}} 0, ptr noundef %[[fp]]) 202 // CHECK: load i32, ptr %[[g_addr]], align 4 203 // CHECK: ret i32 204 // 205 // CHECK: [[cleanuppad]] 206 // CHECK: %[[padtoken:[^ ]*]] = cleanuppad within none [] 207 // CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() 208 // CHECK: call void @"?fin$0@0@basic_finally@@"({{i8 noundef( zeroext)?}} 1, ptr noundef %[[fp]]) 209 // CHECK: cleanupret from %[[padtoken]] unwind to caller 210 211 // CHECK: define internal void @"?fin$0@0@basic_finally@@"({{i8 noundef( zeroext)?}} %abnormal_termination, ptr noundef %frame_pointer) 212 // CHECK: call ptr @llvm.localrecover(ptr @basic_finally, ptr %frame_pointer, i32 0) 213 // CHECK: load i32, ptr %{{.*}}, align 4 214 // CHECK: add nsw i32 %{{.*}}, 1 215 // CHECK: store i32 %{{.*}}, ptr %{{.*}}, align 4 216 // CHECK: ret void 217 218 int returns_int(void); 219 int except_return(void) { 220 __try { 221 return returns_int(); 222 } __except(1) { 223 return 42; 224 } 225 } 226 // CHECK-LABEL: define dso_local i32 @except_return() 227 // CHECK: %[[tmp:[^ ]*]] = invoke i32 @returns_int() 228 // CHECK: to label %[[cont:[^ ]*]] unwind label %[[catchpad:[^ ]*]] 229 // 230 // CHECK: [[catchpad]] 231 // CHECK: catchpad 232 // CHECK: catchret 233 // CHECK: store i32 42, ptr %[[rv:[^ ]*]] 234 // CHECK: br label %[[retbb:[^ ]*]] 235 // 236 // CHECK: [[cont]] 237 // CHECK: store i32 %[[tmp]], ptr %[[rv]] 238 // CHECK: br label %[[retbb]] 239 // 240 // CHECK: [[retbb]] 241 // CHECK: %[[r:[^ ]*]] = load i32, ptr %[[rv]] 242 // CHECK: ret i32 %[[r]] 243 244 245 // PR 24751: don't assert if a variable is used twice in a __finally block. 246 // Also, make sure we don't do redundant work to capture/project it. 247 void finally_capture_twice(int x) { 248 __try { 249 } __finally { 250 int y = x; 251 int z = x; 252 } 253 } 254 // 255 // CHECK-LABEL: define dso_local void @finally_capture_twice( 256 // CHECK: [[X:%.*]] = alloca i32, align 4 257 // CHECK: call void (...) @llvm.localescape(ptr [[X]]) 258 // CHECK-NEXT: store i32 {{.*}}, ptr [[X]], align 4 259 // CHECK-NEXT: [[LOCAL:%.*]] = call ptr @llvm.localaddress() 260 // CHECK-NEXT: call void [[FINALLY:@.*]](i8 noundef{{ zeroext | }}0, ptr noundef [[LOCAL]]) 261 // CHECK: define internal void [[FINALLY]]( 262 // CHECK: [[LOCAL:%.*]] = call ptr @llvm.localrecover( 263 // CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4 264 // CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4 265 // CHECK-NEXT: store ptr 266 // CHECK-NEXT: store i8 267 // CHECK-NEXT: [[T0:%.*]] = load i32, ptr [[LOCAL]], align 4 268 // CHECK-NEXT: store i32 [[T0]], ptr [[Y]], align 4 269 // CHECK-NEXT: [[T0:%.*]] = load i32, ptr [[LOCAL]], align 4 270 // CHECK-NEXT: store i32 [[T0]], ptr [[Z]], align 4 271 // CHECK-NEXT: ret void 272 273 int exception_code_in_except(void) { 274 __try { 275 try_body(0, 0, 0); 276 } __except(1) { 277 return _exception_code(); 278 } 279 return 0; 280 } 281 282 // CHECK-LABEL: define dso_local i32 @exception_code_in_except() 283 // CHECK: %[[ret_slot:[^ ]*]] = alloca i32 284 // CHECK: %[[code_slot:[^ ]*]] = alloca i32 285 // CHECK: invoke void @try_body(i32 noundef 0, i32 noundef 0, ptr noundef null) 286 // CHECK: %[[pad:[^ ]*]] = catchpad 287 // CHECK: catchret from %[[pad]] 288 // X64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]]) 289 // X64: store i32 %[[code]], ptr %[[code_slot]] 290 // ARM64: %[[code:[^ ]*]] = call i32 @llvm.eh.exceptioncode(token %[[pad]]) 291 // ARM64: store i32 %[[code]], ptr %[[code_slot]] 292 // CHECK: %[[ret1:[^ ]*]] = load i32, ptr %[[code_slot]] 293 // CHECK: store i32 %[[ret1]], ptr %[[ret_slot]] 294 // CHECK: %[[ret2:[^ ]*]] = load i32, ptr %[[ret_slot]] 295 // CHECK: ret i32 %[[ret2]] 296 297 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} } 298