Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ class MangleContext {
virtual void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl,
raw_ostream &Out) = 0;

/// SYCL kernel caller functions have names equivalent to a function template
/// specialization named "__sycl_kernel_caller" that has a single type
/// template argument, a void return type, and no parameters.
virtual void mangleSYCLKernelCallerName(QualType KernelNameType,
raw_ostream &Out) = 0;

/// Generates a unique string for an externally visible type for use with TBAA
/// or type uniquing.
/// TODO: Extend this to internal types by generating names that are unique
Expand Down
44 changes: 42 additions & 2 deletions clang/include/clang/AST/SYCLKernelInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,62 @@

namespace clang {

enum class kernel_param_kind_t : int {
kind_accessor = 0,
kind_std_layout = 1,
kind_sampler = 2,
kind_pointer = 3,
kind_specialization_constants_buffer = 4,
kind_stream = 5,
kind_invalid = 0xf, // not a valid kernel kind
};

class SYCLKernelInfo {
public:
SYCLKernelInfo(CanQualType KernelNameType,
const FunctionDecl *KernelEntryPointDecl)
const FunctionDecl *KernelEntryPointDecl,
const std::string &KernelName)
: KernelNameType(KernelNameType),
KernelEntryPointDecl(KernelEntryPointDecl) {}
KernelEntryPointDecl(KernelEntryPointDecl),
KernelName(KernelName) {}

CanQualType getKernelNameType() const { return KernelNameType; }

const FunctionDecl *getKernelEntryPointDecl() const {
return KernelEntryPointDecl;
}

const std::string& GetKernelName() const {
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 = kernel_param_kind_t::kind_invalid;
QualType Type;
KernelParamDesc() = default;
};

CanQualType KernelNameType;
const FunctionDecl *KernelEntryPointDecl;
std::string KernelName;
SmallVector<KernelParamDesc, 8> Params;
};

} // namespace clang
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum LanguageID : uint16_t {
OCL_DSE = 0x400, // builtin requires OpenCL device side enqueue.
ALL_OCL_LANGUAGES = 0x800, // builtin for OCL languages.
HLSL_LANG = 0x1000, // builtin requires HLSL.
SYCL_LANG = 0x2000, // builtin requires SYCL.
ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages.
ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode.
ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode.
Expand Down
61 changes: 61 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4764,6 +4764,67 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
let Prototype = "char const*(...)";
}

// SYCL
def SYCLKernelName : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_name"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "char const*(...)";
}

def SYCLKernelParamCount : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_param_count"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "int(...)";
}

def SYCLKernelParamKind : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_param_kind"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "int(...)";
}

def SYCLKernelParamSize : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_param_size"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "int(...)";
}

def SYCLKernelParamOffset : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_param_offset"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "int(...)";
}

def SYCLKernelParamAccessTarget : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_param_access_target"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "int(...)";
}

def SYCLKernelFileName : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_file_name"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "char const*(...)";
}

def SYCLKernelFunctionName : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_function_name"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "char const*(...)";
}

def SYCLKernelLineNumber : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_line_number"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "unsigned int(...)";
}

def SYCLKernelColumnNumber : LangBuiltin<"SYCL_LANG"> {
let Spellings = ["__builtin_sycl_kernel_column_number"];
let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking];
let Prototype = "unsigned int(...)";
}

// HLSL
def HLSLAddUint64: LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_adduint64"];
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,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>;
Expand Down Expand Up @@ -12586,6 +12589,13 @@ def err_sycl_entry_point_deduced_return_type : Error<
"'sycl_kernel_entry_point' attribute only applies to functions with a"
" non-deduced 'void' return type">;

// SYCL builtins diagnostics
def err_builtin_invalid_argument : Error<"invalid argument; argument must be a class or struct type"
" with a member type alias named 'type'">;
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'">;

def warn_cuda_maxclusterrank_sm_90 : Warning<
"maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
"%1 attribute">, InGroup<IgnoredAttributes>;
Expand Down
85 changes: 81 additions & 4 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12790,6 +12790,22 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (!FD->doesThisDeclarationHaveABody())
return FD->doesDeclarationForceExternallyVisibleDefinition();

// SYCL kernel entry point functions are used to generate and emit
// the offload kernel.
if (LangOpts.SYCLIsDevice) {
if (D->hasAttr<SYCLKernelEntryPointAttr>())
return true;
// FIXME: In SYCL device compilation, the only functions that
// must be emitted are the SYCL kernel entry points, functions
// called from the the SYCL kernel, and functions declared with
// SYCL_EXTERNAL. However, some existing tests fail if the set
// of emitted functions is limited to these. Once support is
// implemented for SYCL_EXTERNAL, this check should be modified
// to return false. The tests should be modified to include
// SYCL_EXTERNAL.
// return false;
}

// Constructors and destructors are required.
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
Expand Down Expand Up @@ -14602,9 +14618,70 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
}
}

static SYCLKernelInfo BuildSYCLKernelInfo(CanQualType KernelNameType,
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
// FIXME: library is then responsible for dynamically resolving the name to
// FIXME: a function in a device image at run-time. At present, it is assumed
// FIXME: that the device ABI is based on the Itanium ABI and a corresponding
// FIXME: name is generated. However, if the device ABI is not based on the
// FIXME: Itanium ABI, this assumption leads to the existence of oddly named
// FIXME: functions relative to the device ABI. Further, this approach
// FIXME: requires that the same name be generated for every host and device
// FIXME: compilation which is difficult to ensure for context sensitive
// FIXME: "unnamed" types like lambda closure types. A better approach would
// FIXME: be to generate an ABI agnostic name and then emit a map with each
// FIXME: device compilation for the ABI dependent name. Alas, naming is hard
// FIXME: and defining an ABI agnostic naming scheme might devolve into
// FIXME: effectively re-creating a large subset of the Itanium ABI name
// FIXME: mangling scheme.

// Host and device compilation may use different ABIs and different ABIs may
// allocate discriminators differently. An override is needed to ensure
// consistent discriminators are allocated for host and device compilation.
auto DeviceDiscriminatorOverrider = [](ASTContext &Ctx, const NamedDecl *ND)
-> std::optional<unsigned> {
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
if (RD->isLambda())
return RD->getDeviceLambdaManglingNumber();
return std::nullopt;
};
std::unique_ptr<MangleContext> MC{ItaniumMangleContext::create(
Context, Context.getDiagnostics(), DeviceDiscriminatorOverrider)};

// Produce the mangled name.
std::string Buffer;
Buffer.reserve(128);
llvm::raw_string_ostream Out(Buffer);
MC->mangleSYCLKernelCallerName(KernelNameType, Out);
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(kernel_param_kind_t::kind_std_layout,
KernelParam->getType());
}
}

static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context,
CanQualType KernelNameType,
const FunctionDecl *FD) {
return {KernelNameType, FD};
// Get the mangled name.
std::string KernelCallerName =
GetSYCLKernelCallerName(Context, KernelNameType);

SYCLKernelInfo KernelInfo{KernelNameType, FD, KernelCallerName};

CreateSYCLKernelParamDesc(Context, FD, KernelInfo);

return KernelInfo;
}

void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
Expand All @@ -14625,8 +14702,8 @@ void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
declaresSameEntity(FD, IT->second.getKernelEntryPointDecl())) &&
"SYCL kernel name conflict");
(void)IT;
SYCLKernels.insert(
std::make_pair(KernelNameType, BuildSYCLKernelInfo(KernelNameType, FD)));
SYCLKernels.insert(std::make_pair(
KernelNameType, BuildSYCLKernelInfo(*this, KernelNameType, FD)));
}

const SYCLKernelInfo &ASTContext::getSYCLKernelInfo(QualType T) const {
Expand Down
Loading