diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index f5955c45fafc5..259da3f4c05b8 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -486,7 +486,13 @@ class Qualifiers { /// Returns true if the address space in these qualifiers is equal to or /// a superset of the address space in the argument qualifiers. bool isAddressSpaceSupersetOf(Qualifiers other) const { - return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace()); + return isAddressSpaceSupersetOf(getAddressSpace(), + other.getAddressSpace()) || + (!hasAddressSpace() && + (other.getAddressSpace() == LangAS::sycl_private || + other.getAddressSpace() == LangAS::sycl_local || + other.getAddressSpace() == LangAS::sycl_global || + other.getAddressSpace() == LangAS::sycl_constant)); } /// Determines if these qualifiers compatibly include another set. diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h index faf7f303aa2d6..aa0fff5e28b1d 100644 --- a/clang/include/clang/Basic/AddressSpaces.h +++ b/clang/include/clang/Basic/AddressSpaces.h @@ -42,6 +42,12 @@ enum class LangAS : unsigned { cuda_constant, cuda_shared, + // SYCL specific address spaces. + sycl_global, + sycl_local, + sycl_constant, + sycl_private, + // Pointer size and extension address spaces. ptr32_sptr, ptr32_uptr, diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index d9d8585970d99..5241d08545e65 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -515,8 +515,8 @@ class ParsedAttr final /// a Spelling enumeration, the value UINT_MAX is returned. unsigned getSemanticSpelling() const; - /// If this is an OpenCL addr space attribute returns its representation - /// in LangAS, otherwise returns default addr space. + /// If this is an OpenCL address space attribute returns its representation + /// in LangAS, otherwise returns default address space. LangAS asOpenCLLangAS() const { switch (getParsedKind()) { case ParsedAttr::AT_OpenCLConstantAddressSpace: @@ -534,6 +534,24 @@ class ParsedAttr final } } + /// If this is an OpenCL address space attribute returns its SYCL + /// representation in LangAS, otherwise returns default address space. + LangAS asSYCLLangAS() const { + switch (getKind()) { + case ParsedAttr::AT_OpenCLConstantAddressSpace: + return LangAS::sycl_constant; + case ParsedAttr::AT_OpenCLGlobalAddressSpace: + return LangAS::sycl_global; + case ParsedAttr::AT_OpenCLLocalAddressSpace: + return LangAS::sycl_local; + case ParsedAttr::AT_OpenCLPrivateAddressSpace: + return LangAS::sycl_private; + case ParsedAttr::AT_OpenCLGenericAddressSpace: + default: + return LangAS::Default; + } + } + AttributeCommonInfo::Kind getKind() const { return getParsedKind(); } }; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a09b1aca7c200..a4ff2a7895748 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -836,6 +836,10 @@ static const LangASMap *getAddressSpaceMap(const TargetInfo &T, 5, // cuda_device 6, // cuda_constant 7, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 2, // sycl_constant + 0, // sycl_private 8, // ptr32_sptr 9, // ptr32_uptr 10 // ptr64 diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0d567edac5216..d73ce7783f013 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2285,7 +2285,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp if (Context.getASTContext().addressSpaceMapManglingFor(AS)) { // ::= "AS" unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS); - if (TargetAS != 0) + if (TargetAS != 0 || (Context.getASTContext().getLangOpts().SYCLIsDevice)) ASString = "AS" + llvm::utostr(TargetAS); } else { switch (AS) { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 0228d637d018f..46c4de0b91c4d 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1777,12 +1777,16 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) { case LangAS::Default: return ""; case LangAS::opencl_global: + case LangAS::sycl_global: return "__global"; case LangAS::opencl_local: + case LangAS::sycl_local: return "__local"; case LangAS::opencl_private: + case LangAS::sycl_private: return ""; case LangAS::opencl_constant: + case LangAS::sycl_constant: return "__constant"; case LangAS::opencl_generic: return "__generic"; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index c063f8ca44720..e5bac9b92a806 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -561,18 +561,10 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new X86_64TargetInfo(Triple, Opts); } - case llvm::Triple::spir: { - if (Triple.getOS() != llvm::Triple::UnknownOS || - Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) - return nullptr; + case llvm::Triple::spir: return new SPIR32TargetInfo(Triple, Opts); - } - case llvm::Triple::spir64: { - if (Triple.getOS() != llvm::Triple::UnknownOS || - Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) - return nullptr; + case llvm::Triple::spir64: return new SPIR64TargetInfo(Triple, Opts); - } case llvm::Triple::wasm32: if (Triple.getSubArch() != llvm::Triple::NoSubArch || Triple.getVendor() != llvm::Triple::UnknownVendor || diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 135ad3f97ce12..8c2ebcb12c8cd 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -48,6 +48,10 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = { Global, // cuda_device Constant, // cuda_constant Local, // cuda_shared + Global, // sycl_global + Local, // sycl_local + Constant, // sycl_constant + Private, // sycl_private Generic, // ptr32_sptr Generic, // ptr32_uptr Generic // ptr64 @@ -63,6 +67,10 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = { Global, // cuda_device Constant, // cuda_constant Local, // cuda_shared + Global, // sycl_global + Local, // sycl_local + Constant, // sycl_constant + Private, // sycl_private Generic, // ptr32_sptr Generic, // ptr32_uptr Generic // ptr64 diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 63780789c474e..717adc45b5a8f 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -33,6 +33,10 @@ static const unsigned NVPTXAddrSpaceMap[] = { 1, // cuda_device 4, // cuda_constant 3, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 4, // sycl_constant + 0, // sycl_private 0, // ptr32_sptr 0, // ptr32_uptr 0 // ptr64 diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 279d1866a4289..f8d0b34b14530 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -31,6 +31,29 @@ static const unsigned SPIRAddrSpaceMap[] = { 0, // cuda_device 0, // cuda_constant 0, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 2, // sycl_constant + 0, // sycl_private + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 +}; + +static const unsigned SYCLAddrSpaceMap[] = { + 4, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 2, // sycl_constant + 0, // sycl_private 0, // ptr32_sptr 0, // ptr32_uptr 0 // ptr64 @@ -40,14 +63,14 @@ class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo { public: SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { - assert(getTriple().getOS() == llvm::Triple::UnknownOS && - "SPIR target must use unknown OS"); - assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && - "SPIR target must use unknown environment type"); TLSSupported = false; VLASupported = false; LongWidth = LongAlign = 64; - AddrSpaceMap = &SPIRAddrSpaceMap; + if (Triple.getEnvironment() == llvm::Triple::SYCLDevice) { + AddrSpaceMap = &SYCLAddrSpaceMap; + } else { + AddrSpaceMap = &SPIRAddrSpaceMap; + } UseAddrSpaceMapMangling = true; HasLegalHalfType = true; HasFloat16 = true; diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h index 9cbf2a3688a2e..5cd9cb444af97 100644 --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -40,6 +40,10 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = { 0, // cuda_device 0, // cuda_constant 0, // cuda_shared + 3, // sycl_global + 4, // sycl_local + 5, // sycl_constant + 0, // sycl_private 0, // ptr32_sptr 0, // ptr32_uptr 0, // ptr64 diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 604198b004725..0b9f480349dff 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -32,6 +32,10 @@ static const unsigned X86AddrSpaceMap[] = { 0, // cuda_device 0, // cuda_constant 0, // cuda_shared + 0, // sycl_global + 0, // sycl_local + 0, // sycl_constant + 0, // sycl_private 270, // ptr32_sptr 271, // ptr32_uptr 272 // ptr64 diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index b49b194d61122..16f39998381ea 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4100,6 +4100,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, V->getType()->isIntegerTy()) V = Builder.CreateZExt(V, ArgInfo.getCoerceToType()); + if (FirstIRArg < IRFuncTy->getNumParams()) { + const auto *LHSPtrTy = dyn_cast(V->getType()); + const auto *RHSPtrTy = + dyn_cast(IRFuncTy->getParamType(FirstIRArg)); + if (LHSPtrTy && RHSPtrTy && + LHSPtrTy->getAddressSpace() != RHSPtrTy->getAddressSpace()) + V = Builder.CreateAddrSpaceCast(V, + IRFuncTy->getParamType(FirstIRArg)); + } + // If the argument doesn't match, perform a bitcast to coerce it. This // can happen due to trivial type mismatches. if (FirstIRArg < IRFuncTy->getNumParams() && @@ -4309,6 +4319,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (!CallArgs.getCleanupsToDeactivate().empty()) deactivateArgCleanupsBeforeCall(*this, CallArgs); + // Addrspace cast to generic if necessary + for (unsigned i = 0; i < IRFuncTy->getNumParams(); ++i) { + if (auto *PtrTy = dyn_cast(IRCallArgs[i]->getType())) { + auto *ExpectedPtrType = + cast(IRFuncTy->getParamType(i)); + unsigned ValueAS = PtrTy->getAddressSpace(); + unsigned ExpectedAS = ExpectedPtrType->getAddressSpace(); + if (ValueAS != ExpectedAS) { + IRCallArgs[i] = Builder.CreatePointerBitCastOrAddrSpaceCast( + IRCallArgs[i], ExpectedPtrType); + } + } + } + // Assert that the arguments we computed match up. The IR verifier // will catch this, but this is a common enough source of problems // during IRGen changes that it's way better for debugging to catch diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 3f3825b762759..3b5aa6645caac 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -319,7 +319,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( EmitTypeCheck(TCK_Upcast, Loc, Value.getPointer(), DerivedTy, DerivedAlign, SkippedChecks); } - return Builder.CreateBitCast(Value, BasePtrTy); + return Builder.CreatePointerBitCastOrAddrSpaceCast(Value, BasePtrTy); } llvm::BasicBlock *origBB = nullptr; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 61fb8fa384cf3..2811fc29edc70 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -344,7 +344,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, OldGV->getLinkage(), Init, "", /*InsertBefore*/ OldGV, OldGV->getThreadLocalMode(), - CGM.getContext().getTargetAddressSpace(D.getType())); + OldGV->getType()->getPointerAddressSpace()); GV->setVisibility(OldGV->getVisibility()); GV->setDSOLocal(OldGV->isDSOLocal()); GV->setComdat(OldGV->getComdat()); diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 3baa0a080f5db..c6d72cb31df88 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -161,13 +161,15 @@ void CodeGenFunction::EmitInvariantStart(llvm::Constant *Addr, CharUnits Size) { // Grab the llvm.invariant.start intrinsic. llvm::Intrinsic::ID InvStartID = llvm::Intrinsic::invariant_start; // Overloaded address space type. - llvm::Type *ObjectPtr[1] = {Int8PtrTy}; + llvm::Type *ResTy = llvm::PointerType::getInt8PtrTy( + CGM.getLLVMContext(), Addr->getType()->getPointerAddressSpace()); + llvm::Type *ObjectPtr[1] = {ResTy}; llvm::Function *InvariantStart = CGM.getIntrinsic(InvStartID, ObjectPtr); // Emit a call with the size in bytes of the object. uint64_t Width = Size.getQuantity(); - llvm::Value *Args[2] = { llvm::ConstantInt::getSigned(Int64Ty, Width), - llvm::ConstantExpr::getBitCast(Addr, Int8PtrTy)}; + llvm::Value *Args[2] = {llvm::ConstantInt::getSigned(Int64Ty, Width), + llvm::ConstantExpr::getBitCast(Addr, ResTy)}; Builder.CreateCall(InvariantStart, Args); } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index cd42faefab00b..5a8fe83f4d831 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1089,10 +1089,8 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, CodeGenFunction::CFITCK_UnrelatedCast, CE->getBeginLoc()); } - return CE->getCastKind() != CK_AddressSpaceConversion - ? Builder.CreateBitCast(Addr, ConvertType(E->getType())) - : Builder.CreateAddrSpaceCast(Addr, - ConvertType(E->getType())); + return Builder.CreatePointerBitCastOrAddrSpaceCast( + Addr, ConvertType(E->getType())); } break; @@ -1750,6 +1748,17 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, return; } + if (auto *PtrTy = dyn_cast(Value->getType())) { + auto *ExpectedPtrType = + cast(Addr.getType()->getElementType()); + unsigned ValueAS = PtrTy->getAddressSpace(); + unsigned ExpectedAS = ExpectedPtrType->getAddressSpace(); + if (ValueAS != ExpectedAS) { + Value = + Builder.CreatePointerBitCastOrAddrSpaceCast(Value, ExpectedPtrType); + } + } + llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile); if (isNontemporal) { llvm::MDNode *Node = @@ -4309,10 +4318,35 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { EmitBlock(contBlock); if (lhs && rhs) { - llvm::PHINode *phi = - Builder.CreatePHI(lhs->getPointer(*this)->getType(), 2, "cond-lvalue"); - phi->addIncoming(lhs->getPointer(*this), lhsBlock); - phi->addIncoming(rhs->getPointer(*this), rhsBlock); + llvm::Value *lhsPtr = lhs->getPointer(*this); + llvm::Value *rhsPtr = rhs->getPointer(*this); + if (rhsPtr->getType() != lhsPtr->getType()) { + if (!getLangOpts().SYCLIsDevice) + llvm_unreachable( + "Unable to find a common address space for two pointers."); + + auto CastToAS = [](llvm::Value *V, llvm::BasicBlock *BB, unsigned AS) { + auto *Ty = cast(V->getType()); + if (Ty->getAddressSpace() == AS) + return V; + llvm::IRBuilder<> Builder(BB->getTerminator()); + auto *TyAS = llvm::PointerType::get(Ty->getElementType(), AS); + return Builder.CreatePointerBitCastOrAddrSpaceCast(V, TyAS); + }; + + // Language rules define if it is legal to cast from one address space + // to another, and which address space we should use as a "common + // denominator". In SYCL, generic address space overlaps with all other + // address spaces. + unsigned GenericAS = + getContext().getTargetAddressSpace(LangAS::opencl_generic); + + lhsPtr = CastToAS(lhsPtr, lhsBlock, GenericAS); + rhsPtr = CastToAS(rhsPtr, rhsBlock, GenericAS); + } + llvm::PHINode *phi = Builder.CreatePHI(lhsPtr->getType(), 2, "cond-lvalue"); + phi->addIncoming(lhsPtr, lhsBlock); + phi->addIncoming(rhsPtr, rhsBlock); Address result(phi, std::min(lhs->getAlignment(), rhs->getAlignment())); AlignmentSource alignSource = std::max(lhs->getBaseInfo().getAlignmentSource(), diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index b8846162508e9..b8e493cdb36a0 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2003,10 +2003,26 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { Value *Src = Visit(const_cast(E)); llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = ConvertType(DestTy); + bool NeedAddrspaceCast = false; if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DstTy->getPointerAddressSpace()) { - llvm_unreachable("wrong cast for pointers in different address spaces" - "(must be an address space cast)!"); + // If we have the same address space in AST, which is then codegen'ed to + // different address spaces in IR, then an address space cast should be + // valid. + // + // This is the case for SYCL, where both types have Default address space + // in AST, but in IR one of them may be in opencl_private, and another in + // opencl_generic address space: + // + // int arr[5]; // automatic variable, default AS in AST, + // // private AS in IR + // + // char* p = arr; // default AS in AST, generic AS in IR + // + if (E->getType().getAddressSpace() != DestTy.getAddressSpace()) + llvm_unreachable("wrong cast for pointers in different address spaces" + "(must be an address space cast)!"); + NeedAddrspaceCast = true; } if (CGF.SanOpts.has(SanitizerKind::CFIUnrelatedCast)) { @@ -2041,6 +2057,13 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { CGF.getDebugInfo()-> addHeapAllocSiteMetadata(CI, CE->getType(), CE->getExprLoc()); + if (NeedAddrspaceCast) { + llvm::Type *SrcPointeeTy = Src->getType()->getPointerElementType(); + llvm::Type *SrcNewAS = llvm::PointerType::get( + SrcPointeeTy, cast(DstTy)->getAddressSpace()); + + Src = Builder.CreateAddrSpaceCast(Src, SrcNewAS); + } return Builder.CreateBitCast(Src, DstTy); } case CK_AddressSpaceConversion: { @@ -2861,6 +2884,53 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { // Binary Operators //===----------------------------------------------------------------------===// +static Value *insertAddressSpaceCast(Value *V, unsigned NewAS) { + auto *VTy = cast(V->getType()); + if (VTy->getAddressSpace() == NewAS) + return V; + + llvm::PointerType *VTyNewAS = + llvm::PointerType::get(VTy->getElementType(), NewAS); + + if (auto *Constant = dyn_cast(V)) + return llvm::ConstantExpr::getAddrSpaceCast(Constant, VTyNewAS); + + llvm::Instruction *NewV = + new llvm::AddrSpaceCastInst(V, VTyNewAS, V->getName() + ".ascast"); + NewV->insertAfter(cast(V)); + return NewV; +} + +static void ensureSameAddrSpace(Value *&RHS, Value *&LHS, + bool CanInsertAddrspaceCast, + const LangOptions &Opts, + const ASTContext &Context) { + if (RHS->getType() == LHS->getType()) + return; + + auto *RHSTy = dyn_cast(RHS->getType()); + auto *LHSTy = dyn_cast(LHS->getType()); + if (!RHSTy || !LHSTy || RHSTy->getAddressSpace() == LHSTy->getAddressSpace()) + return; + + if (!CanInsertAddrspaceCast) + // Pointers have different address spaces and we cannot do anything with + // this. + llvm_unreachable("Pointers are expected to have the same address space."); + + // Language rules define if it is legal to cast from one address space to + // another, and which address space we should use as a "common + // denominator". In SYCL, generic address space overlaps with all other + // address spaces. + if (Opts.SYCLIsDevice) { + unsigned GenericAS = Context.getTargetAddressSpace(LangAS::opencl_generic); + RHS = insertAddressSpaceCast(RHS, GenericAS); + LHS = insertAddressSpaceCast(LHS, GenericAS); + } else + llvm_unreachable("Unable to find a common address space for " + "two pointers."); +} + BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { TestAndClearIgnoreResultAssign(); BinOpInfo Result; @@ -3906,6 +3976,14 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, RHS = Builder.CreateStripInvariantGroup(RHS); } + // Expression operands may have the same addrspace in AST, but different + // addrspaces in LLVM IR, in which case an addrspacecast should be valid. + bool CanInsertAddrspaceCast = + LHSTy.getAddressSpace() == RHSTy.getAddressSpace(); + + ensureSameAddrSpace(RHS, LHS, CanInsertAddrspaceCast, CGF.getLangOpts(), + CGF.getContext()); + Result = Builder.CreateICmp(UICmpOpc, LHS, RHS, "cmp"); } @@ -4211,7 +4289,6 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E, // exist in the source-level program. } - Value *ScalarExprEmitter:: VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { TestAndClearIgnoreResultAssign(); @@ -4307,6 +4384,15 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { assert(!RHS && "LHS and RHS types must match"); return nullptr; } + + // Expressions may have the same addrspace in AST, but different address + // space in LLVM IR, in which case an addrspacecast should be valid. + bool CanInsertAddrspaceCast = rhsExpr->getType().getAddressSpace() == + lhsExpr->getType().getAddressSpace(); + + ensureSameAddrSpace(RHS, LHS, CanInsertAddrspaceCast, CGF.getLangOpts(), + CGF.getContext()); + return Builder.CreateSelect(CondV, LHS, RHS, "cond"); } @@ -4341,6 +4427,14 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { if (!RHS) return LHS; + // Expressions may have the same addrspace in AST, but different address + // space in LLVM IR, in which case an addrspacecast should be valid. + bool CanInsertAddrspaceCast = rhsExpr->getType().getAddressSpace() == + lhsExpr->getType().getAddressSpace(); + + ensureSameAddrSpace(RHS, LHS, CanInsertAddrspaceCast, CGF.getLangOpts(), + CGF.getContext()); + // Create a PHI node for the real part. llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond"); PN->addIncoming(LHS, LHSBlock); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 8d5ec5fa803aa..71e3cbd4c7384 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1113,12 +1113,35 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // If this function returns a reference, take the address of the expression // rather than the value. RValue Result = EmitReferenceBindingToExpr(RV); - Builder.CreateStore(Result.getScalarVal(), ReturnValue); + llvm::Value *Val = Result.getScalarVal(); + if (auto *PtrTy = dyn_cast(Val->getType())) { + auto *ExpectedPtrType = + cast(ReturnValue.getType()->getElementType()); + unsigned ValueAS = PtrTy->getAddressSpace(); + unsigned ExpectedAS = ExpectedPtrType->getAddressSpace(); + if (ValueAS != ExpectedAS) { + Val = Builder.CreatePointerBitCastOrAddrSpaceCast(Val, ExpectedPtrType); + } + } + Builder.CreateStore(Val, ReturnValue); } else { switch (getEvaluationKind(RV->getType())) { case TEK_Scalar: - Builder.CreateStore(EmitScalarExpr(RV), ReturnValue); + { + llvm::Value *Val = EmitScalarExpr(RV); + if (auto *PtrTy = dyn_cast(Val->getType())) { + auto *ExpectedPtrType = + cast(ReturnValue.getType()->getElementType()); + unsigned ValueAS = PtrTy->getAddressSpace(); + unsigned ExpectedAS = ExpectedPtrType->getAddressSpace(); + if (ValueAS != ExpectedAS) { + Val = + Builder.CreatePointerBitCastOrAddrSpaceCast(Val, ExpectedPtrType); + } + } + Builder.CreateStore(Val, ReturnValue); break; + } case TEK_Complex: EmitComplexExprIntoLValue(RV, MakeAddrLValue(ReturnValue, RV->getType()), /*isInit*/ true); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 1fc2beb12ed58..2b58e2a01150f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3750,6 +3750,12 @@ LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { return AddrSpace; } + if (LangOpts.SYCLIsDevice) { + if (!D || D->getType().getAddressSpace() == LangAS::Default) { + return LangAS::opencl_global; + } + } + if (LangOpts.CUDA && LangOpts.CUDAIsDevice) { if (D && D->hasAttr()) return LangAS::cuda_constant; @@ -3775,8 +3781,19 @@ LangAS CodeGenModule::getStringLiteralAddressSpace() const { // OpenCL v1.2 s6.5.3: a string literal is in the constant address space. if (LangOpts.OpenCL) return LangAS::opencl_constant; + + // If we keep a literal string in constant address space, the following code + // becomes illegal: + // + // const char *getLiteral() n{ + // return "AB"; + // } + if (LangOpts.SYCLIsDevice) + return LangAS::opencl_private; + if (auto AS = getTarget().getConstantAddressSpace()) return AS.getValue(); + return LangAS::Default; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 4dc10ffdd64e9..dd2ae544c926b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5940,6 +5940,7 @@ static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx, llvm::APSInt max(addrSpace.getBitWidth()); max = Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace; + if (addrSpace > max) { S.Diag(AttrLoc, diag::err_attribute_address_space_too_high) << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange(); @@ -6073,7 +6074,9 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, Attr.setInvalid(); } else { // The keyword-based type attributes imply which address space to use. - ASIdx = Attr.asOpenCLLangAS(); + ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS() + : Attr.asOpenCLLangAS(); + if (ASIdx == LangAS::Default) llvm_unreachable("Invalid address space"); diff --git a/clang/test/CodeGenSYCL/address-space-cond-op.cpp b/clang/test/CodeGenSYCL/address-space-cond-op.cpp new file mode 100644 index 0000000000000..c975dc5ee8b07 --- /dev/null +++ b/clang/test/CodeGenSYCL/address-space-cond-op.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -x c++ -triple spir64-unknown-linux-sycldevice -disable-llvm-passes -fsycl-is-device -emit-llvm %s -o - | FileCheck %s + +// CHECK: [[STYPE:%.+]] = type { i16 } +struct S { + unsigned short x; +}; + +S foo(bool cond, S &lhs, S rhs) { +// CHECK-LABEL:@_Z3foobR1SS_ +// CHECK: br i1 {{.+}}, label %[[BTRUE:.+]], label %[[BFALSE:.+]] +// +// CHECK: [[BTRUE]]: +// CHECK: %[[LHS:.+]] = load [[STYPE]] addrspace(4)*, [[STYPE]] addrspace(4)** +// CHECK: br label %[[BEND:.+]] +// +// CHECK: [[BFALSE]]: +// CHECK: %[[RHS:.+]] = addrspacecast [[STYPE]]* {{.+}} to [[STYPE]] addrspace(4)* +// CHECK: br label %[[BEND]] +// +// CHECK: [[BEND]]: +// CHECK: %{{.+}} = phi [[STYPE]] addrspace(4)* [ %[[LHS]], %[[BTRUE]] ], [ %[[RHS]], %[[BFALSE]] ] + S val = cond ? lhs : rhs; + return val; +} + +template +__attribute__((sycl_kernel)) void kernel(Func kernelFunc) { + kernelFunc(); +} + +int main() { + kernel([]() { + S lhs, rhs; + foo(true, lhs, rhs); + }); + return 0; +} diff --git a/clang/test/CodeGenSYCL/address-space-of-returns.cpp b/clang/test/CodeGenSYCL/address-space-of-returns.cpp new file mode 100644 index 0000000000000..83226d243d583 --- /dev/null +++ b/clang/test/CodeGenSYCL/address-space-of-returns.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm -x c++ %s -o - | FileCheck %s + +struct A { + int B[42]; +}; + +const char *ret_char() { + return "N"; +} +// CHECK: ret i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i64 0, i64 0) to i8 addrspace(4)*) + +const char *ret_arr() { + static char Arr[42]; + return Arr; +} +// CHECK: ret i8 addrspace(4)* getelementptr inbounds ([42 x i8], [42 x i8] addrspace(4)* addrspacecast ([42 x i8] addrspace(1)* @{{.*}}ret_arr{{.*}}Arr to [42 x i8] addrspace(4)*), i64 0, i64 0) + +const char &ret_ref() { + static char a = 'A'; + return a; +} +// CHECK: ret i8 addrspace(4)* addrspacecast (i8 addrspace(1)* @{{.*}}ret_ref{{.*}} to i8 addrspace(4)*) + +A ret_agg() { + A a; + return a; +} +// CHECK: define spir_func void @{{.*}}ret_agg{{.*}}(%struct.A addrspace(4)* noalias sret %agg.result) + +template +__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { + kernelFunc(); +} + +int main() { + kernel_single_task([]() { + ret_char(); + ret_arr(); + ret_ref(); + ret_agg(); + }); + return 0; +} diff --git a/clang/test/CodeGenSYCL/address-space-parameter-conversions.cpp b/clang/test/CodeGenSYCL/address-space-parameter-conversions.cpp new file mode 100644 index 0000000000000..9cde20925d587 --- /dev/null +++ b/clang/test/CodeGenSYCL/address-space-parameter-conversions.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +void bar(int & Data) {} +// CHECK-DAG: define spir_func void @[[RAW_REF:[a-zA-Z0-9_]+]](i32 addrspace(4)* dereferenceable(4) % +void bar2(int & Data) {} +// CHECK-DAG: define spir_func void @[[RAW_REF2:[a-zA-Z0-9_]+]](i32 addrspace(4)* dereferenceable(4) % +void bar(__attribute__((opencl_local)) int &Data) {} +// CHECK-DAG: define spir_func void [[LOC_REF:@[a-zA-Z0-9_]+]](i32 addrspace(3)* dereferenceable(4) % +void foo(int * Data) {} +// CHECK-DAG: define spir_func void @[[RAW_PTR:[a-zA-Z0-9_]+]](i32 addrspace(4)* % +void foo2(int * Data) {} +// CHECK-DAG: define spir_func void @[[RAW_PTR2:[a-zA-Z0-9_]+]](i32 addrspace(4)* % +void foo(__attribute__((opencl_local)) int * Data) {} +// CHECK-DAG: define spir_func void [[LOC_PTR:@[a-zA-Z0-9_]+]](i32 addrspace(3)* % + +template +void tmpl(T t){} +// See Check Lines below. + +void usages() { + // CHECK-DAG: [[GLOB:%[a-zA-Z0-9]+]] = alloca i32 addrspace(1)* + __attribute__((opencl_global)) int *GLOB; + // CHECK-DAG: [[LOC:%[a-zA-Z0-9]+]] = alloca i32 addrspace(3)* + __attribute__((opencl_local)) int *LOC; + // CHECK-DAG: [[NoAS:%[a-zA-Z0-9]+]] = alloca i32 addrspace(4)* + int *NoAS; + // CHECK-DAG: [[PRIV:%[a-zA-Z0-9]+]] = alloca i32* + __attribute__((opencl_private)) int *PRIV; + + bar(*GLOB); + // CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load i32 addrspace(1)*, i32 addrspace(1)** [[GLOB]] + // CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(1)* [[GLOB_LOAD]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF]](i32 addrspace(4)* dereferenceable(4) [[GLOB_CAST]]) + bar2(*GLOB); + // CHECK-DAG: [[GLOB_LOAD2:%[a-zA-Z0-9]+]] = load i32 addrspace(1)*, i32 addrspace(1)** [[GLOB]] + // CHECK-DAG: [[GLOB_CAST2:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(1)* [[GLOB_LOAD2]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF2]](i32 addrspace(4)* dereferenceable(4) [[GLOB_CAST2]]) + + bar(*LOC); + // CHECK-DAG: [[LOC_LOAD:%[a-zA-Z0-9]+]] = load i32 addrspace(3)*, i32 addrspace(3)** [[LOC]] + // CHECK-DAG: call spir_func void [[LOC_REF]](i32 addrspace(3)* dereferenceable(4) [[LOC_LOAD]]) + bar2(*LOC); + // CHECK-DAG: [[LOC_LOAD2:%[a-zA-Z0-9]+]] = load i32 addrspace(3)*, i32 addrspace(3)** [[LOC]] + // CHECK-DAG: [[LOC_CAST2:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(3)* [[LOC_LOAD2]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF2]](i32 addrspace(4)* dereferenceable(4) [[LOC_CAST2]]) + + bar(*NoAS); + // CHECK-DAG: [[NoAS_LOAD:%[a-zA-Z0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** [[NoAS]] + // CHECK-DAG: call spir_func void @[[RAW_REF]](i32 addrspace(4)* dereferenceable(4) [[NoAS_LOAD]]) + bar2(*NoAS); + // CHECK-DAG: [[NoAS_LOAD2:%[a-zA-Z0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** [[NoAS]] + // CHECK-DAG: call spir_func void @[[RAW_REF2]](i32 addrspace(4)* dereferenceable(4) [[NoAS_LOAD2]]) + + foo(GLOB); + // CHECK-DAG: [[GLOB_LOAD3:%[a-zA-Z0-9]+]] = load i32 addrspace(1)*, i32 addrspace(1)** [[GLOB]] + // CHECK-DAG: [[GLOB_CAST3:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(1)* [[GLOB_LOAD3]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_PTR]](i32 addrspace(4)* [[GLOB_CAST3]]) + foo2(GLOB); + // CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load i32 addrspace(1)*, i32 addrspace(1)** [[GLOB]] + // CHECK-DAG: [[GLOB_CAST4:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(1)* [[GLOB_LOAD4]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_PTR2]](i32 addrspace(4)* [[GLOB_CAST4]]) + foo(LOC); + // CHECK-DAG: [[LOC_LOAD3:%[a-zA-Z0-9]+]] = load i32 addrspace(3)*, i32 addrspace(3)** [[LOC]] + // CHECK-DAG: call spir_func void [[LOC_PTR]](i32 addrspace(3)* [[LOC_LOAD3]]) + foo2(LOC); + // CHECK-DAG: [[LOC_LOAD4:%[a-zA-Z0-9]+]] = load i32 addrspace(3)*, i32 addrspace(3)** [[LOC]] + // CHECK-DAG: [[LOC_CAST4:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(3)* [[LOC_LOAD4]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_PTR2]](i32 addrspace(4)* [[LOC_CAST4]]) + foo(NoAS); + // CHECK-DAG: [[NoAS_LOAD3:%[a-zA-Z0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** [[NoAS]] + // CHECK-DAG: call spir_func void @[[RAW_PTR]](i32 addrspace(4)* [[NoAS_LOAD3]]) + foo2(NoAS); + // CHECK-DAG: [[NoAS_LOAD4:%[a-zA-Z0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** [[NoAS]] + // CHECK-DAG: call spir_func void @[[RAW_PTR2]](i32 addrspace(4)* [[NoAS_LOAD4]]) + + // Ensure that we still get 3 different template instantiations. + tmpl(GLOB); + // CHECK-DAG: [[GLOB_LOAD4:%[a-zA-Z0-9]+]] = load i32 addrspace(1)*, i32 addrspace(1)** [[GLOB]] + // CHECK-DAG: call spir_func void [[GLOB_TMPL:@[a-zA-Z0-9_]+]](i32 addrspace(1)* [[GLOB_LOAD4]]) + tmpl(LOC); + // CHECK-DAG: [[LOC_LOAD5:%[a-zA-Z0-9]+]] = load i32 addrspace(3)*, i32 addrspace(3)** [[LOC]] + // CHECK-DAG: call spir_func void [[LOC_TMPL:@[a-zA-Z0-9_]+]](i32 addrspace(3)* [[LOC_LOAD5]]) + tmpl(PRIV); + // CHECK-DAG: [[PRIV_LOAD5:%[a-zA-Z0-9]+]] = load i32*, i32** [[PRIV]] + // CHECK-DAG: call spir_func void [[PRIV_TMPL:@[a-zA-Z0-9_]+]](i32* [[PRIV_LOAD5]]) + tmpl(NoAS); + // CHECK-DAG: [[NoAS_LOAD5:%[a-zA-Z0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** [[NoAS]] + // CHECK-DAG: call spir_func void [[GEN_TMPL:@[a-zA-Z0-9_]+]](i32 addrspace(4)* [[NoAS_LOAD5]]) +} + +// CHECK-DAG: define linkonce_odr spir_func void [[GLOB_TMPL]](i32 addrspace(1)* % +// CHECK-DAG: define linkonce_odr spir_func void [[LOC_TMPL]](i32 addrspace(3)* % +// CHECK-DAG: define linkonce_odr spir_func void [[PRIV_TMPL]](i32* % +// CHECK-DAG: define linkonce_odr spir_func void [[GEN_TMPL]](i32 addrspace(4)* % + +void usages2() { + __attribute__((opencl_private)) int *PRIV; + // CHECK-DAG: [[PRIV:%[a-zA-Z0-9_]+]] = alloca i32* + __attribute__((opencl_global)) int *GLOB; + // CHECK-DAG: [[GLOB:%[a-zA-Z0-9_]+]] = alloca i32 addrspace(1)* + __attribute__((opencl_constant)) int *CONST; + // CHECK-DAG: [[CONST:%[a-zA-Z0-9_]+]] = alloca i32 addrspace(2)* + __attribute__((opencl_local)) int *LOCAL; + // CHECK-DAG: [[LOCAL:%[a-zA-Z0-9_]+]] = alloca i32 addrspace(3)* + + bar(*PRIV); + // CHECK-DAG: [[PRIV_LOAD:%[a-zA-Z0-9]+]] = load i32*, i32** [[PRIV]] + // CHECK-DAG: [[PRIV_ASCAST:%[a-zA-Z0-9]+]] = addrspacecast i32* [[PRIV_LOAD]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF]](i32 addrspace(4)* dereferenceable(4) [[PRIV_ASCAST]]) + bar(*GLOB); + // CHECK-DAG: [[GLOB_LOAD:%[a-zA-Z0-9]+]] = load i32 addrspace(1)*, i32 addrspace(1)** [[GLOB]] + // CHECK-DAG: [[GLOB_CAST:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(1)* [[GLOB_LOAD]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF]](i32 addrspace(4)* dereferenceable(4) [[GLOB_CAST]]) + bar(*CONST); + // CHECK-DAG: [[CONST_LOAD:%[a-zA-Z0-9]+]] = load i32 addrspace(2)*, i32 addrspace(2)** [[CONST]] + // CHECK-DAG: [[CONST_CAST:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(2)* [[CONST_LOAD]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF]](i32 addrspace(4)* dereferenceable(4) [[CONST_CAST]]) + bar2(*LOCAL); + // CHECK-DAG: [[LOCAL_LOAD:%[a-zA-Z0-9]+]] = load i32 addrspace(3)*, i32 addrspace(3)** [[LOCAL]] + // CHECK-DAG: [[LOCAL_CAST:%[a-zA-Z0-9]+]] = addrspacecast i32 addrspace(3)* [[LOCAL_LOAD]] to i32 addrspace(4)* + // CHECK-DAG: call spir_func void @[[RAW_REF2]](i32 addrspace(4)* dereferenceable(4) [[LOCAL_CAST]]) +} + +template +__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { + kernelFunc(); +} +int main() { + kernel_single_task([]() { usages();usages2(); }); + return 0; +} diff --git a/clang/test/CodeGenSYCL/address-spaces.cpp b/clang/test/CodeGenSYCL/address-spaces.cpp new file mode 100644 index 0000000000000..7bdbed4f945ca --- /dev/null +++ b/clang/test/CodeGenSYCL/address-spaces.cpp @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm -x c++ %s -o - | FileCheck %s + +struct Padding { + int i, j; +}; + +struct HasX { + int x; +}; + +struct Y : Padding, HasX {}; + +void bar(HasX &hx); + +// CHECK: @_ZZ4testvE3foo = internal addrspace(1) constant i32 66, align 4 +// CHECK: @_ZZ4testvE4bars = internal addrspace(1) constant <{ [21 x i32], [235 x i32] }> <{ [21 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20], [235 x i32] zeroinitializer }>, align 4 +// CHECK: @[[STR:[.a-zA-Z0-9_]+]] = private unnamed_addr constant [14 x i8] c"Hello, world!\00", align 1 + +// CHECK-LABEL: @_Z3baz{{.*}} +void baz(Y &y) { + // CHECK: %[[FIRST:[a-zA-Z0-9]+]] = bitcast %struct.Y addrspace(4)* %{{.*}} to i8 addrspace(4)* + // CHECK: %[[OFFSET:[a-zA-Z0-9]+]].ptr = getelementptr inbounds i8, i8 addrspace(4)* %[[FIRST]], i64 8 + // CHECK: %[[SECOND:[a-zA-Z0-9]+]] = bitcast i8 addrspace(4)* %[[OFFSET]].ptr to %struct.HasX addrspace(4)* + // CHECK: call spir_func void @{{.*}}bar{{.*}}(%struct.HasX addrspace(4)* dereferenceable(4) %[[SECOND]]) + bar(y); +} + +// CHECK-LABEL: @_Z4testv +void test() { + static const int foo = 0x42; + + // Intentionally leave a part of an array uninitialized. This triggers a + // different code path contrary to a fully initialized array. + static const unsigned bars[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 + }; + (void)bars; + + + // CHECK: %i.ascast = addrspacecast i32* %i to i32 addrspace(4)* + // CHECK: %[[ARR:[a-zA-Z0-9]+]] = alloca [42 x i32] + + int i = 0; + int *pptr = &i; + // CHECK: %[[GEN:[0-9]+]] = addrspacecast i32* %i to i32 addrspace(4)* + // CHECK: store i32 addrspace(4)* %[[GEN]], i32 addrspace(4)** %pptr + bool is_i_ptr = (pptr == &i); + // CHECK: %[[VALPPTR:[0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** %pptr + // CHECK: %cmp{{[0-9]*}} = icmp eq i32 addrspace(4)* %[[VALPPTR]], %i.ascast + *pptr = foo; + + int var23 = 23; + char *cp = (char *)&var23; + *cp = 41; + // CHECK: store i32 23, i32* %[[VAR:[a-zA-Z0-9]+]] + // CHECK: [[VARAS:[a-zA-Z0-9]+]] = addrspacecast i32* %[[VAR]] to i32 addrspace(4)* + // CHECK: [[VARCAST:[a-zA-Z0-9]+]] = bitcast i32 addrspace(4)* %[[VARAS]] to i8 addrspace(4)* + // CHECK: store i8 addrspace(4)* %[[VARCAST]], i8 addrspace(4)** %{{.*}} + + int arr[42]; + char *cpp = (char *)arr; + *cpp = 43; + // CHECK: %[[ARRDECAY:[a-zA-Z0-9]+]] = getelementptr inbounds [42 x i32], [42 x i32]* %[[ARR]], i64 0, i64 0 + // CHECK: %[[ARRAS:[a-zA-Z0-9]+]] = addrspacecast i32* %[[ARRDECAY]] to i32 addrspace(4)* + // CHECK: %[[ARRCAST:[a-zA-Z0-9]+]] = bitcast i32 addrspace(4)* %[[ARRAS]] to i8 addrspace(4)* + // CHECK: store i8 addrspace(4)* %[[ARRCAST]], i8 addrspace(4)** %{{.*}} + + int *aptr = arr + 10; + if (aptr < arr + sizeof(arr)) + *aptr = 44; + // CHECK: %[[VALAPTR:[0-9]+]] = load i32 addrspace(4)*, i32 addrspace(4)** %aptr + // CHECK: %[[ARRDCY2:[a-zA-Z0-9]+]] = getelementptr inbounds [42 x i32], [42 x i32]* %[[ARR]], i64 0, i64 0 + // CHECK: %[[ADDPTR:[a-zA-Z0-9.]+]] = getelementptr inbounds i32, i32* %[[ARRDCY2]], i64 168 + // CHECK: %[[ADDPTRCAST:[a-zA-Z0-9.]+]] = addrspacecast i32* %[[ADDPTR]] to i32 addrspace(4)* + // CHECK: %cmp{{[0-9]+}} = icmp ult i32 addrspace(4)* %[[VALAPTR]], %[[ADDPTRCAST]] + + const char *str = "Hello, world!"; + // CHECK: store i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[STR]], i64 0, i64 0) to i8 addrspace(4)*), i8 addrspace(4)** %[[STRVAL:[a-zA-Z0-9]+]], align 8 + + i = str[0]; + + const char *phi_str = i > 2 ? str : "Another hello world!"; + (void)phi_str; + // CHECK: %[[COND:[a-zA-Z0-9]+]] = icmp sgt i32 %{{.*}}, 2 + // CHECK: br i1 %[[COND]], label %[[CONDTRUE:[.a-zA-Z0-9]+]], label %[[CONDFALSE:[.a-zA-Z0-9]+]] + + // CHECK: [[CONDTRUE]]: + // CHECK-NEXT: %[[VALTRUE:[a-zA-Z0-9]+]] = load i8 addrspace(4)*, i8 addrspace(4)** %[[STRVAL]] + // CHECK-NEXT: br label %[[CONDEND:[.a-zA-Z0-9]+]] + + // CHECK: [[CONDFALSE]]: + + // CHECK: [[CONDEND]]: + // CHECK-NEXT: phi i8 addrspace(4)* [ %[[VALTRUE]], %[[CONDTRUE]] ], [ addrspacecast (i8* getelementptr inbounds ([21 x i8], [21 x i8]* @{{.*}}, i64 0, i64 0) to i8 addrspace(4)*), %[[CONDFALSE]] ] + + const char *select_null = i > 2 ? "Yet another Hello world" : nullptr; + (void)select_null; + // CHECK: select i1 %{{.*}}, i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([24 x i8], [24 x i8]* @{{.*}}, i64 0, i64 0) to i8 addrspace(4)*), i8 addrspace(4)* null + + const char *select_str_trivial1 = true ? str : "Another hello world!"; + (void)select_str_trivial1; + // CHECK: %[[TRIVIALTRUE:[a-zA-Z0-9]+]] = load i8 addrspace(4)*, i8 addrspace(4)** %[[STRVAL]] + // CHECK: store i8 addrspace(4)* %[[TRIVIALTRUE]], i8 addrspace(4)** %{{.*}}, align 8 + + const char *select_str_trivial2 = false ? str : "Another hello world!"; + (void)select_str_trivial2; + // CHECK: store i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([21 x i8], [21 x i8]* @{{.*}}, i64 0, i64 0) to i8 addrspace(4)*), i8 addrspace(4)** %{{.*}} + // + // + Y yy; + baz(yy); +} + + +template +__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { + kernelFunc(); +} + + +int main() { + kernel_single_task([]() { test(); }); + return 0; +} diff --git a/clang/test/SemaSYCL/address-space-parameter-conversions.cpp b/clang/test/SemaSYCL/address-space-parameter-conversions.cpp new file mode 100644 index 0000000000000..7665f3e6fe438 --- /dev/null +++ b/clang/test/SemaSYCL/address-space-parameter-conversions.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -fsycl-is-device -verify -fsyntax-only -x c++ %s + +void bar(int & Data) {} +void bar2(int & Data) {} +void bar(__attribute__((opencl_private)) int & Data) {} +void foo(int * Data) {} +void foo2(int * Data) {} +void foo(__attribute__((opencl_private)) int * Data) {} + +template +void tmpl(T *t){} + +void usages() { + __attribute__((opencl_global)) int *GLOB; + __attribute__((opencl_private)) int *PRIV; + __attribute__((opencl_local)) int *LOC; + int *NoAS; + + bar(*GLOB); + bar2(*GLOB); + + bar(*PRIV); + bar2(*PRIV); + + bar(*NoAS); + bar2(*NoAS); + + bar(*LOC); + bar2(*LOC); + + foo(GLOB); + foo2(GLOB); + foo(PRIV); + foo2(PRIV); + foo(NoAS); + foo2(NoAS); + foo(LOC); + foo2(LOC); + + tmpl(GLOB); + tmpl(PRIV); + tmpl(NoAS); + tmpl(LOC); + + (void)static_cast(GLOB); + (void)static_cast(GLOB); + // FIXME: determine if we can warn on the below conversions. + int *i = GLOB; + void *v = GLOB; + (void)i; + (void)v; + + + __generic int *IsGeneric; // expected-error{{unknown type name '__generic'}} + __private int *IsPrivate; // expected-error{{unknown type name '__private'}} + __global int *IsGlobal; // expected-error{{unknown type name '__global'}} + __local int *IsLocal; // expected-error{{unknown type name '__local'}} + +} diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp index bab6ca5d7b3d9..d47339e780721 100644 --- a/clang/test/SemaTemplate/address_space-dependent.cpp +++ b/clang/test/SemaTemplate/address_space-dependent.cpp @@ -43,7 +43,7 @@ void neg() { template void tooBig() { - __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388595)}} + __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388591)}} } template @@ -101,7 +101,7 @@ int main() { car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}} HasASTemplateFields<1> HASTF; neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}} - correct<0x7FFFF3>(); + correct<0x7FFFEF>(); tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650>' requested here}} __attribute__((address_space(1))) char *x; diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index b9485e81feb73..9100b1634f7db 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -214,6 +214,7 @@ class Triple { Itanium, Cygnus, CoreCLR, + SYCLDevice, Simulator, // Simulator variants of other systems, e.g., Apple's iOS MacABI, // Mac Catalyst variant of Apple's iOS deployment target. LastEnvironmentType = MacABI @@ -490,6 +491,10 @@ class Triple { return getEnvironment() == Triple::MacABI; } + bool isSYCLDeviceEnvironment() const { + return getEnvironment() == Triple::SYCLDevice; + } + bool isOSNetBSD() const { return getOS() == Triple::NetBSD; } diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index d419463e6a5e6..31ba7ca91a0ac 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -238,6 +238,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case Itanium: return "itanium"; case Cygnus: return "cygnus"; case CoreCLR: return "coreclr"; + case SYCLDevice: return "sycldevice"; case Simulator: return "simulator"; case MacABI: return "macabi"; } @@ -541,6 +542,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .StartsWith("itanium", Triple::Itanium) .StartsWith("cygnus", Triple::Cygnus) .StartsWith("coreclr", Triple::CoreCLR) + .StartsWith("sycldevice", Triple::SYCLDevice) .StartsWith("simulator", Triple::Simulator) .StartsWith("macabi", Triple::MacABI) .Default(Triple::UnknownEnvironment);