Skip to content

Commit

Permalink
[AMDGPU] Allow using integral non-type template parameters
Browse files Browse the repository at this point in the history
Summary:
- Allow using integral non-type template parameters in the following
  attributes

  __attribute__((amdgpu_flat_work_group_size(<min>, <max>)))
  __attribute__((amdgpu_waves_per_eu(<min>[, <max>])))

Reviewers: kzhuravl, yaxunl

Subscribers: jvesely, wdng, nhaehnle, dstuttard, tpr, t-tye, jdoerfert, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D58623

llvm-svn: 354909
  • Loading branch information
darkbuck committed Feb 26, 2019
1 parent c0ffe70 commit 7557afa
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 47 deletions.
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -1484,14 +1484,14 @@ def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {

def AMDGPUFlatWorkGroupSize : InheritableAttr {
let Spellings = [Clang<"amdgpu_flat_work_group_size", 0>];
let Args = [UnsignedArgument<"Min">, UnsignedArgument<"Max">];
let Args = [ExprArgument<"Min">, ExprArgument<"Max">];
let Documentation = [AMDGPUFlatWorkGroupSizeDocs];
let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">;
}

def AMDGPUWavesPerEU : InheritableAttr {
let Spellings = [Clang<"amdgpu_waves_per_eu", 0>];
let Args = [UnsignedArgument<"Min">, UnsignedArgument<"Max", 1>];
let Args = [ExprArgument<"Min">, ExprArgument<"Max", 1>];
let Documentation = [AMDGPUWavesPerEUDocs];
let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">;
}
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -8674,6 +8674,16 @@ class Sema {
void AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex,
RetainOwnershipKind K, bool IsTemplateInstantiation);

/// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size
/// attribute to a particular declaration.
void addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D, Expr *Min,
Expr *Max, unsigned SpellingListIndex);

/// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a
/// particular declaration.
void addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D, Expr *Min,
Expr *Max, unsigned SpellingListIndex);

bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);

//===--------------------------------------------------------------------===//
Expand Down
20 changes: 16 additions & 4 deletions clang/lib/CodeGen/TargetInfo.cpp
Expand Up @@ -7797,8 +7797,16 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(

const auto *FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>();
if (ReqdWGS || FlatWGS) {
unsigned Min = FlatWGS ? FlatWGS->getMin() : 0;
unsigned Max = FlatWGS ? FlatWGS->getMax() : 0;
unsigned Min = 0;
unsigned Max = 0;
if (FlatWGS) {
Min = FlatWGS->getMin()
->EvaluateKnownConstInt(M.getContext())
.getExtValue();
Max = FlatWGS->getMax()
->EvaluateKnownConstInt(M.getContext())
.getExtValue();
}
if (ReqdWGS && Min == 0 && Max == 0)
Min = Max = ReqdWGS->getXDim() * ReqdWGS->getYDim() * ReqdWGS->getZDim();

Expand All @@ -7812,8 +7820,12 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
}

if (const auto *Attr = FD->getAttr<AMDGPUWavesPerEUAttr>()) {
unsigned Min = Attr->getMin();
unsigned Max = Attr->getMax();
unsigned Min =
Attr->getMin()->EvaluateKnownConstInt(M.getContext()).getExtValue();
unsigned Max = Attr->getMax() ? Attr->getMax()
->EvaluateKnownConstInt(M.getContext())
.getExtValue()
: 0;

if (Min != 0) {
assert((Max == 0 || Min <= Max) && "Min must be less than or equal Max");
Expand Down
126 changes: 92 additions & 34 deletions clang/lib/Sema/SemaDeclAttr.cpp
Expand Up @@ -245,11 +245,11 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
!Expr->isIntegerConstantExpr(I, S.Context)) {
if (Idx != UINT_MAX)
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
<< AI << Idx << AANT_ArgumentIntegerConstant
<< &AI << Idx << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
else
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type)
<< AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
<< &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
return false;
}

Expand All @@ -261,7 +261,7 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,

if (StrictlyUnsigned && I.isSigned() && I.isNegative()) {
S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer)
<< AI << /*non-negative*/ 1;
<< &AI << /*non-negative*/ 1;
return false;
}

Expand Down Expand Up @@ -5853,57 +5853,115 @@ static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
static bool
checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
const AMDGPUFlatWorkGroupSizeAttr &Attr) {
// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
return false;

uint32_t Min = 0;
Expr *MinExpr = AL.getArgAsExpr(0);
if (!checkUInt32Argument(S, AL, MinExpr, Min))
return;
if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
return true;

uint32_t Max = 0;
Expr *MaxExpr = AL.getArgAsExpr(1);
if (!checkUInt32Argument(S, AL, MaxExpr, Max))
return;
if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
return true;

if (Min == 0 && Max != 0) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0;
return;
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 0;
return true;
}
if (Min > Max) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
return;
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 1;
return true;
}

D->addAttr(::new (S.Context)
AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max,
AL.getAttributeSpellingListIndex()));
return false;
}

static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t Min = 0;
Expr *MinExpr = AL.getArgAsExpr(0);
if (!checkUInt32Argument(S, AL, MinExpr, Min))
void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D,
Expr *MinExpr, Expr *MaxExpr,
unsigned SpellingListIndex) {
AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
SpellingListIndex);

if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;

D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr(
AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex));
}

static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = AL.getArgAsExpr(1);

S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr,
AL.getAttributeSpellingListIndex());
}

static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
Expr *MaxExpr,
const AMDGPUWavesPerEUAttr &Attr) {
if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
(MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
return true;

// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
return false;

uint32_t Min = 0;
if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
return true;

uint32_t Max = 0;
if (AL.getNumArgs() == 2) {
Expr *MaxExpr = AL.getArgAsExpr(1);
if (!checkUInt32Argument(S, AL, MaxExpr, Max))
return;
}
if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
return true;

if (Min == 0 && Max != 0) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0;
return;
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 0;
return true;
}
if (Max != 0 && Min > Max) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
return;
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 1;
return true;
}

D->addAttr(::new (S.Context)
AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max,
AL.getAttributeSpellingListIndex()));
return false;
}

void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D,
Expr *MinExpr, Expr *MaxExpr,
unsigned SpellingListIndex) {
AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
SpellingListIndex);

if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;

D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr,
MaxExpr, SpellingListIndex));
}

static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkAttributeAtLeastNumArgs(S, AL, 1) ||
!checkAttributeAtMostNumArgs(S, AL, 2))
return;

Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;

S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr,
AL.getAttributeSpellingListIndex());
}

static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
57 changes: 57 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Expand Up @@ -344,6 +344,51 @@ static void instantiateOMPDeclareSimdDeclAttr(
Attr.getRange());
}

static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) {
// Both min and max expression are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);

ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MinExpr = Result.getAs<Expr>();

Result = S.SubstExpr(Attr.getMax(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MaxExpr = Result.getAs<Expr>();

S.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
Attr.getSpellingListIndex());
}

static void instantiateDependentAMDGPUWavesPerEUAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
// Both min and max expression are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);

ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MinExpr = Result.getAs<Expr>();

Expr *MaxExpr = nullptr;
if (auto Max = Attr.getMax()) {
Result = S.SubstExpr(Max, TemplateArgs);
if (Result.isInvalid())
return;
MaxExpr = Result.getAs<Expr>();
}

S.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
Attr.getSpellingListIndex());
}

void Sema::InstantiateAttrsForDecl(
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
Decl *New, LateInstantiatedAttrVec *LateAttrs,
Expand Down Expand Up @@ -437,6 +482,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}

if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) {
instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
*this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New);
}

if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) {
instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs,
*AMDGPUFlatWorkGroupSize, New);
}

// Existing DLL attribute on the instantiation takes precedence.
if (TmplAttr->getKind() == attr::DLLExport ||
TmplAttr->getKind() == attr::DLLImport) {
Expand Down

0 comments on commit 7557afa

Please sign in to comment.