diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -494,7 +494,12 @@ /// 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)); } /// Determines if these qualifiers compatibly include another set. diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h --- a/clang/include/clang/Basic/AddressSpaces.h +++ b/clang/include/clang/Basic/AddressSpaces.h @@ -44,6 +44,11 @@ cuda_constant, cuda_shared, + // SYCL specific address spaces. + sycl_global, + sycl_local, + 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 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -598,8 +598,8 @@ /// 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: @@ -621,6 +621,23 @@ } } + // TBD: SYCL-specific ParsedAttr? + /// 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_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 AttributeCommonInfo::Kind(Info.AttrKind); } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -930,6 +930,9 @@ 7, // cuda_device 8, // cuda_constant 9, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 0, // sycl_private 10, // ptr32_sptr 11, // ptr32_uptr 12 // ptr64 diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2377,7 +2377,7 @@ 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 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -2073,10 +2073,13 @@ 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 "__private"; case LangAS::opencl_constant: return "__constant"; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -573,18 +573,10 @@ 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 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -51,6 +51,9 @@ Global, // cuda_device Constant, // cuda_constant Local, // cuda_shared + Global, // sycl_global + Local, // sycl_local + Private, // sycl_private Generic, // ptr32_sptr Generic, // ptr32_uptr Generic // ptr64 @@ -68,6 +71,9 @@ Global, // cuda_device Constant, // cuda_constant Local, // cuda_shared + Global, // sycl_global + Local, // sycl_local + 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 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -35,6 +35,9 @@ 1, // cuda_device 4, // cuda_constant 3, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 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 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -33,6 +33,29 @@ 0, // cuda_device 0, // cuda_constant 0, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 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 + 5, // opencl_global_device + 6, // opencl_global_host + 0, // cuda_device + 0, // cuda_constant + 0, // cuda_shared + 1, // sycl_global + 3, // sycl_local + 0, // sycl_private 0, // ptr32_sptr 0, // ptr32_uptr 0 // ptr64 @@ -42,14 +65,14 @@ 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 --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -42,6 +42,9 @@ 0, // cuda_device 0, // cuda_constant 0, // cuda_shared + 3, // sycl_global + 4, // sycl_local + 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 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -35,6 +35,9 @@ 0, // cuda_device 0, // cuda_constant 0, // cuda_shared + 0, // sycl_global + 0, // sycl_local + 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 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4585,6 +4585,16 @@ 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() && @@ -4805,6 +4815,20 @@ 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 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -341,7 +341,7 @@ 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 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -353,12 +353,11 @@ if (GV->getValueType() != Init->getType()) { llvm::GlobalVariable *OldGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), - OldGV->isConstant(), - OldGV->getLinkage(), Init, "", - /*InsertBefore*/ OldGV, - OldGV->getThreadLocalMode(), - CGM.getContext().getTargetAddressSpace(D.getType())); + GV = new llvm::GlobalVariable( + CGM.getModule(), Init->getType(), OldGV->isConstant(), + OldGV->getLinkage(), Init, "", + /*InsertBefore*/ OldGV, OldGV->getThreadLocalMode(), + 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 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -161,13 +161,15 @@ // 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 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1124,10 +1124,8 @@ 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; @@ -1834,6 +1832,17 @@ 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 = @@ -4531,10 +4540,35 @@ 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 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1954,10 +1954,26 @@ 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)) { @@ -2024,6 +2040,13 @@ return EmitLoadOfLValue(DestLV, 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: { @@ -2899,6 +2922,53 @@ // 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; @@ -4015,6 +4085,14 @@ 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"); } @@ -4326,7 +4404,6 @@ // exist in the source-level program. } - Value *ScalarExprEmitter:: VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { TestAndClearIgnoreResultAssign(); @@ -4435,6 +4512,15 @@ 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"); } @@ -4469,6 +4555,14 @@ 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 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1211,12 +1211,34 @@ // 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); + case TEK_Scalar: { + 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 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3968,6 +3968,12 @@ 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; @@ -3993,8 +3999,19 @@ // 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 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -6328,6 +6328,7 @@ 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(); @@ -6461,7 +6462,9 @@ 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 --- /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 -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 --- /dev/null +++ b/clang/test/CodeGenSYCL/address-space-of-returns.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl -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 const char Arr[42] = {0}; + 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 const 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(%struct.A) align 4 %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 --- /dev/null +++ b/clang/test/CodeGenSYCL/address-space-parameter-conversions.cpp @@ -0,0 +1,124 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl -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)* align 4 dereferenceable(4) % +void bar2(int &Data) {} +// CHECK-DAG: define spir_func void @[[RAW_REF2:[a-zA-Z0-9_]+]](i32 addrspace(4)* align 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)* align 4 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)* align 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)* align 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)* align 4 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)* align 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)* align 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)* align 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_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)* align 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)* align 4 dereferenceable(4) [[GLOB_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)* align 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 --- /dev/null +++ b/clang/test/CodeGenSYCL/address-spaces.cpp @@ -0,0 +1,121 @@ +// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -fsycl -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)* align 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 --- /dev/null +++ b/clang/test/SemaSYCL/address-space-parameter-conversions.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -fsycl -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 --- a/clang/test/SemaTemplate/address_space-dependent.cpp +++ b/clang/test/SemaTemplate/address_space-dependent.cpp @@ -43,7 +43,7 @@ template void tooBig() { - __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388593)}} + __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388590)}} } template @@ -101,7 +101,7 @@ 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<0x7FFFF1>(); + correct<0x7FFFED>(); 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 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -217,8 +217,9 @@ 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. + MacABI, // Mac Catalyst variant of Apple's iOS deployment target. LastEnvironmentType = MacABI }; enum ObjectFormatType { @@ -492,6 +493,10 @@ isMacCatalystEnvironment())); } + 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 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -244,6 +244,8 @@ case Musl: return "musl"; case MuslEABI: return "musleabi"; case MuslEABIHF: return "musleabihf"; + case SYCLDevice: + return "sycldevice"; case Simulator: return "simulator"; } @@ -529,26 +531,27 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch(EnvironmentName) - .StartsWith("eabihf", Triple::EABIHF) - .StartsWith("eabi", Triple::EABI) - .StartsWith("gnuabin32", Triple::GNUABIN32) - .StartsWith("gnuabi64", Triple::GNUABI64) - .StartsWith("gnueabihf", Triple::GNUEABIHF) - .StartsWith("gnueabi", Triple::GNUEABI) - .StartsWith("gnux32", Triple::GNUX32) - .StartsWith("code16", Triple::CODE16) - .StartsWith("gnu", Triple::GNU) - .StartsWith("android", Triple::Android) - .StartsWith("musleabihf", Triple::MuslEABIHF) - .StartsWith("musleabi", Triple::MuslEABI) - .StartsWith("musl", Triple::Musl) - .StartsWith("msvc", Triple::MSVC) - .StartsWith("itanium", Triple::Itanium) - .StartsWith("cygnus", Triple::Cygnus) - .StartsWith("coreclr", Triple::CoreCLR) - .StartsWith("simulator", Triple::Simulator) - .StartsWith("macabi", Triple::MacABI) - .Default(Triple::UnknownEnvironment); + .StartsWith("eabihf", Triple::EABIHF) + .StartsWith("eabi", Triple::EABI) + .StartsWith("gnuabin32", Triple::GNUABIN32) + .StartsWith("gnuabi64", Triple::GNUABI64) + .StartsWith("gnueabihf", Triple::GNUEABIHF) + .StartsWith("gnueabi", Triple::GNUEABI) + .StartsWith("gnux32", Triple::GNUX32) + .StartsWith("code16", Triple::CODE16) + .StartsWith("gnu", Triple::GNU) + .StartsWith("android", Triple::Android) + .StartsWith("musleabihf", Triple::MuslEABIHF) + .StartsWith("musleabi", Triple::MuslEABI) + .StartsWith("musl", Triple::Musl) + .StartsWith("msvc", Triple::MSVC) + .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); } static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) {