diff options
| author | Reid Kleckner <rnk@google.com> | 2015-09-11 16:29:27 +0000 | 
|---|---|---|
| committer | Reid Kleckner <rnk@google.com> | 2015-09-11 16:29:27 +0000 | 
| commit | fb06c84be8e94bcc0cb9003cee274fc68f11ce6d (patch) | |
| tree | 8eb2db0cd521616c39f19964b63449987834e891 /clang/test | |
| parent | 3943adb57f535c6123a4fa1531c4f08dea9de50e (diff) | |
| download | bcm5719-llvm-fb06c84be8e94bcc0cb9003cee274fc68f11ce6d.tar.gz bcm5719-llvm-fb06c84be8e94bcc0cb9003cee274fc68f11ce6d.zip | |
[SEH] Port __try / __leave test to new IR
It turns out that the IR we already generate for __leave is fine, so no
code changes were needed.
llvm-svn: 247424
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/CodeGen/exceptions-seh-leave-new.c | 347 | 
1 files changed, 347 insertions, 0 deletions
| diff --git a/clang/test/CodeGen/exceptions-seh-leave-new.c b/clang/test/CodeGen/exceptions-seh-leave-new.c new file mode 100644 index 00000000000..69c1a56bca9 --- /dev/null +++ b/clang/test/CodeGen/exceptions-seh-leave-new.c @@ -0,0 +1,347 @@ +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -fnew-ms-eh -emit-llvm -o - | FileCheck %s + +void g(void); + +////////////////////////////////////////////////////////////////////////////// +// __leave with __except + +// Nothing in the __try block can trap, so __try.cont isn't created. +int __leave_with___except_simple() { +  int myres = 0; +  __try { +    myres = 15; +    __leave; +    myres = 23; +  } __except (1) { +    return 0; +  } +  return 1; +} +// CHECK-LABEL: define i32 @__leave_with___except_simple() +// CHECK: store i32 15, i32* %myres +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 +// CHECK: [[tryleave]] +// CHECK-NEXT: ret i32 1 + + +// The "normal" case. +int __leave_with___except() { +  int myres = 0; +  __try { +    g(); +    __leave; +    myres = 23; +  } __except (1) { +    return 0; +  } +  return 1; +} +// CHECK-LABEL: define i32 @__leave_with___except() +// CHECK: invoke void @g() +// CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}} +// For __excepts, instead of an explicit __try.__leave label, we could use +// use invoke.cont as __leave jump target instead.  However, not doing this +// keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will +// simplify this anyways. +// CHECK: [[cont]] +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 +// CHECK: [[tryleave]] +// CHECK-NEXT: br label % + + +////////////////////////////////////////////////////////////////////////////// +// __leave with __finally + +void abort(void) __attribute__((noreturn)); + +// Nothing in the __try block can trap, so __finally.cont and friends aren't +// created. +int __leave_with___finally_simple() { +  int myres = 0; +  __try { +    myres = 15; +    __leave; +    myres = 23; +  } __finally { +    return 0; +  } +  return 1; +} +// CHECK-LABEL: define i32 @__leave_with___finally_simple() +// CHECK: store i32 15, i32* %myres +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 +// CHECK: [[tryleave]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i8 0, i8* %[[fp]]) + +// __finally block doesn't return, __finally.cont doesn't exist. +int __leave_with___finally_noreturn() { +  int myres = 0; +  __try { +    myres = 15; +    __leave; +    myres = 23; +  } __finally { +    abort(); +  } +  return 1; +} +// CHECK-LABEL: define i32 @__leave_with___finally_noreturn() +// CHECK: store i32 15, i32* %myres +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 +// CHECK: [[tryleave]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i8 0, i8* %[[fp]]) + +// The "normal" case. +int __leave_with___finally() { +  int myres = 0; +  __try { +    g(); +    __leave; +    myres = 23; +  } __finally { +    return 0; +  } +  return 1; +} +// CHECK-LABEL: define i32 @__leave_with___finally() +// CHECK: invoke void @g() +// CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}} +// For __finally, there needs to be an explicit __try.__leave, because +// abnormal.termination.slot needs to be set there. +// CHECK: [[cont]] +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 +// CHECK: [[tryleave]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i8 0, i8* %[[fp]]) + + +////////////////////////////////////////////////////////////////////////////// +// Mixed, nested cases. + +int nested___except___finally() { +  int myres = 0; +  __try { +    __try { +      g(); +    } __finally { +      g(); +      __leave;  // Refers to the outer __try, not the __finally! +      myres = 23; +      return 0; +    } + +    myres = 51; +  } __except (1) { +  } +  return 1; +} +// CHECK-LABEL: define i32 @nested___except___finally() + +// CHECK-LABEL: invoke void @g() +// CHECK-NEXT:       to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] + +// CHECK: [[g1_cont1]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 0, i8* %[[fp]]) +// CHECK-NEXT:       to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]] + +// CHECK: [[fin_cont]] +// CHECK: store i32 51, i32* % +// CHECK-NEXT: br label %[[trycont:[^ ]*]] + +// CHECK: [[g1_lpad]] +// CHECK-NEXT: cleanuppad +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i8 1, i8* %[[fp]]) +// CHECK-NEXT:       to label %[[g1_resume:.*]] unwind label %[[cleanupend:[^ ]*]] +// CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]] + +// CHECK: [[g2_lpad]] +// CHECK: catchpad [i8* null] +// CHECK: catchret +// CHECK: br label %[[trycont]] + +// CHECK: [[trycont]] +// CHECK-NEXT: ret i32 1 + +// CHECK: [[cleanupend]] +// CHECK-NEXT: cleanupendpad {{.*}} unwind label %[[g2_lpad]] + +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: call void @g() +// CHECK: unreachable + +int nested___except___except() { +  int myres = 0; +  __try { +    __try { +      g(); +      myres = 16; +    } __except (1) { +      g(); +      __leave;  // Refers to the outer __try, not the __except we're in! +      myres = 23; +      return 0; +    } + +    myres = 51; +  } __except (1) { +  } +  return 1; +} +// The order of basic blocks in the below doesn't matter. +// CHECK-LABEL: define i32 @nested___except___except() + +// CHECK-LABEL: invoke void @g() +// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] + +// CHECK: [[g1_lpad]] +// CHECK: catchpad [i8* null] +// CHECK: catchret {{.*}} to label %[[except:[^ ]*]] +// CHECK: [[except]] +// CHECK: invoke void @g() +// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] + +// CHECK: [[g2_lpad]] +// CHECK: catchpad [i8* null] +// CHECK: catchret +// CHECK: br label %[[trycont4:[^ ]*]] + +// CHECK: [[trycont4]] +// CHECK-NEXT: ret i32 1 + +// CHECK: [[g2_cont]] +// CHECK-NEXT: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: store i32 23 + +// CHECK: [[g1_cont]] +// CHECK: store i32 16, i32* %myres +// CHECK-NEXT: br label %[[trycont:[^ ]*]] + +// CHECK: [[trycont]] +// CHECK-NEXT: store i32 51, i32* %myres +// CHECK-NEXT: br label %[[tryleave]] + +// CHECK: [[tryleave]] +// CHECK-NEXT: br label %[[trycont4]] + +int nested___finally___except() { +  int myres = 0; +  __try { +    __try { +      g(); +    } __except (1) { +      g(); +      __leave;  // Refers to the outer __try, not the __except! +      myres = 23; +      return 0; +    } + +    myres = 51; +  } __finally { +  } +  return 1; +} +// The order of basic blocks in the below doesn't matter. +// CHECK-LABEL: define i32 @nested___finally___except() + +// CHECK-LABEL: invoke void @g() +// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] + +// CHECK: [[g1_lpad]] +// CHECK: catchpad +// CHECK: catchret +// CHECK: invoke void @g() +// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] + +// CHECK: [[g2_cont]] +// CHECK: br label %[[tryleave:[^ ]*]] +// CHECK-NOT: 23 + +// CHECK: [[g1_cont]] +// CHECK-NEXT: br label %[[trycont:[^ ]*]] + +// CHECK: [[trycont]] +// CHECK: store i32 51, i32* % +// CHECK-NEXT: br label %[[tryleave]] + +// CHECK: [[tryleave]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i8 0, i8* %[[fp]]) +// CHECK-NEXT: ret i32 1 + +// CHECK: [[g2_lpad]] +// CHECK: cleanuppad +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___except@@"(i8 1, i8* %[[fp]]) +// CHECK: cleanupret {{.*}} unwind to caller + +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: ret void + +int nested___finally___finally() { +  int myres = 0; +  __try { +    __try { +      g(); +      myres = 16; +    } __finally { +      g(); +      __leave;  // Refers to the outer __try, not the __finally we're in! +      myres = 23; +      return 0; +    } + +    myres = 51; +  } __finally { +  } +  return 1; +} +// The order of basic blocks in the below doesn't matter. +// CHECK-LABEL: define i32 @nested___finally___finally() + +// CHECK: invoke void @g() +// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] + +// CHECK: [[g1_cont]] +// CHECK: store i32 16, i32* %[[myres:[^ ]*]], +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) +// CHECK-NEXT:       to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] + +// CHECK: [[finally_cont]] +// CHECK: store i32 51, i32* %[[myres]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]]) +// CHECK-NEXT: ret i32 1 + +// CHECK: [[g1_lpad]] +// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad [] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) +// CHECK-NEXT:       to label %[[finally_cont2:.*]] unwind label %[[endcleanup:[^ ]*]] +// CHECK: [[finally_cont2]] +// CHECK: cleanupret %[[padtoken]] unwind label %[[g2_lpad]] + +// CHECK: [[endcleanup]] +// CHECK-NEXT: cleanupendpad %[[padtoken]] unwind label %[[g2_lpad]] + +// CHECK: [[g2_lpad]] +// CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad [] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]]) +// CHECK: cleanupret %[[padtoken]] unwind to caller + +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: ret void + +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer) +// CHECK: call void @g() +// CHECK: unreachable | 

