Skip to content

Commit e267dbb

Browse files
committed
Support for label expressions with type const char *
- nanos6_task_implementation_info_t is no constant when label expr is not a string literal because we need to perform a store of the result value just before creating the task - We do not need to capture the label because it is not used in the task body Closes llvm#75
1 parent 90250d4 commit e267dbb

File tree

12 files changed

+211
-23
lines changed

12 files changed

+211
-23
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10842,6 +10842,8 @@ class Sema final {
1084210842
bool StrictlyPositive);
1084310843
ExprResult
1084410844
CheckSignedIntegerValue(Expr *ValExpr);
10845+
ExprResult
10846+
CheckIsConstCharPtrConvertibleExpr(Expr *E);
1084510847
/// Called on start of new data sharing attribute block.
1084610848
void StartOmpSsDSABlock(OmpSsDirectiveKind K,
1084710849
Scope *CurScope,

clang/lib/CodeGen/CGOmpSsRuntime.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,10 +1979,8 @@ void CGOmpSsRuntime::EmitTaskData(
19791979
TaskInfo.emplace_back(getBundleStr(OSSB_priority), V);
19801980
}
19811981
if (Data.Label) {
1982-
LValue LV = CGF.EmitLValue(Data.Label);
1983-
// TODO: do we need to capture stmt for variables? First guess, yes
1984-
// CapturedList.push_back(V);
1985-
TaskInfo.emplace_back(getBundleStr(OSSB_label), LV.getPointer(CGF));
1982+
llvm::Value *V = CGF.EmitScalarExpr(Data.Label);
1983+
TaskInfo.emplace_back(getBundleStr(OSSB_label), V);
19861984
}
19871985
if (Data.Wait) {
19881986
TaskInfo.emplace_back(
@@ -2160,6 +2158,10 @@ RValue CGOmpSsRuntime::emitTaskFunction(CodeGenFunction &CGF,
21602158
CapturedList.push_back(V);
21612159
TaskInfo.emplace_back(getBundleStr(OSSB_priority), V);
21622160
}
2161+
if (const Expr *E = Attr->getLabelExpr()) {
2162+
llvm::Value *V = CGF.EmitScalarExpr(E);
2163+
TaskInfo.emplace_back(getBundleStr(OSSB_label), V);
2164+
}
21632165
// in()
21642166
for (const Expr *E : Attr->ins()) {
21652167
OSSDepDataTy Dep;

clang/lib/Sema/SemaOmpSs.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOmpSsDeclareTaskDirective(
12191219
++ParI;
12201220
}
12211221

1222-
ExprResult IfRes, FinalRes, CostRes, PriorityRes;
1222+
ExprResult IfRes, FinalRes, CostRes, PriorityRes, LabelRes;
12231223
if (If) {
12241224
IfRes = VerifyBooleanConditionWithCleanups(If, If->getExprLoc());
12251225
}
@@ -1234,8 +1234,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOmpSsDeclareTaskDirective(
12341234
PriorityRes = CheckSignedIntegerValue(Priority);
12351235
}
12361236
if (Label) {
1237-
if (!isa<StringLiteral>(Label))
1238-
Diag(Label->getExprLoc(), diag::err_expr_not_string_literal);
1237+
LabelRes = CheckIsConstCharPtrConvertibleExpr(Label);
12391238
}
12401239
for (Expr *RefExpr : Ins) {
12411240
checkOutlineDependency(*this, RefExpr, /*OSSSyntax=*/true);
@@ -1301,7 +1300,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOmpSsDeclareTaskDirective(
13011300
auto *NewAttr = OSSTaskDeclAttr::CreateImplicit(
13021301
Context,
13031302
IfRes.get(), FinalRes.get(), CostRes.get(), PriorityRes.get(),
1304-
Label,
1303+
LabelRes.get(),
13051304
Wait,
13061305
const_cast<Expr **>(Ins.data()), Ins.size(),
13071306
const_cast<Expr **>(Outs.data()), Outs.size(),
@@ -2674,6 +2673,27 @@ ExprResult Sema::VerifyBooleanConditionWithCleanups(
26742673
return Condition;
26752674
}
26762675

2676+
ExprResult Sema::CheckIsConstCharPtrConvertibleExpr(Expr *E) {
2677+
const QualType &ConstCharPtrTy =
2678+
Context.getPointerType(Context.CharTy.withConst());
2679+
2680+
if (!E->isValueDependent() && !E->isTypeDependent() &&
2681+
!E->isInstantiationDependent() &&
2682+
!E->containsUnexpandedParameterPack()) {
2683+
2684+
VarDecl *LabelVD =
2685+
buildVarDecl(*this, E->getExprLoc(), ConstCharPtrTy, ".tmp.label");
2686+
AddInitializerToDecl(LabelVD,
2687+
DefaultLvalueConversion(E).get(),
2688+
/*DirectInit=*/false);
2689+
if (!LabelVD->hasInit())
2690+
return ExprError();
2691+
2692+
return LabelVD->getInit();
2693+
}
2694+
return E;
2695+
}
2696+
26772697
OSSClause *Sema::ActOnOmpSsIfClause(Expr *Condition,
26782698
SourceLocation StartLoc,
26792699
SourceLocation LParenLoc,
@@ -2741,11 +2761,11 @@ OSSClause *Sema::ActOnOmpSsLabelClause(Expr *E,
27412761
SourceLocation StartLoc,
27422762
SourceLocation LParenLoc,
27432763
SourceLocation EndLoc) {
2744-
if (!isa<StringLiteral>(E)) {
2745-
Diag(E->getExprLoc(), diag::err_expr_not_string_literal);
2764+
ExprResult Res = CheckIsConstCharPtrConvertibleExpr(E);
2765+
if (Res.isInvalid())
27462766
return nullptr;
2747-
}
2748-
return new (Context) OSSLabelClause(E, StartLoc, LParenLoc, EndLoc);
2767+
2768+
return new (Context) OSSLabelClause(Res.get(), StartLoc, LParenLoc, EndLoc);
27492769
}
27502770

27512771
OSSClause *Sema::ActOnOmpSsSingleExprClause(OmpSsClauseKind Kind, Expr *Expr,

clang/lib/Sema/TreeTransform.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10125,7 +10125,6 @@ OSSClause *TreeTransform<Derived>::TransformOSSPriorityClause(OSSPriorityClause
1012510125

1012610126
template <typename Derived>
1012710127
OSSClause *TreeTransform<Derived>::TransformOSSLabelClause(OSSLabelClause *C) {
10128-
// TODO: do we really need to transform?
1012910128
ExprResult E = getDerived().TransformExpr(C->getExpression());
1013010129
if (E.isInvalid())
1013110130
return nullptr;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*--------------------------------------------------------------------
2+
(C) Copyright 2006-2013 Barcelona Supercomputing Center
3+
Centro Nacional de Supercomputacion
4+
5+
This file is part of Mercurium C/C++ source-to-source compiler.
6+
7+
See AUTHORS file in the top level directory for information
8+
regarding developers and contributors.
9+
10+
This library is free software; you can redistribute it and/or
11+
modify it under the terms of the GNU Lesser General Public
12+
License as published by the Free Software Foundation; either
13+
version 3 of the License, or (at your option) any later version.
14+
15+
Mercurium C/C++ source-to-source compiler is distributed in the hope
16+
that it will be useful, but WITHOUT ANY WARRANTY; without even the
17+
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
18+
PURPOSE. See the GNU Lesser General Public License for more
19+
details.
20+
21+
You should have received a copy of the GNU Lesser General Public
22+
License along with Mercurium C/C++ source-to-source compiler; if
23+
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
24+
Cambridge, MA 02139, USA.
25+
--------------------------------------------------------------------*/
26+
27+
// RUN: %oss-compile && NANOS6=verbose NANOS6_VERBOSE=AddTask %oss-run 2>&1 | FileCheck %s
28+
// RUN: %oss-O2-compile && NANOS6=verbose NANOS6_VERBOSE=AddTask %oss-run 2>&1 | FileCheck %s
29+
30+
const char text[] = "CoronaTask";
31+
32+
#pragma oss task label(str)
33+
void foo(const char *str) {}
34+
35+
int main() {
36+
#pragma oss task label(text)
37+
{}
38+
foo(text);
39+
#pragma oss taskwait
40+
}
41+
42+
// CHECK: CoronaTask
43+
// CHECK: CoronaTask

clang/test/OmpSs/IR/task_label.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
// RUN: %clang_cc1 -verify -fompss-2 -disable-llvm-passes -ferror-limit 100 %s -S -emit-llvm -o - | FileCheck %s
22
// expected-no-diagnostics
33

4+
#pragma oss task label(s)
5+
void bar(const char *s);
6+
7+
const char text[] = "T2";
48
void foo() {
59
#pragma oss task label("T1")
610
{}
11+
#pragma oss task label(text)
12+
{}
13+
bar("T3");
714
}
815

9-
// CHECK: @.str = private unnamed_addr constant [3 x i8] c"T1\00", align 1
10-
// CHECK: %0 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00"), "QUAL.OSS.LABEL"([3 x i8]* @.str) ]
16+
// CHECK: %0 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00"), "QUAL.OSS.LABEL"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0)) ]
17+
// CHECK: %1 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00"), "QUAL.OSS.LABEL"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @text, i64 0, i64 0)) ]
18+
19+
// CHECK: store i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i64 0, i64 0), i8** %call_arg, align 8
20+
// CHECK-NEXT: %2 = load i8*, i8** %call_arg, align 8
21+
// CHECK-NEXT: %3 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00"), "QUAL.OSS.FIRSTPRIVATE"(i8** %call_arg), "QUAL.OSS.LABEL"(i8* %2) ]
22+

clang/test/OmpSs/Print/task_label.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#pragma oss task label("hola")
55
void foo();
66

7+
const char text[] = "asdf";
8+
#pragma oss task label(text)
9+
void foo1();
10+
711
void bar() {
812
#pragma oss task label("caracola")
913
{}
@@ -12,6 +16,9 @@ void bar() {
1216
// CHECK: #pragma oss task label("hola")
1317
// CHECK-NEXT: void foo();
1418

19+
// CHECK: #pragma oss task label(text)
20+
// CHECK-NEXT: void foo1();
21+
1522
// CHECK: void bar() {
1623
// CHECK-NEXT: #pragma oss task label("caracola")
1724
// CHECK-NEXT: {

clang/test/OmpSs/Sema/task_label.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
// RUN: %clang_cc1 -verify -fompss-2 -ferror-limit 100 -o - %s
22

33
const char *s = "asdf";
4-
#pragma oss task label(s) // expected-error {{expression is not a string literal}}
4+
#pragma oss task label(s)
55
void foo1();
66

7-
#pragma oss task label(p) // expected-error {{expression is not a string literal}}
7+
#pragma oss task label(p)
88
void foo1(const char *p);
99

1010
void bar() {
1111
const char *o = "blabla";
12-
#pragma oss task label(o) // expected-error {{expression is not a string literal}}
12+
#pragma oss task label(o)
1313
#pragma oss task label("L1")
1414
{}
15+
const int *pint = 0;
16+
#pragma oss task label(pint) // expected-warning {{incompatible pointer types initializing 'const char *' with an expression of type 'const int *'}}
17+
{}
1518
}

clang/test/OmpSs/Sema/task_label.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -verify -fompss-2 -ferror-limit 100 -o - %s
2+
3+
template<typename T>
4+
void tfoo(const T *t = nullptr) {
5+
#pragma oss task label(t) // expected-error {{cannot initialize a variable of type 'const char *' with an rvalue of type 'const int *'}}
6+
{}
7+
}
8+
9+
const char *s = "asdf";
10+
#pragma oss task label(s)
11+
void foo1();
12+
13+
#pragma oss task label(p)
14+
void foo1(const char *p);
15+
16+
void bar() {
17+
const char *o = "blabla";
18+
const int *pint = 0;
19+
#pragma oss task label(o)
20+
{}
21+
#pragma oss task label("L1")
22+
{}
23+
#pragma oss task label(pint) // expected-error{{cannot initialize a variable of type 'const char *' with an rvalue of type 'const int *'}}
24+
{}
25+
tfoo<int>(); // expected-note {{in instantiation of function template specialization 'tfoo<int>' requested here}}
26+
tfoo<char>();
27+
}

llvm/lib/Transforms/OmpSs/OmpSsTransform.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,8 +1093,9 @@ struct OmpSs : public ModulePass {
10931093
&OlConstraintsFuncVar, &Nanos6TaskLocStr,
10941094
&TI,
10951095
&taskNum] {
1096+
bool IsConstLabelOrNull = !TI.Label || isa<Constant>(TI.Label);
10961097
GlobalVariable *GV = new GlobalVariable(M, ArrayType::get(Nanos6TaskImplInfo::getInstance(M).getType(), 1),
1097-
/*isConstant=*/true,
1098+
/*isConstant=*/IsConstLabelOrNull,
10981099
GlobalVariable::InternalLinkage,
10991100
ConstantArray::get(ArrayType::get(Nanos6TaskImplInfo::getInstance(M).getType(), 1), // TODO: More than one implementations?
11001101
ConstantStruct::get(Nanos6TaskImplInfo::getInstance(M).getType(),
@@ -1104,7 +1105,7 @@ struct OmpSs : public ModulePass {
11041105
? ConstantExpr::getPointerCast(OlConstraintsFuncVar,
11051106
Nanos6TaskImplInfo::getInstance(M).getType()->getElementType(2))
11061107
: ConstantPointerNull::get(cast<PointerType>(Nanos6TaskImplInfo::getInstance(M).getType()->getElementType(2))),
1107-
TI.Label
1108+
TI.Label && isa<Constant>(TI.Label)
11081109
? ConstantExpr::getPointerCast(cast<Constant>(TI.Label),
11091110
Nanos6TaskImplInfo::getInstance(M).getType()->getElementType(3))
11101111
: ConstantPointerNull::get(cast<PointerType>(Nanos6TaskImplInfo::getInstance(M).getType()->getElementType(3))),
@@ -1227,9 +1228,10 @@ struct OmpSs : public ModulePass {
12271228
auto emitOmpSsCaptureAndSubmitTask
12281229
= [this, &M, &DLoc, &TaskArgsTy,
12291230
&TI, &TaskArgsToStructIdxMap,
1230-
&TaskInfoVar, &TaskInvInfoVar](Function *newFunction,
1231-
BasicBlock *codeReplacer,
1232-
const SetVector<BasicBlock *> &Blocks) {
1231+
&TaskInfoVar, &TaskImplInfoVar,
1232+
&TaskInvInfoVar](Function *newFunction,
1233+
BasicBlock *codeReplacer,
1234+
const SetVector<BasicBlock *> &Blocks) {
12331235

12341236
IRBuilder<> IRB(codeReplacer);
12351237
// Set debug info from the task entry to all instructions
@@ -1296,6 +1298,17 @@ struct OmpSs : public ModulePass {
12961298
+ TI.DependsInfo.WeakCommutatives.size()
12971299
+ TI.DependsInfo.Reductions.size()
12981300
+ TI.DependsInfo.WeakReductions.size();
1301+
1302+
// Store label if it's not a string literal (i.e label("L1"))
1303+
if (TI.Label && !isa<Constant>(TI.Label)) {
1304+
Value *Idx[3];
1305+
Idx[0] = Constant::getNullValue(Type::getInt32Ty(IRB.getContext()));
1306+
Idx[1] = Constant::getNullValue(Type::getInt32Ty(IRB.getContext()));
1307+
Idx[2] = ConstantInt::get(Type::getInt32Ty(IRB.getContext()), 3);
1308+
Value *LabelField = IRB.CreateGEP(TaskImplInfoVar, Idx, "ASDF");
1309+
IRB.CreateStore(TI.Label, LabelField);
1310+
}
1311+
12991312
IRB.CreateCall(CreateTaskFuncCallee, {TaskInfoVar,
13001313
TaskInvInfoVar,
13011314
TaskArgsSizeOf,

llvm/test/Bitcode/operand-bundles-bc-analyzer.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
; CHECK-NEXT: <OPERAND_BUNDLE_TAG
3636
; CHECK-NEXT: <OPERAND_BUNDLE_TAG
3737
; CHECK-NEXT: <OPERAND_BUNDLE_TAG
38+
; CHECK-NEXT: <OPERAND_BUNDLE_TAG
3839
; CHECK-NEXT: </OPERAND_BUNDLE_TAGS_BLOCK
3940

4041
; CHECK: <FUNCTION_BLOCK
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
; RUN: opt %s -ompss-2 -S | FileCheck %s
2+
; ModuleID = 'task_no_const_label.c'
3+
source_filename = "task_no_const_label.c"
4+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
5+
target triple = "x86_64-unknown-linux-gnu"
6+
7+
@__const.foo.text = private unnamed_addr constant [3 x i8] c"T1\00", align 1
8+
9+
; void foo() {
10+
; const char text[] = "T1";
11+
; #pragma oss task label(text)
12+
; {}
13+
; }
14+
15+
; Function Attrs: noinline nounwind optnone
16+
define void @foo() #0 !dbg !6 {
17+
entry:
18+
%text = alloca [3 x i8], align 1
19+
%0 = bitcast [3 x i8]* %text to i8*, !dbg !9
20+
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds ([3 x i8], [3 x i8]* @__const.foo.text, i32 0, i32 0), i64 3, i1 false), !dbg !9
21+
%arraydecay = getelementptr inbounds [3 x i8], [3 x i8]* %text, i64 0, i64 0, !dbg !10
22+
%1 = call token @llvm.directive.region.entry() [ "DIR.OSS"([5 x i8] c"TASK\00"), "QUAL.OSS.LABEL"(i8* %arraydecay) ], !dbg !10
23+
call void @llvm.directive.region.exit(token %1), !dbg !11
24+
ret void, !dbg !12
25+
}
26+
27+
; store the label ptr into nanos6_task_implementation_info_t
28+
; CHECK: store i8* %arraydecay, i8** getelementptr inbounds ([1 x %nanos6_task_implementation_info_t], [1 x %nanos6_task_implementation_info_t]* @implementations_var_foo0, i32 0, i32 0, i32 3), align 8
29+
30+
; Function Attrs: argmemonly nounwind willreturn
31+
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1
32+
33+
; Function Attrs: nounwind
34+
declare token @llvm.directive.region.entry() #2
35+
36+
; Function Attrs: nounwind
37+
declare void @llvm.directive.region.exit(token) #2
38+
39+
attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
40+
attributes #1 = { argmemonly nounwind willreturn }
41+
attributes #2 = { nounwind }
42+
43+
!llvm.dbg.cu = !{!0}
44+
!llvm.module.flags = !{!3, !4}
45+
!llvm.ident = !{!5}
46+
47+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, enums: !2, nameTableKind: None)
48+
!1 = !DIFile(filename: "<stdin>", directory: "")
49+
!2 = !{}
50+
!3 = !{i32 2, !"Debug Info Version", i32 3}
51+
!4 = !{i32 1, !"wchar_size", i32 4}
52+
!5 = !{!"clang version 11.0.0 "}
53+
!6 = distinct !DISubprogram(name: "foo", scope: !7, file: !7, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
54+
!7 = !DIFile(filename: "task_no_const_label.c", directory: "")
55+
!8 = !DISubroutineType(types: !2)
56+
!9 = !DILocation(line: 2, scope: !6)
57+
!10 = !DILocation(line: 3, scope: !6)
58+
!11 = !DILocation(line: 4, scope: !6)
59+
!12 = !DILocation(line: 5, scope: !6)

0 commit comments

Comments
 (0)