Skip to content

Commit

Permalink
Merge from 'sycl' to 'sycl-web' (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
iclsrc committed Dec 18, 2020
2 parents 317f72b + d4251e3 commit a631a0f
Show file tree
Hide file tree
Showing 31 changed files with 999 additions and 205 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1311,7 +1311,7 @@ def SYCLIntelMaxGlobalWorkDim : InheritableAttr {
def SYCLIntelNoGlobalWorkOffset : InheritableAttr {
let Spellings = [CXX11<"intelfpga","no_global_work_offset">,
CXX11<"intel","no_global_work_offset">];
let Args = [BoolArgument<"Enabled", 1>];
let Args = [ExprArgument<"Value", /*optional*/1>];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [SYCLIntelNoGlobalWorkOffsetAttrDocs];
Expand Down
4 changes: 1 addition & 3 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -669,10 +669,8 @@ def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">;
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
def UnknownAttributes : DiagGroup<"unknown-attributes">;
def IgnoredAttributes : DiagGroup<"ignored-attributes">;
def AdjustedAttributes : DiagGroup<"adjusted-attributes">;
def Attributes : DiagGroup<"attributes", [UnknownAttributes,
IgnoredAttributes,
AdjustedAttributes]>;
IgnoredAttributes]>;
def UnknownSanitizers : DiagGroup<"unknown-sanitizers">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
[CXX98CompatUnnamedTypeTemplateArgs]>;
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -11170,9 +11170,6 @@ def err_sycl_function_attribute_mismatch : Error<
"SYCL kernel without %0 attribute can't call a function with this attribute">;
def err_sycl_x_y_z_arguments_must_be_one : Error<
"%0 X-, Y- and Z- sizes must be 1 when %1 attribute is used with value 0">;
def warn_boolean_attribute_argument_is_not_valid: Warning<
"The value of %0 attribute should be 0 or 1. Adjusted to 1">,
InGroup<AdjustedAttributes>;
def err_sycl_attibute_cannot_be_applied_here
: Error<"%0 attribute cannot be applied to a "
"static function or function in an anonymous namespace">;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ class SYCLIntegrationHeader {
/// Registers a specialization constant to emit info for it into the header.
void addSpecConstant(StringRef IDName, QualType IDType);

/// Notes that this_item is called within the kernel.
void setCallsThisItem(bool B);

private:
// Kernel actual parameter descriptor.
struct KernelParamDesc {
Expand Down Expand Up @@ -382,6 +385,9 @@ class SYCLIntegrationHeader {
/// Descriptor of kernel actual parameters.
SmallVector<KernelParamDesc, 8> Params;

// Whether kernel calls this_item()
bool CallsThisItem;

KernelDesc() = default;
};

Expand Down
7 changes: 6 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,12 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,

if (const SYCLIntelNoGlobalWorkOffsetAttr *A =
FD->getAttr<SYCLIntelNoGlobalWorkOffsetAttr>()) {
if (A->getEnabled())
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");
if (ArgVal->getBoolValue())
Fn->setMetadata("no_global_work_offset", llvm::MDNode::get(Context, {}));
}

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3970,10 +3970,9 @@ class OffloadingActionBuilder final {

bool NoDeviceLibs = false;
int NumOfDeviceLibLinked = 0;
// Currently, libc, libm-fp32 will be linked in by default. In order
// to use libm-fp64, -fsycl-device-lib=libm-fp64/all should be used.
// Currently, all SYCL device libraries will be linked by default
llvm::StringMap<bool> devicelib_link_info = {
{"libc", true}, {"libm-fp32", true}, {"libm-fp64", false}};
{"libc", true}, {"libm-fp32", true}, {"libm-fp64", true}};
if (Arg *A = Args.getLastArg(options::OPT_fsycl_device_lib_EQ,
options::OPT_fno_sycl_device_lib_EQ)) {
if (A->getValues().size() == 0)
Expand Down
20 changes: 7 additions & 13 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5351,24 +5351,18 @@ static void handleNoGlobalWorkOffsetAttr(Sema &S, Decl *D,

checkForDuplicateAttribute<SYCLIntelNoGlobalWorkOffsetAttr>(S, D, Attr);

uint32_t Enabled = 1;
if (Attr.getNumArgs()) {
const Expr *E = Attr.getArgAsExpr(0);
if (!checkUInt32Argument(S, Attr, E, Enabled, 0,
/*StrictlyUnsigned=*/true))
return;
}
if (Enabled > 1)
S.Diag(Attr.getLoc(), diag::warn_boolean_attribute_argument_is_not_valid)
<< Attr;

if (Attr.getKind() == ParsedAttr::AT_SYCLIntelNoGlobalWorkOffset &&
checkDeprecatedSYCLAttributeSpelling(S, Attr))
S.Diag(Attr.getLoc(), diag::note_spelling_suggestion)
<< "'intel::no_global_work_offset'";

D->addAttr(::new (S.Context)
SYCLIntelNoGlobalWorkOffsetAttr(S.Context, Attr, Enabled));
// If no attribute argument is specified, set to default value '1'.
Expr *E = Attr.isArgExpr(0)
? Attr.getArgAsExpr(0)
: IntegerLiteral::Create(S.Context, llvm::APInt(32, 1),
S.Context.IntTy, Attr.getLoc());
S.addIntelSYCLSingleArgFunctionAttr<SYCLIntelNoGlobalWorkOffsetAttr>(D, Attr,
E);
}

/// Handle the [[intelfpga::doublepump]] and [[intelfpga::singlepump]] attributes.
Expand Down
152 changes: 116 additions & 36 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,23 @@ class Util {
/// \param Tmpl whether the class is template instantiation or simple record
static bool isSyclType(const QualType &Ty, StringRef Name, bool Tmpl = false);

/// Checks whether given function is a standard SYCL API function with given
/// name.
/// \param FD the function being checked.
/// \param Name the function name to be checked against.
static bool isSyclFunction(const FunctionDecl *FD, StringRef Name);

/// Checks whether given clang type is a full specialization of the SYCL
/// specialization constant class.
static bool isSyclSpecConstantType(const QualType &Ty);

// Checks declaration context hierarchy.
/// \param DC the context of the item to be checked.
/// \param Scopes the declaration scopes leading from the item context to the
/// translation unit (excluding the latter)
static bool matchContext(const DeclContext *DC,
ArrayRef<Util::DeclContextDesc> Scopes);

/// Checks whether given clang type is declared in the given hierarchy of
/// declaration contexts.
/// \param Ty the clang type being checked
Expand Down Expand Up @@ -165,38 +178,14 @@ static bool IsSyclMathFunc(unsigned BuiltinID) {
case Builtin::BI__builtin_truncl:
case Builtin::BIlroundl:
case Builtin::BI__builtin_lroundl:
case Builtin::BIcopysign:
case Builtin::BI__builtin_copysign:
case Builtin::BIfloor:
case Builtin::BI__builtin_floor:
case Builtin::BIfmax:
case Builtin::BI__builtin_fmax:
case Builtin::BIfmin:
case Builtin::BI__builtin_fmin:
case Builtin::BInearbyint:
case Builtin::BI__builtin_nearbyint:
case Builtin::BIrint:
case Builtin::BI__builtin_rint:
case Builtin::BIround:
case Builtin::BI__builtin_round:
case Builtin::BItrunc:
case Builtin::BI__builtin_trunc:
case Builtin::BIcopysignf:
case Builtin::BI__builtin_copysignf:
case Builtin::BIfloorf:
case Builtin::BI__builtin_floorf:
case Builtin::BIfmaxf:
case Builtin::BI__builtin_fmaxf:
case Builtin::BIfminf:
case Builtin::BI__builtin_fminf:
case Builtin::BInearbyintf:
case Builtin::BI__builtin_nearbyintf:
case Builtin::BIrintf:
case Builtin::BI__builtin_rintf:
case Builtin::BIroundf:
case Builtin::BI__builtin_roundf:
case Builtin::BItruncf:
case Builtin::BI__builtin_truncf:
case Builtin::BIlroundf:
case Builtin::BI__builtin_lroundf:
case Builtin::BI__builtin_fpclassify:
Expand Down Expand Up @@ -511,6 +500,21 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
FunctionDecl *FD = WorkList.back().first;
FunctionDecl *ParentFD = WorkList.back().second;

// To implement rounding-up of a parallel-for range the
// SYCL header implementation modifies the kernel call like this:
// auto Wrapper = [=](TransformedArgType Arg) {
// if (Arg[0] >= NumWorkItems[0])
// return;
// Arg.set_allowed_range(NumWorkItems);
// KernelFunc(Arg);
// };
//
// This transformation leads to a condition where a kernel body
// function becomes callable from a new kernel body function.
// Hence this test.
if ((ParentFD == KernelBody) && isSYCLKernelBodyFunction(FD))
KernelBody = FD;

if ((ParentFD == SYCLKernel) && isSYCLKernelBodyFunction(FD)) {
assert(!KernelBody && "inconsistent call graph - only one kernel body "
"function can be called");
Expand Down Expand Up @@ -2691,15 +2695,63 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler {
return !SemaRef.getASTContext().hasSameType(FD->getType(), Ty);
}

// Sets a flag if the kernel is a parallel_for that calls the
// free function API "this_item".
void setThisItemIsCalled(const CXXRecordDecl *KernelObj,
FunctionDecl *KernelFunc) {
if (getKernelInvocationKind(KernelFunc) != InvokeParallelFor)
return;

const CXXMethodDecl *WGLambdaFn = getOperatorParens(KernelObj);
if (!WGLambdaFn)
return;

// The call graph for this translation unit.
CallGraph SYCLCG;
SYCLCG.addToCallGraph(SemaRef.getASTContext().getTranslationUnitDecl());
using ChildParentPair =
std::pair<const FunctionDecl *, const FunctionDecl *>;
llvm::SmallPtrSet<const FunctionDecl *, 16> Visited;
llvm::SmallVector<ChildParentPair, 16> WorkList;
WorkList.push_back({WGLambdaFn, nullptr});

while (!WorkList.empty()) {
const FunctionDecl *FD = WorkList.back().first;
WorkList.pop_back();
if (!Visited.insert(FD).second)
continue; // We've already seen this Decl

// Check whether this call is to sycl::this_item().
if (Util::isSyclFunction(FD, "this_item")) {
Header.setCallsThisItem(true);
return;
}

CallGraphNode *N = SYCLCG.getNode(FD);
if (!N)
continue;

for (const CallGraphNode *CI : *N) {
if (auto *Callee = dyn_cast<FunctionDecl>(CI->getDecl())) {
Callee = Callee->getMostRecentDecl();
if (!Visited.count(Callee))
WorkList.push_back({Callee, FD});
}
}
}
}

public:
static constexpr const bool VisitInsideSimpleContainers = false;
SyclKernelIntHeaderCreator(Sema &S, SYCLIntegrationHeader &H,
const CXXRecordDecl *KernelObj, QualType NameType,
StringRef Name, StringRef StableName)
StringRef Name, StringRef StableName,
FunctionDecl *KernelFunc)
: SyclKernelFieldHandler(S), Header(H) {
bool IsSIMDKernel = isESIMDKernelType(KernelObj);
Header.startKernel(Name, NameType, StableName, KernelObj->getLocation(),
IsSIMDKernel);
setThisItemIsCalled(KernelObj, KernelFunc);
}

bool handleSyclAccessorType(const CXXRecordDecl *RD,
Expand Down Expand Up @@ -3147,7 +3199,7 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc,
SyclKernelIntHeaderCreator int_header(
*this, getSyclIntegrationHeader(), KernelObj,
calculateKernelNameType(Context, KernelCallerFunc), KernelName,
StableName);
StableName, KernelCallerFunc);

KernelObjVisitor Visitor{*this};
Visitor.VisitRecordBases(KernelObj, kernel_decl, kernel_body, int_header);
Expand Down Expand Up @@ -3866,6 +3918,9 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) {
O << " __SYCL_DLL_LOCAL\n";
O << " static constexpr bool isESIMD() { return " << K.IsESIMDKernel
<< "; }\n";
O << " __SYCL_DLL_LOCAL\n";
O << " static constexpr bool callsThisItem() { return ";
O << K.CallsThisItem << "; }\n";
O << "};\n";
CurStart += N;
}
Expand Down Expand Up @@ -3924,6 +3979,12 @@ void SYCLIntegrationHeader::addSpecConstant(StringRef IDName, QualType IDType) {
SpecConsts.emplace_back(std::make_pair(IDType, IDName.str()));
}

void SYCLIntegrationHeader::setCallsThisItem(bool B) {
KernelDesc *K = getCurKernelDesc();
assert(K && "no kernels");
K->CallsThisItem = B;
}

SYCLIntegrationHeader::SYCLIntegrationHeader(DiagnosticsEngine &_Diag,
bool _UnnamedLambdaSupport,
Sema &_S)
Expand Down Expand Up @@ -3991,6 +4052,21 @@ bool Util::isSyclType(const QualType &Ty, StringRef Name, bool Tmpl) {
return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::isSyclFunction(const FunctionDecl *FD, StringRef Name) {
if (!FD->isFunctionOrMethod() || !FD->getIdentifier() ||
FD->getName().empty() || Name != FD->getName())
return false;

const DeclContext *DC = FD->getDeclContext();
if (DC->isTranslationUnit())
return false;

std::array<DeclContextDesc, 2> Scopes = {
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "cl"},
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "sycl"}};
return matchContext(DC, Scopes);
}

bool Util::isAccessorPropertyListType(const QualType &Ty) {
const StringRef &Name = "accessor_property_list";
std::array<DeclContextDesc, 4> Scopes = {
Expand All @@ -4001,21 +4077,15 @@ bool Util::isAccessorPropertyListType(const QualType &Ty) {
return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::matchQualifiedTypeName(const QualType &Ty,
ArrayRef<Util::DeclContextDesc> Scopes) {
// The idea: check the declaration context chain starting from the type
bool Util::matchContext(const DeclContext *Ctx,
ArrayRef<Util::DeclContextDesc> Scopes) {
// The idea: check the declaration context chain starting from the item
// itself. At each step check the context is of expected kind
// (namespace) and name.
const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl();

if (!RecTy)
return false; // only classes/structs supported
const auto *Ctx = cast<DeclContext>(RecTy);
StringRef Name = "";

for (const auto &Scope : llvm::reverse(Scopes)) {
clang::Decl::Kind DK = Ctx->getDeclKind();

if (DK != Scope.first)
return false;

Expand All @@ -4029,11 +4099,21 @@ bool Util::matchQualifiedTypeName(const QualType &Ty,
Name = cast<NamespaceDecl>(Ctx)->getName();
break;
default:
llvm_unreachable("matchQualifiedTypeName: decl kind not supported");
llvm_unreachable("matchContext: decl kind not supported");
}
if (Name != Scope.second)
return false;
Ctx = Ctx->getParent();
}
return Ctx->isTranslationUnit();
}

bool Util::matchQualifiedTypeName(const QualType &Ty,
ArrayRef<Util::DeclContextDesc> Scopes) {
const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl();

if (!RecTy)
return false; // only classes/structs supported
const auto *Ctx = cast<DeclContext>(RecTy);
return Util::matchContext(Ctx, Scopes);
}
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
*this, TemplateArgs, SYCLIntelMaxGlobalWorkDim, New);
continue;
}
if (const auto *SYCLIntelNoGlobalWorkOffset =
dyn_cast<SYCLIntelNoGlobalWorkOffsetAttr>(TmplAttr)) {
instantiateIntelSYCLFunctionAttr<SYCLIntelNoGlobalWorkOffsetAttr>(
*this, TemplateArgs, SYCLIntelNoGlobalWorkOffset, New);
continue;
}
// Existing DLL attribute on the instantiation takes precedence.
if (TmplAttr->getKind() == attr::DLLExport ||
TmplAttr->getKind() == attr::DLLImport) {
Expand Down
12 changes: 12 additions & 0 deletions clang/test/CodeGenSYCL/Inputs/sycl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ struct id {
int Data;
};

template <int dim> struct item {
template <typename... T>
item(T... args) {} // fake constructor
private:
// Some fake field added to see using of item arguments in the
// kernel wrapper
int Data;
};

template <int Dims> item<Dims>
this_item() { return item<Dims>{}; }

template <int dim>
struct range {
template <typename... T>
Expand Down
Loading

0 comments on commit a631a0f

Please sign in to comment.