Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -3123,6 +3123,7 @@ case CC_Swift: case CC_X86Pascal: case CC_IntelOclBicc: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -4829,6 +4830,7 @@ case CC_PreserveMost: case CC_PreserveAll: case CC_X86RegCall: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -4902,6 +4904,7 @@ case CC_X86_64SysV: case CC_Swift: case CC_X86RegCall: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -5854,6 +5857,7 @@ case CC_AAPCS: case CC_AAPCS_VFP: case CC_Swift: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -6013,6 +6017,7 @@ case CC_X86VectorCall: return CCCR_Ignore; case CC_C: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -6323,6 +6328,7 @@ case CC_Swift: case CC_PreserveMost: case CC_PreserveAll: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -7374,6 +7380,7 @@ switch (CC) { case CC_C: case CC_Swift: + case CC_OpenCLKernel: return CCCR_OK; default: return CCCR_Warning; @@ -7657,6 +7664,15 @@ ArrayRef getGCCRegAliases() const override { return None; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_OpenCLKernel: + return CCCR_OK; + } + } }; class MipsTargetInfo : public TargetInfo { Index: lib/CodeGen/ABIInfo.h =================================================================== --- lib/CodeGen/ABIInfo.h +++ lib/CodeGen/ABIInfo.h @@ -149,7 +149,6 @@ return info->supportsSwift(); } }; - } // end namespace CodeGen } // end namespace clang Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -707,6 +707,12 @@ signature.getRequiredArgs()); } +namespace clang { +namespace CodeGen { +void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI); +} +} + /// Arrange the argument and result information for an abstract value /// of a given function type. This is the method which all of the /// above functions ultimately defer to. @@ -741,12 +747,16 @@ bool inserted = FunctionsBeingProcessed.insert(FI).second; (void)inserted; assert(inserted && "Recursively being processed?"); - + // Compute ABI information. - if (info.getCC() != CC_Swift) { + if (CC == llvm::CallingConv::SPIR_KERNEL) { + // Force target independent argument handling for the host visible + // kernel functions. + computeSPIRKernelABIInfo(CGM, *FI); + } else if (info.getCC() == CC_Swift) { + swiftcall::computeABIInfo(CGM, *FI); + } else { getABIInfo().computeInfo(*FI); - } else { - swiftcall::computeABIInfo(CGM, *FI); } // Loop over all of the computed argument and return value info. If any of Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -398,7 +398,18 @@ } unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const { - return llvm::CallingConv::C; + // OpenCL kernels are called via an explicit runtime API with arguments + // set with clSetKernelArg(), not as normal sub-functions. + // Return SPIR_KERNEL by default as the kernel calling convention to + // ensure the fingerprint is fixed such way that each OpenCL argument + // gets one matching argument in the produced kernel function argument + // list to enable feasible implementation of clSetKernelArg() with + // aggregates etc. In case we would use the default C calling conv here, + // clSetKernelArg() might break depending on the target-specific + // conventions; different targets might split structs passed as values + // to multiple function arguments etc. + // See: https://github.com/pocl/pocl/issues/1 + return llvm::CallingConv::SPIR_KERNEL; } llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM, @@ -8038,8 +8049,18 @@ CodeGen::CodeGenModule &M) const override; unsigned getOpenCLKernelCallingConv() const override; }; + } // End anonymous namespace. +namespace clang { +namespace CodeGen { +void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { + DefaultABIInfo SPIRABI(CGM.getTypes()); + SPIRABI.computeInfo(FI); +} +} +} + /// Emit SPIR specific metadata: OpenCL and SPIR version. void SPIRTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3175,11 +3175,7 @@ for (const AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); Attr; Attr = Attr->getNext()) { if (Attr->getKind() == AttributeList::AT_OpenCLKernel) { - llvm::Triple::ArchType arch = S.Context.getTargetInfo().getTriple().getArch(); - if (arch == llvm::Triple::spir || arch == llvm::Triple::spir64 || - arch == llvm::Triple::amdgcn || arch == llvm::Triple::r600) { - CC = CC_OpenCLKernel; - } + CC = CC_OpenCLKernel; break; } } Index: test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl =================================================================== --- test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl +++ test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl @@ -0,0 +1,65 @@ +// Test that the kernels always use the SPIR calling convention +// to have unambiguous mapping of arguments to feasibly implement +// clSetKernelArg(). +// RUN: %clang_cc1 %s -cl-std=CL1.2 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=CL1.2 -emit-llvm -triple amdgcn-unknown-unknown -o - | FileCheck -check-prefixes=AMDGCN %s + +typedef struct int_single { + int a; +} int_single; + +typedef struct int_pair { + long a; + long b; +} int_pair; + +typedef struct test_struct { + int elementA; + int elementB; + long elementC; + char elementD; + long elementE; + float elementF; + short elementG; + double elementH; +} test_struct; + +kernel void test_single(int_single input, global int* output) { +// CHECK: spir_kernel +// AMDGCN: define amdgpu_kernel void @test_single +// CHECK: struct.int_single* byval nocapture +// CHECK: i32* nocapture %output + output[0] = input.a; +} + +kernel void test_pair(int_pair input, global int* output) { +// CHECK: spir_kernel +// AMDGCN: define amdgpu_kernel void @test_pair +// CHECK: struct.int_pair* byval nocapture +// CHECK: i32* nocapture %output + output[0] = (int)input.a; + output[1] = (int)input.b; +} + +kernel void test_kernel(test_struct input, global int* output) { +// CHECK: spir_kernel +// AMDGCN: define amdgpu_kernel void @test_kernel +// CHECK: struct.test_struct* byval nocapture +// CHECK: i32* nocapture %output + output[0] = input.elementA; + output[1] = input.elementB; + output[2] = (int)input.elementC; + output[3] = (int)input.elementD; + output[4] = (int)input.elementE; + output[5] = (int)input.elementF; + output[6] = (int)input.elementG; + output[7] = (int)input.elementH; +}; + +void test_function(int_pair input, global int* output) { +// CHECK-NOT: spir_kernel +// AMDGCN-NOT: define amdgpu_kernel void @test_function +// CHECK: i64 %input.coerce0, i64 %input.coerce1, i32* nocapture %output + output[0] = (int)input.a; + output[1] = (int)input.b; +}