Skip to content

[SYCL] Store expression as ConstantExpr in Semantic Attribute #3169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 12, 2021
88 changes: 34 additions & 54 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -13065,14 +13065,12 @@ void Sema::addIntelSYCLSingleArgFunctionAttr(Decl *D,
assert(E && "Attribute must have an argument.");

if (!E->isInstantiationDependent()) {
Optional<llvm::APSInt> ArgVal = E->getIntegerConstantExpr(getASTContext());
if (!ArgVal) {
Diag(E->getExprLoc(), diag::err_attribute_argument_type)
<< CI.getAttrName() << AANT_ArgumentIntegerConstant
<< E->getSourceRange();
llvm::APSInt ArgVal;
ExprResult ICE = VerifyIntegerConstantExpression(E, &ArgVal);
if (ICE.isInvalid())
return;
}
int32_t ArgInt = ArgVal->getSExtValue();
E = ICE.get();
int32_t ArgInt = ArgVal.getSExtValue();
if (CI.getParsedKind() == ParsedAttr::AT_SYCLIntelNumSimdWorkItems ||
CI.getParsedKind() == ParsedAttr::AT_IntelReqdSubGroupSize) {
if (ArgInt <= 0) {
Expand All @@ -13098,77 +13096,59 @@ void Sema::addIntelSYCLSingleArgFunctionAttr(Decl *D,
D->addAttr(::new (Context) AttrType(Context, CI, E));
}

template <typename AttrInfo>
static bool handleMaxWorkSizeAttrExpr(Sema &S, const AttrInfo &AI,
const Expr *E, unsigned &Val,
unsigned Idx) {
static Expr *checkMaxWorkSizeAttrExpr(Sema &S, const AttributeCommonInfo &CI,
Expr *E) {
assert(E && "Attribute must have an argument.");

if (!E->isInstantiationDependent()) {
Optional<llvm::APSInt> ArgVal =
E->getIntegerConstantExpr(S.getASTContext());
llvm::APSInt ArgVal;
ExprResult ICE = S.VerifyIntegerConstantExpression(E, &ArgVal);

if (!ArgVal) {
S.Diag(AI.getLocation(), diag::err_attribute_argument_type)
<< &AI << AANT_ArgumentIntegerConstant << E->getSourceRange();
return false;
}
if (ICE.isInvalid())
return nullptr;

E = ICE.get();

if (ArgVal->isNegative()) {
if (ArgVal.isNegative()) {
S.Diag(E->getExprLoc(),
diag::warn_attribute_requires_non_negative_integer_argument)
<< E->getType() << S.Context.UnsignedLongLongTy
<< E->getSourceRange();
return true;
return E;
}

Val = ArgVal->getZExtValue();
unsigned Val = ArgVal.getZExtValue();
if (Val == 0) {
S.Diag(E->getExprLoc(), diag::err_attribute_argument_is_zero)
<< &AI << E->getSourceRange();
return false;
<< CI << E->getSourceRange();
return nullptr;
}
}
return true;
}

template <typename AttrType>
static bool checkMaxWorkSizeAttrArguments(Sema &S, Expr *XDimExpr,
Expr *YDimExpr, Expr *ZDimExpr,
const AttrType &Attr) {
// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (XDimExpr->isValueDependent() ||
(YDimExpr && YDimExpr->isValueDependent()) ||
(ZDimExpr && ZDimExpr->isValueDependent()))
return false;

unsigned XDim = 0;
if (!handleMaxWorkSizeAttrExpr(S, Attr, XDimExpr, XDim, 0))
return true;

unsigned YDim = 0;
if (YDimExpr && !handleMaxWorkSizeAttrExpr(S, Attr, YDimExpr, YDim, 1))
return true;

unsigned ZDim = 0;
if (ZDimExpr && !handleMaxWorkSizeAttrExpr(S, Attr, ZDimExpr, ZDim, 2))
return true;

return false;
return E;
}

template <typename WorkGroupAttrType>
void Sema::addIntelSYCLTripleArgFunctionAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *XDimExpr, Expr *YDimExpr,
Expr *ZDimExpr) {
WorkGroupAttrType TmpAttr(Context, CI, XDimExpr, YDimExpr, ZDimExpr);

if (checkMaxWorkSizeAttrArguments(*this, XDimExpr, YDimExpr, ZDimExpr,
TmpAttr))
return;
assert((XDimExpr && YDimExpr && ZDimExpr) &&
"argument has unexpected null value");

// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (!XDimExpr->isValueDependent() && !YDimExpr->isValueDependent() &&
!ZDimExpr->isValueDependent()) {

// Save ConstantExpr in semantic attribute
XDimExpr = checkMaxWorkSizeAttrExpr(*this, CI, XDimExpr);
YDimExpr = checkMaxWorkSizeAttrExpr(*this, CI, YDimExpr);
ZDimExpr = checkMaxWorkSizeAttrExpr(*this, CI, ZDimExpr);

if (!XDimExpr || !YDimExpr || !ZDimExpr)
return;
}
D->addAttr(::new (Context)
WorkGroupAttrType(Context, CI, XDimExpr, YDimExpr, ZDimExpr));
}
Expand Down
35 changes: 15 additions & 20 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,6 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
}

if (const ReqdWorkGroupSizeAttr *A = FD->getAttr<ReqdWorkGroupSizeAttr>()) {
llvm::LLVMContext &Context = getLLVMContext();
ASTContext &ClangCtx = FD->getASTContext();
Optional<llvm::APSInt> XDimVal = A->getXDimVal(ClangCtx);
Optional<llvm::APSInt> YDimVal = A->getYDimVal(ClangCtx);
Expand All @@ -643,10 +642,9 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const IntelReqdSubGroupSizeAttr *A =
FD->getAttr<IntelReqdSubGroupSizeAttr>()) {
llvm::LLVMContext &Context = getLLVMContext();
Optional<llvm::APSInt> ArgVal =
A->getValue()->getIntegerConstantExpr(FD->getASTContext());
assert(ArgVal.hasValue() && "Not an integer constant expression");
const auto *CE = dyn_cast<ConstantExpr>(A->getValue());
assert(CE && "Not an integer constant expression");
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
llvm::Metadata *AttrMDArgs[] = {llvm::ConstantAsMetadata::get(
Builder.getInt32(ArgVal->getSExtValue()))};
Fn->setMetadata("intel_reqd_sub_group_size",
Expand All @@ -663,10 +661,9 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const SYCLIntelNumSimdWorkItemsAttr *A =
FD->getAttr<SYCLIntelNumSimdWorkItemsAttr>()) {
llvm::LLVMContext &Context = getLLVMContext();
Optional<llvm::APSInt> ArgVal =
A->getValue()->getIntegerConstantExpr(FD->getASTContext());
assert(ArgVal.hasValue() && "Not an integer constant expression");
const auto *CE = dyn_cast<ConstantExpr>(A->getValue());
assert(CE && "Not an integer constant expression");
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
llvm::Metadata *AttrMDArgs[] = {llvm::ConstantAsMetadata::get(
Builder.getInt32(ArgVal->getSExtValue()))};
Fn->setMetadata("num_simd_work_items",
Expand All @@ -675,9 +672,9 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const SYCLIntelSchedulerTargetFmaxMhzAttr *A =
FD->getAttr<SYCLIntelSchedulerTargetFmaxMhzAttr>()) {
Optional<llvm::APSInt> ArgVal =
A->getValue()->getIntegerConstantExpr(FD->getASTContext());
assert(ArgVal.hasValue() && "Not an integer constant expression");
const auto *CE = dyn_cast<ConstantExpr>(A->getValue());
assert(CE && "Not an integer constant expression");
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
llvm::Metadata *AttrMDArgs[] = {llvm::ConstantAsMetadata::get(
Builder.getInt32(ArgVal->getSExtValue()))};
Fn->setMetadata("scheduler_target_fmax_mhz",
Expand All @@ -686,10 +683,9 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const SYCLIntelMaxGlobalWorkDimAttr *A =
FD->getAttr<SYCLIntelMaxGlobalWorkDimAttr>()) {
llvm::LLVMContext &Context = getLLVMContext();
Optional<llvm::APSInt> ArgVal =
A->getValue()->getIntegerConstantExpr(FD->getASTContext());
assert(ArgVal.hasValue() && "Not an integer constant expression");
const auto *CE = dyn_cast<ConstantExpr>(A->getValue());
assert(CE && "Not an integer constant expression");
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
llvm::Metadata *AttrMDArgs[] = {llvm::ConstantAsMetadata::get(
Builder.getInt32(ArgVal->getSExtValue()))};
Fn->setMetadata("max_global_work_dim",
Expand All @@ -698,7 +694,6 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const SYCLIntelMaxWorkGroupSizeAttr *A =
FD->getAttr<SYCLIntelMaxWorkGroupSizeAttr>()) {
llvm::LLVMContext &Context = getLLVMContext();
ASTContext &ClangCtx = FD->getASTContext();
Optional<llvm::APSInt> XDimVal = A->getXDimVal(ClangCtx);
Optional<llvm::APSInt> YDimVal = A->getYDimVal(ClangCtx);
Expand All @@ -723,9 +718,9 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
FD->getAttr<SYCLIntelNoGlobalWorkOffsetAttr>()) {
const Expr *Arg = A->getValue();
assert(Arg && "Got an unexpected null argument");
Optional<llvm::APSInt> ArgVal =
Arg->getIntegerConstantExpr(FD->getASTContext());
assert(ArgVal.hasValue() && "Not an integer constant expression");
const auto *CE = dyn_cast<ConstantExpr>(Arg);
assert(CE && "Not an integer constant expression");
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
if (ArgVal->getBoolValue())
Fn->setMetadata("no_global_work_offset", llvm::MDNode::get(Context, {}));
}
Expand Down
10 changes: 9 additions & 1 deletion clang/test/SemaSYCL/intel-fpga-no-global-work-offset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,34 @@ struct FuncObj {
int main() {
q.submit([&](handler &h) {
// CHECK: SYCLIntelNoGlobalWorkOffsetAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
h.single_task<class test_kernel1>(FuncObj());

// CHECK: SYCLIntelNoGlobalWorkOffsetAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 0
// CHECK-NEXT: IntegerLiteral{{.*}}0{{$}}
h.single_task<class test_kernel2>(
[]() [[intel::no_global_work_offset(0)]]{});

// CHECK: SYCLIntelNoGlobalWorkOffsetAttr{{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 42
// CHECK-NEXT: IntegerLiteral{{.*}}42{{$}}
h.single_task<class test_kernel3>(
[]() [[intel::no_global_work_offset(42)]]{});

// CHECK: SYCLIntelNoGlobalWorkOffsetAttr{{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int -1
// CHECK-NEXT: UnaryOperator{{.*}} 'int' prefix '-'
// CHECK-NEXT-NEXT: IntegerLiteral{{.*}}1{{$}}
h.single_task<class test_kernel4>(
[]() [[intel::no_global_work_offset(-1)]]{});

// expected-error@+2{{'no_global_work_offset' attribute requires an integer constant}}
// expected-error@+2{{integral constant expression must have integral or unscoped enumeration type, not 'const char [4]'}}
h.single_task<class test_kernel5>(
[]() [[intel::no_global_work_offset("foo")]]{});

Expand Down
34 changes: 34 additions & 0 deletions clang/test/SemaSYCL/intel-max-global-work-dim-device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,15 @@ int main() {
q.submit([&](handler &h) {
// CHECK-LABEL: FunctionDecl {{.*}}test_kernel1
// CHECK: SYCLIntelMaxGlobalWorkDimAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
h.single_task<class test_kernel1>(FuncObj());

// CHECK-LABEL: FunctionDecl {{.*}}test_kernel2
// CHECK: SYCLIntelMaxGlobalWorkDimAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 2
// CHECK-NEXT: IntegerLiteral{{.*}}2{{$}}
// expected-warning@+3 {{attribute 'intelfpga::max_global_work_dim' is deprecated}}
// expected-note@+2 {{did you mean to use 'intel::max_global_work_dim' instead?}}
Expand All @@ -74,34 +78,64 @@ int main() {

// CHECK-LABEL: FunctionDecl {{.*}}test_kernel3
// CHECK: SYCLIntelMaxGlobalWorkDimAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 2
// CHECK-NEXT: IntegerLiteral{{.*}}2{{$}}
h.single_task<class test_kernel3>(
[]() { func_do_not_ignore(); });

h.single_task<class test_kernel4>(TRIFuncObjGood1());
// CHECK-LABEL: FunctionDecl {{.*}}test_kernel4
// CHECK: ReqdWorkGroupSizeAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK: SYCLIntelMaxWorkGroupSizeAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK: SYCLIntelMaxGlobalWorkDimAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 0
// CHECK-NEXT: IntegerLiteral{{.*}}0{{$}}

h.single_task<class test_kernel5>(TRIFuncObjGood2());
// CHECK-LABEL: FunctionDecl {{.*}}test_kernel5
// CHECK: ReqdWorkGroupSizeAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 4
// CHECK-NEXT: IntegerLiteral{{.*}}4{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK: SYCLIntelMaxWorkGroupSizeAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 8
// CHECK-NEXT: IntegerLiteral{{.*}}8{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 1
// CHECK-NEXT: IntegerLiteral{{.*}}1{{$}}
// CHECK: SYCLIntelMaxGlobalWorkDimAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
// CHECK-NEXT: value: Int 3
// CHECK-NEXT: IntegerLiteral{{.*}}3{{$}}
#ifdef TRIGGER_ERROR
[[intel::max_global_work_dim(1)]] int Var = 0; // expected-error{{'max_global_work_dim' attribute only applies to functions}}
Expand Down
Loading