-
Notifications
You must be signed in to change notification settings - Fork 1
[SYCL] Builtin support + missing changes #42
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
base: sycl-upstream-fe
Are you sure you want to change the base?
Changes from all commits
bbbf20e
27f4840
250cbc9
e0504d5
e95f817
31831f2
3d08e3b
e9b255e
914bf9a
60d2caa
0f4b443
9b28367
582049a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,15 +21,25 @@ namespace clang { | |
|
||
class SYCLKernelInfo { | ||
public: | ||
SYCLKernelInfo( | ||
CanQualType KernelNameType, | ||
const FunctionDecl *KernelEntryPointDecl, | ||
const std::string &KernelName) | ||
: | ||
KernelNameType(KernelNameType), | ||
KernelEntryPointDecl(KernelEntryPointDecl), | ||
KernelName(KernelName) | ||
{} | ||
// FIXME: Added full enum to match the library implementation. | ||
// Why does kind_first and kind_last exist? | ||
enum kernel_param_kind_t { | ||
kind_first, | ||
kind_accessor = kind_first, | ||
kind_std_layout, | ||
kind_sampler, | ||
kind_pointer, | ||
kind_specialization_constants_buffer, | ||
kind_stream, | ||
kind_last = kind_stream | ||
}; | ||
|
||
public: | ||
SYCLKernelInfo(CanQualType KernelNameType, | ||
const FunctionDecl *KernelEntryPointDecl, | ||
const std::string &KernelName) | ||
: KernelNameType(KernelNameType), | ||
KernelEntryPointDecl(KernelEntryPointDecl), KernelName(KernelName) {} | ||
|
||
CanQualType GetKernelNameType() const { | ||
return KernelNameType; | ||
|
@@ -43,10 +53,33 @@ class SYCLKernelInfo { | |
return KernelName; | ||
} | ||
|
||
size_t GetParamCount() const { return Params.size(); } | ||
|
||
void addParamDesc(kernel_param_kind_t Kind, QualType Ty) { | ||
KernelParamDesc PD; | ||
PD.Kind = Kind; | ||
PD.Type = Ty; | ||
Params.push_back(PD); | ||
} | ||
|
||
const kernel_param_kind_t &GetParamKind(int i) const { | ||
return Params[i].Kind; | ||
} | ||
|
||
const QualType &GetParamTy(int i) const { return Params[i].Type; } | ||
|
||
private: | ||
// Kernel caller function parameter descriptor. | ||
struct KernelParamDesc { | ||
kernel_param_kind_t Kind = kind_last; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not have a good answer here. I just kept the implementation of the enum as it is in syclos. |
||
QualType Type; | ||
KernelParamDesc() = default; | ||
}; | ||
|
||
CanQualType KernelNameType; | ||
const FunctionDecl *KernelEntryPointDecl; | ||
std::string KernelName; | ||
SmallVector<KernelParamDesc, 8> Params; | ||
}; | ||
|
||
} // namespace clang | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -744,6 +744,9 @@ def warn_unreachable_association : Warning< | |||||||||||||
InGroup<UnreachableCodeGenericAssoc>; | ||||||||||||||
|
||||||||||||||
/// Built-in functions. | ||||||||||||||
def err_builtin_invalid_argument_count : Error< | ||||||||||||||
"builtin %plural{0:takes no arguments|1:takes one argument|" | ||||||||||||||
":requires exactly %0 arguments}0">; | ||||||||||||||
def ext_implicit_lib_function_decl : ExtWarn< | ||||||||||||||
"implicitly declaring library function '%0' with type %1">, | ||||||||||||||
InGroup<ImplicitFunctionDeclare>; | ||||||||||||||
|
@@ -12199,6 +12202,9 @@ def err_sycl_kernel_name_type : Error< | |||||||||||||
def err_sycl_kernel_name_conflict : Error< | ||||||||||||||
"'sycl_kernel_entry_point' kernel name argument conflicts with a previous" | ||||||||||||||
" declaration">; | ||||||||||||||
def err_sycl_kernel_name_invalid_arg : Error<"invalid argument; expected a class " | ||||||||||||||
"or structure with a member typedef " | ||||||||||||||
"or type alias alias named 'type'">; | ||||||||||||||
Comment on lines
+12205
to
+12207
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
def warn_cuda_maxclusterrank_sm_90 : Warning< | ||||||||||||||
"maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " | ||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -11994,8 +11994,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { | |||||||||||||||||||
|
||||||||||||||||||||
// SYCL kernel entry point functions are used to generate and emit | ||||||||||||||||||||
// the offload kernel. | ||||||||||||||||||||
if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelEntryPointAttr>()) | ||||||||||||||||||||
if (LangOpts.SYCLIsDevice) { | ||||||||||||||||||||
if (D->hasAttr<SYCLKernelEntryPointAttr>()) | ||||||||||||||||||||
return true; | ||||||||||||||||||||
// FIXME: Existing tests fail if we limit emission to the kernel caller | ||||||||||||||||||||
// function and functions called from it. Once the sycl_device attribute | ||||||||||||||||||||
// is implemented, modify this check (and tests) to include it and | ||||||||||||||||||||
// return false. | ||||||||||||||||||||
Comment on lines
+12000
to
+12003
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since I suspect more changes will be needed in this function. For example, should we be returning (I tend to prefix "FIXME" on every line of a FIXME comment so that a grep for FIXME yields the entire comment. It also helps to separate FIXME content from other content. Not everyone does this of course).
Suggested change
|
||||||||||||||||||||
// return false; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
// Constructors and destructors are required. | ||||||||||||||||||||
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) | ||||||||||||||||||||
|
@@ -13781,9 +13788,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, | |||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context, | ||||||||||||||||||||
CanQualType KernelNameType, | ||||||||||||||||||||
const FunctionDecl *FD) { | ||||||||||||||||||||
static std::string GetSYCLKernelCallerName(ASTContext &Context, | ||||||||||||||||||||
CanQualType KernelNameType) { | ||||||||||||||||||||
// FIXME: Host and device compilations must agree on a name for the generated | ||||||||||||||||||||
// FIXME: SYCL kernel caller function. The name is provided to the SYCL | ||||||||||||||||||||
// FIXME: library on the host via __builtin_sycl_kernel_name() and the SYCL | ||||||||||||||||||||
|
@@ -13820,9 +13826,32 @@ static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context, | |||||||||||||||||||
Buffer.reserve(128); | ||||||||||||||||||||
llvm::raw_string_ostream Out(Buffer); | ||||||||||||||||||||
MC->mangleSYCLKernelCallerName(KernelNameType, Out); | ||||||||||||||||||||
std::string KernelName = Out.str(); | ||||||||||||||||||||
return Out.str(); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
static void CreateSYCLKernelParamDesc(ASTContext &Ctx, const FunctionDecl *FD, | ||||||||||||||||||||
SYCLKernelInfo &KernelInfo) { | ||||||||||||||||||||
if (FD->getNumParams() == 0) | ||||||||||||||||||||
return; | ||||||||||||||||||||
|
||||||||||||||||||||
for (const ParmVarDecl *KernelParam : FD->parameters()) { | ||||||||||||||||||||
KernelInfo.addParamDesc(SYCLKernelInfo::kind_std_layout, | ||||||||||||||||||||
KernelParam->getType()); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context, | ||||||||||||||||||||
CanQualType KernelNameType, | ||||||||||||||||||||
const FunctionDecl *FD) { | ||||||||||||||||||||
// Get the mangled name. | ||||||||||||||||||||
std::string KernelCallerName = | ||||||||||||||||||||
GetSYCLKernelCallerName(Context, KernelNameType); | ||||||||||||||||||||
|
||||||||||||||||||||
SYCLKernelInfo KernelInfo{KernelNameType, FD, KernelCallerName}; | ||||||||||||||||||||
|
||||||||||||||||||||
CreateSYCLKernelParamDesc(Context, FD, KernelInfo); | ||||||||||||||||||||
|
||||||||||||||||||||
return { KernelNameType, FD, KernelName }; | ||||||||||||||||||||
return KernelInfo; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) { | ||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -30,6 +30,7 @@ | |||||||||
#include "clang/Basic/TargetBuiltins.h" | ||||||||||
#include "clang/Basic/TargetInfo.h" | ||||||||||
#include "clang/Basic/TargetOptions.h" | ||||||||||
#include "clang/Basic/IdentifierTable.h" | ||||||||||
#include "clang/CodeGen/CGFunctionInfo.h" | ||||||||||
#include "clang/Frontend/FrontendDiagnostic.h" | ||||||||||
#include "llvm/ADT/APFloat.h" | ||||||||||
|
@@ -2538,6 +2539,22 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF, | |||||||||
return RValue::get(CGF->Builder.CreateCall(UBF, Args)); | ||||||||||
} | ||||||||||
|
||||||||||
static const SYCLKernelInfo *GetSYCLKernelInfo(ASTContext &Ctx, | ||||||||||
const CallExpr *E) { | ||||||||||
// Argument to the builtin is a type trait which is used to retrieve the | ||||||||||
// kernel name type. | ||||||||||
// FIXME: Improve the comment. | ||||||||||
RecordDecl *RD = E->getArg(0)->getType()->castAs<RecordType>()->getDecl(); | ||||||||||
IdentifierTable &IdentTable = Ctx.Idents; | ||||||||||
auto Name = DeclarationName(&(IdentTable.get("type"))); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
NamedDecl *ND = (RD->lookup(Name)).front(); | ||||||||||
TypedefNameDecl *TD = cast<TypedefNameDecl>(ND); | ||||||||||
CanQualType KernelNameType = Ctx.getCanonicalType(TD->getUnderlyingType()); | ||||||||||
|
||||||||||
// Retrieve KernelInfo using the kernel name. | ||||||||||
return Ctx.findSYCLKernelInfo(KernelNameType); | ||||||||||
} | ||||||||||
|
||||||||||
RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, | ||||||||||
const CallExpr *E, | ||||||||||
ReturnValueSlot ReturnValue) { | ||||||||||
|
@@ -5992,6 +6009,81 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, | |||||||||
auto Str = CGM.GetAddrOfConstantCString(Name, ""); | ||||||||||
return RValue::get(Str.getPointer()); | ||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_name: { | ||||||||||
// Retrieve the kernel info corresponding to kernel name type. | ||||||||||
const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); | ||||||||||
assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); | ||||||||||
|
||||||||||
// Emit the mangled name. | ||||||||||
auto Str = CGM.GetAddrOfConstantCString(KernelInfo->GetKernelName(), ""); | ||||||||||
return RValue::get(Str.getPointer()); | ||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_param_count: { | ||||||||||
// Retrieve the kernel info corresponding to kernel name type. | ||||||||||
const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); | ||||||||||
assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); | ||||||||||
return RValue::get( | ||||||||||
llvm::ConstantInt::get(Int32Ty, KernelInfo->GetParamCount())); | ||||||||||
Comment on lines
+6025
to
+6026
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The builtin signature specifies that it returns
Suggested change
|
||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_param_kind: { | ||||||||||
// Retrieve the kernel info corresponding to kernel name type. | ||||||||||
const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); | ||||||||||
assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); | ||||||||||
// Emit total number of parameters of kernel caller function. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment doesn't match.
Suggested change
|
||||||||||
const Expr *ParamNoExpr = E->getArg(1); | ||||||||||
Expr::EvalResult Result; | ||||||||||
ParamNoExpr->EvaluateAsInt(Result, getContext()); | ||||||||||
unsigned ParamNo = Result.Val.getInt().getZExtValue(); | ||||||||||
Comment on lines
+6034
to
+6036
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is error checking needed here? Can the evaluation fail? What happens if the evaluation produces a negative number? It looks like that will get implicitly converted to an unsigned value that is likely to exceed the parameter count. |
||||||||||
return RValue::get( | ||||||||||
llvm::ConstantInt::get(Int32Ty, KernelInfo->GetParamKind(ParamNo))); | ||||||||||
Comment on lines
+6037
to
+6038
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The type here should match the underlying type of the
Suggested change
|
||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_param_size: { | ||||||||||
// Retrieve the kernel info corresponding to kernel name type. | ||||||||||
const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); | ||||||||||
assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); | ||||||||||
// Emit total number of parameters of kernel caller function. | ||||||||||
const Expr *ParamNoExpr = E->getArg(1); | ||||||||||
Expr::EvalResult Result; | ||||||||||
ParamNoExpr->EvaluateAsInt(Result, getContext()); | ||||||||||
unsigned ParamNo = Result.Val.getInt().getZExtValue(); | ||||||||||
QualType ParamTy = KernelInfo->GetParamTy(ParamNo); | ||||||||||
// FIXME: Add check to ensure complete type. | ||||||||||
return RValue::get(llvm::ConstantInt::get( | ||||||||||
Int32Ty, getContext().getTypeSizeInChars(ParamTy).getQuantity())); | ||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_param_offset: { | ||||||||||
// Retrieve the kernel info corresponding to kernel name type. | ||||||||||
const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); | ||||||||||
assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); | ||||||||||
// FIXME: Offset is used only when kernel object is decomposed to identify | ||||||||||
// offset of field in kernel object. What should the offset be for | ||||||||||
// additional non-kernel object parameters? | ||||||||||
return RValue::get(llvm::ConstantInt::get(Int32Ty, 0)); | ||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_param_access_target: { | ||||||||||
// FIXME: This is a dummy value. This builtin will be implemented when | ||||||||||
// support for special sycl types is implemented. | ||||||||||
return RValue::get(llvm::ConstantInt::get(Int32Ty, 0)); | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the above builtins that take a parameter index as an argument, we'll need to support the parameter index argument being a non-constant; see how Sergey implemented
There are a few implications of this.
|
||||||||||
case Builtin::BI__builtin_sycl_kernel_file_name: | ||||||||||
case Builtin::BI__builtin_sycl_kernel_function_name: { | ||||||||||
// FIXME: This is a dummy value. These builtins provide information | ||||||||||
// about the kernel object. In the new design, the we do not have | ||||||||||
// special status for the kernel object, so it is unclear what these | ||||||||||
// builtins should return, or if they even need to exist. Support will | ||||||||||
// be added or removed after investigation. | ||||||||||
auto Str = CGM.GetAddrOfConstantCString("DummyString", ""); | ||||||||||
return RValue::get(Str.getPointer()); | ||||||||||
} | ||||||||||
case Builtin::BI__builtin_sycl_kernel_line_number: | ||||||||||
case Builtin::BI__builtin_sycl_kernel_column_number: { | ||||||||||
// FIXME: This is a dummy value. These builtins provide information | ||||||||||
// about the kernel object. In the new design, the we do not have | ||||||||||
// special status for the kernel object, so it is unclear what these | ||||||||||
// builtins should return, or if they even need to exist. Support will | ||||||||||
// be added or removed after investigation. | ||||||||||
return RValue::get(llvm::ConstantInt::get(Int32Ty, 0)); | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Earlier comments apply to the above builtins as well. E.g., prefer |
||||||||||
} | ||||||||||
|
||||||||||
// If this is an alias for a lib function (e.g. __builtin_sin), emit | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the motivation for defining
kernel_param_kind_t
as a member ofSYCLKernelInfo
? I think it makes sense forKernelParamDesc
to be a member since it is just implementation detail, but since the enumeration is exposed as part of the interface, I think it would be more ergonomic to define it at namespace scope.The enumeration name and enumerators should be renamed to follow LLVM style. Perhaps
SYCLKernelParamKind
with the enumerators namesSKPK_*
(seePrimitiveCopyKind
andDestructionKind
as precedents). Alternatively, use ofenum class
would allow omitting theSKPK_
prefix (seeNonConstantStorageReason
andAutoTypeKeyword
as precedents).Since this enumeration is expected to match a definition in the SYCL run-time, it would be good to define an explicit underlying type for it; perhaps just
int8_t
.If we don't have a use for
kind_first
andkind_last
, they can be omitted for now.