Skip to content
Draft
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
100 changes: 64 additions & 36 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ static const unsigned SPIRDefIsGenMap[] = {

// Base class for SPIR and SPIR-V target info.
class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
protected:
std::unique_ptr<TargetInfo> HostTarget;

protected:
BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: TargetInfo(Triple) {
assert((Triple.isSPIR() || Triple.isSPIRV()) &&
Expand Down Expand Up @@ -164,6 +164,18 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();
ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();

// Copy pointer-related type representations from host so that
// sizeof(size_t), sizeof(ptrdiff_t), sizeof(intptr_t) match
// between host and device. Without this, LLP64 hosts (Windows)
// get incorrect LP64-style defaults.
SizeType = HostTarget->getSizeType();
PtrDiffType = HostTarget->getPtrDiffType(LangAS::Default);
IntPtrType = HostTarget->getIntPtrType();

// Inherit Microsoft C mangling if the host uses it.
if (HostTarget->shouldUseMicrosoftCCforMangling())
UseMicrosoftManglingForC = true;

// This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and
// we need those macros to be identical on host and device, because (among
// other things) they affect which standard library classes are defined,
Expand Down Expand Up @@ -191,6 +203,8 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
}

BuiltinVaListKind getBuiltinVaListKind() const override {
if (HostTarget)
return HostTarget->getBuiltinVaListKind();
return TargetInfo::VoidPtrBuiltinVaList;
}

Expand All @@ -200,8 +214,11 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
}

CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_SpirFunction || CC == CC_DeviceKernel) ? CCCR_OK
: CCCR_Warning;
if (CC == CC_SpirFunction || CC == CC_DeviceKernel)
return CCCR_OK;
if (HostTarget && HostTarget->checkCallingConvention(CC) == CCCR_OK)
return CCCR_OK;
return CCCR_Warning;
}

CallingConv getDefaultCallingConv() const override {
Expand Down Expand Up @@ -272,8 +289,10 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
assert(Triple.getArch() == llvm::Triple::spir &&
"Invalid architecture for 32-bit SPIR.");
PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
if (!HostTarget) {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
}
// SPIR32 has support for atomic ops if atomic extension is enabled.
// Take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
Expand All @@ -292,8 +311,10 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
assert(Triple.getArch() == llvm::Triple::spir64 &&
"Invalid architecture for 64-bit SPIR.");
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
if (!HostTarget) {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
}
// SPIR64 has support for atomic ops if atomic extension is enabled.
// Take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
Expand Down Expand Up @@ -369,51 +390,58 @@ class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
MacroBuilder &Builder) const override;
};

class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
// Common base for physical SPIR-V targets (spirv32/spirv64). Derives pointer
// width from the host target when available; defaults to 32 or 64 based on
// the target architecture.
class LLVM_LIBRARY_VISIBILITY SPIRVPhysicalTargetInfo
: public BaseSPIRVTargetInfo {
public:
SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
SPIRVPhysicalTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: BaseSPIRVTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spirv32 &&
"Invalid architecture for 32-bit SPIR-V.");
assert((Triple.getArch() == llvm::Triple::spirv32 ||
Triple.getArch() == llvm::Triple::spirv64) &&
"Invalid architecture for physical SPIR-V.");
assert((getTriple().getOS() == llvm::Triple::UnknownOS ||
getTriple().getOS() == llvm::Triple::ChipStar ||
getTriple().getOS() == llvm::Triple::Vulkan) &&
"32-bit SPIR-V target must use unknown, chipstar, or vulkan OS");
"Physical SPIR-V target must use unknown, chipstar, or vulkan OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"32-bit SPIR-V target must use unknown environment type");
PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
// SPIR-V has core support for atomic ops, and Int32 is always available;
// we take the maximum because it's possible the Host supports wider types.
"Physical SPIR-V target must use unknown environment type");

if (HostTarget) {
PointerWidth = PointerAlign =
HostTarget->getPointerWidth(LangAS::Default);
} else {
PointerWidth = PointerAlign =
(Triple.getArch() == llvm::Triple::spirv32) ? 32 : 64;
if (PointerWidth == 32) {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
} else {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
}
}
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
resetDataLayout();
}
};

class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo
: public SPIRVPhysicalTargetInfo {
public:
SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: SPIRVPhysicalTargetInfo(Triple, Opts) {}

void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
};

class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo
: public SPIRVPhysicalTargetInfo {
public:
SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: BaseSPIRVTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spirv64 &&
"Invalid architecture for 64-bit SPIR-V.");
assert((getTriple().getOS() == llvm::Triple::UnknownOS ||
getTriple().getOS() == llvm::Triple::ChipStar ||
getTriple().getOS() == llvm::Triple::Vulkan) &&
"64-bit SPIR-V target must use unknown, chipstar, or vulkan OS");
assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
"64-bit SPIR-V target must use unknown environment type");
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
// SPIR-V has core support for atomic ops, and Int64 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
resetDataLayout();
}
: SPIRVPhysicalTargetInfo(Triple, Opts) {}

void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
Expand Down
16 changes: 16 additions & 0 deletions clang/test/CodeGenSYCL/spirv-host-adaptation-mangling.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// Tests UseMicrosoftManglingForC inheritance from the Windows host target.

// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=WIN %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=LINUX %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown \
// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=LINUX %s

[[clang::sycl_external]] int square(int x) { return x * x; }
// WIN: define {{.*}} @_Z6squarei
// LINUX: define {{.*}} @_Z6squarei

extern "C" [[clang::sycl_external]] int cfunc(int x) { return x + 1; }
// WIN: define {{.*}} @cfunc
// LINUX: define {{.*}} @cfunc
23 changes: 23 additions & 0 deletions clang/test/CodeGenSYCL/spirv-host-adaptation-new.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// Tests operator new/delete mangling reflects the adapted SizeType.
/// Itanium mangling encodes the type name: _Znwm (unsigned long) vs _Znwy
/// (unsigned long long), even though both are 64-bit.

// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=WIN %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=LINUX %s

typedef __SIZE_TYPE__ size_t;

[[clang::sycl_external]] void *operator new(size_t n);
[[clang::sycl_external]] void operator delete(void *p, size_t n) noexcept;

[[clang::sycl_external]] void foo() {
int *p = new int;
delete p;
}

// WIN: declare {{.*}} @_Znwy(i64 noundef)
// WIN: declare {{.*}} @_ZdlPvy(ptr addrspace(4) noundef, i64 noundef)
// LINUX: declare {{.*}} @_Znwm(i64 noundef)
// LINUX: declare {{.*}} @_ZdlPvm(ptr addrspace(4) noundef, i64 noundef)
33 changes: 33 additions & 0 deletions clang/test/Preprocessor/spir-target-host-adaptation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// Tests legacy SPIR target adaptation of type properties from the host.

// RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR64-LINUX %s
// RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR64-WIN %s
// RUN: %clang_cc1 -triple spir-unknown-unknown -aux-triple i386-unknown-linux-gnu \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR32-LINUX %s
// RUN: %clang_cc1 -triple spir64-unknown-unknown \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR64-NOHOST %s

// SPIR64 + Linux (LP64)
// SPIR64-LINUX-DAG: #define __SIZE_TYPE__ long unsigned int
// SPIR64-LINUX-DAG: #define __PTRDIFF_TYPE__ long int
// SPIR64-LINUX-DAG: #define __INTPTR_TYPE__ long int
// SPIR64-LINUX-DAG: #define __SIZEOF_LONG__ 8

// SPIR64 + Windows (LLP64)
// SPIR64-WIN-DAG: #define __SIZE_TYPE__ long long unsigned int
// SPIR64-WIN-DAG: #define __PTRDIFF_TYPE__ long long int
// SPIR64-WIN-DAG: #define __INTPTR_TYPE__ long long int
// SPIR64-WIN-DAG: #define __SIZEOF_LONG__ 4

// SPIR32 + Linux i386 (ILP32)
// SPIR32-LINUX-DAG: #define __SIZE_TYPE__ unsigned int
// SPIR32-LINUX-DAG: #define __PTRDIFF_TYPE__ int
// SPIR32-LINUX-DAG: #define __INTPTR_TYPE__ int
// SPIR32-LINUX-DAG: #define __SIZEOF_POINTER__ 4

// SPIR64 no host (defaults)
// SPIR64-NOHOST-DAG: #define __SIZE_TYPE__ long unsigned int
// SPIR64-NOHOST-DAG: #define __PTRDIFF_TYPE__ long int
// SPIR64-NOHOST-DAG: #define __INTPTR_TYPE__ long int
12 changes: 12 additions & 0 deletions clang/test/Preprocessor/spirv-host-adaptation-valist.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// Tests that SPIRV64 compiles with different getBuiltinVaListKind() delegations.

// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=LINUX %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=WIN %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=NOHOST %s

// LINUX: #define __SPIRV64__ 1
// WIN: #define __SPIRV64__ 1
// NOHOST: #define __SPIRV64__ 1
70 changes: 70 additions & 0 deletions clang/test/Preprocessor/spirv-target-host-adaptation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/// Tests SPIR-V device target adaptation of SizeType, PtrDiffType, and
/// IntPtrType from the host target via -aux-triple.

// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=LINUX64 %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=WIN64 %s
// RUN: %clang_cc1 -triple spirv32-unknown-unknown -aux-triple i386-unknown-linux-gnu \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=LINUX32 %s
// RUN: %clang_cc1 -triple spirv64-unknown-unknown \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=NOHOST64 %s
// RUN: %clang_cc1 -triple spirv32-unknown-unknown \
// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=NOHOST32 %s

// Linux x86_64 host (LP64)
// LINUX64-DAG: #define __SIZE_TYPE__ long unsigned int
// LINUX64-DAG: #define __PTRDIFF_TYPE__ long int
// LINUX64-DAG: #define __INTPTR_TYPE__ long int
// LINUX64-DAG: #define __SIZEOF_SIZE_T__ 8
// LINUX64-DAG: #define __SIZEOF_PTRDIFF_T__ 8
// LINUX64-DAG: #define __SIZEOF_LONG__ 8
// LINUX64-DAG: #define __SIZEOF_POINTER__ 8

// Windows x86_64 host (LLP64)
// WIN64-DAG: #define __SIZE_TYPE__ long long unsigned int
// WIN64-DAG: #define __PTRDIFF_TYPE__ long long int
// WIN64-DAG: #define __INTPTR_TYPE__ long long int
// WIN64-DAG: #define __SIZEOF_SIZE_T__ 8
// WIN64-DAG: #define __SIZEOF_PTRDIFF_T__ 8
// WIN64-DAG: #define __SIZEOF_LONG__ 4
// WIN64-DAG: #define __SIZEOF_POINTER__ 8

// Linux i386 host (ILP32)
// LINUX32-DAG: #define __SIZE_TYPE__ unsigned int
// LINUX32-DAG: #define __PTRDIFF_TYPE__ int
// LINUX32-DAG: #define __INTPTR_TYPE__ int
// LINUX32-DAG: #define __SIZEOF_SIZE_T__ 4
// LINUX32-DAG: #define __SIZEOF_PTRDIFF_T__ 4
// LINUX32-DAG: #define __SIZEOF_POINTER__ 4

// No host (SPIRV64 defaults)
// NOHOST64-DAG: #define __SIZE_TYPE__ long unsigned int
// NOHOST64-DAG: #define __PTRDIFF_TYPE__ long int
// NOHOST64-DAG: #define __INTPTR_TYPE__ long int
// NOHOST64-DAG: #define __SIZEOF_SIZE_T__ 8
// NOHOST64-DAG: #define __SIZEOF_PTRDIFF_T__ 8
// NOHOST64-DAG: #define __SIZEOF_POINTER__ 8

// No host (SPIRV32 defaults)
// NOHOST32-DAG: #define __SIZE_TYPE__ unsigned int
// NOHOST32-DAG: #define __PTRDIFF_TYPE__ int
// NOHOST32-DAG: #define __INTPTR_TYPE__ int
// NOHOST32-DAG: #define __SIZEOF_SIZE_T__ 4
// NOHOST32-DAG: #define __SIZEOF_PTRDIFF_T__ 4
// NOHOST32-DAG: #define __SIZEOF_POINTER__ 4

// Aux-target OS macros
// WIN64-DAG: #define _WIN32 1
// WIN64-DAG: #define _WIN64 1
// LINUX64-DAG: #define __linux__ 1

// SPIRV device macros always present
// LINUX64-DAG: #define __SPIRV__ 1
// LINUX64-DAG: #define __SPIRV64__ 1
// WIN64-DAG: #define __SPIRV__ 1
// WIN64-DAG: #define __SPIRV64__ 1
// NOHOST64-DAG: #define __SPIRV__ 1
// NOHOST64-DAG: #define __SPIRV64__ 1
// NOHOST32-DAG: #define __SPIRV__ 1
// NOHOST32-DAG: #define __SPIRV32__ 1
8 changes: 8 additions & 0 deletions clang/test/SemaSYCL/sycl-spirv-cconv-nohost.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// Tests that SPIRV64 warns on non-SPIR-V calling conventions without a host.

// RUN: %clang_cc1 -fsycl-is-device \
// RUN: -triple spirv64-unknown-unknown \
// RUN: -fsyntax-only -verify %s

void __vectorcall vector_func(float x, float y) {} // expected-warning {{'__vectorcall' calling convention is not supported for this target}}
void default_func(int x) {}
18 changes: 18 additions & 0 deletions clang/test/SemaSYCL/sycl-spirv-cconv-win.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// Tests that SPIRV64 accepts Windows calling conventions with Windows aux-triple.

// RUN: %clang_cc1 -fsycl-is-device \
// RUN: -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsyntax-only -verify %s

// expected-no-diagnostics

void __vectorcall vector_func(float x, float y) {}
void __regcall regcall_func(int x) {}
void __stdcall stdcall_func(int x) {}
void default_func(int x) {}

typedef void (__vectorcall *VecFnPtr)(float, float);
typedef void (__regcall *RegFnPtr)(int);

VecFnPtr vfp = &vector_func;
RegFnPtr rfp = &regcall_func;
18 changes: 18 additions & 0 deletions clang/test/SemaSYCL/sycl-spirv-host-adaptation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// Tests SPIRV64 with Windows MSVC aux-triple: LLP64 type sizes.
// RUN: %clang_cc1 -fsycl-is-device \
// RUN: -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \
// RUN: -fsyntax-only -verify %s

// expected-no-diagnostics

static_assert(sizeof(void *) == 8, "pointer should be 64-bit on spirv64");
static_assert(sizeof(long) == 4, "long should be 32-bit with Windows aux-triple");

typedef __SIZE_TYPE__ size_t_type;
static_assert(sizeof(size_t_type) == 8, "size_t must be 64-bit on Win64 SPIRV64");

typedef __PTRDIFF_TYPE__ ptrdiff_t_type;
static_assert(sizeof(ptrdiff_t_type) == 8, "ptrdiff_t must be 64-bit on Win64 SPIRV64");

typedef __INTPTR_TYPE__ intptr_t_type;
static_assert(sizeof(intptr_t_type) == 8, "intptr_t must be 64-bit on Win64 SPIRV64");