Skip to content

Commit 53196d7

Browse files
committed
Support throwing exceptions outside try/catch BBs inside a task. Support cleanups inside a task
Closes llvm#48
1 parent 80e9495 commit 53196d7

File tree

6 files changed

+191
-18
lines changed

6 files changed

+191
-18
lines changed

clang/lib/CodeGen/CGCleanup.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "CGCleanup.h"
2020
#include "CodeGenFunction.h"
21+
#include "CGOmpSsRuntime.h"
2122
#include "llvm/Support/SaveAndRestore.h"
2223

2324
using namespace clang;
@@ -1262,6 +1263,19 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
12621263
}
12631264

12641265
Address CodeGenFunction::getNormalCleanupDestSlot() {
1266+
if (getContext().getLangOpts().OmpSs
1267+
&& CGM.getOmpSsRuntime().inTaskBody()) {
1268+
Address NCleanupDest = CGM.getOmpSsRuntime().getTaskNormalCleanupDestSlot();
1269+
if (NCleanupDest.isValid())
1270+
return NCleanupDest;
1271+
1272+
NCleanupDest =
1273+
CreateDefaultAlignTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");
1274+
1275+
CGM.getOmpSsRuntime().setTaskNormalCleanupDestSlot(NCleanupDest);
1276+
return NCleanupDest;
1277+
1278+
}
12651279
if (!NormalCleanupDest.isValid())
12661280
NormalCleanupDest =
12671281
CreateDefaultAlignTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");

clang/lib/CodeGen/CGOmpSsRuntime.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -914,10 +914,15 @@ llvm::BasicBlock *CGOmpSsRuntime::getTaskUnreachableBlock() {
914914
Address CGOmpSsRuntime::getTaskExceptionSlot() {
915915
return TaskStack.back().ExceptionSlot;
916916
}
917+
917918
Address CGOmpSsRuntime::getTaskEHSelectorSlot() {
918919
return TaskStack.back().EHSelectorSlot;
919920
}
920921

922+
Address CGOmpSsRuntime::getTaskNormalCleanupDestSlot() {
923+
return TaskStack.back().NormalCleanupDestSlot;
924+
}
925+
921926
void CGOmpSsRuntime::setTaskTerminateHandler(llvm::BasicBlock *BB) {
922927
TaskStack.back().TerminateHandler = BB;
923928
}
@@ -933,10 +938,15 @@ void CGOmpSsRuntime::setTaskUnreachableBlock(llvm::BasicBlock *BB) {
933938
void CGOmpSsRuntime::setTaskExceptionSlot(Address Addr) {
934939
TaskStack.back().ExceptionSlot = Addr;
935940
}
941+
936942
void CGOmpSsRuntime::setTaskEHSelectorSlot(Address Addr) {
937943
TaskStack.back().EHSelectorSlot = Addr;
938944
}
939945

946+
void CGOmpSsRuntime::setTaskNormalCleanupDestSlot(Address Addr) {
947+
TaskStack.back().NormalCleanupDestSlot = Addr;
948+
}
949+
940950
// Borrowed brom CodeGenFunction.cpp
941951
static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
942952
if (!BB) return;
@@ -1025,7 +1035,8 @@ void CGOmpSsRuntime::emitTaskCall(CodeGenFunction &CGF,
10251035
/*TerminateHandler=*/nullptr,
10261036
/*UnreachableBlock=*/nullptr,
10271037
/*ExceptionSlot=*/Address::invalid(),
1028-
/*EHSelectorSlot=*/Address::invalid()});
1038+
/*EHSelectorSlot=*/Address::invalid(),
1039+
/*NormalCleanupDestSlot=*/Address::invalid()});
10291040

10301041
// The point of exit cannot be a branch out of the structured block.
10311042
// longjmp() and throw() must not violate the entry/exit criteria.

clang/lib/CodeGen/CGOmpSsRuntime.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class CGOmpSsRuntime {
8686
llvm::BasicBlock *UnreachableBlock;
8787
Address ExceptionSlot;
8888
Address EHSelectorSlot;
89+
Address NormalCleanupDestSlot;
8990
};
9091

9192
SmallVector<TaskContext, 2> TaskStack;
@@ -116,10 +117,12 @@ class CGOmpSsRuntime {
116117
llvm::BasicBlock *getTaskTerminateLandingPad();
117118
// returns the innermost nested task UnreachableBlock BB
118119
llvm::BasicBlock *getTaskUnreachableBlock();
119-
// returns the innermost nested task ExceptionSlot instruction
120+
// returns the innermost nested task ExceptionSlot address
120121
Address getTaskExceptionSlot();
121-
// returns the innermost nested task ExceptionSlot instruction
122+
// returns the innermost nested task EHSelectorSlot address
122123
Address getTaskEHSelectorSlot();
124+
// returns the innermost nested task NormalCleanupDestSlot address
125+
Address getTaskNormalCleanupDestSlot();
123126

124127
// sets the innermost nested task TerminateHandler instruction
125128
void setTaskTerminateHandler(llvm::BasicBlock *BB);
@@ -131,6 +134,8 @@ class CGOmpSsRuntime {
131134
void setTaskExceptionSlot(Address Addr);
132135
// sets the innermost nested task EHSelectorSlot address
133136
void setTaskEHSelectorSlot(Address Addr);
137+
// returns the innermost nested task NormalCleanupDestSlot address
138+
void setTaskNormalCleanupDestSlot(Address Addr);
134139

135140
/// Emit code for 'taskwait' directive.
136141
virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc);

clang/lib/CodeGen/ItaniumCXXABI.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,10 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
12351235
if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
12361236

12371237
llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
1238-
CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
1238+
if (getContext().getLangOpts().OmpSs)
1239+
CGF.EmitRuntimeCallOrInvoke(getThrowFn(CGM), args);
1240+
else
1241+
CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
12391242
}
12401243

12411244
static llvm::FunctionCallee getItaniumDynamicCastFn(CodeGenFunction &CGF) {

clang/test/OmpSs/IR/task_cleanup.cpp

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %clang_cc1 -verify -fompss-2 -disable-llvm-passes -ferror-limit 100 %s -S -emit-llvm -o - | FileCheck %s
2+
// expected-no-diagnostics
3+
4+
struct Foo {
5+
~Foo() { }
6+
};
7+
8+
void foo()
9+
{
10+
#pragma oss task
11+
{
12+
int n;
13+
while (1) {
14+
Foo f;
15+
goto l;
16+
}
17+
l: n++; // to put something in the label
18+
}
19+
#pragma oss taskwait
20+
}
21+
22+
// CHECK: %0 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00") ]
23+
// CHECK-NEXT: %n = alloca i32, align 4
24+
// CHECK-NEXT: %f = alloca %struct.Foo, align 1
25+
// CHECK-NEXT: %cleanup.dest.slot = alloca i32, align 4
26+
// CHECK-NEXT: br label %while.cond
27+
// CHECK: while.cond: ; preds = %entry
28+
// CHECK-NEXT: br label %while.body
29+
// CHECK: while.body: ; preds = %while.cond
30+
// CHECK-NEXT: store i32 4, i32* %cleanup.dest.slot, align 4
31+
// CHECK-NEXT: call void @_ZN3FooD1Ev(%struct.Foo* %f)
32+
// CHECK-NEXT: %cleanup.dest = load i32, i32* %cleanup.dest.slot, align 4
33+
// CHECK-NEXT: switch i32 %cleanup.dest, label %unreachable [
34+
// CHECK-NEXT: i32 4, label %l
35+
// CHECK-NEXT: ]
36+
// CHECK: l: ; preds = %while.body
37+
// CHECK-NEXT: %1 = load i32, i32* %n, align 4
38+
// CHECK-NEXT: %inc = add nsw i32 %1, 1
39+
// CHECK-NEXT: store i32 %inc, i32* %n, align 4
40+
// CHECK-NEXT: call void @llvm.directive.region.exit(token %0)
41+
// CHECK-NEXT: %2 = call i1 @llvm.directive.marker() [ "DIR.OSS"([9 x i8] c"TASKWAIT\00") ]
42+
// CHECK-NEXT: ret void
43+
// CHECK: unreachable: ; preds = %while.body
44+
// CHECK-NEXT: unreachable
45+
+109-14
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
// RUN: %clang_cc1 -verify -fompss-2 -fexceptions -fcxx-exceptions -disable-llvm-passes -ferror-limit 100 %s -S -emit-llvm -o - | FileCheck %s
22
// expected-no-diagnostics
33

4-
5-
// TODO: Fix this
64
void foo1() {
75
#pragma oss task
86
{
97
throw 1;
108
}
119
}
1210

13-
void foo1() {
11+
// CHECK: %0 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00") ]
12+
// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 4)
13+
// CHECK-NEXT: %1 = bitcast i8* %exception to i32*
14+
// CHECK-NEXT: store i32 1, i32* %1, align 16
15+
// CHECK-NEXT: invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
16+
// CHECK-NEXT: to label %invoke.cont unwind label %terminate.lpad
17+
// CHECK: invoke.cont: ; preds = %entry
18+
// CHECK-NEXT: br label %throw.cont
19+
// CHECK: throw.cont: ; preds = %invoke.cont
20+
// CHECK-NEXT: call void @llvm.directive.region.exit(token %0)
21+
// CHECK-NEXT: ret void
22+
// CHECK: terminate.lpad: ; preds = %entry
23+
// CHECK-NEXT: %2 = landingpad { i8*, i32 }
24+
// CHECK-NEXT: catch i8* null
25+
// CHECK-NEXT: %3 = extractvalue { i8*, i32 } %2, 0
26+
// CHECK-NEXT: call void @__clang_call_terminate(i8* %3) #4
27+
// CHECK-NEXT: unreachable
28+
29+
void foo2() {
1430
#pragma oss task
1531
{
1632
try {
@@ -20,8 +36,10 @@ void foo1() {
2036
}
2137
#pragma oss task
2238
{
39+
int n;
2340
try {
2441
throw 1;
42+
n++;
2543
} catch (int e) {
2644
}
2745
}
@@ -30,15 +48,92 @@ void foo1() {
3048
// Each task has its own exn.slot, ehselector.slot, and all it's exception
3149
// handling BB
3250

33-
// CHECK: %0 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00") ]
34-
// CHECK-NEXT: %exn.slot = alloca i8*
35-
// CHECK-NEXT: %ehselector.slot = alloca i32
36-
// CHECK: try.cont: ; preds = %catch
37-
// CHECK: call void @llvm.directive.region.exit(token %0)
38-
// CHECK-NEXT: %9 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00") ]
39-
// CHECK-NEXT: %exn.slot4 = alloca i8*
40-
// CHECK-NEXT: %ehselector.slot5 = alloca i32
41-
// CHECK: try.cont12: ; preds = %catch9
42-
// CHECK: call void @llvm.directive.region.exit(token %9)
43-
// CHECK-NEXT: ret void
51+
// CHECK: %0 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00") ]
52+
// CHECK-NEXT: %exn.slot = alloca i8*
53+
// CHECK-NEXT: %ehselector.slot = alloca i32
54+
// CHECK-NEXT: %e = alloca i32, align 4
55+
// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 4) #1
56+
// CHECK-NEXT: %1 = bitcast i8* %exception to i32*
57+
// CHECK-NEXT: store i32 1, i32* %1, align 16
58+
// CHECK-NEXT: invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
59+
// CHECK-NEXT: to label %invoke.cont unwind label %lpad
60+
// CHECK: invoke.cont: ; preds = %entry
61+
// CHECK-NEXT: br label %throw.cont
62+
// CHECK: throw.cont: ; preds = %invoke.cont
63+
// CHECK-NEXT: br label %try.cont
64+
// CHECK: lpad: ; preds = %entry
65+
// CHECK-NEXT: %2 = landingpad { i8*, i32 }
66+
// CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
67+
// CHECK-NEXT: catch i8* null
68+
// CHECK-NEXT: %3 = extractvalue { i8*, i32 } %2, 0
69+
// CHECK-NEXT: store i8* %3, i8** %exn.slot, align 8
70+
// CHECK-NEXT: %4 = extractvalue { i8*, i32 } %2, 1
71+
// CHECK-NEXT: store i32 %4, i32* %ehselector.slot, align 4
72+
// CHECK-NEXT: br label %catch.dispatch
73+
// CHECK: catch.dispatch: ; preds = %lpad
74+
// CHECK-NEXT: %sel = load i32, i32* %ehselector.slot, align 4
75+
// CHECK-NEXT: %5 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
76+
// CHECK-NEXT: %matches = icmp eq i32 %sel, %5
77+
// CHECK-NEXT: br i1 %matches, label %catch, label %terminate.handler
78+
// CHECK: catch: ; preds = %catch.dispatch
79+
// CHECK-NEXT: %exn = load i8*, i8** %exn.slot, align 8
80+
// CHECK-NEXT: %6 = call i8* @__cxa_begin_catch(i8* %exn) #1
81+
// CHECK-NEXT: %7 = bitcast i8* %6 to i32*
82+
// CHECK-NEXT: %8 = load i32, i32* %7, align 4
83+
// CHECK-NEXT: store i32 %8, i32* %e, align 4
84+
// CHECK-NEXT: call void @__cxa_end_catch() #1
85+
// CHECK-NEXT: br label %try.cont
86+
// CHECK: try.cont: ; preds = %catch, %throw.cont
87+
// CHECK-NEXT: call void @llvm.directive.region.exit(token %0)
88+
89+
// CHECK: %9 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00") ]
90+
// CHECK-NEXT: %n = alloca i32, align 4
91+
// CHECK-NEXT: %exn.slot4 = alloca i8*
92+
// CHECK-NEXT: %ehselector.slot5 = alloca i32
93+
// CHECK-NEXT: %e12 = alloca i32, align 4
94+
// CHECK-NEXT: %exception2 = call i8* @__cxa_allocate_exception(i64 4) #1
95+
// CHECK-NEXT: %10 = bitcast i8* %exception2 to i32*
96+
// CHECK-NEXT: store i32 1, i32* %10, align 16
97+
// CHECK-NEXT: invoke void @__cxa_throw(i8* %exception2, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
98+
// CHECK-NEXT: to label %invoke.cont6 unwind label %lpad3
99+
// CHECK: invoke.cont6: ; preds = %try.cont
100+
// CHECK-NEXT: br label %throw.cont7
101+
// CHECK: throw.cont7: ; preds = %invoke.cont6
102+
// CHECK-NEXT: %11 = load i32, i32* %n, align 4
103+
// CHECK-NEXT: %inc = add nsw i32 %11, 1
104+
// CHECK-NEXT: store i32 %inc, i32* %n, align 4
105+
// CHECK-NEXT: br label %try.cont14
106+
// CHECK: terminate.handler: ; preds = %catch.dispatch
107+
// CHECK-NEXT: %exn1 = load i8*, i8** %exn.slot, align 8
108+
// CHECK-NEXT: call void @__clang_call_terminate(i8* %exn1) #4
109+
// CHECK-NEXT: unreachable
110+
// CHECK: lpad3: ; preds = %try.cont
111+
// CHECK-NEXT: %12 = landingpad { i8*, i32 }
112+
// CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*)
113+
// CHECK-NEXT: catch i8* null
114+
// CHECK-NEXT: %13 = extractvalue { i8*, i32 } %12, 0
115+
// CHECK-NEXT: store i8* %13, i8** %exn.slot4, align 8
116+
// CHECK-NEXT: %14 = extractvalue { i8*, i32 } %12, 1
117+
// CHECK-NEXT: store i32 %14, i32* %ehselector.slot5, align 4
118+
// CHECK-NEXT: br label %catch.dispatch8
119+
// CHECK: catch.dispatch8: ; preds = %lpad3
120+
// CHECK-NEXT: %sel9 = load i32, i32* %ehselector.slot5, align 4
121+
// CHECK-NEXT: %15 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
122+
// CHECK-NEXT: %matches10 = icmp eq i32 %sel9, %15
123+
// CHECK-NEXT: br i1 %matches10, label %catch11, label %terminate.handler16
124+
// CHECK: catch11: ; preds = %catch.dispatch8
125+
// CHECK-NEXT: %exn13 = load i8*, i8** %exn.slot4, align 8
126+
// CHECK-NEXT: %16 = call i8* @__cxa_begin_catch(i8* %exn13) #1
127+
// CHECK-NEXT: %17 = bitcast i8* %16 to i32*
128+
// CHECK-NEXT: %18 = load i32, i32* %17, align 4
129+
// CHECK-NEXT: store i32 %18, i32* %e12, align 4
130+
// CHECK-NEXT: call void @__cxa_end_catch() #1
131+
// CHECK-NEXT: br label %try.cont14
132+
// CHECK: try.cont14: ; preds = %catch11, %throw.cont7
133+
// CHECK-NEXT: call void @llvm.directive.region.exit(token %9)
134+
// CHECK-NEXT: ret void
135+
// CHECK: terminate.handler16: ; preds = %catch.dispatch8
136+
// CHECK-NEXT: %exn15 = load i8*, i8** %exn.slot4, align 8
137+
// CHECK-NEXT: call void @__clang_call_terminate(i8* %exn15) #4
138+
// CHECK-NEXT: unreachable
44139

0 commit comments

Comments
 (0)