diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 63f7bfbfe5e..bb471acf970 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -986,9 +986,6 @@ class CXXRecordDecl : public RecordDecl { #endif } - /// Returns the deserialization constructor for this class. - CXXMethodDecl *getCXXAMPDeserializationConstructor() const; - /// Determine whether this class has any user-declared constructors. /// /// When true, a default constructor will not be implicitly declared. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 59f99b04066..add8b1abdb2 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2367,7 +2367,7 @@ class Type : public ExtQualsTypeCommonBase { friend class ASTReader; friend class ASTWriter; - /// \brief True if object is of hc::array or Concurrency:type + /// \brief True if object is of hc::array. bool isGPUArrayType() const; }; diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index c83bddf477a..6dc90eea188 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -3157,17 +3157,12 @@ def InternalLinkage : InheritableAttr { // C++AMP attributes -def CXXAMPRestrictAMP : InheritableAttr { - let Spellings = [GNU<"amp">, GNU<"hc">]; +def HCRestrictHC : InheritableAttr { + let Spellings = [GNU<"hc">]; let Documentation = [Undocumented]; } -def CXXAMPRestrictAUTO : InheritableAttr { - let Spellings = [GNU<"auto">]; - let Documentation = [Undocumented]; -} - -def CXXAMPRestrictCPU : InheritableAttr { +def HCRestrictCPU : InheritableAttr { let Spellings = [GNU<"cpu">]; let Documentation = [Undocumented]; } diff --git a/include/clang/Basic/CodeGenOptions.def b/include/clang/Basic/CodeGenOptions.def index eb93300abc2..1d285736faf 100644 --- a/include/clang/Basic/CodeGenOptions.def +++ b/include/clang/Basic/CodeGenOptions.def @@ -42,8 +42,7 @@ CODEGENOPT(ControlFlowGuard , 1, 0) ///< -cfguard CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files. CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files. CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files. -CODEGENOPT(AMPIsDevice , 1, 0) ///< Set when compiling for C++AMP kernels. -CODEGENOPT(AMPCPU , 1, 0) ///< Set when compiling for C++AMP kernels on CPU. +CODEGENOPT(HCIsDevice , 1, 0) ///< Set when compiling for HC kernels. CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors. CODEGENOPT(RegisterGlobalDtorsWithAtExit, 1, 1) ///< Use atexit or __cxa_atexit to register global destructors. CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ab57e1b99f1..099d2348303 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -8672,7 +8672,7 @@ def err_amp_bad_reinterpret_cast_from_pointer_to_functionptr : Error< def err_amp_memory_operation : Error< "operator is not supported in amp-compatible codes'">; def err_amp_unsupported_reference_or_pointer : Error< -"pointer or reference is not allowed as pointed to type, array element type or data member type (except reference to concurrency::array/texture)">; +"pointer or reference is not allowed as pointed to type, array element type or data member type (except reference to hc::array/texture)">; def err_amp_incompatible : Error< "the field type is not amp-compatible">; def err_amp_type_unsupported : Error< @@ -8706,7 +8706,7 @@ def err_amp_call_from_cpu_to_amp : Error< def err_amp_call_from_amp_to_cpu : Error< "call from AMP-restricted function to CPU-restricted function">; def err_amp_call_from_both_amp_and_cpu_to_disctint : Error< -"call from both amp and cpu restricted function to disctint restricted function">; +"call from both amp and cpu restricted function to distinct restricted function">; def err_amp_need_4_byte_aligned : Error< "variables in AMP-restricted function shall be 4-bytes aligned">; def err_amp_captured_variable_type : Error< diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 6274cec2f20..344b6c9f907 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -218,10 +218,7 @@ LANGOPT(GPURelocatableDeviceCode, 1, 0, "generate relocatable device code") LANGOPT(CPlusPlusAMP , 1, 0, "C++AMP") LANGOPT(DevicePath , 1, 0, "C++AMP Device Path") -LANGOPT(AMPCPU , 1, 0, "C++AMP CPU Path") LANGOPT(HSAExtension , 1, 0, "C++AMP Extension for HSA") -LANGOPT(AutoAuto , 1, 0, "Enable auto-auto") -LANGOPT(AutoCompileForAccelerator, 1, 0, "Enable auto-compile-for-accelerator") LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index cdf6cbc84b9..e3a9d33de87 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -331,8 +331,7 @@ namespace clang { enum CPPAMPSpecifier { CPPAMP_None = 0x0, CPPAMP_CPU = 0x1, - CPPAMP_AMP = 0x2, - CPPAMP_AUTO = 0x4 + CPPAMP_AMP = 0x2 }; } // end namespace clang diff --git a/include/clang/Basic/Version.inc.in b/include/clang/Basic/Version.inc.in index a4579b18971..60daa8e8d69 100644 --- a/include/clang/Basic/Version.inc.in +++ b/include/clang/Basic/Version.inc.in @@ -7,7 +7,7 @@ #define HCC_VERSION_STRING "@HCC_VERSION_STRING@" #define HCC_VERSION_MAJOR @HCC_VERSION_MAJOR@ #define HCC_VERSION_MINOR @HCC_VERSION_MINOR@ -#define HCC_VERSION_PATCH "@HCC_VERSION_PATCH@-@KALMAR_SDK_COMMIT@-@KALMAR_FRONTEND_COMMIT@-@KALMAR_BACKEND_COMMIT@" +#define HCC_VERSION_PATCH "@HCC_VERSION_PATCH@-@HC_SDK_COMMIT@-@HC_FRONTEND_COMMIT@-@HC_BACKEND_COMMIT@" #define HCC_VERSION_WORKWEEK @HCC_VERSION_PATCH@ -#define KALMAR_BACKEND @KALMAR_BACKEND@ +#define HC_BACKEND @HC_BACKEND@ diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index d735317b870..bc5bab40224 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -842,21 +842,9 @@ def fopenmp_host_ir_file_path : Separate<["-"], "fopenmp-host-ir-file-path">, def famp_is_device : Flag<["-"], "famp-is-device">, HelpText<"Generate code for AMP kernels">; -def famp_cpu : Flag<["-"], "famp-cpu">, - HelpText<"Generate code for AMP CPU kernels">; - def fhsa_extension : Flag<["-"], "fhsa-ext">, HelpText<"Enable HSA-specific rules for C++AMP kernels">; -def fno_auto_auto : Flag<["-"], "fno-auto-auto">, - HelpText<"Disable auto-auto feature (Obsolete, use -fauto-auto to explicit enable it instead)">; - -def fauto_auto : Flag<["-"], "fauto-auto">, - HelpText<"Enable auto-auto feature">; - -def fauto_compile_for_accelerator : Flag<["-"], "fauto-compile-for-accelerator">, - HelpText<"Enable auto-compile-for-accelerator feature">; - } // let Flags = [CC1Option] //===----------------------------------------------------------------------===// diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 488497299d3..3e2b276b352 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -156,7 +156,7 @@ class InputKind { ///@{ Languages that the frontend can parse and compile. C, CXX, - CXXAMP, + CXXAMP, ObjC, ObjCXX, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index c7d86af4d00..f2f455500bc 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -718,9 +718,9 @@ class Parser : public CodeCompletionHandler { return PP.LookAhead(N-1); } - /// C++ AMP-specific - /// check if the given scope is AMP-restricted - bool IsInAMPFunction(Scope *); + /// HC-specific + /// check if the given scope is [[hc]] + bool IsInHCFunction(Scope *); public: /// NextToken - This peeks ahead one token and returns it without @@ -1414,9 +1414,6 @@ class Parser : public CodeCompletionHandler { bool StopAtSemi = true, bool ConsumeFinalToken = true); - // C++AMP - bool CXXAMPFindRestrictionSeq(CachedTokens &Toks, bool ConsumeFinalToken); - //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. struct ParsedAttributesWithRange : ParsedAttributes { @@ -2653,11 +2650,6 @@ class Parser : public CodeCompletionHandler { void ParseBracketDeclarator(Declarator &D); void ParseMisplacedBracketDeclarator(Declarator &D); - // C++AMP - unsigned ParseRestrictionSpecification(Declarator &D, - ParsedAttributes &Attrs, - SourceLocation &DeclEndLoc); - //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index 143f67eef65..3346b72722b 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -202,8 +202,8 @@ class Scope { /// Used to determine if errors occurred in this scope. DiagnosticErrorTrap ErrorTrap; - /// C++AMP restriction specifier - unsigned short CXXAMPSpecifier; + /// HC restriction specifier + unsigned short HCSpecifier; /// A lattice consisting of undefined, a single NRVO candidate variable in /// this scope, or over-defined. The bit is true when over-defined. @@ -386,24 +386,20 @@ class Scope { return getFlags() & Scope::FunctionPrototypeScope; } - /// \brief C++AMP restriction specifiers - enum CPPAMPSpecifier { - CPPAMP_None = 0x0, - CPPAMP_CPU = 0x1, - CPPAMP_AMP = 0x2, - CPPAMP_AUTO = 0x4 + /// \brief HC restriction specifiers + enum HCSpecifier { + HC_None = 0x0, + HC_CPU = 0x1, + HC_HC = 0x2 }; - void setCXXAMPSpecifier(unsigned A) { CXXAMPSpecifier = A; } - void setAMPScope() { CXXAMPSpecifier |= CPPAMP_AMP; } - void setCPUScope() { CXXAMPSpecifier |= CPPAMP_CPU; } - bool isAMPScope() const { - return CXXAMPSpecifier & CPPAMP_AMP; + void setHCSpecifier(unsigned A) { HCSpecifier = A; } + void setHCScope() { HCSpecifier |= HC_HC; } + void setCPUScope() { HCSpecifier |= HC_CPU; } + bool isHCScope() const { + return HCSpecifier & HC_HC; } bool isCPUScope() const { - return CXXAMPSpecifier & CPPAMP_CPU; - } - bool isAUTOScope() const { - return CXXAMPSpecifier & CPPAMP_AUTO; + return HCSpecifier & HC_CPU; } /// isAtCatchScope - Return true if this scope is \@catch. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 3130cdf50f9..d1c68ea72a5 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1864,9 +1864,9 @@ class Sema { std::unique_ptr CCC = nullptr); // C++AMP declarator diagnostic functions - bool DiagnoseCXXAMPDecl(Decl* Dcl, bool CheckContainer = false, bool IsInfer = false); - bool IsCXXAMPTileStatic(Declarator &D); - void DiagnosticCXXAMPTileStatic(Declarator &D, Decl *Dcl); + bool DiagnoseHCDecl(Decl* Dcl, bool CheckContainer = false, bool IsInfer = false); + bool IsHCTileStatic(Declarator &D); + void DiagnosticHCTileStatic(Declarator &D, Decl *Dcl); /// Describes the detailed kind of a template name. Used in diagnostics. enum class TemplateNameKindForDiagnostics { @@ -2070,9 +2070,6 @@ class Sema { /// \c constexpr in C++11 or has an 'auto' return type in C++14). bool canSkipFunctionBody(Decl *D); - // C++AMP restriction specifier inferring routine - void TryCXXAMPRestrictionInferring(Decl *D, Stmt *Body); - void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); @@ -2552,9 +2549,8 @@ class Sema { Ovl_NonFunction }; - // C++AMP diagnostic routine on destructor overload resolution - void DiagnoseCXXAMPDtorOverload(FunctionDecl *New, - const LookupResult &Old); + // HC diagnostic routine on destructor overload resolution + void DiagnoseHCDtorOverload(FunctionDecl *New, const LookupResult &Old); OverloadKind CheckOverload(Scope *S, FunctionDecl *New, @@ -2861,12 +2857,11 @@ class Sema { OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); - // C++AMP restriction specifier scope checking routines - bool IsInAMPRestricted(); + // HC restriction specifier scope checking routines + bool IsInHCRestricted(); // Determine if in CPU and/or AMP restricted codes bool IsInAnyExplicitRestricted(); - void GetCXXAMPParentRestriction(Scope* SC, bool& ParentCPU, - bool& ParentAMP, bool&ParentAUTO); + void GetHCParentRestriction(Scope *SC, bool &ParentCPU, bool &ParentHC); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, @@ -2981,8 +2976,8 @@ class Sema { Expr *Range, ExprResult *CallExpr); // C++AMP diagnostic routine on overloaded call expressions - void DiagnoseCXXAMPOverloadedCallExpr(SourceLocation LParenLoc, - FunctionDecl* Callee); + void DiagnoseHCOverloadedCallExpr(SourceLocation LParenLoc, + FunctionDecl* Callee); ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, @@ -3175,15 +3170,16 @@ class Sema { typedef std::function TypoRecoveryCallback; - // C++AMP type checking routine for kernel codes + // TODO: Fix for winter cleanup. + // HC type checking routine for kernel codes public: bool IsIncompatibleType(const Type* Ty, bool CheckContainer = false, bool IsInfer = false); private: - // C++AMP type checking routine for kernel codes - bool IsCXXAMPUnsupportedPointerType(const Type* Ty, + // HC type checking routine for kernel codes + bool IsHCUnsupportedPointerType(const Type *Ty, bool CheckContainer = false, bool IsInfer = false); - bool IsCXXAMPUnsupportedReferenceType(const Type* Ty, + bool IsHCUnsupportedReferenceType(const Type* Ty, bool CheckContainer = false, bool IsInfer = false); bool CppLookupName(LookupResult &R, Scope *S); @@ -4419,9 +4415,9 @@ class Sema { ParmVarDecl *Param, const Expr *ArgExpr); - // C++AMP diagnotic routine on C++ method call expressions - void DiagnoseCXXAMPMethodCallExpr(SourceLocation LParenLoc, - CXXMethodDecl *Callee); + // HC diagnotic routine on C++ method call expressions + void DiagnoseHCMethodCallExpr(SourceLocation LParenLoc, + CXXMethodDecl *Callee); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma @@ -5014,22 +5010,6 @@ class Sema { void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); - /// Defines an AMP CUP-side serialize function. - void DefineAmpCpuSerializeFunction(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl); - /// Defines an AMP GPU-side deserialize function. - void DefineAmpGpuDeSerializeFunction(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl); - /// Declare trampoline name lookup code for AMP CPU-side - void DeclareAMPTrampolineName(CXXRecordDecl *ClassDecl, - DeclarationName Name); - /// Declare trampoline code for AMP GPU-side entry - void DeclareAMPTrampoline(CXXRecordDecl *ClassDecl, - DeclarationName Name); - /// Define trampoline code for AMP GPU-side entry - void DefineAMPTrampoline(SourceLocation CurrentLocation, - CXXMethodDecl *OperatorCall); - /// Declare the implicit move assignment operator for the given class. /// /// \param ClassDecl The Class declaration into which the implicit @@ -5941,19 +5921,6 @@ class Sema { /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); - /// \brief Test if a given class requires a - /// C++AMP deserializer declaration - bool NeedAMPDeserializer(CXXRecordDecl *ClassDecl); - /// \brief Test if a given class has a C++AMP deserializer declaration - bool HasDeclaredAMPDeserializer(CXXRecordDecl *ClassDecl); - - // Declare C++AMP serializer and deserializer - typedef SmallVector AMPDeserializerArgs; - void DeclareAMPSerializer(CXXRecordDecl *ClassDecl, - DeclarationName Name); - void DeclareAMPDeserializer(CXXRecordDecl *ClassDecl, - AMPDeserializerArgs *Args); - void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); void ActOnMemInitializers(Decl *ConstructorDecl, @@ -6487,10 +6454,10 @@ class Sema { }; // C++AMP diagnotic routine for template arguments - void DiagnoseCXXAMPTemplateArgument(NamedDecl *Param, - const TemplateArgumentLoc &AL, - NamedDecl *Template, - SourceLocation TemplateLoc); + void DiagnoseHCTemplateArgument(NamedDecl *Param, + const TemplateArgumentLoc &AL, + NamedDecl *Template, + SourceLocation TemplateLoc); bool CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, @@ -9668,8 +9635,9 @@ class Sema { Incompatible }; - // C++AMP diagnostic routine for expressions - void DiagnoseCXXAMPExpr(Expr* Stripped, ExprResult &HS, bool DiagnoseWhenStatic=false); + // HC diagnostic routine for expressions + void DiagnoseHCExpr(Expr *Stripped, + ExprResult &HS, bool DiagnoseWhenStatic = false); /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h index d51fce550ae..318cb5d379e 100644 --- a/include/clang/Sema/SemaInternal.h +++ b/include/clang/Sema/SemaInternal.h @@ -66,11 +66,37 @@ inline bool DeclAttrsMatchCUDAMode(const LangOptions &LangOpts, Decl *D) { inline bool DeclAttrsMatchHCCMode(const LangOptions &LangOpts, Decl *D) { if (!LangOpts.CPlusPlusAMP || !D) return true; - bool isDeviceSideDecl = D->hasAttr() || + bool isDeviceSideDecl = D->hasAttr() || D->hasAttr(); return isDeviceSideDecl == LangOpts.DevicePath; } +// Helper function to (possibly) add [[cpu]] and / or [[hc]] to local classes +// (e.g. lambdas) which are defined in a [[cpu]] and / or [[hc]] context. +inline void MaybeAddHCAttr(const LangOptions &LangOpts, FunctionDecl *FD) { + if (!FD) return; + if (!LangOpts.CPlusPlusAMP) return; + + bool hasCPU = FD->hasAttr(); + bool hasHC = FD->hasAttr(); + auto DC = FD->getDeclContext(); + + while (DC && (!hasHC || !hasCPU)) { + if (auto ParentFD = dyn_cast(DC)) { + if (ParentFD->hasAttr() && !hasHC) { + FD->addAttr(HCRestrictHCAttr::CreateImplicit(FD->getASTContext())); + hasHC = true; + } + if (ParentFD->hasAttr() && !hasCPU) { + FD->addAttr(HCRestrictCPUAttr::CreateImplicit(FD->getASTContext())); + hasCPU = true; + } + } + + DC = DC->getParent(); + } +} + // Directly mark a variable odr-used. Given a choice, prefer to use // MarkVariableReferenced since it does additional checks and then // calls MarkVarDeclODRUsed. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 625ee0e0f30..19336377734 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -9638,6 +9638,21 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, return GVA_DiscardableODR; } +static bool isDeclareTargetToDeclaration(const Decl *VD) { + for (const Decl *D : VD->redecls()) { + if (!D->hasAttrs()) + continue; + if (const auto *Attr = D->getAttr()) + return Attr->getMapType() == OMPDeclareTargetDeclAttr::MT_To; + } + if (const auto *V = dyn_cast(VD)) { + if (const VarDecl *TD = V->getTemplateInstantiationPattern()) + return isDeclareTargetToDeclaration(TD); + } + + return false; +} + static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, const Decl *D, GVALinkage L) { // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx @@ -9654,8 +9669,12 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, // visible externally so they can be launched from host. if (L == GVA_DiscardableODR || L == GVA_Internal) return GVA_StrongODR; - } else if (Context.getLangOpts().CPlusPlusAMP && Context.getLangOpts().DevicePath && D->hasAttr() && (D->getAttr()->getAnnotation() == "__cxxamp_trampoline")) { - return GVA_StrongODR; + } else if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice && + isDeclareTargetToDeclaration(D)) { + // Static variables must be visible externally so they can be mapped from + // host. + if (L == GVA_Internal) + return GVA_StrongODR; } return L; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 707897db3e9..aa9200fe736 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -546,17 +546,6 @@ bool CXXRecordDecl::isTriviallyCopyable() const { return true; } -CXXMethodDecl *CXXRecordDecl::getCXXAMPDeserializationConstructor() const { - CXXMethodDecl *Deserializer = NULL; - for (ctor_iterator CtorIt = ctor_begin(), CtorE = ctor_end(); - CtorIt != CtorE; ++CtorIt) { - if (CtorIt->hasAttr()) - if (CtorIt->getAttr()->getAnnotation().find("deserialize") != StringRef::npos) - Deserializer = *CtorIt; - } - return Deserializer; -} - void CXXRecordDecl::markedVirtualFunctionPure() { // C++ [class.abstract]p2: // A class is abstract if it has at least one pure virtual function. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ba2e0b8b3f2..03020c0bd0e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4021,7 +4021,7 @@ bool Type::isGPUArrayType() const { CXXRecordDecl* ClassDecl = type->getAsCXXRecordDecl(); NamespaceDecl* NSDecl = dyn_cast(ClassDecl->getEnclosingNamespaceContext()); if (ClassDecl && (ClassDecl->getName() == "array") - && NSDecl && (NSDecl->getName() == "hc" || NSDecl->getName() == "Concurrency")) { + && NSDecl && (NSDecl->getName() == "hc")) { gpu_array_flag = true; } } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index c025cb6e763..a257e5ec651 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -728,9 +728,10 @@ FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const { const SrcMgr::SLocEntry *I; // FIXME: Handle file start location - // It is CXXAMP Specific. However it shall be ok in general - bool patch = (LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() <= SLocOffset); - if (LastFileIDLookup.ID < 0 || patch || + // It is HC Specific. However it shall be ok in general - TODO: review. + bool Patch = + (LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() <= SLocOffset); + if (LastFileIDLookup.ID < 0 || Patch || LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { // Neither loc prunes our search. I = LocalSLocEntryTable.end(); diff --git a/lib/CodeGen/CGAMPRuntime.cpp b/lib/CodeGen/CGAMPRuntime.cpp index a83d52a1ac1..dc8574e7d8c 100644 --- a/lib/CodeGen/CGAMPRuntime.cpp +++ b/lib/CodeGen/CGAMPRuntime.cpp @@ -7,9 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This provides an abstract class for C++ AMP code generation. Concrete -// subclasses of this implement code generation for specific C++ AMP -// runtime libraries. +// This provides an abstract class for HC code generation. Concrete subclasses +// of this implement code generation for specific HC runtime libraries. // //===----------------------------------------------------------------------===// @@ -23,369 +22,9 @@ namespace clang { namespace CodeGen { -CGAMPRuntime::~CGAMPRuntime() {} - -/// Creates an instance of a C++ AMP runtime class. -CGAMPRuntime *CreateAMPRuntime(CodeGenModule &CGM) { - return new CGAMPRuntime(CGM); -} -static CXXMethodDecl *findValidIndexType(QualType IndexTy) { - CXXRecordDecl *IndexClass = (*IndexTy).getAsCXXRecordDecl(); - CXXMethodDecl *IndexConstructor = NULL; - if (IndexClass) { - for (CXXRecordDecl::method_iterator CtorIt = IndexClass->method_begin(), - CtorE = IndexClass->method_end(); - CtorIt != CtorE; ++CtorIt) { - if (CtorIt->hasAttr() && - CtorIt->getAttr()->getAnnotation() == - "__cxxamp_opencl_index") { - IndexConstructor = *CtorIt; - } - } - } - return IndexConstructor; -} - - -void CGAMPRuntime::EmitCXXAMPDeserializer(CodeGenFunction &CGF, - const FunctionDecl *Trampoline, FunctionArgList& Args, - Address& ai) { - - const CXXRecordDecl *ClassDecl = dyn_cast(Trampoline)->getParent(); - - CXXConstructorDecl *DeserializeConstructor = - dyn_cast(ClassDecl->getCXXAMPDeserializationConstructor()); - assert(DeserializeConstructor); - - CallArgList DeserializerArgs; - - // this - DeserializerArgs.add(RValue::get(ai.getPointer()), - DeserializeConstructor->getThisType()); - - // the rest of constructor args. Create temporary objects for references - // on stack - CXXConstructorDecl::param_iterator CPI = DeserializeConstructor->param_begin(), - CPE = DeserializeConstructor->param_end(); - - for (FunctionArgList::iterator I = Args.begin(); - I != Args.end() && CPI != CPE; ++CPI) { - // Reference types are only allowed to have one level; i.e. no - // class base {&int}; class foo { bar &base; }; - QualType MemberType = (*CPI)->getType().getNonReferenceType(); - if (MemberType != (*CPI)->getType()) { - if (!CGM.getLangOpts().HSAExtension) { - - assert(MemberType.getTypePtr()->isClassType() == true && - "Only supporting taking reference of classes"); - - CXXRecordDecl *MemberClass = MemberType.getTypePtr()->getAsCXXRecordDecl(); - - CXXConstructorDecl *MemberDeserializer = dyn_cast( - MemberClass->getCXXAMPDeserializationConstructor()); - assert(MemberDeserializer); - - std::vectorMemberArgDeclRefs; - for (CXXMethodDecl::param_iterator MCPI = MemberDeserializer->param_begin(), - MCPE = MemberDeserializer->param_end(); MCPI!=MCPE; ++MCPI, ++I) { - - Expr *ArgDeclRef = DeclRefExpr::Create(CGM.getContext(), - NestedNameSpecifierLoc(), - SourceLocation(), - const_cast(*I), - false, - SourceLocation(), - (*MCPI)->getType(), VK_RValue); - MemberArgDeclRefs.push_back(ArgDeclRef); - } - - // Allocate "this" for member referenced objects - Address mai = CGF.CreateMemTemp(MemberType); - - // Emit code to call the deserializing constructor of temp objects - CXXConstructExpr *CXXCE = CXXConstructExpr::Create(CGM.getContext(), - MemberType, - SourceLocation(), - MemberDeserializer, - false, - MemberArgDeclRefs, - false, false, false, false, - CXXConstructExpr::CK_Complete, - SourceLocation()); - - CGF.EmitCXXConstructorCall(MemberDeserializer, Ctor_Complete, false, false, mai, CXXCE, AggValueSlot::DoesNotOverlap, false); - DeserializerArgs.add(RValue::get(mai.getPointer()), (*CPI)->getType()); - - } else { // HSA extension check - - if (MemberType.getTypePtr()->isClassType()) { - - // hc::array should still be serialized as traditional C++AMP objects - if (MemberType.getTypePtr()->isGPUArrayType()) { - - CXXRecordDecl *MemberClass = MemberType.getTypePtr()->getAsCXXRecordDecl(); - - CXXConstructorDecl *MemberDeserializer = - dyn_cast(MemberClass->getCXXAMPDeserializationConstructor()); - assert(MemberDeserializer); - - std::vectorMemberArgDeclRefs; - for (CXXMethodDecl::param_iterator MCPI = MemberDeserializer->param_begin(), - MCPE = MemberDeserializer->param_end(); MCPI!=MCPE; ++MCPI, ++I) { - - Expr *ArgDeclRef = DeclRefExpr::Create(CGM.getContext(), - NestedNameSpecifierLoc(), - SourceLocation(), - const_cast(*I), - false, - SourceLocation(), - (*MCPI)->getType(), VK_RValue); - - MemberArgDeclRefs.push_back(ArgDeclRef); - } - - // Allocate "this" for member referenced objects - Address mai = CGF.CreateMemTemp(MemberType); - - // Emit code to call the deserializing constructor of temp objects - CXXConstructExpr *CXXCE = CXXConstructExpr::Create(CGM.getContext(), - MemberType, - SourceLocation(), - MemberDeserializer, - false, - MemberArgDeclRefs, - false, false, false, false, - CXXConstructExpr::CK_Complete, - SourceLocation()); - - CGF.EmitCXXConstructorCall(MemberDeserializer, Ctor_Complete, false, false, mai, CXXCE, AggValueSlot::DoesNotOverlap, false); - DeserializerArgs.add(RValue::get(mai.getPointer()), (*CPI)->getType()); - - } else { - - // capture by refernce for HSA - Expr *ArgDeclRef = DeclRefExpr::Create(CGM.getContext(), - NestedNameSpecifierLoc(), - SourceLocation(), - const_cast(*I), false, - SourceLocation(), - (*I)->getType(), VK_RValue); - - RValue ArgRV = CGF.EmitAnyExpr(ArgDeclRef); - DeserializerArgs.add(ArgRV, CGM.getContext().getPointerType(MemberType)); - ++I; - } - - } else { - - // capture by refernce for HSA - Expr *ArgDeclRef = DeclRefExpr::Create(CGM.getContext(), - NestedNameSpecifierLoc(), - SourceLocation(), - const_cast(*I), false, - SourceLocation(), - (*I)->getType(), VK_RValue); - - RValue ArgRV = CGF.EmitAnyExpr(ArgDeclRef); - DeserializerArgs.add(ArgRV, CGM.getContext().getPointerType(MemberType)); - ++I; - } - } // HSA extension check - - } else { - - Expr *ArgDeclRef = DeclRefExpr::Create(CGM.getContext(), - NestedNameSpecifierLoc(), - SourceLocation(), - const_cast(*I), false, - SourceLocation(), - (*I)->getType(), VK_RValue); - - RValue ArgRV = CGF.EmitAnyExpr(ArgDeclRef); - DeserializerArgs.add(ArgRV, (*CPI)->getType()); - ++I; - } - } - - // Emit code to call the deserializing constructor - llvm::Constant *Callee = CGM.getAddrOfCXXStructor(DeserializeConstructor, - StructorType::Complete); - - const FunctionProtoType *FPT = - DeserializeConstructor->getType()->castAs(); - - const CGFunctionInfo &DesFnInfo = - CGM.getTypes().arrangeCXXStructorDeclaration(DeserializeConstructor, StructorType::Complete); - - for (unsigned I = 1, E = DeserializerArgs.size(); I != E; ++I) { - auto T = FPT->getParamType(I-1); - // EmitFromMemory is necessary in case function has bool parameter. - if (T->isBooleanType()) { - DeserializerArgs[I] = - CallArg(RValue::get(CGF.EmitFromMemory( - DeserializerArgs[I].getKnownRValue().getScalarVal(), T)), - T); - } - } - CGF.EmitCall(DesFnInfo, CGCallee::forDirect(Callee), ReturnValueSlot(), DeserializerArgs); -} - -/// Operations: -/// For each reference-typed members, construct temporary object -/// Invoke constructor of index -/// Invoke constructor of the class -/// Invoke operator(index) -void CGAMPRuntime::EmitTrampolineBody(CodeGenFunction &CGF, - const FunctionDecl *Trampoline, FunctionArgList& Args) { - const CXXRecordDecl *ClassDecl = dyn_cast(Trampoline)->getParent(); - assert(ClassDecl); - // Allocate "this" - Address ai = CGF.CreateMemTemp(QualType(ClassDecl->getTypeForDecl(),0)); - // Locate the constructor to call - if(ClassDecl->getCXXAMPDeserializationConstructor()!=NULL) { - EmitCXXAMPDeserializer(CGF,Trampoline,Args,ai); - } - - // Locate the type of Concurrency::index<1> - // Locate the operator to call - CXXMethodDecl *KernelDecl = NULL; - CXXMethodDecl *KernelDeclNoArg = NULL; - const FunctionType *MT = NULL; - QualType IndexTy; - for (CXXRecordDecl::method_iterator Method = ClassDecl->method_begin(), - MethodEnd = ClassDecl->method_end(); - Method != MethodEnd; ++Method) { - - CXXMethodDecl *MethodDecl = *Method; - if (MethodDecl->isOverloadedOperator() && - MethodDecl->getOverloadedOperator() == OO_Call && - MethodDecl->hasAttr()) { - - //Check types. - if(MethodDecl->getNumParams() > 1) { - continue; - } - else if (MethodDecl->getNumParams() == 0) { - MT = dyn_cast(MethodDecl->getType().getTypePtr()); - assert(MT); - KernelDeclNoArg = MethodDecl; - continue; - } - else { - ParmVarDecl *P = MethodDecl->getParamDecl(0); - IndexTy = P->getType().getNonReferenceType(); - if (!findValidIndexType(IndexTy)) - continue; - MT = dyn_cast(MethodDecl->getType().getTypePtr()); - assert(MT); - KernelDecl = MethodDecl; - break; - } - } - } - - // in case we couldn't find any kernel declarator - // raise error - if (!KernelDecl && !KernelDeclNoArg) { - CGF.CGM.getDiags().Report(ClassDecl->getLocation(), diag::err_amp_ill_formed_functor); - return; - } - - CXXMethodDecl *Kernel = (KernelDecl != NULL) ? KernelDecl : KernelDeclNoArg; - - // Invoke this->operator(index) - // Prepate the operator() to call - llvm::FunctionType *fnType = - CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeCXXMethodDeclaration(Kernel)); - llvm::Constant *fnAddr = CGM.GetAddrOfFunction(Kernel, fnType); - - // Prepare argument - CallArgList KArgs; - - // this - KArgs.add(RValue::get(ai.getPointer()), Kernel->getThisType()); - - if (KernelDecl) { - - // Allocate Index - Address index = CGF.CreateMemTemp(IndexTy); - - // Locate the constructor to call - CXXMethodDecl *IndexConstructor = findValidIndexType(IndexTy); - assert(IndexConstructor); - - // Emit code to call the Concurrency::index<1>::__cxxamp_opencl_index() - if (!CGF.getLangOpts().AMPCPU) { - if (CXXConstructorDecl *Constructor = - dyn_cast (IndexConstructor)) { - - CXXConstructExpr *CXXCE = CXXConstructExpr::Create(CGM.getContext(), - IndexTy, - SourceLocation(), - Constructor, - false, - ArrayRef(), - false, false, false, false, - CXXConstructExpr::CK_Complete, - SourceLocation()); - CGF.EmitCXXConstructorCall(Constructor, Ctor_Complete, false, false, index, CXXCE, AggValueSlot::DoesNotOverlap, false); - - } else { - llvm::FunctionType *indexInitType = CGM.getTypes().GetFunctionType( - CGM.getTypes().arrangeCXXMethodDeclaration(IndexConstructor)); - - llvm::Constant *indexInitAddr = CGM.GetAddrOfFunction(IndexConstructor, indexInitType); - - CGF.EmitCXXMemberOrOperatorCall(IndexConstructor, CGCallee::forDirect(indexInitAddr), - ReturnValueSlot(), index.getPointer(), /*ImplicitParam=*/0, - QualType(), /*CallExpr=*/nullptr, /*RtlArgs=*/nullptr); - } - } - - // *index - // index is of reference type of IndexTy. - KArgs.add(RValue::get(index.getPointer()), - CGF.getContext().getLValueReferenceType(IndexTy)); - } - - const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(KArgs, MT, false); - CGF.EmitCall(FnInfo, CGCallee::forDirect(fnAddr), ReturnValueSlot(), KArgs); - CGM.getTargetCodeGenInfo().setTargetAttributes(Kernel, CGF.CurFn, CGM); -} - -void CGAMPRuntime::EmitTrampolineNameBody(CodeGenFunction &CGF, - const FunctionDecl *Trampoline, FunctionArgList& Args) { - const CXXRecordDecl *ClassDecl = dyn_cast(Trampoline)->getParent(); - assert(ClassDecl); - // Locate the trampoline - // Locate the operator to call - CXXMethodDecl *TrampolineDecl = NULL; - for (CXXRecordDecl::method_iterator Method = ClassDecl->method_begin(), - MethodEnd = ClassDecl->method_end(); - Method != MethodEnd; ++Method) { - CXXMethodDecl *MethodDecl = *Method; - if (Method->hasAttr() && - Method->getAttr()->getAnnotation() == "__cxxamp_trampoline") { - TrampolineDecl = MethodDecl; - break; - } - } - assert(TrampolineDecl && "Trampoline not declared!"); - GlobalDecl GD(TrampolineDecl); - llvm::Constant *S = llvm::ConstantDataArray::getString(CGM.getLLVMContext(), - CGM.getMangledName(GD)); - llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), S->getType(), - true, llvm::GlobalValue::PrivateLinkage, S, "__cxxamp_trampoline.kernelname"); - GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - - //Create GetElementPtr(0, 0) - std::vector indices; - llvm::ConstantInt *zero = llvm::ConstantInt::get(CGM.getLLVMContext(), llvm::APInt(32, StringRef("0"), 10)); - indices.push_back(zero); - indices.push_back(zero); - llvm::Constant *const_ptr = llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, indices); - CGF.Builder.CreateStore(const_ptr, CGF.ReturnValue); - +/// Creates an instance of a HC runtime class. +CGHCRuntime *CreateHCRuntime(CodeGenModule &CGM) { + return new CGHCRuntime(CGM); } } // namespace CodeGen } // namespace clang diff --git a/lib/CodeGen/CGAMPRuntime.h b/lib/CodeGen/CGAMPRuntime.h index cc0490820f9..6e6a5aebea3 100755 --- a/lib/CodeGen/CGAMPRuntime.h +++ b/lib/CodeGen/CGAMPRuntime.h @@ -26,27 +26,17 @@ class FunctionArgList; class ReturnValueSlot; class RValue; -class CGAMPRuntime { -protected: +class CGHCRuntime { +protected: // TODO: Who would ever inherit from this? CodeGenModule &CGM; public: - CGAMPRuntime(CodeGenModule &CGM) : CGM(CGM) {} - virtual ~CGAMPRuntime(); - virtual void EmitTrampolineBody(CodeGenFunction &CGF, const FunctionDecl *FD, - FunctionArgList &Args); - void EmitTrampolineNameBody(CodeGenFunction &CGF, const FunctionDecl *FD, - FunctionArgList &Args); - -private: - - void EmitCXXAMPDeserializer(CodeGenFunction &CGF, - const FunctionDecl *Trampoline, - FunctionArgList& Args, Address& ai); + CGHCRuntime(CodeGenModule &CGM) : CGM(CGM) {} + virtual ~CGHCRuntime() = default; }; /// Creates an instance of a C++ AMP runtime class. -CGAMPRuntime *CreateAMPRuntime(CodeGenModule &CGM); +CGHCRuntime *CreateHCRuntime(CodeGenModule &CGM); } } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 8bcdeeaa305..21a9566cd5c 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -187,11 +187,11 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod, // which can be used orthogonally to OpenCL, such as e.g. __stdcall. FunctionType::ExtInfo Tmp = FTP->getExtInfo(); - if (FD && - FD->hasAttr() && - FD->getAttr()->getAnnotation() == - "__HIP_global_function__") { - Tmp = Tmp.withCallingConv(CallingConv::CC_OpenCLKernel); + if (FD && FD->hasAttr()) { + auto Annot = FD->getAttr()->getAnnotation(); + if (Annot == "__HCC_KERNEL__" || Annot == "__HIP_global_function__") { + Tmp = Tmp.withCallingConv(CallingConv::CC_OpenCLKernel); + } } return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 7c9d72bae1b..61a7233bc99 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -428,9 +428,9 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, D->hasAttr())) return; - if ( (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath && - D->hasAttr()) || - (getLangOpts().OpenMP && getOpenMPRuntime().emitDeclareTargetVarDefinition(D, Addr, PerformInit))) + if ((getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath && + D->hasAttr()) || + (getLangOpts().OpenMP && getOpenMPRuntime().emitDeclareTargetVarDefinition(D, Addr, PerformInit))) return; // Check if we've already initialized this decl. diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 7ca09c7402b..42728b41c80 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -26,13 +26,15 @@ #include "clang/AST/ASTLambda.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" -#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Intrinsics.h" @@ -55,7 +57,7 @@ static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts, return false; // Disable lifetime markers in HCC kernel build - if (LangOpts.CPlusPlusAMP && CGOpts.AMPIsDevice) + if (LangOpts.CPlusPlusAMP && CGOpts.HCIsDevice) return false; // Asan uses markers for use-after-scope checks. @@ -721,8 +723,7 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, llvm::MDNode::get(Context, argBaseTypeNames)); Fn->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(Context, argTypeQuals)); - if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata || - CGM.getLangOpts().CPlusPlusAMP) + if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata || CGM.getLangOpts().CPlusPlusAMP) Fn->setMetadata("kernel_arg_name", llvm::MDNode::get(Context, argNames)); } @@ -851,6 +852,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, CurFn = Fn; CurFnInfo = &FnInfo; + // TODO: Fix for winter cleanup // Relax duplicated function definition for C++AMP // // The reason is because in the modified GPU build path, both CPU and GPU @@ -861,11 +863,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, // Therefore, in the following case StartFunction() might be called twice // for function foo(), and thus we need to relax the assert check for C++AMP. // - // void foo() restrict(amp) { return 1; } - // void foo() restrict(cpu) { return 2; } + // void foo() [[hc]] { return 1; } + // void foo() [[cpu]] { return 2; } - if (getContext().getLangOpts().CPlusPlusAMP && - (CGM.getCodeGenOpts().AMPIsDevice || CGM.getCodeGenOpts().AMPCPU)) { + if (getContext().getLangOpts().CPlusPlusAMP && CGM.getCodeGenOpts().HCIsDevice) { } else { assert(CurFn->isDeclaration() && "Function already has body?"); } @@ -901,7 +902,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, } // Device code has all sanitizers disabled for now - if (CGM.getCodeGenOpts().AMPIsDevice) + if (CGM.getCodeGenOpts().HCIsDevice) SanOpts.clear(); // Apply sanitizer attributes to the function. @@ -981,13 +982,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath) { if (const FunctionDecl *FD = dyn_cast_or_null(D)) { - if (FD->hasAttr() && - FD->getAttr()->getAnnotation() == - "__HIP_global_function__") { - Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL); + if (FD->hasAttr()) { + auto Annot = FD->getAttr()->getAnnotation(); + + if (Annot == "__HCC_KERNEL__" || Annot == "__HIP_global_function__") { Fn->setDoesNotRecurse(); Fn->setDoesNotThrow(); Fn->setLinkage(llvm::Function::LinkageTypes::WeakODRLinkage); + } } } } @@ -1354,6 +1356,79 @@ shouldUseUndefinedBehaviorReturnOptimization(const FunctionDecl *FD, return !T.isTriviallyCopyableType(Context); } +static void handleHCArrayField(CodeGenFunction &CGF, FieldDecl *Field, + const FunctionDecl *FD, Expr *CallableRef) +{ + if (!Field->getType()->isReferenceType()) return; + if (Field->getType().getNonReferenceType().isConstQualified()) return; + if (!Field->getType().getNonReferenceType()->isGPUArrayType()) return; + + MemberExpr ArrRef{CallableRef, false, SourceLocation{}, Field, + Field->getBeginLoc(), + Field->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary}; + auto Array = Field->getType().getNonReferenceType()->getAsCXXRecordDecl(); + auto AddFn = *std::find_if(Array->method_begin(), + Array->method_end(), + [](const CXXMethodDecl *MD) { + static constexpr const char AddToCaptured[]{"add_to_captured_"}; + + return MD->getName().find(AddToCaptured) != std::string::npos; + }); + + MemberExpr AddFnRef{&ArrRef, false, SourceLocation{}, AddFn, + AddFn->getBeginLoc(), AddFn->getType(), VK_LValue, + OK_Ordinary}; + + CGF.EmitCallExpr(CXXMemberCallExpr::Create(CGF.CGM.getContext(), + &AddFnRef, {}, AddFn->getType(), + VK_LValue, + FD->getBody()->getBeginLoc())); +} + +static void maybeEmitHCArrayCapturePropagation(CodeGenFunction &CGF, + const FunctionDecl *FD) { + if (!FD->hasAttr()) return; + + static constexpr const char HCPfe[]{"__HC_PFE__"}; + if (FD->getAttr()->getAnnotation() != HCPfe) return; + + static constexpr unsigned int CallableIdx{2u}; + auto CallableT = FD->parameters()[CallableIdx] + ->getOriginalType() + .getNonReferenceType(); + auto Callable = CallableT->getAsCXXRecordDecl(); + auto TSI = FD->getASTContext() + .getTrivialTypeSourceInfo(CallableT, Callable->getBeginLoc()); + + auto CallableRef = + DeclRefExpr::Create(FD->parameters()[CallableIdx]->getASTContext(), + FD->parameters()[CallableIdx]->getQualifierLoc(), + SourceLocation{}, FD->parameters()[CallableIdx], false, + FD->parameters()[CallableIdx]->getBeginLoc(), + FD->parameters()[CallableIdx]->getOriginalType() + .getNonReferenceType(), + VK_LValue); + // TODO: fields should be visited as well + for (auto &&Field : Callable->fields()) { + handleHCArrayField(CGF, Field, FD, CallableRef); + } + // TODO: bases should be visited recursively. + for (auto &&Base : Callable->bases()) { + for (auto &&Field : Base.getType()->getAsRecordDecl()->fields()) { + CXXCastPath Tmp{&Base}; + auto BaseRef = CXXStaticCastExpr::Create(FD->getASTContext(), + CallableT, VK_LValue, + CastKind::CK_DerivedToBase, + CallableRef, &Tmp, TSI, + FD->getBody()->getBeginLoc(), + FD->getBody()->getBeginLoc(), + SourceRange{}); + handleHCArrayField(CGF, Field, FD, BaseRef); + } + } +} + void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo) { const FunctionDecl *FD = cast(GD.getDecl()); @@ -1404,18 +1479,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, EmitDestructorBody(Args); else if (isa(FD)) EmitConstructorBody(Args); - else if (getContext().getLangOpts().CPlusPlusAMP && - CGM.getCodeGenOpts().AMPIsDevice && - FD->hasAttr() && - FD->getAttr()->getAnnotation() == "__cxxamp_trampoline") - CGM.getAMPRuntime().EmitTrampolineBody(*this, FD, Args); - else if (getContext().getLangOpts().CPlusPlusAMP && - (!CGM.getCodeGenOpts().AMPIsDevice || CGM.getCodeGenOpts().AMPCPU)&& - FD->hasAttr() && - FD->getAttr()->getAnnotation() == "__cxxamp_trampoline_name") - CGM.getAMPRuntime().EmitTrampolineNameBody(*this, FD, Args); - else if (getContext().getLangOpts().CPlusPlusAMP && - !getContext().getLangOpts().DevicePath && + else if (getLangOpts().CPlusPlusAMP && + !getLangOpts().DevicePath && FD->hasAttr() && FD->getAttr()->getAnnotation() == "__HIP_global_function__") { @@ -1439,6 +1504,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // copy-constructors. emitImplicitAssignmentOperatorBody(Args); } else if (Body) { + if (getLangOpts().CPlusPlusAMP && !getLangOpts().DevicePath) { + maybeEmitHCArrayCapturePropagation(*this, FD); + } EmitFunctionBody(Body); } else llvm_unreachable("no definition for emitted function"); @@ -1449,9 +1517,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // C11 6.9.1p12: // If the '}' that terminates a function is reached, and the value of the // function call is used by the caller, the behavior is undefined. - // Relax the rule for C++AMP - if (!getLangOpts().CPlusPlusAMP && getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && !SawAsmBlock && - !FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) { + if (getLangOpts().CPlusPlus && + !FD->hasImplicitReturnZero() && + !SawAsmBlock && + !FD->getReturnType()->isVoidType() && + Builder.GetInsertBlock()) { bool ShouldEmitUnreachable = CGM.getCodeGenOpts().StrictReturn || shouldUseUndefinedBehaviorReturnOptimization(FD, getContext()); @@ -2405,10 +2475,10 @@ void CodeGenFunction::checkTargetFeatures(const CallExpr *E, if (!FeatureList || StringRef(FeatureList) == "") return; StringRef(FeatureList).split(ReqFeatures, ','); - if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature)) - CGM.getDiags().Report(E->getBeginLoc(), diag::err_builtin_needs_feature) - << TargetDecl->getDeclName() - << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); + // if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature)) + // CGM.getDiags().Report(E->getBeginLoc(), diag::err_builtin_needs_feature) + // << TargetDecl->getDeclName() + // << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); } else if (TargetDecl->hasAttr() || TargetDecl->hasAttr()) { @@ -2431,9 +2501,9 @@ void CodeGenFunction::checkTargetFeatures(const CallExpr *E, if (F.getValue()) ReqFeatures.push_back(F.getKey()); } - if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature)) - CGM.getDiags().Report(E->getBeginLoc(), diag::err_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; + // if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature)) + // CGM.getDiags().Report(E->getBeginLoc(), diag + // << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; } } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a9a50604cb9..23fa8d2c32c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -139,7 +139,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, if (LangOpts.CUDA) createCUDARuntime(); if (LangOpts.CPlusPlusAMP) - createAMPRuntime(); + createHCRuntime(); // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0. if (LangOpts.Sanitize.has(SanitizerKind::Thread) || @@ -227,8 +227,8 @@ void CodeGenModule::createCUDARuntime() { CUDARuntime.reset(CreateNVCUDARuntime(*this)); } -void CodeGenModule::createAMPRuntime() { - AMPRuntime.reset(CreateAMPRuntime(*this)); +void CodeGenModule::createHCRuntime() { + HCRuntime.reset(CreateHCRuntime(*this)); } void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) { @@ -435,7 +435,7 @@ void CodeGenModule::Release() { EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); // skip global annotation for HCC kernel path - if (Context.getLangOpts().CPlusPlusAMP && getCodeGenOpts().AMPIsDevice) { + if (Context.getLangOpts().CPlusPlusAMP && getCodeGenOpts().HCIsDevice) { } else { EmitGlobalAnnotations(); } @@ -1588,14 +1588,11 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, else if (const auto *SA = FD->getAttr()) F->setSection(SA->getName()); + // TODO: Fix for winter cleanup. // Prevent barrier functions be duplicated // Set C++AMP kernels carry AMDGPU_KERNEL calling convention if (getLangOpts().OpenCL || - (getLangOpts().CPlusPlusAMP && CodeGenOpts.AMPIsDevice)) { - if (F->getName()=="amp_barrier") { - F->addFnAttr(llvm::Attribute::NoDuplicate); - F->addFnAttr(llvm::Attribute::NoUnwind); - } + (getLangOpts().CPlusPlusAMP && CodeGenOpts.HCIsDevice)) { if (FD->hasAttr()) F->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL); } @@ -2206,23 +2203,23 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } // If this is C++AMP, be selective about which declarations we emit. - if (LangOpts.CPlusPlusAMP && !CodeGenOpts.AMPCPU) { - if (CodeGenOpts.AMPIsDevice) { - // If -famp-is-device switch is on, we are in GPU build path. + if (LangOpts.CPlusPlusAMP) { + if (CodeGenOpts.HCIsDevice) { + // If -fhc-is-device switch is on, we are in GPU build path. // Since we will emit both CPU codes and GPU codes to make C++ mangling // algorithm happy, we won't reject anything other than ones with only - // restrict(cpu). Another optimization pass will remove all CPU codes. - if (!Global->hasAttr() && - Global->hasAttr()) + // [[cpu]]. Another optimization pass will remove all CPU codes. + if (!Global->hasAttr() && + Global->hasAttr()) return; } else { // In host path: // let file-scope global variables be emitted - // let functions qualifired with restrict(amp) or [[hc]], - // but not with restrict(cpu) or [[cpu]] not be emitted + // let functions qualifired with [[hc]] or [[hc]], + // but not with [[cpu]] or [[cpu]] not be emitted if (!isa(Global) && - Global->hasAttr() && - !Global->hasAttr()) + Global->hasAttr() && + !Global->hasAttr()) return; } } @@ -2529,7 +2526,7 @@ namespace public: bool operator()(const Decl* x) { - if (!x || x->hasAttr()) return true; + if (!x || x->hasAttr()) return true; if (d_.count(x)) return d_[x]; if (d_.count(x->getNonClosureContext()) && @@ -2578,14 +2575,14 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); // If this is C++AMP, be selective about which declarations we emit. - if (LangOpts.CPlusPlusAMP && !CodeGenOpts.AMPCPU) { - if (CodeGenOpts.AMPIsDevice) { - // If -famp-is-device switch is on, we are in GPU build path. + if (LangOpts.CPlusPlusAMP) { + if (CodeGenOpts.HCIsDevice) { + // If -fhc-is-device switch is on, we are in GPU build path. if (!isWhiteListForHCC(*this, GD)) return; } else if (!isa(D) && - D->hasAttr() && - !D->hasAttr()) { + D->hasAttr() && + !D->hasAttr()) { return; } } @@ -2901,7 +2898,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( setDSOLocal(Entry); } - // Relax the rule for C++AMP + // Relax the rule for HC if (!LangOpts.CPlusPlusAMP) { // If there are two attempts to define the same mangled name, issue an @@ -3511,8 +3508,10 @@ LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { return LangAS::cuda_device; } - if (LangOpts.CPlusPlusAMP && LangOpts.DevicePath && - D && D->hasAttr()) + if (LangOpts.CPlusPlusAMP && + LangOpts.DevicePath && + D && + D->hasAttr()) return LangAS::hcc_tilestatic; return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D); @@ -4155,7 +4154,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, /*DontDefer=*/true, ForDefinition)); - if (D->getAttr()) { + if (D->getAttr()) { cast(GV)->addFnAttr("HC"); } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 7cec7379b62..d6a7c5bcb93 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -90,7 +90,7 @@ class CGObjCRuntime; class CGOpenCLRuntime; class CGOpenMPRuntime; class CGCUDARuntime; -class CGAMPRuntime; +class CGHCRuntime; class BlockFieldFlags; class FunctionArgList; class CoverageMappingModuleGen; @@ -318,7 +318,7 @@ class CodeGenModule : public CodeGenTypeCache { std::unique_ptr OpenCLRuntime; std::unique_ptr OpenMPRuntime; std::unique_ptr CUDARuntime; - std::unique_ptr AMPRuntime; + std::unique_ptr HCRuntime; std::unique_ptr DebugInfo; std::unique_ptr ObjCData; llvm::MDNode *NoObjCARCExceptionsMetadata = nullptr; @@ -485,7 +485,7 @@ class CodeGenModule : public CodeGenTypeCache { void createOpenCLRuntime(); void createOpenMPRuntime(); void createCUDARuntime(); - void createAMPRuntime(); + void createHCRuntime(); bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(GlobalDecl GD); @@ -582,10 +582,10 @@ class CodeGenModule : public CodeGenTypeCache { return *CUDARuntime; } - /// Return a reference to the configured C++AMP runtime. - CGAMPRuntime &getAMPRuntime() { - assert(AMPRuntime != nullptr); - return *AMPRuntime; + /// Return a reference to the configured HC runtime. + CGHCRuntime &getHCRuntime() { + assert(HCRuntime != nullptr); + return *HCRuntime; } ObjCEntrypoints &getObjCEntrypoints() const { diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 07aa639867a..c454681578c 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -7689,8 +7689,8 @@ ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, Ty = useFirstFieldIfTransparentUnion(Ty); - if (isAggregateTypeForABI(Ty) - && !getContext().getLangOpts().CPlusPlusAMP) { + if (isAggregateTypeForABI(Ty) && !getContext().getLangOpts().CPlusPlusAMP) { + // TODO: Fix for winter cleanup. // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (auto RAA = getRecordArgABI(Ty, getCXXABI())) @@ -7776,17 +7776,14 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { }; } -namespace { -inline llvm::APSInt getConstexprInt(const Expr *E, const ASTContext &Ctx) { - clang::Expr::EvalResult r; - APValue Val(llvm::APSInt(32)); - r.Val = Val; - if (E) - E->EvaluateAsInt(r, Ctx); +static llvm::APSInt getConstexprInt(const Expr *E, const ASTContext &Ctx) +{ + assert(E); - return r.Val.getInt(); + llvm::APSInt R = E->EvaluateKnownConstInt(Ctx); + + return R; } -} // namespace void AMDGPUTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { @@ -7808,10 +7805,8 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( const auto *FlatWGS = FD->getAttr(); if (ReqdWGS || FlatWGS) { - llvm::APSInt min = getConstexprInt(FlatWGS ? FlatWGS->getMin() : nullptr, - FD->getASTContext()); - llvm::APSInt max = getConstexprInt(FlatWGS ? FlatWGS->getMax() : nullptr, - FD->getASTContext()); + llvm::APSInt min = getConstexprInt(FlatWGS->getMin(), M.getContext()); + llvm::APSInt max = getConstexprInt(FlatWGS->getMax(), M.getContext()); unsigned Min = min.getZExtValue(); unsigned Max = max.getZExtValue(); @@ -7831,8 +7826,8 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( } if (const auto *Attr = FD->getAttr()) { - llvm::APSInt min = getConstexprInt(Attr->getMin(), FD->getASTContext()); - llvm::APSInt max = getConstexprInt(Attr->getMax(), FD->getASTContext()); + llvm::APSInt min = getConstexprInt(Attr->getMin(), M.getContext()); + llvm::APSInt max = getConstexprInt(Attr->getMax(), M.getContext()); unsigned Min = min.getZExtValue(); unsigned Max = max.getZExtValue(); @@ -7851,7 +7846,7 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( if (const auto *Attr = FD->getAttr()) { llvm::APSInt sgprs = - getConstexprInt(Attr->getNumSGPR(), FD->getASTContext()); + getConstexprInt(Attr->getNumSGPR(), M.getContext()); unsigned NumSGPR = sgprs.getZExtValue(); if (NumSGPR != 0) @@ -7860,7 +7855,7 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( if (const auto *Attr = FD->getAttr()) { llvm::APSInt vgprs = - getConstexprInt(Attr->getNumVGPR(), FD->getASTContext()); + getConstexprInt(Attr->getNumVGPR(), M.getContext()); unsigned NumVGPR = vgprs.getZExtValue(); if (NumVGPR != 0) @@ -7868,9 +7863,9 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( } if (const auto *Attr = FD->getAttr()) { - llvm::APSInt x = getConstexprInt(Attr->getX(), FD->getASTContext()); - llvm::APSInt y = getConstexprInt(Attr->getY(), FD->getASTContext()); - llvm::APSInt z = getConstexprInt(Attr->getZ(), FD->getASTContext()); + llvm::APSInt x = getConstexprInt(Attr->getX(), M.getContext()); + llvm::APSInt y = getConstexprInt(Attr->getY(), M.getContext()); + llvm::APSInt z = getConstexprInt(Attr->getZ(), M.getContext()); unsigned X = x.getZExtValue(); unsigned Y = y.getZExtValue(); diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 1a46073aaa3..5b3118d32e7 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -224,6 +224,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask Kinds = 0; const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); + if (TC.getTriple().getOS() == llvm::Triple::OSType::AMDHSA) return; + CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, options::OPT_fno_sanitize_cfi_cross_dso, false); diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 36d1d81286a..09a9850641a 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -3451,11 +3451,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // add HCC macros, based on compiler modes if (Args.hasArg(options::OPT_hc_mode)) { - CmdArgs.push_back("-D__KALMAR_HC__=1"); CmdArgs.push_back("-D__HCC_HC__=1"); } else if (Args.hasArg(options::OPT_famp) || Args.getLastArgValue(options::OPT_std_EQ).equals("c++amp")) { - CmdArgs.push_back("-D__KALMAR_AMP__=1"); CmdArgs.push_back("-D__HCC_AMP__=1"); } diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index 9a99db04d44..9d47b2c4d82 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -584,7 +584,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, ArgStringList CmdArgs; if (!HCLinker) - HCLinker = std::unique_ptr(new HCC::CXXAMPLink(getToolChain())); + HCLinker = std::unique_ptr(new HCC::HCLink(getToolChain())); HCLinker->ConstructLinkerJob(C, JA, Output, Inputs, Args, LinkingOutput, CmdArgs); this->ConstructLinkerJob(C, JA, Output, Inputs, Args, LinkingOutput, CmdArgs); diff --git a/lib/Driver/ToolChains/Gnu.h b/lib/Driver/ToolChains/Gnu.h index 348b0afd5f7..37b2bf9cb7b 100644 --- a/lib/Driver/ToolChains/Gnu.h +++ b/lib/Driver/ToolChains/Gnu.h @@ -63,7 +63,7 @@ class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { }; class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { - mutable std::unique_ptr HCLinker; + mutable std::unique_ptr HCLinker; public: Linker(const ToolChain &TC) : GnuTool("GNU::Linker", "linker", TC) {} @@ -293,7 +293,7 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { CudaInstallationDetector CudaInstallation; HCCInstallationDetector HCCInstallation; - friend class tools::HCC::CXXAMPLink; + friend class tools::HCC::HCLink; public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, diff --git a/lib/Driver/ToolChains/Hcc.cpp b/lib/Driver/ToolChains/Hcc.cpp index bc3d506c6e7..9dd23a9ba03 100755 --- a/lib/Driver/ToolChains/Hcc.cpp +++ b/lib/Driver/ToolChains/Hcc.cpp @@ -27,7 +27,9 @@ using namespace clang::driver::toolchains; using namespace clang::driver::tools; using namespace llvm::opt; -HCCInstallationDetector::HCCInstallationDetector(const Driver &D, const llvm::opt::ArgList &Args) : D(D) { +HCCInstallationDetector::HCCInstallationDetector(const Driver &D, + const llvm::opt::ArgList &Args) + : D(D) { std::string BinPath = D.Dir; std::string InstallPath = D.InstalledDir; auto &FS = D.getVFS(); @@ -36,14 +38,15 @@ HCCInstallationDetector::HCCInstallationDetector(const Driver &D, const llvm::op if (Args.hasArg(options::OPT_hcc_path_EQ)) HCCPathCandidates.push_back( Args.getLastArgValue(options::OPT_hcc_path_EQ)); - + HCCPathCandidates.push_back(InstallPath + "/.."); HCCPathCandidates.push_back(BinPath + "/.."); HCCPathCandidates.push_back(BinPath + "/../.."); for (const auto &HCCPath: HCCPathCandidates) { if (HCCPath.empty() || - !(FS.exists(HCCPath + "/include/hc.hpp") || FS.exists(HCCPath + "/include/hcc/hc.hpp")) || + !(FS.exists(HCCPath + "/include/hc.hpp") || + FS.exists(HCCPath + "/include/hcc/hc.hpp")) || !FS.exists(HCCPath + "/lib/libmcwamp.so")) continue; @@ -55,18 +58,26 @@ HCCInstallationDetector::HCCInstallationDetector(const Driver &D, const llvm::op } } -void HCCInstallationDetector::AddHCCIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { +void HCCInstallationDetector::AddHCCIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { if (IsValid) { CC1Args.push_back(DriverArgs.MakeArgString("-I" + IncPath + "/include")); - CC1Args.push_back(DriverArgs.MakeArgString("-I" + IncPath + "/hcc/include")); + CC1Args.push_back( + DriverArgs.MakeArgString("-I" + IncPath + "/hcc/include")); + CC1Args.push_back( + DriverArgs.MakeArgString("-I" + IncPath + "/third_party")); + CC1Args.push_back(DriverArgs.MakeArgString("-I/opt/rocm/hsa/include")); } } -void HCCInstallationDetector::AddHCCLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { +void HCCInstallationDetector::AddHCCLibArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { if (IsValid) { // add verbose flag to linker script if clang++ is invoked with --verbose flag if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("--verbose"); - + // Reverse translate the -lstdc++ option // Or add -lstdc++ when running on RHEL 7 or CentOS 7 if (Args.hasArg(options::OPT_Z_reserved_lib_stdcxx) || @@ -75,11 +86,13 @@ void HCCInstallationDetector::AddHCCLibArgs(const llvm::opt::ArgList &Args, llvm } CmdArgs.push_back(Args.MakeArgString("-L" + LibPath)); + CmdArgs.push_back(Args.MakeArgString("-L/opt/rocm/lib")); CmdArgs.push_back(Args.MakeArgString("--rpath=" + LibPath)); + CmdArgs.push_back(Args.MakeArgString("--rpath=/opt/rocm/lib")); for (auto &lib: SystemLibs) CmdArgs.push_back(lib); - + for (auto &lib: RuntimeLibs) CmdArgs.push_back(lib); @@ -226,7 +239,8 @@ namespace void remove_duplicate_targets(std::vector& TargetVec) { std::sort(TargetVec.begin(), TargetVec.end()); - TargetVec.erase(unique(TargetVec.begin(), TargetVec.end()), TargetVec.end()); + TargetVec.erase( + std::unique(TargetVec.begin(), TargetVec.end()), TargetVec.end()); } void construct_amdgpu_target_cmdargs( @@ -309,7 +323,7 @@ void HCC::Assembler::ConstructJob(Compilation &C, const JobAction &JA, #define HCC_TOOLCHAIN_RHEL false #endif -void HCC::CXXAMPLink::ConstructLinkerJob( +void HCC::HCLink::ConstructLinkerJob( Compilation &C, const JobAction &JA, const InputInfo &Output, @@ -324,7 +338,7 @@ void HCC::CXXAMPLink::ConstructLinkerJob( construct_amdgpu_target_cmdargs(C, getToolChain(), Args, CmdArgs); } -void HCC::CXXAMPLink::ConstructJob(Compilation &C, +void HCC::HCLink::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -422,5 +436,5 @@ Tool *HCCToolChain::buildAssembler() const { } Tool *HCCToolChain::buildLinker() const { - return new tools::HCC::CXXAMPLink(*this); + return new tools::HCC::HCLink(*this); } diff --git a/lib/Driver/ToolChains/Hcc.h b/lib/Driver/ToolChains/Hcc.h index 8b49f816ba2..c9516cc96a4 100755 --- a/lib/Driver/ToolChains/Hcc.h +++ b/lib/Driver/ToolChains/Hcc.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HCC_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HCC_H +#include "clang/Basic/Sanitizers.h" #include "clang/Driver/Action.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Tool.h" @@ -26,18 +27,21 @@ class HCCInstallationDetector { std::string IncPath; std::string LibPath; - std::vector SystemLibs = {"-ldl", "-lm", "-lpthread"}; - std::vector RuntimeLibs = {"-lhc_am", "-lmcwamp"}; + std::vector SystemLibs = {"-ldl","-lm", "-lpthread", + "-lhsa-runtime64"}; + std::vector RuntimeLibs; public: HCCInstallationDetector(const Driver &D, const llvm::opt::ArgList &Args); - - void AddHCCIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; - void AddHCCLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - + void AddHCCIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + void AddHCCLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + bool isValid() const { return IsValid; } - + void print(raw_ostream &OS) const; }; @@ -62,9 +66,9 @@ class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { }; // \brief C++AMP linker. -class LLVM_LIBRARY_VISIBILITY CXXAMPLink : public Tool { +class LLVM_LIBRARY_VISIBILITY HCLink : public Tool { public: - CXXAMPLink(const ToolChain &TC) : Tool("clamp-link", "HC linker", TC) {} + HCLink(const ToolChain &TC) : Tool("clamp-link", "HC linker", TC) {} bool hasGoodDiagnostics() const override { return true; } bool hasIntegratedAssembler() const override { return false; } @@ -105,17 +109,27 @@ class LLVM_LIBRARY_VISIBILITY HCCToolChain : public ToolChain { llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; - void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddHCCIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; - void AddHCCIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool useIntegratedAs() const override { return false; } // HCC ToolChain use DWARF version 2 by default unsigned GetDefaultDwarfVersion() const override { return 2; } + // No sanitizer support yet. + clang::SanitizerMask getSupportedSanitizers() const override { + return HostTC.getSupportedSanitizers(); + } + // HCC ToolChain doesn't support "-pg"-style profiling yet bool SupportsProfiling() const override { return false; } diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index b18bec6d4a5..972c527ec1d 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -912,7 +912,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { return false; // Create TargetInfo for the other side of CUDA and HCC compilation. - if ((getLangOpts().CUDA || getLangOpts().CPlusPlusAMP) && !getFrontendOpts().AuxTriple.empty()) { + if ((getLangOpts().CUDA || getLangOpts().CPlusPlusAMP) && + !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared(); TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple); TO->HostTriple = getTarget().getTriple().str(); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 13a0fb5b75c..b26e14b7f41 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -805,8 +805,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.PreserveAsmComments = !Args.hasArg(OPT_fno_preserve_as_comments); Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); - Opts.AMPIsDevice = Args.hasArg(OPT_famp_is_device); - Opts.AMPCPU = Args.hasArg(OPT_famp_cpu); + Opts.HCIsDevice = Args.hasArg(OPT_famp_is_device); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.RegisterGlobalDtorsWithAtExit = Args.hasArg(OPT_fregister_global_dtors_with_atexit); @@ -2909,17 +2908,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // C++ AMP: Decide host path or device path Opts.DevicePath = Args.hasArg(OPT_famp_is_device); - Opts.AMPCPU = Args.hasArg(OPT_famp_cpu); Opts.HSAExtension = Args.hasArg(OPT_fhsa_extension); - // rules for auto-auto: - // disabled by default, or explicitly disabled by -fno-auto-auto - // enabled by -fauto-auto - Opts.AutoAuto = Args.hasArg(OPT_fauto_auto) && !Args.hasArg(OPT_fno_auto_auto); - - // rules for auto-compile-for-accelerator: - Opts.AutoCompileForAccelerator = Args.hasArg(OPT_fauto_compile_for_accelerator); - // set CUDA mode for OpenMP target NVPTX if specified in options Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && T.isNVPTX() && Args.hasArg(options::OPT_fopenmp_cuda_mode); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 16554569194..49c3cab3c03 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -462,18 +462,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__HIP_DEVICE_COMPILE__"); } if(LangOpts.DevicePath) { - if(LangOpts.AMPCPU) { - Builder.defineMacro("__AMP_CPU__", "1"); - Builder.defineMacro("__KALMAR_ACCELERATOR__", "2"); - Builder.defineMacro("__HCC_ACCELERATOR__", "2"); - } else { - Builder.defineMacro("__GPU__", "1"); - Builder.defineMacro("__KALMAR_ACCELERATOR__", "1"); - Builder.defineMacro("__HCC_ACCELERATOR__", "1"); - } - } else { - Builder.defineMacro("__KALMAR_CPU__", "1"); - Builder.defineMacro("__HCC_CPU__", "1"); + Builder.defineMacro("__GPU__", "1"); + Builder.defineMacro("__HCC_ACCELERATOR__", "1"); } } @@ -575,7 +565,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__clang__"); // Clang Frontend // hcc macros - Builder.defineMacro("__KALMAR_CC__", "1"); + Builder.defineMacro("__HC_CC__", "1"); Builder.defineMacro("__HCC__", "1"); #define TOSTR2(X) #X @@ -598,7 +588,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // - CL : for non-HSA systems // - HLC : for HLC backend // - AMDGPU : for Lightning backend - Builder.defineMacro("__hcc_backend__", TOSTR(KALMAR_BACKEND)); + Builder.defineMacro("__hcc_backend__", TOSTR(HC_BACKEND)); #undef TOSTR #undef TOSTR2 @@ -1138,7 +1128,8 @@ void clang::InitializePreprocessor( if (InitOpts.UsePredefines) { // FIXME: This will create multiple definitions for most of the predefined // macros. This is not the right way to handle this. - if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice || LangOpts.CPlusPlusAMP) && PP.getAuxTargetInfo()) + if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice || LangOpts.CPlusPlusAMP) && + PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, Builder); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 132ce3778ad..e201f809584 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2268,7 +2268,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( if (isTokenEqualOrEqualTypo()) { SourceLocation EqualLoc = ConsumeToken(); - // C++ AMP-specific + // TODO: Fix for winter cleanup (maybe) + // HC-specific // tile_static variables can't be initialized. if (getLangOpts().CPlusPlusAMP) { if (IsTileStatic(D)) { @@ -2328,7 +2329,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } } else if (Tok.is(tok::l_paren)) { - // C++ AMP-specific + // TODO: Fix for winter cleanup (maybe) + // HC-specific // tile_static variables can't be initialized. if (getLangOpts().CPlusPlusAMP) { if (IsTileStatic(D)) { @@ -2390,6 +2392,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) && (!CurParsedObjCImpl || !D.isFunctionDeclarator())) { + // TODO: Fix for winter cleanup (maybe) // C++ AMP-specific // tile_static variables can't be initialized. if (getLangOpts().CPlusPlusAMP) { @@ -3775,13 +3778,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, getLangOpts()); break; case tok::kw_restrict: - // Must distinguish between '__restrict' and 'restrict(cpu,amp)': - // '__restrict' is a type qualifier - // 'restrict(cpu,amp)' is C++AMP restriction specifier - if (getLangOpts().CPlusPlusAMP) { - if (NextToken().is(tok::l_paren)) - return; - } isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLangOpts()); break; @@ -5744,6 +5740,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetRangeEnd(Tok.getLocation()); ConsumeToken(); goto PastIdentifier; + // TODO: Fix for winter cleanup (maybe) } else if (Tok.is(tok::identifier) && !D.mayHaveIdentifier() && !getLangOpts().CPlusPlusAMP) { // Relax the rule for C++AMP // We're not allowed an identifier here, but we got one. Try to figure out @@ -6189,65 +6186,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - // Parse C++AMP restriction specifier - unsigned cppampSpec = CPPAMP_None; - if (getLangOpts().CPlusPlusAMP) { - cppampSpec = ParseRestrictionSpecification(D, FnAttrs, EndLoc); - // Reset Scope's CXXAMP specifier - getCurScope()->setCXXAMPSpecifier(0); - // AMP-restricted function-only - if (cppampSpec & CPPAMP_AMP) { - - // check if there's incompatible parameters in the function declarator - for (SmallVector::iterator param = ParamInfo.begin(); param != ParamInfo.end(); ++param) { - ParmVarDecl *pvDecl = dyn_cast_or_null(param->Param); - if (pvDecl) { - QualType t = pvDecl->getOriginalType(); - const Type* Ty = t.getTypePtrOrNull(); - // reject incompatible scalar types - if (getLangOpts().HSAExtension) { - ; // hsa-ext - } else { - if (Ty->isCharType() || Ty->isWideCharType() || Ty->isSpecificBuiltinType(BuiltinType::Short) || Ty->isSpecificBuiltinType(BuiltinType::LongLong) || Ty->isSpecificBuiltinType(BuiltinType::LongDouble)) { - Diag(param->IdentLoc, diag::err_amp_illegal_function_parameter); - } - } - - // reject incompatible volatile type qualifier - if (t.isVolatileQualified()) { - Diag(param->IdentLoc, diag::err_amp_illegal_function_parameter_volatile); - } - - // reject incompatible enum types - if (Ty && Ty->isEnumeralType()) { - const EnumType* ETy = dyn_cast(Ty); - if (ETy && ETy->getDecl()) { - const Type* UTy = ETy->getDecl()->getIntegerType().getTypePtrOrNull(); - if (UTy->isCharType() || UTy->isWideCharType() || UTy->isSpecificBuiltinType(BuiltinType::Short) || UTy->isSpecificBuiltinType(BuiltinType::LongLong) || UTy->isSpecificBuiltinType(BuiltinType::LongDouble)) { - Diag(param->IdentLoc, diag::err_amp_illegal_function_parameter); - Diag(ETy->getDecl()->getBeginLoc(), diag::err_amp_illegal_function_parameter); - } - } - } - } - } - - // check if the return type is of incompatible type - if (!getLangOpts().HSAExtension && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_char) { - Diag(D.getBeginLoc(), diag::err_amp_illegal_function_return_char); - } else if (!getLangOpts().HSAExtension && D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_short) { - Diag(D.getBeginLoc(), diag::err_amp_illegal_function_return_short); - } else if (D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_volatile) { - Diag(D.getBeginLoc(), diag::err_amp_illegal_function_return_volatile); - } - - // check if the function is volatile-qualified - if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) { - Diag(D.getBeginLoc(), diag::err_amp_illegal_function_return_volatile); - } - } - } - // C++11 [expr.prim.general]p3: // If a declaration declares a member function or member function // template of a class X, the expression this is a prvalue of type @@ -6300,17 +6238,20 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ExceptionSpecTokens); if (ESpecType != EST_None) { EndLoc = ESpecRange.getEnd(); - - // C++AMP specific, reject exception specifiers for amp-restricted functions - if (getLangOpts().CPlusPlusAMP && (cppampSpec & CPPAMP_AMP)) { - Diag(ESpecRange.getBegin(), diag::err_amp_no_throw); - } } // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes // after the exception-specification. MaybeParseCXX11Attributes(FnAttrs); + // TODO: Fix for winter cleanup. + if (getLangOpts().CPlusPlusAMP && ESpecType == EST_Dynamic) { + for (auto &&A : FnAttrs) { + if (A.getKind() != ParsedAttr::AT_HC_HC) continue; + Diag(ESpecRange.getBegin(), diag::err_amp_no_throw); + } + } + // Parse trailing-return-type[opt]. LocalEndLoc = EndLoc; if (getLangOpts().CPlusPlus11 && Tok.is(tok::arrow)) { @@ -6320,18 +6261,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D, LocalEndLoc = Tok.getLocation(); SourceRange Range; - // C++AMP specific - // Update Scope to mark if it is in AMP, CPU or dual context - // FIXME: only used in Trailing return case for now - if (getLangOpts().CPlusPlusAMP) { - // Reset Scope's CXXAMP specifier - getCurScope()->setCXXAMPSpecifier(0); - if (cppampSpec & CPPAMP_AMP) - getCurScope()->setAMPScope(); - - if (cppampSpec & CPPAMP_CPU) - getCurScope()->setCPUScope(); - } TrailingReturnType = ParseTrailingReturnType(Range, D.mayBeFollowedByCXXDirectInit()); EndLoc = Range.getEnd(); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index a1b00ad7283..90306c248c9 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -4316,236 +4316,4 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration( } Braces.consumeClose(); -} - -/// CXXAMPFindRestrictionSeq - Consume and store the token at the passed -/// token container until the token '(' is reached (which gets -/// consumed/stored too, if ConsumeFinalToken) or End Chars are reached. -/// The EndChars are '{', '}' and ';' which present Funcion Definition Start, End and -/// Declaration End respectively. -/// Returns true if token '(' is found. -/// NOTE: This is a specialized version of Parser::ConsumeAndStoreUntil. -bool Parser::CXXAMPFindRestrictionSeq(CachedTokens &Toks, - bool ConsumeFinalToken) { - // We always want this function to consume at least one token if the first - // token isn't T and if not at EOF. - while (1) { - // If we found one of the tokens, stop and return true. - if (Tok.is(tok::l_paren)) { - if (ConsumeFinalToken) { - Toks.push_back(Tok); - ConsumeAnyToken(); - } - return true; - } - - switch (Tok.getKind()) { - case tok::eof: - // Ran out of tokens. - return false; - // End Chars - case tok::l_brace: - return false; - break; - case tok::r_brace: - return false; - break; - - case tok::code_completion: - Toks.push_back(Tok); - ConsumeCodeCompletionToken(); - break; - - case tok::string_literal: - case tok::wide_string_literal: - case tok::utf8_string_literal: - case tok::utf16_string_literal: - case tok::utf32_string_literal: - Toks.push_back(Tok); - ConsumeStringToken(); - break; - case tok::semi: - return false; - // FALL THROUGH. - default: - // consume this token. - Toks.push_back(Tok); - ConsumeToken(); - break; - } - } -} - -/// Parse a C++ restriction-specification if present (C++AMP restrict(amp,cpu)). -/// -/// restriction-specifier-seq: -/// restriction-specifier -/// restriction-specifier-seq restriction-specifier -/// -/// restriction-specifier: -/// 'restrict' ( restriction-seq ) -/// -/// restriction-seq: -/// restriction -/// restriction-seq, restriction -/// -/// restriction: -/// amp-restriction -/// 'cpu' -/// -/// amp-restriction: -/// 'amp' -unsigned Parser::ParseRestrictionSpecification(Declarator& D, - ParsedAttributes &Attrs, - SourceLocation &DeclEndLoc) { - unsigned retSpec = CPPAMP_None; - while (1) - { - if (Tok.isNot(tok::identifier)) // 'restrict' is an identifier - break; - - CachedTokens Ids; - if (CXXAMPFindRestrictionSeq(Ids, /*ConsumeFinalToken=*/false)) { - if (Ids.size() == 1) { - IdentifierInfo* II = Ids[0].getIdentifierInfo(); - if (II->getName() != "restrict") { - Diag(Ids[0], diag::err_expected_restrict); - DeclEndLoc = Tok.getLocation(); - break; - } - } else if (Ids.size() == 0) { - Diag(Tok, diag::err_expected_restrict); - DeclEndLoc = Tok.getLocation(); - break; - } else { - IdentifierInfo* II = Ids[0].getIdentifierInfo(); - if (II->getName() != "restrict") { - Diag(Ids[0], diag::err_expected_restrict); - DeclEndLoc = Tok.getLocation(); - break; - } - Diag(Ids[1], diag::err_expected_lparen_after_restriction); - DeclEndLoc = Tok.getLocation(); - break; - } - } else { - break; - } - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after_restriction); - DeclEndLoc = Tok.getLocation(); - break; - } - - BalancedDelimiterTracker T(*this, tok::l_paren); - T.consumeOpen(); - CachedTokens Toks; - if (ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) { - // We find the ')' we expected - // Parse restriction-seq: 'cpu', 'amp' - if (Toks.size() == 0) - Diag(Tok, diag::err_amp_empty_restriction); - - // The following usages are supported, - // restrict(,), restrict(,,,,), where number of ',' is not cared - // restrict(THE_RES,), restrict(THE_RES,,,,), where THE_RES is cpu, amp, auto - // or any supported restriction specifier in C++AMP - bool isStart = true; - for (unsigned i = 0; i < Toks.size(); ++i) { - if (Toks[i].is(tok::comma)) { - isStart = true; - } else { - IdentifierInfo* II = Toks[i].getIdentifierInfo(); - if(II) { - if (II->getName() == "cpu" || // 'cpu' is an identifier - II->getName() == "auto" || // 'auto' is a keyword - II->getName() == "amp" ) { // 'amp' is an identifier - // Clean front and next is tok::comma - if(isStart && ((i == Toks.size()-1) ||Toks[i+1].is(tok::comma))) { - SourceLocation AttrNameLoc = Toks[i].getLocation(); - Attrs.addNew(II, AttrNameLoc, 0, AttrNameLoc, /*0, - AttrNameLoc, */0, 0, ParsedAttr::AS_GNU); - - if (II->getName() == "cpu") - retSpec |= CPPAMP_CPU; - - if (II->getName() == "amp") - retSpec |= CPPAMP_AMP; - - if (II->getName() == "auto") - retSpec |= CPPAMP_AUTO; - } - } else { - // Not valid specifier - Diag(Toks[i], diag::err_amp_unrecognized_restriction) << II->getName(); - } - } else { - // Punctuators - Diag(Toks[i], diag::err_amp_unrecognized_restriction) - <getLocation(), diag::note_auto_restricted_prev_declaration); - } - } - // FIXME: this is an inefficient, yet effective method - // try walk up enclising scopes and find restriction specifiers - if (retSpec == CPPAMP_None) { - Scope *scope = getCurScope(); - while (scope) { - if (scope->getFlags() & Scope::FnScope) { - FunctionDecl *FD = dyn_cast_or_null(static_cast(scope->getEntity())); - if (FD) { - if (FD->hasAttr()) { - IdentifierInfo *II = &PP.getIdentifierTable().get("amp"); - assert(II); - Attrs.addNew(II, DeclEndLoc, 0, DeclEndLoc, /*0, DeclEndLoc, */0, 0, ParsedAttr::AS_GNU); - retSpec |= CPPAMP_AMP; - } - if (FD->hasAttr()) { - IdentifierInfo *II = &PP.getIdentifierTable().get("cpu"); - assert(II); - Attrs.addNew(II, DeclEndLoc, 0, DeclEndLoc, /*0, DeclEndLoc, */0, 0, ParsedAttr::AS_GNU); - retSpec |= CPPAMP_CPU; - } - } - } - scope = scope->getParent(); - } - } - - return retSpec; -} +} \ No newline at end of file diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d4740bf994b..3cf3b41ab58 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -32,14 +32,13 @@ #include "llvm/ADT/SmallVector.h" using namespace clang; -bool Parser::IsInAMPFunction(Scope *scope) { +bool Parser::IsInHCFunction(Scope *scope) { while (scope) { - if (scope->getFlags() & Scope::FnScope) { - FunctionDecl *FD = dyn_cast_or_null(static_cast(scope->getEntity())); - if (FD && FD->hasAttr()) { - return true; - } + if (!(scope->getFlags() & Scope::FnScope)) return false; + if (auto FD = dyn_cast_or_null(scope->getEntity())) { + if (FD->hasAttr()) return true; } + scope = scope->getParent(); } return false; @@ -178,9 +177,9 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { } if (Tok.is(tok::kw_throw)) { - // C++ AMP-specific, reject if we are in an AMP-restricted function - if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath && !getLangOpts().AMPCPU) { - if (IsInAMPFunction(getCurScope())) { + // HC-specific, reject if we are in an HC-restricted function + if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath) { + if (IsInHCFunction(getCurScope())) { Diag(Tok, diag::err_amp_illegal_keyword_throw); } } @@ -1222,9 +1221,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return Res; } case tok::kw_dynamic_cast: - // C++ AMP-specific, reject if we are in an AMP-restricted function + // HC-specific, reject if we are in an [[hc]] function if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath) { - if (IsInAMPFunction(getCurScope())) { + if (IsInHCFunction(getCurScope())) { Diag(Tok, diag::err_amp_illegal_keyword_dynamiccast); } } @@ -1234,9 +1233,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseCXXCasts(); break; case tok::kw_typeid: - // C++ AMP-specific, reject if we are in an AMP-restricted function + // HC-specific, reject if we are in an [[hc]] function if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath) { - if (IsInAMPFunction(getCurScope())) { + if (IsInHCFunction(getCurScope())) { Diag(Tok, diag::err_amp_illegal_keyword_typeid); } } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index dc6ec7dc26e..267c569b284 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -757,7 +757,7 @@ Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // try parse attributes before parameter list SourceLocation DeclEndLoc = Intro.Range.getEnd(); - if (getLangOpts().CPlusPlusAMP) { + if (getLangOpts().CPlusPlusAMP) { // TODO: Fix for winter cleanup (maybe) MaybeParseGNUAttributes(AttrIntro, &DeclEndLoc); } @@ -1143,7 +1143,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // try parse attributes before parameter list SourceLocation DeclEndLoc = Intro.Range.getBegin(); ParsedAttributes AttrPre(AttrFactory); - if (getLangOpts().CPlusPlusAMP) { + if (getLangOpts().CPlusPlusAMP) { // TODO: Fix for winter cleanup (maybe) MaybeParseGNUAttributes(AttrPre, &DeclEndLoc); } @@ -1190,24 +1190,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - // Parse C++AMP restriction specifier - unsigned cppampSpec = CPPAMP_None; - if (getLangOpts().CPlusPlusAMP) { - cppampSpec = ParseRestrictionSpecification(D, Attr, DeclEndLoc); - - if (getLangOpts().HSAExtension && getLangOpts().AutoAuto) { - // auto-auto: automatically append restrict(auto) in case no restriction specifier is found - if (cppampSpec == CPPAMP_None) { - cppampSpec = CPPAMP_AUTO; - IdentifierInfo *II = &PP.getIdentifierTable().get("auto"); - assert(II); - Attr.addNew(II, DeclEndLoc, 0, DeclEndLoc, /*0, DeclEndLoc,*/ 0, 0, ParsedAttr::AS_GNU); - } - } - } - - // C++AMP - if (getLangOpts().CPlusPlusAMP) { + // TODO: Fix for winter cleanup + // HC + //unsigned hcSpec = HC_None; + if (getLangOpts().CPlusPlusAMP) { // TODO: Fix for winter cleanup (maybe) // take all attributed parsed before introducer Attr.takeAllFrom(AttrIntro); // take all attributes parsed before parameter list @@ -1230,16 +1216,20 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( if (ESpecType != EST_None) { DeclEndLoc = ESpecRange.getEnd(); - - // C++AMP specific, reject exception specifiers for amp-restricted functions - if (getLangOpts().CPlusPlusAMP && (cppampSpec & CPPAMP_AMP)) { - Diag(ESpecRange.getBegin(), diag::err_amp_no_throw); - } } // Parse attribute-specifier[opt]. MaybeParseCXX11Attributes(Attr, &DeclEndLoc); + // TODO - Fix for winter cleanup (maybe) + // HC specific, reject exception specifiers for [[hc]] functions + if (getLangOpts().CPlusPlusAMP && ESpecType == EST_Dynamic) { + for (auto &&A : Attr) { + if (A.getKind() != ParsedAttr::AT_HC_HC) continue; + Diag(ESpecRange.getBegin(), diag::err_amp_no_throw); + } + } + SourceLocation FunLocalRangeEnd = DeclEndLoc; // Parse trailing-return-type[opt]. @@ -1335,23 +1325,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, TrailingReturnType), std::move(Attr), DeclEndLoc); - } else if (Tok.is(tok::l_brace)) { - // Next is compound-statement. - // Parse C++AMP restrict specifier though the lambda expression has no params, so that - // context inside lambda compound-statement is distinguished from cpu codes or amp codes. - // And the lambda's calloperator will be attached with the same restrictions as its parent - // function's if any. Such lambda expression is as follows, - // [] { - // // The compound-statement - // }; - if (getLangOpts().CPlusPlusAMP) { - // Place restriction after r_square - SourceLocation LambdaEndLoc = Intro.Range.getEnd(); - ParsedAttributes Attr(AttrFactory); - ParseRestrictionSpecification(D, Attr, LambdaEndLoc); - D.getAttributes().addAll(Attr.begin(), Attr.end()); - D.getAttributePool().takeAllFrom(Attr.getPool()); - } } // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index ec6aab16d06..377d6d66926 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -251,12 +251,6 @@ Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, return ParseForStatement(TrailingElseLoc); case tok::kw_goto: // C99 6.8.6.1: goto-statement - // C++ AMP-specific, reject if we are in an AMP-restricted function - if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath) { - if (!getLangOpts().HSAExtension && IsInAMPFunction(getCurScope())) { - Diag(Tok, diag::err_amp_illegal_keyword_goto); - } - } Res = ParseGotoStatement(); SemiError = "goto"; break; @@ -278,15 +272,6 @@ Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, break; case tok::kw_asm: { - - // C++ AMP-specific, reject if we are in an AMP-restricted function - if (getLangOpts().CPlusPlusAMP && - !getLangOpts().HSAExtension && - getLangOpts().DevicePath) { - if (IsInAMPFunction(getCurScope())) { - Diag(Tok, diag::err_amp_illegal_keyword_asm); - } - } ProhibitAttributes(Attrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); @@ -305,9 +290,9 @@ Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, return StmtEmpty(); case tok::kw_try: // C++ 15: try-block - // C++ AMP-specific, reject if we are in an AMP-restricted function + // HC-specific, reject if we are in a [[hc]] function if (getLangOpts().CPlusPlusAMP && getLangOpts().DevicePath) { - if (IsInAMPFunction(getCurScope())) { + if (IsInHCFunction(getCurScope())) { Diag(Tok, diag::err_amp_illegal_keyword_trycatch); } } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 462eceae6ca..0a1a05b03bf 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1964,18 +1964,6 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { // ref-qualifier[opt] if (Tok.isOneOf(tok::amp, tok::ampamp)) ConsumeToken(); - - // C++AMP - // 'restrict' is an identifier, not a keyword - if (getLangOpts().CPlusPlusAMP && Tok.is(tok::identifier) && (Tok.getIdentifierInfo()->getName() == "restrict")) { - ConsumeToken(); - if (Tok.isNot(tok::l_paren)) - return TPResult::Error; - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error; - } - // exception-specification if (Tok.is(tok::kw_throw)) { ConsumeToken(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 78dca47c916..5f248f594cc 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -883,12 +883,8 @@ bool Parser::isDeclarationAfterDeclarator() { /// Determine whether the current token, if it occurs after a /// declarator, indicates the start of a function definition. bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { - // Relax the rule for C++AMP because there may not necessarily be a - // declarator when used in C++AMP to parse 'auto' - if(Actions.getLangOpts().CPlusPlusAMP) { - } else { - assert(Declarator.isFunctionDeclarator() && "Isn't a function declarator"); - } + assert(Declarator.isFunctionDeclarator() && "Isn't a function declarator"); + if (Tok.is(tok::l_brace)) // int X() {} return true; @@ -1878,7 +1874,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { - // C++AMP + // HC assert((getLangOpts().CPlusPlus || getLangOpts().CPlusPlusAMP) && "Call sites of this function should be guarded by checking for C++"); assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index d14ed99adda..5f20af01fb7 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -56,7 +56,6 @@ add_clang_library(clangSema SemaTemplateInstantiateDecl.cpp SemaTemplateVariadic.cpp SemaType.cpp - StmtResInfer.cpp TypeLocBuilder.cpp LINK_LIBS diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 11390c815c6..db52e536c34 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1932,20 +1932,6 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, Sema &Self) { QualType SrcType = SrcExpr->getType(); - // C++AMP-specific rule checks - if (Self.getLangOpts().CPlusPlusAMP - && Self.IsInAMPRestricted() - && !Self.getLangOpts().HSAExtension - && !CStyle && SrcType->isIntegralType(Self.Context) - && !SrcType->isBooleanType() - && !SrcType->isEnumeralType() - && !SrcExpr->isIntegerConstantExpr(Self.Context) - && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType)) { - // C++AMP - Self.Diag(Loc, diag::err_amp_int_to_pointer_cast)<< SrcType << DestType; - return; - } - // Not warning on reinterpret_cast, boolean, constant expressions, etc // are not explicit design choices, but consistent with GCC's behavior. // Feel free to modify them if you've reason/evidence for an alternative. @@ -1956,14 +1942,6 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType)) { - // C++AMP - if(Self.getLangOpts().CPlusPlusAMP - && Self.IsInAMPRestricted() - && !Self.getLangOpts().HSAExtension) { - Self.Diag(Loc, diag::err_amp_int_to_pointer_cast)<< SrcType << DestType; - return; - } - // Separate between casts to void* and non-void* pointers. // Some APIs use (abuse) void* for something like a user context, // and often that value is an integer even if it isn't a pointer itself. @@ -2063,23 +2041,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; } - // C++AMP - if(Self.getLangOpts().CPlusPlusAMP && SrcType->isIntegralOrEnumerationType() && - !Self.Context.getPointerType(SrcType).isNull()) { - // The expression, - // int foo; - // int *& r = (int*&)foo; // Error - // where at this point, - // SrcType is 'int' which will be coverted to 'int*' - // DestType is 'int*&' which will be converted to be 'int**' - // Note that, the trick is 'int*&' is taken as 'int**' - if (Self.getLangOpts().CPlusPlusAMP && - Self.IsInAMPRestricted() && - !Self.getLangOpts().HSAExtension) - Self.Diag(OpRange.getBegin(), diag::err_amp_int_to_pointer_cast) - << SrcType << DestType; - } - // This code does this transformation for the checked types. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); @@ -2128,7 +2089,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, assert(!IsLValueCast); Kind = CK_ReinterpretMemberPointer; - // C++AMP + // HC - TODO: Fix for winter cleanup if(Self.getLangOpts().CPlusPlusAMP && Self.IsInAnyExplicitRestricted()) { // FIXME: It is not clear if it is necessary to reject since usage of this DestType is unknown // in current context, e.g. there is only defintion without any usage. @@ -2217,14 +2178,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (DestType->isIntegralType(Self.Context)) { assert(srcIsPtr && "One type must be a pointer"); - // C++AMP - if(Self.getLangOpts().CPlusPlusAMP && !Self.getLangOpts().HSAExtension) { - if(Self.IsInAnyExplicitRestricted()) { - msg = diag::err_amp_bad_reinterpret_cast_from_pointer_to_int; - return TC_Failed; - } - } - // C++ 5.2.10p4: A pointer can be explicitly converted to any integral // type large enough to hold it; except in Microsoft mode, where the // integral type size doesn't matter (except we don't allow bool). @@ -2809,9 +2762,10 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, if (Op.SrcExpr.isInvalid()) return ExprError(); - // C++AMP [2.4.1.2.1] + // TODO - Fix for winter cleanup + // HC [2.4.1.2.1] if(getLangOpts().CPlusPlusAMP) { - if(IsInAMPRestricted()) { + if(IsInHCRestricted()) { if (IntegerLiteral *I = dyn_cast(CastExpr->IgnoreParenCasts())){ // Case by case // int xxxn = (int) 0x2ffffffffLL; // Error diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index d80308c1ebd..ca2abf28d5a 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -11042,20 +11042,6 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, std::string PrettySourceValue = Value.toString(10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); - // C++AMP [2.4.1.2.1] - // int xxxn = 0x2ffffffffLL; // Error by using higher precision integer - // int xxxn = 0xffffffffLL; // Correct. the TargetRange == SourceRange == 32 - if(S.getLangOpts().CPlusPlusAMP) { - // Suppress the warning - if(S.IsInAMPRestricted()) - S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag::err_amp_constant_too_big)); - } else { - S.DiagRuntimeBehavior(E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_integer_precision_constant) - << PrettySourceValue << PrettyTargetValue - << E->getType() << T << E->getSourceRange() - << clang::SourceRange(CC)); - } return; } @@ -12449,14 +12435,6 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, } } - // C++AMP - // Error if try to access char string since 'char' is not amp compatible type, e.g. - // The StringLiteral " "Hello"[0] " - if (getLangOpts().CPlusPlusAMP && dyn_cast(BaseExpr) && - IsInAMPRestricted()) { - Diag(BaseExpr->getExprLoc(), diag::err_amp_unsupported_string_literals); - } - if (size.getBitWidth() > index.getBitWidth()) index = index.zext(size.getBitWidth()); else if (size.getBitWidth() < index.getBitWidth()) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 57034e55f9c..f128209b343 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4460,16 +4460,18 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, } } - // C++AMP - if(getLangOpts().CPlusPlusAMP && TagD) { + // HC + // TODO: Fix for winter cleanup + if (getLangOpts().CPlusPlusAMP && TagD) { // If TagD is not null, Dcl itself presents a CXXRecordDecl - if(CXXRecordDecl* RD = dyn_cast(TagD)) { - for ( CXXRecordDecl::method_iterator MethodIt = RD->method_begin(), - MethodItE = RD->method_end(); MethodIt != MethodItE; ++MethodIt) { - if(MethodIt->isUserProvided() && MethodIt->hasAttr() && - MethodIt->isVirtual()) { - Diag(MethodIt->getSourceRange().getBegin(), diag::err_amp_virtual_member_function); - } + if (auto *RD = dyn_cast(TagD)) { + for (auto &&Method : RD->methods()) { + if (!Method->isUserProvided()) continue; + if (!Method->hasAttr()) continue; + if (!Method->isVirtual()) continue; + + Diag(Method->getSourceRange().getBegin(), + diag::err_amp_virtual_member_function); } } } @@ -5194,235 +5196,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, return false; } -static void Track4ByteAligned(const CXXRecordDecl* RDecl, Sema& S, Declarator &D, - std::vector&FoundVec, bool& Aligned) -{ - // It is myself, Walk the field - for (CXXRecordDecl::field_iterator It = RDecl->field_begin(), - ItE = RDecl->field_end(); It != ItE; ++It) { - const FieldDecl *FD = *It; - if(!FD) - continue; - const RecordType *RT = S.Context.getBaseElementType(FD->getType())->getAs(); - // The field contains RecordType - if (RT) { - Aligned = true; - break; - } - - QualType FieldType = FD->getType(); - // Array - if(const ArrayType* ArrayTy = dyn_cast(FieldType)) { - FieldType = ArrayTy->getElementType(); - if( FieldType->getAs()) { - Aligned = true; - break; - } - } - - if(const Type* Ty = FieldType.getTypePtrOrNull()) { - if(Ty->isBooleanType()) { - Aligned = false; - // Temporarily append, will remove if determine they are aligned - FoundVec.push_back(const_cast(FD)); - } else - Aligned = true; - } else - Aligned= true; - } - - if(RDecl->getDefinition()) { - RDecl = RDecl->getDefinition(); - for(CXXRecordDecl::base_class_const_iterator BaseIt = RDecl->bases_begin(); - BaseIt!=RDecl->bases_end(); BaseIt++) { - const CXXRecordDecl *BaseRDecl = - cast(BaseIt->getType()->getAs()->getDecl()); - Track4ByteAligned(BaseRDecl, S, D, FoundVec, Aligned); - } - } - return; -} - -static bool IsIncompatibleScalarType(const Type* Ty, bool HSAExtension = false) { - assert(Ty); - if (HSAExtension) { - return false; - } else { - return Ty->isCharType() || - Ty->isWideCharType() || - Ty->isSpecificBuiltinType(BuiltinType::Short) || - Ty->isSpecificBuiltinType(BuiltinType::LongLong) || - Ty->isSpecificBuiltinType(BuiltinType::LongDouble); - } -} - -static inline bool IsCompatibleScalarType(const Type* Ty, bool HSAExtension = false) { - assert(Ty); - if (HSAExtension) { - return Ty->isVoidType() || - Ty->isCharType() || - Ty->isBooleanType() || - Ty->isWideCharType() || - Ty->isSpecificBuiltinType(BuiltinType::Int) || - Ty->isSpecificBuiltinType(BuiltinType::Long) || - Ty->isSpecificBuiltinType(BuiltinType::Short) || - Ty->isSpecificBuiltinType(BuiltinType::Float) || - Ty->isSpecificBuiltinType(BuiltinType::Double) || - Ty->isSpecificBuiltinType(BuiltinType::LongLong) || - Ty->isSpecificBuiltinType(BuiltinType::LongDouble); - } else { - return Ty->isVoidType() || - Ty->isBooleanType() || - Ty->isSpecificBuiltinType(BuiltinType::Int) || - Ty->isSpecificBuiltinType(BuiltinType::Long) || - Ty->isSpecificBuiltinType(BuiltinType::Float) || - Ty->isSpecificBuiltinType(BuiltinType::Double); - } -} - -static inline bool hasUnsupportedTypeQualifier(QualType Ty, bool HSAExtension = false) { - return (HSAExtension) ? false : Ty.isVolatileQualified(); -} - -bool Sema::IsCXXAMPUnsupportedReferenceType(const Type* Ty, - bool CheckContainer, bool IsInfer) { - assert(Ty); - - // relax all reference types as ok in HSA extension mode - if (getLangOpts().HSAExtension) { - return false; - } - - const ReferenceType* RTy = dyn_cast(Ty); - if(!RTy) - return false; - - // Recursively test its pointee type - QualType PointeeType = RTy->getPointeeType(); - const Type* TargetTy= RTy->getPointeeType().getTypePtrOrNull(); - assert(TargetTy); - - // reject reference to volatile type - if(hasUnsupportedTypeQualifier(PointeeType, getLangOpts().HSAExtension)) - return true; - - //References (lvalue and rvalue) shall refer only to amp-compatible types - if(IsIncompatibleScalarType(TargetTy, getLangOpts().HSAExtension)) - return true; - if(IsCompatibleScalarType(TargetTy, getLangOpts().HSAExtension)) - return false; - - // reject reference to function type - if (TargetTy->isFunctionType()) - return true; - - //No reference type is considered amp-compatible - if (TargetTy->isReferenceType()) - return true; - - //Reference to std::nullptr_t is not allowed - // Need to be ahead of PointerType check - if(TargetTy->isNullPtrType() && PointeeType.getAsString().find("std::nullptr_t")) - return true; - - // Additionally, references to pointers are supported as long as the pointer type is itself - // supported - if(TargetTy->isPointerType() || TargetTy->isMemberPointerType()) - return IsCXXAMPUnsupportedPointerType(TargetTy, CheckContainer, IsInfer); - - if (TargetTy->isRecordType()) { - // Support reference to concurrency::array and/or concurrency::graphics::texture - if(CXXRecordDecl* RD = Ty->getAsCXXRecordDecl()) { - if((RD->getName() == "array" && PointeeType.getAsString().find("Concurrency::array")) || - (RD->getName() == "texture"&& PointeeType.getAsString().find("graphics::texture")) || - RD->getQualifiedNameAsString().find("std::")!=std::string::npos) - return false; - else - return IsIncompatibleType(TargetTy, CheckContainer, IsInfer); - } - } - - // TODO: References are onlysupported as local variables - // and/or function parameters - // and/or function return types - return false; -} - -// Check PointerType & MemberPointerType -bool Sema::IsCXXAMPUnsupportedPointerType(const Type* Ty, - bool CheckContainer, bool IsInfer) { - assert(Ty); - - // relax all pointer types as ok in HSA extension mode - if (getLangOpts().HSAExtension) { - return false; - } - - // reject incompatible function pointer types - if (Ty->isFunctionPointerType() || Ty->isMemberFunctionPointerType()) - return true; - // Pointers to members (C++11 8.3.3) shall only refer to non-static data members. - if(Ty->isMemberPointerType()) { - // FIXME: no way to check if it is non-static or not - if(Ty->isMemberDataPointerType()) - return true; - else - return true; - } - - const PointerType* PTy = dyn_cast(Ty); - if(!PTy) - return false; - - // Recursively test its pointee type - QualType PointeeType = PTy->getPointeeType(); - const Type* TargetTy= PTy->getPointeeType().getTypePtrOrNull(); - assert(TargetTy); - - //std::nullptr_t type is supported and treated as a pointer type - if(Ty->isNullPtrType() && PointeeType.getAsString().find("std::nullptr_t")) - return true; - - // reject reference to volatile type - if(hasUnsupportedTypeQualifier(PointeeType, getLangOpts().HSAExtension)) - return true; - - //Pointers shall only point to amp-compatible types - if(IsIncompatibleScalarType(TargetTy, getLangOpts().HSAExtension)) - return true; - if(IsCompatibleScalarType(TargetTy, getLangOpts().HSAExtension)) { - // FIXME: reject this kind of pointer type - if(Ty->isMemberDataPointerType()) - return true; - else - return false; - } - // reject pointer to pointer type - // No pointer type is considered amp-compatible - if (TargetTy->isPointerType() || TargetTy->isMemberPointerType()) - return true; - - // test pointer to class type - if (TargetTy->isRecordType()) { - // Pointers can point to amp-compatible types or - // concurrency::array or concurrency::graphics::texture - if(CXXRecordDecl* RD = TargetTy->getAsCXXRecordDecl()) { - if((RD->getName() == "array" && PointeeType.getAsString().find("Concurrency::array")) || - (RD->getName() == "texture"&& PointeeType.getAsString().find("graphics::texture")) || - RD->getQualifiedNameAsString().find("std::")!=std::string::npos) - return false; - else - return IsIncompatibleType(TargetTy, CheckContainer, IsInfer); - } - } - - // TODO: Pointers are only supported as local variables - // and/or function parameters - // and/or function return types - return false; -} - -bool Sema::DiagnoseCXXAMPDecl(Decl* Dcl, bool CheckContainer, bool IsInfer) { +bool Sema::DiagnoseHCDecl(Decl* Dcl, bool CheckContainer, bool IsInfer) { + // TODO: Fix for winter cleanup. if(!Dcl) return false; @@ -5439,63 +5214,20 @@ bool Sema::DiagnoseCXXAMPDecl(Decl* Dcl, bool CheckContainer, bool IsInfer) { RDecl->getName() == "extent" || RDecl->getName() == "index" || RDecl->getName() == "accelerator_view" || RDecl->getName() == "accelerator" || // FIXM: Restrictly skip checking of public APIs and other underlying codes - RDecl->getQualifiedNameAsString().find("std::")!=std::string::npos || - // Allow customized impl. - // TODO: Need a user code scope - RDecl->getName() == "Serialize" || RDecl->getName().find("__gmac") != std::string::npos || - RDecl->getName().find("Gmac") != std::string::npos) + RDecl->getQualifiedNameAsString().find("std::") != std::string::npos) // TODO: probably bogus. return false; if(RDecl->getName() == "") { // FIXME:need to consider 'typedef' operator } - // Check if the record decl* is 4-byte aligned - if (!getLangOpts().HSAExtension) { - if(RDecl->hasDefinition() && RDecl->isStruct() && !RDecl->isLambda()) { - CXXRecordDecl* DefRDecl = RDecl->getDefinition(); - if(const TypeDecl* TD = dyn_cast(Dcl)) { - const Type* Ty = TD->getTypeForDecl(); - if(!Ty->isIncompleteType()) { - Type::TypeClass TC = Ty->getTypeClass(); - if(TC == Type::Elaborated ||TC == Type::InjectedClassName || - (TC == Type::TemplateSpecialization && Context.getCanonicalType(Ty) == Ty)){ - // FIXME: The following TypeClass might cause endless loop. Just skip them for now - // TypeClass: Elaborated, e.g, struct obj_N identifier - // template - // struct obj_N { - // char m; - // int i; - // }; - // - // TypeClass: InjectedClassName, e.g, obj_N_T identifier - // template - // struct obj_N_T { - // T m; - // int i; - // }; - } else { - unsigned Alignment = Context.getTypeAlignInChars(Ty).getQuantity(); - bool isPowerOf2 = Context.getTypeSizeInChars(Ty).isPowerOfTwo(); - if(!isPowerOf2 && (Alignment & 0x3)) { - if(!IsInfer) - Diag(DefRDecl->getBeginLoc(), diag::err_amp_data_member_offset_not_natural_alignment); - return false; - } - } - } - } - } - } - if(RDecl->getDefinition()) { RDecl = RDecl->getDefinition(); // Walk through base classes for(CXXRecordDecl::base_class_const_iterator BaseIt = RDecl->bases_begin(); BaseIt!=RDecl->bases_end(); BaseIt++) { // it shall not have virtual base classes, and virtual member functions - if(!getLangOpts().HSAExtension && BaseIt->isVirtual()) { - if(!IsInfer) + if (BaseIt->isVirtual()) { Diag(BaseIt->getBeginLoc(), diag::err_amp_incompatible); return true; } @@ -5503,89 +5235,17 @@ bool Sema::DiagnoseCXXAMPDecl(Decl* Dcl, bool CheckContainer, bool IsInfer) { const CXXRecordDecl *BaseRDecl = cast(RT->getDecl()); if(!BaseRDecl) continue; - return DiagnoseCXXAMPDecl(const_cast(BaseRDecl), CheckContainer, IsInfer); + return DiagnoseHCDecl(const_cast(BaseRDecl), CheckContainer, IsInfer); } } } - // traverse each field, reject incompatible field - for (CXXRecordDecl::field_iterator It = RDecl->field_begin(), ItE = RDecl->field_end(); It != ItE; ++It) { - const FieldDecl *FD = *It; - QualType FieldType = FD->getType(); - const Type* FTy = FieldType.getTypePtrOrNull(); - // At this point, float* is not diagnosed - if (hasUnsupportedTypeQualifier(FieldType, getLangOpts().HSAExtension) || IsIncompatibleType(FTy, CheckContainer, IsInfer)) { - if(!IsInfer) - Diag(FD->getBeginLoc(), diag::err_amp_incompatible); - return true; - } - - // no bitfield is amp-compatible - if (!getLangOpts().HSAExtension && FD->isBitField()) { - if(!IsInfer) - Diag(FD->getBeginLoc(), diag::err_amp_incompatible); - return true; - } - // no pointer type is amp-compatible - // no reference type is amp-compatible - // At this point, float* is diagnosed when we know it is a member data pointer - if (!getLangOpts().HSAExtension && (FTy->isPointerType() || FTy->isReferenceType())) { - //pointer or reference is not allowed as pointed to - // type, array element type or data member type - // (except reference to concurrency::array/texture) - QualType PointeeType = FTy->getPointeeType(); - const Type* TargetTy = PointeeType.getTypePtrOrNull(); - bool is = true; - // Test pointer type - if(FTy->isPointerType()) - is = IsIncompatibleType(TargetTy, CheckContainer, IsInfer); - - // Handle special case in struct - // struct A { - // float* m; // not allowed - // } - if(RDecl->isStruct()) - is = true; - - // Handle special case in lambda - // parallel_for_each[]() { - // float* m; // is allowed - // float** m1; // not allowed - // } - #if 0 - if(RDecl->isClass() && RDecl->isLambda()) { - // do nothing - } - #endif - - // Handle special case - if (FTy->isReferenceType() && TargetTy && TargetTy->isRecordType()) { - if(CXXRecordDecl* RD = TargetTy->getAsCXXRecordDecl()) { - if((RD->getName() == "array" && PointeeType.getAsString().find("Concurrency::array")) || - (RD->getName() == "texture"&& PointeeType.getAsString().find("graphics::texture"))) - is = false; - } - } - if(is) { - if(!IsInfer) - Diag(FD->getBeginLoc(), diag::err_amp_incompatible); - return true; - } - } - - //It is a typename - - } - // traverse each member function, reject incompatible member function - for (CXXRecordDecl::method_iterator It = RDecl->method_begin(), - ItE = RDecl->method_end(); It != ItE; ++It) { - const CXXMethodDecl *MD = *It; - if (MD->isVirtual()) { - if(!IsInfer) - Diag(MD->getBeginLoc(), diag::err_amp_incompatible); - return true; - } + for (auto &&Method : RDecl->methods()) { + if (!Method->isVirtual()) continue; + + Diag(Method->getBeginLoc(), diag::err_amp_incompatible); + return true; } } @@ -5609,48 +5269,10 @@ bool Sema::IsIncompatibleType(const Type* Ty, bool CheckContainer, bool IsInfer) return false; } - // reject incompatible scalar types - if(IsIncompatibleScalarType(Ty, getLangOpts().HSAExtension)) - return true; - - if(IsCompatibleScalarType(Ty, getLangOpts().HSAExtension)) - return false; - - // Check EnumeralType - if(const EnumType* ET = dyn_cast(Ty)) { - // Enumeration types shall have underlying types consisting of - // int, unsigned int, long, or unsigned long. - EnumDecl * EDcl = ET->getDecl(); - assert(EDcl); - const Type* ETy = EDcl->getIntegerType().getTypePtrOrNull(); - return !(ETy->isSpecificBuiltinType(BuiltinType::Int) || - ETy->isSpecificBuiltinType(BuiltinType::UInt) || - ETy->isSpecificBuiltinType(BuiltinType::Long) || - ETy->isSpecificBuiltinType(BuiltinType::ULong)); - } - - // Check reference type - if (Ty->isReferenceType()) - return IsCXXAMPUnsupportedReferenceType(Ty, CheckContainer, IsInfer); - - // Check pointer type - if (Ty->isPointerType() || Ty->isMemberPointerType()) - return IsCXXAMPUnsupportedPointerType(Ty, CheckContainer, IsInfer); - // reject incompatible array types if (Ty->isArrayType()) { - if (const ArrayType* ATy = dyn_cast(Ty)) { - if (const Type* ETy = ATy->getElementType().getTypePtrOrNull()) { - // reject array of pointer - if (!getLangOpts().HSAExtension && ETy->isPointerType()) { - return true; - } - - // reject array of incompatible scalar type - if (!getLangOpts().HSAExtension && (IsIncompatibleScalarType(ETy) || ETy->isBooleanType())) { // array of bool is not 4-bytes aligned - return true; - } - + if (auto ATy = dyn_cast(Ty)) { + if (auto ETy = ATy->getElementType().getTypePtrOrNull()) { // test array of class type if (ETy->isClassType()) { return IsIncompatibleType(ETy, CheckContainer, IsInfer); @@ -5666,50 +5288,31 @@ bool Sema::IsIncompatibleType(const Type* Ty, bool CheckContainer, bool IsInfer) if(ClassTemplateDecl* CTDecl = dyn_cast_or_null( TST->getTemplateName().getAsTemplateDecl())) { if(CTDecl->getTemplatedDecl()) - return DiagnoseCXXAMPDecl(CTDecl->getTemplatedDecl(), CheckContainer, IsInfer); + return DiagnoseHCDecl(CTDecl->getTemplatedDecl(), + CheckContainer, IsInfer); } } // reject incompatible class types if (Ty->isRecordType()) { - return DiagnoseCXXAMPDecl(Ty->getAsCXXRecordDecl(), CheckContainer, IsInfer); + return DiagnoseHCDecl(Ty->getAsCXXRecordDecl(), CheckContainer, IsInfer); } return false; } -bool Sema::IsCXXAMPTileStatic(Declarator &D) { - if (D.getDeclSpec().hasAttributes()) { - return D.getDeclSpec().getAttributes().hasAttribute(ParsedAttr::AT_HCCTileStatic); - } - return false; -} +bool Sema::IsHCTileStatic(Declarator &D) { + if (!D.getDeclSpec().hasAttributes()) return false; - void Sema::DiagnosticCXXAMPTileStatic(Declarator &D, Decl *Dcl) { - if(!IsInAMPRestricted()) - Diag(D.getIdentifierLoc(), diag::err_amp_tile_static_unsupported_usage); - - if(!Dcl) - return; + return D.getDeclSpec() + .getAttributes() + .hasAttribute(ParsedAttr::AT_HCCTileStatic); +} - if (getLangOpts().HSAExtension) - return; + void Sema::DiagnosticHCTileStatic(Declarator &D, Decl *Dcl) { + if (IsInHCRestricted()) return; - clang::Decl::Kind DK= Dcl->getKind(); - if(DK == clang::Decl::Var) { - if (const ValueDecl *VD = dyn_cast(Dcl)) { - const Type* Ty = VD->getType().getTypePtrOrNull(); - if(Ty && (Ty->isPointerType() ||Ty->isReferenceType())) - Diag(D.getIdentifierLoc(), diag::err_amp_tile_static_pointer_or_reference); - // std::nullptr_t is not a base type - if (!VD->getType().getBaseTypeIdentifier()) { - QualType Child = VD->getType().IgnoreParens(); - if(Child.getAsString().find("std::nullptr_t")!=std::string::npos) - Diag(D.getIdentifierLoc(), diag::err_amp_using_nullptr_in_tile_static) - << Child.getAsString(); - } - } - } + Diag(D.getIdentifierLoc(), diag::err_amp_tile_static_unsupported_usage); } @@ -5717,10 +5320,11 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FDK_Declaration); Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); - // C++AMP + // HC + // TODO: Fix for winter cleanup. if(getLangOpts().CPlusPlusAMP) { // handle incompatible types for variables - if(IsInAMPRestricted()) { + if(IsInHCRestricted()) { clang::Decl::Kind DK= Dcl->getKind(); if(DK == clang::Decl::Var) { @@ -5736,26 +5340,22 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { if(QTy.getAsString().find("ecl_accelerator_info")!=std::string::npos || QTy.getAsString().find("std::")!=std::string::npos) { // Skip own implementation - } else { - if (hasUnsupportedTypeQualifier(QTy, getLangOpts().HSAExtension) || IsIncompatibleType(Ty)) - Diag(D.getDeclSpec().getBeginLoc(), diag::err_amp_type_unsupported) - << QTy.getAsString(); } } } } // Diagnose tile_static - if(IsCXXAMPTileStatic(D)) { - DiagnosticCXXAMPTileStatic(D, Dcl); + if (IsHCTileStatic(D)) { + DiagnosticHCTileStatic(D, Dcl); } else { // Not tile_static - if(IsInAMPRestricted()) { + if(IsInHCRestricted()) { clang::Decl::Kind DK= Dcl->getKind(); //base class, data member or array element must be at least 4 byte aligned // - // parallel_for_each(arr.get_extent(), [&](index<1> idx) restrict(amp) { + // parallel_for_each(arr.get_extent(), [&](index<1> idx) [[hc]] { // struct A_base // { // bool m1; // Only a bool.local, and not 4 byte aligned @@ -5766,55 +5366,6 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { // A local_array[10]; // is not allowed // }); // - - - //FIXME: the following cases should also be handled - //(1) class A3 // supported for amp since m2 now has 32-bit alignment - // { - // bool m1; - // __declspec(align(4)) bool m2; - // }; - // - //(2) __declspec(align(4)) bool a1[10]; // not supported since this __declspec(align(4)) - //(3) typedef __declspec(align(4)) struct S{ bool m;} ALIGNED_BOOL; - // ALIGNED_BOOL a2[10]; // supported since each array element is now 32-bit aligned - // - if(DK == clang::Decl::Var) { - if (const ValueDecl *VD = dyn_cast(Dcl)) { - QualType DestType = VD->getType(); - if(const ArrayType* CA = dyn_cast(DestType)) - DestType = CA->getElementType(); - - const RecordType *DestRecordType = DestType->getAs(); - // Only need struct/union/class which has ctors - if (DestRecordType) { - CXXRecordDecl *DestRecordDecl = cast(DestRecordType->getDecl()); - assert(DestRecordDecl && "Should have constructor initialization!"); - - // FIXME: There is a clang bug in ClassTemplateSpecializationDecl which we can't - // interate its base classes - if(!getLangOpts().HSAExtension && - !dyn_cast(DestRecordDecl)) { - // Empty class type of array element - if(DestRecordDecl && DestRecordDecl->isEmpty() && dyn_cast(VD->getType())) - Diag(Dcl->getLocation(), diag::err_amp_need_4_byte_aligned); - - // Recursively walk up base class for amp_need_4_byte_aligned - std::vector FoundVec; - bool Aligned = true; - Track4ByteAligned(DestRecordDecl, *this, D, FoundVec, Aligned); - if(!Aligned) { - for (unsigned i=0; igetInnerLocStart(), diag::err_amp_need_4_byte_aligned); - - // The problematic VarDecl - Diag(Dcl->getLocation(), diag::err_amp_incompatible); - } - } - } - } - } } } } @@ -7356,6 +6907,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + // TODO: Fix for winter cleanup. if (getLangOpts().CPlusPlusAMP) { if (SC == SC_None && S->getFnParent() != nullptr && (NewVD->hasAttr())) { @@ -8374,10 +7926,11 @@ static NamedDecl *DiagnoseInvalidRedeclaration( : Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); - // C++ AMP-specific + // HC-specific // - // relax the rule to allow out-of-line definitions of CPU-restrited member functions or operators - if (SemaRef.getLangOpts().CPlusPlusAMP && NewFD->hasAttr()) { + // relax the rule to allow out-of-line definitions of CPU-restricted member + // functions or operators + if (SemaRef.getLangOpts().CPlusPlusAMP && NewFD->hasAttr()) { return nullptr; } @@ -8606,11 +8159,12 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, NameInfo, R, TInfo, isInline, /*isImplicitlyDeclared=*/false); - // C++AMP-specific + // HC-specific + // TODO: Fix for winter cleanup if (SemaRef.getLangOpts().CPlusPlusAMP) { - bool isAMP = Record->hasAttr(); - bool isCPU = Record->hasAttr(); - if (isAMP ^ isCPU) { + bool isHC = Record->hasAttr(); + bool isCPU = Record->hasAttr(); + if (isHC ^ isCPU) { SemaRef.Diag(D.getIdentifierLoc(), diag::err_amp_destructor_overloading); return 0; } @@ -9364,7 +8918,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // // can't call an amp function through a pointer // return 1; // } - if(Param->hasAttr()) + if(Param->hasAttr()) Diag(Param->getLocation(), diag::err_amp_bad_reinterpret_cast_from_pointer_to_functionptr); } } @@ -9379,7 +8933,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // int test(int (*p)(int, int) __GPU) { // Error overloaded param // return p(3, 4); // Error in call // } - if(Param->hasAttr()) + if(Param->hasAttr()) // FIXME: is it overloaded? Diag(Param->getLocation(), diag::err_amp_bad_reinterpret_cast_from_pointer_to_functionptr); } @@ -9505,16 +9059,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // C++AMP - if(getLangOpts().CPlusPlusAMP && (NewFD->getType().getAddressSpace() == LangAS::hcc_tilestatic)) { + // HC + // TODO: Fix for winter cleanup + if (getLangOpts().CPlusPlusAMP && + (NewFD->getType().getAddressSpace() == LangAS::hcc_tilestatic)) { Diag(D.getIdentifierLoc(), diag::err_amp_tile_static_on_function_return_result); } - if (getLangOpts().CPlusPlusAMP && NewFD->hasAttr()) { + if (getLangOpts().CPlusPlusAMP && NewFD->hasAttr()) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); - if(!getLangOpts().HSAExtension && FTI.getEllipsisLoc().isValid()) { - Diag(FTI.getEllipsisLoc(), diag::err_amp_ellipsis_param_on_function_declarator); - } - // C++AMP + // HC // Check function params if it is amp restricted { for(unsigned i = 0; i< Params.size(); i++) { @@ -10728,10 +10281,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } - // C++AMP + // TODO: Fix for winter cleanup + // HC // Apply this routine only when we have function definition. // FIXME: This should be applied after all C++/C++11 semantic checks - // And the following assumptiions should be considered if not correct in further impl. + // And the following assumptiions should be considered if not correct + // in further impl. // (1) No AMP specific restrictions in signature // (2) Do not merge or overload if AMP restriction is not intersected correctly // (3) No intersections of all overloaded functions, only Ovl_Match @@ -10752,16 +10307,16 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // return 1; // } // Ugly codes - bool CurCPU = NewFD->hasAttr(); - bool CurAMP = NewFD->hasAttr(); + bool CurCPU = NewFD->hasAttr(); + bool CurHC = NewFD->hasAttr(); bool PreviousCPU = false; - bool PreviousAMP = false; - for(LookupResult::iterator PreDecl = Previous.begin(); PreDecl!=Previous.end(); PreDecl++) { - PreviousCPU |= (*PreDecl)->hasAttr(); - PreviousAMP |= (*PreDecl)->hasAttr(); + bool PreviousHC = false; + for (LookupResult::iterator PreDecl = Previous.begin(); PreDecl!=Previous.end(); PreDecl++) { + PreviousCPU |= (*PreDecl)->hasAttr(); + PreviousHC |= (*PreDecl)->hasAttr(); } // Case by Case - if(PreviousCPU && PreviousAMP && CurAMP && !CurCPU) { + if(PreviousCPU && PreviousHC && CurHC && !CurCPU) { // Previous __GPU, current __GPU_ONLY Diag(NewFD->getLocation(), diag::err_amp_function_redefinition) << NewFD->getNameInfo().getAsString(); @@ -11040,18 +10595,19 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, checkCUDATargetOverload(NewFD, Previous); } - // C++AMP + // TODO: Fix for winter cleanup + // HC // C linkage functions can't have multiple restriction specifiers - // extern "C" void foo() restrict(amp, cpu) {} // Error + // extern "C" void foo() [[cpu, hc]] {} // Error // However, for HIP __global__ functions we allow it orthogonally to the // linkage specifier, since our mechanism for implementing restrictions is not // in any way impacting mangling, unlike what the original C++AMP had. // TODO: this is too verbose, should be split up into separate functions. if (getLangOpts().CPlusPlusAMP && NewFD->isExternC() && - NewFD->hasAttr() && - NewFD->hasAttr() && - (!NewFD->hasAttr() || - NewFD->getAttr()->getAnnotation() != "__HIP_global_function__")) + NewFD->hasAttr() && + NewFD->hasAttr() && + (!NewFD->hasAttr() || + NewFD->getAttr()->getAnnotation() != "__HIP_global_function__")) Diag(NewFD->getLocation(), diag::err_amp_c_linkage_function_has_multiple_restrictions) << NewFD->getDeclName(); @@ -12519,43 +12075,44 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, AttrEnd.isValid() ? AttrEnd : IdentLoc); } +// TODO: Fix for winter cleanup /// True if the expression is valid for the initialization expression of a -/// C++AMP global array. -static bool checkCXXAMPGlobalArrayInitExpr(Stmt *E) { +/// HC global array. +static bool checkHCGlobalArrayInitExpr(Stmt *E) { if (auto *CE = dyn_cast(E)) { auto *CD = CE->getConstructor(); - if (CD->hasAttr() && - !CD->hasAttr()) + if (CD->hasAttr() && + !CD->hasAttr()) return false; for (auto I : CE->arguments()) { - if (!checkCXXAMPGlobalArrayInitExpr(I)) + if (!checkHCGlobalArrayInitExpr(I)) return false; } for (auto I : CD->inits()) { - if (!checkCXXAMPGlobalArrayInitExpr(I->getInit())) + if (!checkHCGlobalArrayInitExpr(I->getInit())) return false; } return true; } else if (auto *EWC = dyn_cast(E)) { for (auto I : EWC->children()) { - if (!checkCXXAMPGlobalArrayInitExpr(I)) + if (!checkHCGlobalArrayInitExpr(I)) return false; } return true; } else if (auto *IL = dyn_cast(E)) { for (auto I : IL->children()) { - if (!checkCXXAMPGlobalArrayInitExpr(I)) + if (!checkHCGlobalArrayInitExpr(I)) return false; } return true; } else if (auto *MTE = dyn_cast(E)) { - return checkCXXAMPGlobalArrayInitExpr(MTE->GetTemporaryExpr()); + return checkHCGlobalArrayInitExpr(MTE->GetTemporaryExpr()); } else if (auto *CBE = dyn_cast(E)) { - return checkCXXAMPGlobalArrayInitExpr(CBE->getSubExpr()); + return checkHCGlobalArrayInitExpr(CBE->getSubExpr()); } else if (auto *IC = dyn_cast(E)) { - return checkCXXAMPGlobalArrayInitExpr(IC->getSubExpr()); + return checkHCGlobalArrayInitExpr(IC->getSubExpr()); } else if (auto *FC = dyn_cast(E)) { - return checkCXXAMPGlobalArrayInitExpr(FC->getSubExpr()); + return checkHCGlobalArrayInitExpr(FC->getSubExpr()); } return true; } @@ -12703,7 +12260,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { bool IsGlobal = GlobalStorage && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); - // C++AMP + // HC + // TODO: fix for winter cleanup. if(IsGlobal && dyn_cast(type)) { const ArrayType* AT = dyn_cast(type); const RecordType *RT = AT->getElementType()->getAs(); @@ -12713,13 +12271,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // struct A // { // int var; - // A() restrict(amp) { } + // A() [[hc]] { } // }; // // A arr[5]; // Error: Array initialization in global scope, CPU restricted by default // if(RDecl && RDecl->hasUserDeclaredConstructor()) { - if (!checkCXXAMPGlobalArrayInitExpr(var->getInit())) + if (!checkHCGlobalArrayInitExpr(var->getInit())) Diag(var->getLocation(), diag::err_amp_call_from_cpu_to_amp); } } @@ -13486,6 +13044,22 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); + + if (LangOpts.CPlusPlusAMP && SkipBody) { + const bool HC = DP->hasAttr(); + const bool CPU = DP->hasAttr(); + + SkipBody->ShouldSkip = LangOpts.DevicePath ? (!HC && CPU) : (HC && !CPU); + + if (SkipBody->ShouldSkip) { + auto Empty = new (getASTContext()) NullStmt{DP->getLocation()}; + cast(DP)->setBody(Empty); + cast(DP)->addAttr( + CXX11NoReturnAttr::CreateImplicit(getASTContext())); + return DP; + } + } + return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); } @@ -13639,14 +13213,15 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, return; } - // C++AMP + // HC + // TODO: Fix for winter cleanup. // FIXME: Remove && Definition ? if (getLangOpts().CPlusPlusAMP && FD->isExternC() && Definition) { // Mangling is removed and linker will have 2 definitions of the same function - // extern "C" void foo() restrict(amp) { } - // extern "C" void foo() restrict(cpu) { } // Error - if (FD->hasAttr()!=Definition->hasAttr() || - FD->hasAttr()!=Definition->hasAttr()) + // extern "C" void foo() [[hc]] { } + // extern "C" void foo() [[cpu]] { } // Error + if (FD->hasAttr()!=Definition->hasAttr() || + FD->hasAttr()!=Definition->hasAttr()) Diag(Definition->getLocation(), diag::err_amp_has_second_c_linkage_overloaded_function) << FD->getDeclName(); } else if (getLangOpts().GNUMode && Definition->isInlineSpecified() && @@ -14169,22 +13744,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } } - // C++AMP - if(getLangOpts().CPlusPlusAMP && !getLangOpts().HSAExtension && - ((getCurLambda() && (FD == getCurLambda()->CallOperator)) || - FD->isGlobal())) { - if (FD->hasAttr()) { - std::vector FoundVec; - TrackMemoryOperator(Body, FoundVec); - if(FoundVec.size()) { - for (unsigned i = 0; i getExprLoc(), diag::err_amp_memory_operation); - } - } - } - } - assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { @@ -14337,9 +13896,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiscardCleanupsInEvaluationContext(); } - // C++AMP try use restriction specifier inferring logic - TryCXXAMPRestrictionInferring(dcl, Body); - return dcl; } @@ -16965,23 +16521,24 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } } - // C++AMP - if (getLangOpts().CPlusPlusAMP && CXXRecord->hasUserDeclaredDestructor()) { - bool hasAMP = false; - bool hasCPU = false; - for (CXXRecordDecl::ctor_iterator CtorIt = CXXRecord->ctor_begin(), - CtorE = CXXRecord->ctor_end(); - CtorIt != CtorE; ++CtorIt) { - hasAMP |= CtorIt->hasAttr(); - hasCPU |= CtorIt->hasAttr(); - } - CXXDestructorDecl *Dtor = CXXRecord->getDestructor(); - if ((hasAMP && !Dtor->hasAttr()) || - (hasCPU && !Dtor->hasAttr())) { - Diag(Dtor->getLocation(), diag::err_amp_dtor_rest_cover_all_ctor); - Record->setInvalidDecl(); - } - } + // // HC + // // TODO: Fix for winter cleanup + // if (getLangOpts().CPlusPlusAMP && CXXRecord->hasUserDeclaredDestructor()) { + // bool hasHC = false; + // bool hasCPU = false; + // for (CXXRecordDecl::ctor_iterator CtorIt = CXXRecord->ctor_begin(), + // CtorE = CXXRecord->ctor_end(); + // CtorIt != CtorE; ++CtorIt) { + // hasHC |= CtorIt->hasAttr(); + // hasCPU |= CtorIt->hasAttr(); + // } + // CXXDestructorDecl *Dtor = CXXRecord->getDestructor(); + // if ((hasHC && !Dtor->hasAttr()) || + // (hasCPU && !Dtor->hasAttr())) { + // Diag(Dtor->getLocation(), diag::err_amp_dtor_rest_cover_all_ctor); + // Record->setInvalidDecl(); + // } + // } } if (!Completed) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 020199c210c..e3ed5fbd4a6 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -5740,25 +5740,6 @@ class AMDGPUISAVersionChecker { } }; -namespace -{ - inline - bool checkAllAreIntegral(const ParsedAttr &Attr, Sema &S) { - for (auto i = 0u; i != Attr.getNumArgs(); ++i) { - auto e = Attr.getArgAsExpr(i); - if (e && !e->getType()->isIntegralOrEnumerationType()) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << Attr << i << AANT_ArgumentIntegerConstant - << e->getSourceRange(); - - return false; - } - } - - return true; - } -} - static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Min = 0; @@ -5796,9 +5777,6 @@ static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, } static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!checkAllAreIntegral(AL, S)) - return; - uint32_t Min = 0; Expr *MinExpr = AL.getArgAsExpr(0); if (MinExpr->isEvaluatable(S.Context) && @@ -5832,10 +5810,6 @@ static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - - if (!checkAllAreIntegral(AL, S)) - return; - uint32_t NumSGPR = 0; Expr *NumSGPRExpr = AL.getArgAsExpr(0); if (NumSGPRExpr->isEvaluatable(S.Context) && @@ -5848,10 +5822,6 @@ static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - - if (!checkAllAreIntegral(AL, S)) - return; - uint32_t NumVGPR = 0; Expr *NumVGPRExpr = AL.getArgAsExpr(0); if (NumVGPRExpr->isEvaluatable(S.Context) && @@ -5865,8 +5835,6 @@ static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleAMDGPUMaxWorkGroupDimAttr(Sema &S, Decl *D, const ParsedAttr &Attr) { - if (!checkAllAreIntegral(Attr, S)) - return; if (!checkAttributeAtLeastNumArgs(S, Attr, 3)) return; @@ -6401,23 +6369,10 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, } //===----------------------------------------------------------------------===// -// C++ AMP specific attribute handlers. +// HC specific attribute handlers. // FIXME: Merge these handlers with handleSimpleAttribute //===----------------------------------------------------------------------===// -static void handleAutoAttr(Sema &S, Decl *D, const ParsedAttr &Attr) { - if (S.LangOpts.CUDA) { - // No support for now - } else if (S.LangOpts.CPlusPlusAMP) { - D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), - S.Context, Attr.getAttributeSpellingListIndex())); - D->addAttr(::new (S.Context) CXXAMPRestrictAUTOAttr(Attr.getRange(), - S.Context, Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "auto"; - } -} - static void handleDeviceAttr(Sema &S, Decl *D, const ParsedAttr &Attr) { if (S.LangOpts.CUDA) { // check the attribute arguments. @@ -6436,11 +6391,12 @@ static void handleDeviceAttr(Sema &S, Decl *D, const ParsedAttr &Attr) { CUDADeviceAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } else if (S.LangOpts.CPlusPlusAMP) { - if (!S.LangOpts.AMPCPU) - D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), - S.Context, Attr.getAttributeSpellingListIndex())); - D->addAttr(::new (S.Context) CXXAMPRestrictAMPAttr(Attr.getRange(), - S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AlwaysInlineAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + HCRestrictHCAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device"; } @@ -6462,8 +6418,9 @@ static void handleHostAttr(Sema &S, Decl *D, const ParsedAttr &Attr) { CUDAHostAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } else if (S.LangOpts.CPlusPlusAMP) { - D->addAttr(::new (S.Context) CXXAMPRestrictCPUAttr(Attr.getRange(), - S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + HCRestrictCPUAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host"; } @@ -6674,16 +6631,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleGlobalAttr(S, D, AL); break; case ParsedAttr::AT_HC_HC: - case ParsedAttr::AT_CXXAMPRestrictAMP: + case ParsedAttr::AT_HCRestrictHC: handleDeviceAttr(S, D, AL); break; case ParsedAttr::AT_HC_CPU: - case ParsedAttr::AT_CXXAMPRestrictCPU: + case ParsedAttr::AT_HCRestrictCPU: handleHostAttr(S, D, AL); break; - case ParsedAttr::AT_CXXAMPRestrictAUTO: - handleAutoAttr(S, D, AL); - break; case ParsedAttr::AT_CUDADevice: handleSimpleAttributeWithExclusions(S, D, AL); break; @@ -7230,7 +7184,9 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, // good to have a way to specify "these attributes must appear as a group", // for these. Additionally, it would be good to have a way to specify "these // attribute must never appear as a group" for attributes like cold and hot. - if (!D->hasAttr()) { + if (!D->hasAttr() && + (!D->hasAttr() || // TODO: hoist into a more robust check. + D->getAttr()->getAnnotation() != "__HCC_KERNEL__")) { // These attributes cannot be applied to a non-kernel function. if (const auto *A = D->getAttr()) { // FIXME: This emits a different error message than @@ -7246,7 +7202,8 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (!D->hasAttr() && !D->hasAttr()) { + } else if (!D->hasAttr() && + !D->hasAttr()) { if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) << A << ExpectedKernelFunction; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index d099f79587e..fb393f96408 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3859,11 +3859,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (ValueDecl *Member = tryLookupCtorInitMemberDecl( ClassDecl, SS, TemplateTypeTy, MemberOrBase)) { - // C++AMP - // FIMXE: Need to consider non member initializer cases + // HC - TODO: fix for Winter Cleanup + // FIXME: Need to consider non member initializer cases if(getLangOpts().CPlusPlusAMP && ClassDecl->isStruct() - && (Constructor->hasAttr() || - Constructor->hasAttr())) { + && (Constructor->hasAttr() || + Constructor->hasAttr())) { // Can't use IsIncompatibleType const Type* Ty = Member->getType().getTypePtrOrNull(); QualType TheType = Member->getType(); @@ -7968,266 +7968,6 @@ void Sema::ActOnFinishCXXMemberSpecification( CheckCompletedCXXClass(cast(TagDecl)); } -/// FIXME: O(n) -bool Sema::NeedAMPDeserializer(CXXRecordDecl *ClassDecl) { -#if 0 - //FIXME(Ray) have problem supporting templates - if (ClassTemplateDecl *Template = ClassDecl->getDescribedClassTemplate()) - return false; -#endif - bool HasRestrict=false, HasDeserializerDecl=false; - for (CXXRecordDecl::method_iterator CI = ClassDecl->method_begin(), - CE = ClassDecl->method_end(); CI!=CE; CI++) { - if (CXXMethodDecl *MD = dyn_cast(*CI)) { - if (MD->hasAttr()) { - HasRestrict = true; - if (MD->hasAttr() && - (MD->getAttr()->getAnnotation().find("deserialize") != StringRef::npos)) - HasDeserializerDecl = true; - } - } - } - return HasRestrict && !HasDeserializerDecl; -} - -//FIXME: Refactor this -bool Sema::HasDeclaredAMPDeserializer(CXXRecordDecl *ClassDecl) { - return ClassDecl->getCXXAMPDeserializationConstructor() != NULL; -} - -void Sema::DeclareAMPSerializer(CXXRecordDecl *ClassDecl, DeclarationName Name) { - SourceLocation CurrentLocation = ClassDecl->getLocation(); - for (CXXRecordDecl::method_iterator Method = ClassDecl->method_begin(), - MethodEnd = ClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if (CXXMethodDecl *MD = dyn_cast(*Method)) { - if (MD->hasAttr() && - MD->getAttr()->getAnnotation() == "serialize") { - return; - } - } - } - - DeclarationNameInfo DNI(Name, CurrentLocation); - const FunctionProtoType *SerializeType; - FunctionProtoType::ExtProtoInfo ExtInfo; - const CXXRecordDecl *ParmClassDecl; - - AMPDeserializerArgs LocalArgs; -#if 0 - for (ASTContext::type_iterator it = ClassDecl->getASTContext().types_begin(), - e = ClassDecl->getASTContext().types_end(); it != e; ++it) { -#endif - auto &Types = ClassDecl->getASTContext().getTypes(); - for (unsigned I = 0; I != Types.size(); ++I) { - const auto *it = Types[I]; - if(/*(**/it/*)*/->isRecordType()) { - ParmClassDecl = /*(**/it/*)*/->getAsCXXRecordDecl(); - std::string RecordName = ParmClassDecl->getDeclName().getAsString(); - if(RecordName == "Serialize") { - QualType ArgType = Context.getTypeDeclType(ParmClassDecl); - ArgType = Context.getLValueReferenceType(ArgType); - LocalArgs.push_back(ArgType); - break; - } - } - ; - } - - ExtInfo.TypeQuals.addConst(); - SerializeType = dyn_cast(Context.getFunctionType(Context.VoidTy, - LocalArgs, - ExtInfo).getTypePtr()); - assert(SerializeType != NULL); - // SerializeType->TypeQuals |= Qualifiers::Const; - TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(QualType(SerializeType, 0), - CurrentLocation); - // Set correct parameter information for templates - TypeLoc TL = TI->getTypeLoc(); - FunctionProtoTypeLoc ProtoTL = TL.getAs(); - - CXXMethodDecl * SerializeFunc = CXXMethodDecl::Create(Context, - ClassDecl, - CurrentLocation, - DNI, - QualType(SerializeType, 0), - /*TInfo=*/TI, - SC_None, - /*Inline=*/false, - /*isConstExpr*/false, - CurrentLocation); - SerializeFunc->setAccess(AS_public); - - int i = 0; - SmallVector FieldAsArgs; - for (AMPDeserializerArgs::iterator it = LocalArgs.begin(), - e = LocalArgs.end(); it != e; it ++, i++) { - ParmVarDecl *PVD = ParmVarDecl::Create(Context, SerializeFunc, - CurrentLocation, - CurrentLocation, - /*Id=*/0, - *it, - /*TypeSourceInfo*/ Context.getTrivialTypeSourceInfo(*it ,CurrentLocation), - SC_None, 0); - PVD->setScopeInfo(0, i); - FieldAsArgs.push_back(PVD); - ProtoTL.setParam(i, PVD); - } - SerializeFunc->setParams(FieldAsArgs); - // Set appropriate attributes for AMP - if (getLangOpts().AMPCPU) - SerializeFunc->addAttr(new (Context) - CXXAMPRestrictAMPAttr(CurrentLocation, Context, 0)); - SerializeFunc->addAttr(::new (Context) - CXXAMPRestrictCPUAttr(CurrentLocation, Context, 0)); - SerializeFunc->addAttr(::new (Context) - AnnotateAttr(CurrentLocation, Context, "serialize", 0)); - ClassDecl->addDecl(SerializeFunc); - // Now we've obtained a valid Name. Use that to recursively declare - // __cxxamp_serialize() for member classes. TBD: base classes? - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - QualType FieldType = Field->getType().getNonReferenceType(); - if (const RecordType *RecordTy = FieldType->getAs()) { - const CXXRecordDecl *MemberClassDecl = dyn_cast( - RecordTy->getDecl()); - if (!MemberClassDecl) - continue; - DeclareAMPSerializer(const_cast(MemberClassDecl), Name); - } - } - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { - QualType BaseType = Base->getType().getNonReferenceType(); - if (const RecordType *RecordTy = BaseType->getAs()) { - const CXXRecordDecl *MemberClassDecl = dyn_cast(RecordTy->getDecl()); - if (!MemberClassDecl) - continue; - DeclareAMPSerializer(const_cast(MemberClassDecl), Name); - } - } - MarkFunctionReferenced(CurrentLocation, SerializeFunc); -} - -void Sema::DeclareAMPDeserializer(CXXRecordDecl *ClassDecl, AMPDeserializerArgs *Args) { - // Create the deserializer declaration. - CanQualType ClassType - = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); - SourceLocation ClassLoc = ClassDecl->getLocation(); - // Build up a function type for this particular constructor. - const Type *NewCtorType; - AMPDeserializerArgs LocalArgs; - //Recursively declare base-class deserializers - for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), - BEnd = ClassDecl->bases_end(); B!=BEnd; ++B ) { - if (const RecordType *BaseType = B->getType()->getAs()) { - CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); - if (!HasDeclaredAMPDeserializer(BaseClassDecl)) { - DeclareAMPDeserializer(BaseClassDecl, &LocalArgs); - } else if(CXXMethodDecl *MD = - BaseClassDecl->getCXXAMPDeserializationConstructor()) { - for (CXXMethodDecl::param_iterator CPI = MD->param_begin(), - CPE = MD->param_end(); CPI!=CPE; CPI++) { - LocalArgs.push_back((*CPI)->getType()); - } - } - } - } - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; Field++) { - // Skip fields that are not supposed to be marshalled to GPU space - if((Field->getType())->isArrayType()&&!(Field->getType()).isVolatileQualified()) { - if(ClassDecl->getQualifiedNameAsString().find("std::")==std::string::npos) { - if (getLangOpts().HSAExtension) { - // relax this rule in HSA to allow capturing raw pointers - } else { - const ArrayType* AT = dyn_cast(Field->getType()); - if(IsIncompatibleType(AT->getElementType().getTypePtrOrNull())) { - Diag(Field->getLocation(), diag::err_amp_incompatible); - return; - } - } - } - } - if (Field->hasAttr() && - !Field->hasAttr()) { - continue; - } - if (Field->isUnnamedBitfield()) - continue; - if (Field->getType()->isRecordType()) { - CXXRecordDecl *FieldClassDecl = Field->getType()->getAsCXXRecordDecl(); - if (!HasDeclaredAMPDeserializer(FieldClassDecl)) { - DeclareAMPDeserializer(FieldClassDecl, &LocalArgs); - } else if(CXXMethodDecl *MD = - FieldClassDecl->getCXXAMPDeserializationConstructor()) { - for (CXXMethodDecl::param_iterator CPI = MD->param_begin(), - CPE = MD->param_end(); CPI!=CPE; CPI++) { - LocalArgs.push_back((*CPI)->getType()); - } - } - continue; - } - LocalArgs.push_back(Field->getType()); - } - if (!LocalArgs.size()) { - return; - } - if(Args) - Args->insert(Args->end(), LocalArgs.begin(), LocalArgs.end()); - - FunctionProtoType::ExtProtoInfo ExtInfo; - NewCtorType = Context.getFunctionType(Context.VoidTy, - LocalArgs, ExtInfo) - .getTypePtr(); - - DeclarationName Name - = Context.DeclarationNames.getCXXConstructorName(ClassType); - DeclarationNameInfo NameInfo(Name, ClassLoc); - TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(QualType(NewCtorType, 0),ClassLoc); - // Set correct parameter information for templates - TypeLoc TL = TI->getTypeLoc(); - FunctionProtoTypeLoc ProtoTL = TL.getAs(); - assert(ProtoTL && "Missing prototype?"); - CXXConstructorDecl *Constructor - = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - QualType(NewCtorType, 0), - /*TypeSourceInfo*/ TI, - /*isExplicit=*/false, - /*isInline=*/true, - /*isImplicitlyDeclared=*/true, - /*isConstexp*/false - ); - Constructor->setAccess(AS_public); - SmallVector FieldAsArgs; - // Compute arguments needed - int i = 0; - for (AMPDeserializerArgs::iterator it = LocalArgs.begin(), - e = LocalArgs.end(); it != e; it ++, i++) { - ParmVarDecl *PVD = ParmVarDecl::Create(Context, Constructor, - ClassLoc, ClassLoc, /*Id=*/0, - *it, - /*TypeSourceInfo*/ Context.getTrivialTypeSourceInfo(*it ,ClassLoc), - SC_None, 0); - PVD->setScopeInfo(0, i); - FieldAsArgs.push_back(PVD); - ProtoTL.setParam(i, PVD); - } - // Popluate arguments - Constructor->setParams(FieldAsArgs); - // Set appropriate attributes for AMP - if (getLangOpts().AMPCPU) - Constructor->addAttr(new (Context) CXXAMPRestrictCPUAttr(ClassLoc, Context, 0)); - Constructor->addAttr(::new (Context) CXXAMPRestrictAMPAttr(ClassLoc, Context, 0)); - Constructor->addAttr(::new (Context) - AnnotateAttr(ClassLoc, Context, "auto_deserialize", 0)); - // Introduce this constructor into its scope. - if (Scope *S = getScopeForContext(ClassDecl)) - PushOnScopeChains(Constructor, S, false); - ClassDecl->addDecl(Constructor); -} - /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared /// special functions, such as the default constructor, copy /// constructor, or destructor, to the given C++ class (C++ @@ -11253,6 +10993,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /* ConstRHS */ false, /* Diagnose */ false); } + if (getLangOpts().CPlusPlusAMP) { + DefaultCon->addAttr(HCRestrictCPUAttr::CreateImplicit(Context)); + DefaultCon->addAttr(HCRestrictHCAttr::CreateImplicit(Context)); + } // Build an exception specification pointing back at this constructor. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon); @@ -11526,6 +11270,10 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { /* ConstRHS */ false, /* Diagnose */ false); } + if (getLangOpts().CPlusPlusAMP) { + Destructor->addAttr(HCRestrictCPUAttr::CreateImplicit(Context)); + Destructor->addAttr(HCRestrictHCAttr::CreateImplicit(Context)); + } // Build an exception specification pointing back at this destructor. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor); @@ -12128,6 +11876,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { /* ConstRHS */ Const, /* Diagnose */ false); } + if (getLangOpts().CPlusPlusAMP) { + CopyAssignment->addAttr(HCRestrictCPUAttr::CreateImplicit(Context)); + CopyAssignment->addAttr(HCRestrictHCAttr::CreateImplicit(Context)); + } // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = @@ -12412,904 +12164,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } -void Sema::DeclareAMPTrampolineName(CXXRecordDecl *ClassDecl, DeclarationName Name) { - SourceLocation CurrentLocation = ClassDecl->getLocation(); - CXXMethodDecl *Trampoline = NULL; - for (CXXRecordDecl::method_iterator Method = ClassDecl->method_begin(), - MethodEnd = ClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if (Method->hasAttr() && - Method->getAttr()->getAnnotation() == "__cxxamp_trampoline_name") { - return; - } - } - DeclarationNameInfo DNI(Name, CurrentLocation); - - const Type *TrampolineType; - FunctionProtoType::ExtProtoInfo ExtInfo; - TypeSourceInfo *TI; - TypeLoc TL; - FunctionProtoTypeLoc ProtoTL; - // Generate name lookup routine: char *__cxxamp_trampoline_name(void) - TrampolineType = Context.getFunctionType( - Context.getPointerType(Context.CharTy), - None, - ExtInfo).getTypePtr(); - TI = Context.getTrivialTypeSourceInfo(QualType(TrampolineType, 0), - CurrentLocation); - // Set correct parameter information for templates - TL = TI->getTypeLoc(); - ProtoTL = TL.getAs(); - assert(ProtoTL && "Missing prototype?"); - Trampoline = CXXMethodDecl::Create( - Context, ClassDecl, CurrentLocation, DNI, QualType(TrampolineType, 0), - /*TInfo=*/TI, - SC_Static, - /*Inline=*/false, - /*isConstExpr*/false, - CurrentLocation - ); - Trampoline->setAccess(AS_public); - // Set appropriate attributes for AMP - if (getLangOpts().AMPCPU) - Trampoline->addAttr(new (Context) CXXAMPRestrictAMPAttr(CurrentLocation, Context, 0)); - Trampoline->addAttr(new (Context) CXXAMPRestrictCPUAttr(CurrentLocation, Context, 0)); - Trampoline->addAttr(new (Context) AnnotateAttr(CurrentLocation, Context, "__cxxamp_trampoline_name", 0)); - ClassDecl->addDecl(Trampoline); - // Generate definition - MarkFunctionReferenced(CurrentLocation, Trampoline); -} - -void CreateDummyAMPTrampoline(Sema& S, DeclarationName Name, CXXRecordDecl *&ClassDecl, CXXMethodDecl *&Trampoline) { - if(Trampoline) - return; - SourceLocation CurrentLocation = ClassDecl->getLocation(); - DeclarationNameInfo DNI(Name, CurrentLocation); - ASTContext& Context = S.Context; - Sema::AMPDeserializerArgs LocalArgs; - FunctionProtoType::ExtProtoInfo ExtInfo; - - // Generate name lookup routine: char *__cxxamp_trampoline(void) - const Type *TrampolineType = Context.getFunctionType(Context.VoidTy, - LocalArgs, - ExtInfo).getTypePtr(); - TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(QualType(TrampolineType, 0), - CurrentLocation); - Trampoline = CXXMethodDecl::Create( - Context, ClassDecl, CurrentLocation, DNI, QualType(TrampolineType, 0), - /*TInfo=*/TI, - SC_Static, - /*Inline=*/false, - /*isConstExpr*/false, - CurrentLocation - ); - Trampoline->setAccess(AS_public); - - // Popluate no arguments - // FIXME: Side effects on CPU side - #if 0 - Trampoline->setParams(TrampolineParams); - #endif - - // Set appropriate attributes for AMP - Trampoline->addAttr(::new (Context) OpenCLKernelAttr(CurrentLocation, Context, 0)); - Trampoline->addAttr(::new (Context) CXXAMPRestrictAMPAttr(CurrentLocation, Context, 0)); - - // In CPU compilation mode, we need an empty implementation of trampoline - // so that parallel_for_each can find it. - Trampoline->addAttr(::new (Context) CXXAMPRestrictCPUAttr(CurrentLocation, Context, 0)); - Trampoline->addAttr(::new (Context) AnnotateAttr(CurrentLocation, Context, "__cxxamp_trampoline", 0)); - // Manually add this Attribute on this stage to avoid - // ClassDecl->getCXXAMPDeserializationConstructor() == NULL - Trampoline->addAttr(::new (Context) AnnotateAttr(CurrentLocation, Context, "dummy_deserialize", 0)); - ClassDecl->addDecl(Trampoline); -} - -void Sema::DeclareAMPTrampoline(CXXRecordDecl *ClassDecl, - DeclarationName Name) { - SourceLocation CurrentLocation = ClassDecl->getLocation(); - CXXMethodDecl *Trampoline = NULL; - // Deserializer is declared lazily until first lookup, so - // if it's not done yet, do so. - if (!HasDeclaredAMPDeserializer(ClassDecl)) { - DeclareAMPDeserializer(ClassDecl, NULL); - } - for (CXXRecordDecl::method_iterator Method = ClassDecl->method_begin(), - MethodEnd = ClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if (Method->hasAttr() && - Method->getAttr()->getAnnotation() == "__cxxamp_trampoline") { - return; - } - } - // The AMP deserialized constructor might be NULL if the actual declaration is invalid. - // Return at this point to force the compiler to throw compilation errors as expected - if(ClassDecl->getCXXAMPDeserializationConstructor() == NULL) { - CreateDummyAMPTrampoline(*this, Name, ClassDecl, Trampoline); - return; - } - CXXConstructorDecl *DeserializeConstructor = - dyn_cast( - ClassDecl->getCXXAMPDeserializationConstructor()); - #if 0 - assert(DeserializeConstructor); - #endif - DeclarationNameInfo DNI(Name, CurrentLocation); - - const Type *TrampolineType; - FunctionProtoType::ExtProtoInfo ExtInfo; - // Now collect the constructors that we already have in the current class. - AMPDeserializerArgs LocalArgs; - for (CXXMethodDecl::param_iterator CPI = DeserializeConstructor->param_begin(), - CPE = DeserializeConstructor->param_end(); CPI!=CPE; CPI++) { - // Reference types are only allowed to have one level; i.e. no - // class base {&int}; class foo { bar &base; }; - QualType MemberType = (*CPI)->getType().getNonReferenceType(); - if (MemberType != (*CPI)->getType()) { - if (!getLangOpts().HSAExtension) { - if (!MemberType.getTypePtr()->isClassType()) { - Diag((*CPI)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberType.getTypePtr()->isClassType() == true && - "Only supporting taking reference of classes"); - CXXRecordDecl *MemberClass = MemberType.getTypePtr()->getAsCXXRecordDecl(); - if (!HasDeclaredAMPDeserializer(MemberClass)) { - DeclareAMPDeserializer(MemberClass, NULL); - } - CXXMethodDecl *MemberDeserializer = - MemberClass->getCXXAMPDeserializationConstructor(); - if (!MemberDeserializer) { - Diag((*CPI)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberDeserializer); - for (CXXMethodDecl::param_iterator CPI = MemberDeserializer->param_begin(), - CPE = MemberDeserializer->param_end(); CPI!=CPE; CPI++) { - LocalArgs.push_back((*CPI)->getType()); - } - } - } - } else { // HSA extension check - if (MemberType.getTypePtr()->isClassType()) { - // hc::array should still be serialized as traditional C++AMP objects - if (MemberType.getTypePtr()->isGPUArrayType()) { - CXXRecordDecl *MemberClass = MemberType.getTypePtr()->getAsCXXRecordDecl(); - if (!HasDeclaredAMPDeserializer(MemberClass)) { - DeclareAMPDeserializer(MemberClass, NULL); - } - CXXMethodDecl *MemberDeserializer = - MemberClass->getCXXAMPDeserializationConstructor(); - if (!MemberDeserializer) { - Diag((*CPI)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberDeserializer); - for (CXXMethodDecl::param_iterator CPI = MemberDeserializer->param_begin(), - CPE = MemberDeserializer->param_end(); CPI!=CPE; CPI++) { - LocalArgs.push_back((*CPI)->getType()); - } - } - } else { - // In HSA extension mode, capture by reference is simply a pointer - LocalArgs.push_back(Context.getPointerType(MemberType)); - } - } else { - // In HSA extension mode, capture by reference is simply a pointer - LocalArgs.push_back(Context.getPointerType(MemberType)); - } - } // HSA extension check - } else { - // Since OpenCL kernel argument does not allow system dependent built-in types, - // e.g. bool. The following is a tricky method to replace _Bool type with Char8. - // The alternative way is to replace it in function ActOnVariableDeclarator - // line 4876, before a NewVD is created. - if((*CPI)->getType()->isScalarType() && Type::STK_Bool == (*CPI)->getType()->getScalarTypeKind()) - (*CPI)->setType(Context.CharTy); - - LocalArgs.push_back((*CPI)->getType()); - } - } - TrampolineType = Context.getFunctionType(Context.VoidTy, - LocalArgs, - ExtInfo).getTypePtr(); - TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(QualType(TrampolineType, 0), - CurrentLocation); - // Set correct parameter information for templates - Trampoline = CXXMethodDecl::Create( - Context, ClassDecl, CurrentLocation, DNI, QualType(TrampolineType, 0), - /*TInfo=*/TI, - SC_Static, - /*Inline=*/false, - /*isConstExpr*/false, - CurrentLocation - ); - Trampoline->setAccess(AS_public); - SmallVector TrampolineParams; - for (CXXConstructorDecl::param_iterator it = DeserializeConstructor->param_begin(); - it != DeserializeConstructor->param_end(); it++) { - QualType MemberType = (*it)->getType().getNonReferenceType(); - if (MemberType != (*it)->getType()) { - if (!getLangOpts().HSAExtension) { - if (!MemberType.getTypePtr()->isClassType()) { - Diag((*it)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberType.getTypePtr()->isClassType() == true && - "Only supporting taking reference of classes"); - CXXRecordDecl *MemberClass = - MemberType.getTypePtr()->getAsCXXRecordDecl(); - CXXMethodDecl *MemberDeserializer = - MemberClass->getCXXAMPDeserializationConstructor(); - if (!MemberDeserializer) { - Diag((*it)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberDeserializer); - for (CXXMethodDecl::param_iterator CPI = - MemberDeserializer->param_begin(), - CPE = MemberDeserializer->param_end(); CPI!=CPE; CPI++) { - ParmVarDecl *FromParam = ParmVarDecl::Create(Context, Trampoline, - CurrentLocation, CurrentLocation, - (*CPI)->getIdentifier(), - (*CPI)->getType(), - /*TInfo=*/0, - SC_None, 0); - TrampolineParams.push_back(FromParam); - } - } - } - } else { // HSA extension check - if (MemberType.getTypePtr()->isClassType()) { - // hc::array should still be serialized as traditional C++AMP objects - if (MemberType.getTypePtr()->isGPUArrayType()) { - CXXRecordDecl *MemberClass = - MemberType.getTypePtr()->getAsCXXRecordDecl(); - CXXMethodDecl *MemberDeserializer = - MemberClass->getCXXAMPDeserializationConstructor(); - if (!MemberDeserializer) { - Diag((*it)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberDeserializer); - for (CXXMethodDecl::param_iterator CPI = - MemberDeserializer->param_begin(), - CPE = MemberDeserializer->param_end(); CPI!=CPE; CPI++) { - ParmVarDecl *FromParam = ParmVarDecl::Create(Context, Trampoline, - CurrentLocation, CurrentLocation, - (*CPI)->getIdentifier(), - (*CPI)->getType(), - /*TInfo=*/0, - SC_None, 0); - TrampolineParams.push_back(FromParam); - } - } - } else { - ParmVarDecl *FromParam = ParmVarDecl::Create(Context, Trampoline, - CurrentLocation, CurrentLocation, - (*it)->getIdentifier(), - Context.getPointerType(MemberType), - /*TInfo=*/0, - SC_None, 0); - TrampolineParams.push_back(FromParam); - } - } else { - ParmVarDecl *FromParam = ParmVarDecl::Create(Context, Trampoline, - CurrentLocation, CurrentLocation, - (*it)->getIdentifier(), - Context.getPointerType(MemberType), - /*TInfo=*/0, - SC_None, 0); - TrampolineParams.push_back(FromParam); - } - } // HSA extension check - } else { - TrampolineParams.push_back(*it); - } - } - // Popluate arguments - Trampoline->setParams(TrampolineParams); - // Set appropriate attributes for AMP - Trampoline->addAttr(::new (Context) OpenCLKernelAttr(CurrentLocation, Context, 0)); - Trampoline->addAttr(::new (Context) CXXAMPRestrictAMPAttr(CurrentLocation, Context, 0)); - // In CPU compilation mode, we need an empty implementation of trampoline - // so that parallel_for_each can find it. - Trampoline->addAttr(::new (Context) CXXAMPRestrictCPUAttr(CurrentLocation, Context, 0)); - Trampoline->addAttr(::new (Context) AnnotateAttr(CurrentLocation, Context, "__cxxamp_trampoline", 0)); - ClassDecl->addDecl(Trampoline); - // Generate definition - MarkFunctionReferenced(CurrentLocation, Trampoline); - MarkFunctionReferenced(CurrentLocation, DeserializeConstructor); -} - - -/// Generate an empty body of trampoline code so that the -/// CodeGenFunction would be invoked on the generated trampoline function; -/// the actual definition will be done at CodeGen phase. -void Sema::DefineAMPTrampoline(SourceLocation CurrentLocation, - CXXMethodDecl *Trampoline) { - StmtResult Body; // Populate an empty Compound statement body - { - CompoundScopeRAII CompoundScope(*this); - Body = ActOnCompoundStmt(CurrentLocation, CurrentLocation, - MultiStmtArg(), - /*isStmtExpr=*/false); - assert(!Body.isInvalid() && "Compound statement creation cannot fail"); - } - Trampoline->setBody(Body.getAs()); - if (ASTMutationListener *L = getASTMutationListener()) { - L->CompletedImplicitDefinition(Trampoline); - } - // The constructors for reference types are only referenced - // in codegen stage. mark them as referenced so that the code - // can be generated. - CXXMethodDecl *DeserializeConstructor = - Trampoline->getParent()->getCXXAMPDeserializationConstructor(); - // The AMP deserialized constructor might be NULL if the actual definition is empty. - // Return at this point to force the compiler to throw compilation errors as expected - if(!DeserializeConstructor) { - return; - } - #if 0 - assert(DeserializeConstructor&& - "Trampoline assumes deserialization constructor"); - #endif - for (CXXConstructorDecl::param_iterator it = - DeserializeConstructor->param_begin(); - it != DeserializeConstructor->param_end(); it++) { - QualType MemberType = (*it)->getType().getNonReferenceType(); - if (MemberType != (*it)->getType()) { - if (!getLangOpts().HSAExtension) { - if (!MemberType.getTypePtr()->isClassType()) { - Diag((*it)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberType.getTypePtr()->isClassType() == true && - "Only supporting taking reference of classes"); - CXXRecordDecl *MemberClass = - MemberType.getTypePtr()->getAsCXXRecordDecl(); - CXXMethodDecl *MemberDeserializer = - MemberClass->getCXXAMPDeserializationConstructor(); - if (!MemberDeserializer) { - Diag((*it)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberDeserializer); - MarkFunctionReferenced(CurrentLocation, MemberDeserializer); - } - } - } else { - if (MemberType.getTypePtr()->isClassType()) { - // hc::array should still be serialized as traditional C++AMP objects - if (MemberType.getTypePtr()->isGPUArrayType()) { - CXXRecordDecl *MemberClass = - MemberType.getTypePtr()->getAsCXXRecordDecl(); - CXXMethodDecl *MemberDeserializer = - MemberClass->getCXXAMPDeserializationConstructor(); - if (!MemberDeserializer) { - Diag((*it)->getLocation(), diag::err_amp_incompatible); - } else { - assert(MemberDeserializer); - MarkFunctionReferenced(CurrentLocation, MemberDeserializer); - } - } - } - } // HSA extension check - } - } - -} - -/// GPU-side Deserialization constructor. Pair arguments to each members -/// recursively if member is of a compound type -void Sema::DefineAmpGpuDeSerializeFunction(SourceLocation CurrentLocation, - CXXMethodDecl *Deserialization) { - if (Deserialization->hasBody() - || Deserialization->hasInlineBody() - || Deserialization->isOutOfLine() - || (Deserialization->hasAttr() && - Deserialization->getAttr()->getAnnotation() - == "user_deserialize")) - return; - SourceLocation Loc = Deserialization->getLocation(); - if (CXXConstructorDecl *Constructor = - dyn_cast(Deserialization)) { - Deserialization->setIsUsed(); - - CXXRecordDecl *ClassDecl = Deserialization->getParent(); - - if (ClassDecl->isInvalidDecl() || Deserialization->isInvalidDecl()) { - Deserialization->setInvalidDecl(); - return; - } - - SmallVector NewInits; - CXXCtorInitializer *CCI; - // Assign non-static members. - int i = 0; - - // Call direct base-class deserialize. - for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), - BEnd = ClassDecl->bases_end(); - B != BEnd; ++B) { - if (const RecordType *BaseType = B->getType()->getAs()) { - CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); - SmallVector BaseCtorArgs; - int NumArgs = 0; - bool FoundBaseClassCtor = false; - for (CXXRecordDecl::ctor_iterator CI = BaseClassDecl->ctor_begin(), - CE = BaseClassDecl->ctor_end(); CI!=CE; CI++) { - CXXMethodDecl *MD = *CI; - if (MD->hasAttr() && - MD->hasAttr() && - MD->getAttr()->getAnnotation() - .find("deserialize") != StringRef::npos) { - NumArgs += MD->getNumParams(); - FoundBaseClassCtor = true; - break; - } - } - // Skip base classes that do not have a deserializer defined. - if (!FoundBaseClassCtor) - continue; - for (int j=0; j < NumArgs; j++) { - ParmVarDecl *Param = Constructor->getParamDecl(i+j); - QualType ParamType = Param->getType().getNonReferenceType(); - Expr *MemberExprBase = - DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), - SourceLocation(), Param, false, - Loc, ParamType, VK_LValue, 0); - Param->setIsUsed(); - BaseCtorArgs.push_back(MemberExprBase); - } - i += NumArgs; - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, B, B->isVirtual()); - InitializationKind InitKind = - InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence InitSeq(*this, InitEntity, InitKind, - MultiExprArg(BaseCtorArgs.data(), NumArgs)); - ExprResult BaseInit = - InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(BaseCtorArgs.data(), NumArgs)); - BaseInit = MaybeCreateExprWithCleanups(BaseInit); - assert (!BaseInit.isInvalid() && "Base initialization failure"); - CCI = new (Context) CXXCtorInitializer(Context, - B->getTypeSourceInfo(), B->isVirtual(), CurrentLocation, - BaseInit.get(), CurrentLocation, CurrentLocation); - NewInits.push_back(CCI); - } - } - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - if (Field->hasAttr() && - !Field->hasAttr()) { - // if any data members of the class is restrict(cpu), - // skip that field - continue; - } - if (Field->isUnnamedBitfield()) - continue; - // Suppress assigning zero-width bitfields. - if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) - continue; - - QualType FieldType = Field->getType(); - if (FieldType->isIncompleteArrayType()) { - assert(ClassDecl->hasFlexibleArrayMember() && - "Incomplete array type is not valid"); - continue; - } - - if (FieldType->isRecordType()) { - // Locate the deserialization constructor of the member class, - // find # of arguments required. - int NumArgs = 0; - SmallVector FieldArgs; - - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - CXXMethodDecl *FieldDes = - FieldClassDecl->getCXXAMPDeserializationConstructor(); - // Skip member classes that do not have a deserializer defined. - if (!FieldDes) - continue; - NumArgs = FieldDes->getNumParams(); - for (int j=0; j < NumArgs; j++) { - ParmVarDecl *Param = Constructor->getParamDecl(i+j); - QualType ParamType = Param->getType().getNonReferenceType(); - Expr *MemberExprBase = - DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), - SourceLocation(), Param, false, - Loc, ParamType, VK_LValue, 0); - Param->setIsUsed(); - FieldArgs.push_back(MemberExprBase); - } - i+=NumArgs; - - InitializedEntity InitEntity - = InitializedEntity::InitializeMember(*Field); - InitializationKind InitKind = - InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence InitSeq(*this, InitEntity, InitKind, - MultiExprArg(FieldArgs.data(), NumArgs)); - ExprResult MemberInit = - InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(FieldArgs.data(), NumArgs)); - - MemberInit = MaybeCreateExprWithCleanups(MemberInit); - assert (!MemberInit.isInvalid() && "Member initialization failure"); - - CCI = new (Context) CXXCtorInitializer(Context, - *Field, CurrentLocation, CurrentLocation, MemberInit.get(), - CurrentLocation); - } else { - assert(0); - } - } else { // POD member - ParmVarDecl *Param = Constructor->getParamDecl(i++); - QualType ParamType = Param->getType().getNonReferenceType(); - - Expr *MemberExprBase = - DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), - SourceLocation(), Param, false, - Loc, ParamType, VK_LValue, 0); - Param->setIsUsed(); - CCI= new (Context) CXXCtorInitializer(Context, *Field, - CurrentLocation, CurrentLocation, MemberExprBase, CurrentLocation); - } - NewInits.push_back(CCI); - } - SetCtorInitializers(Constructor, false, NewInits); - } - - StmtResult Body; // Populate an empty Compound statement body - { - CompoundScopeRAII CompoundScope(*this); - Body = ActOnCompoundStmt(Loc, Loc, MultiStmtArg(), - /*isStmtExpr=*/false); - assert(!Body.isInvalid() && "Compound statement creation cannot fail"); - } - Deserialization->setBody(Body.getAs()); - Deserialization->setImplicitlyInline(); - - if (ASTMutationListener *L = getASTMutationListener()) { - L->CompletedImplicitDefinition(Deserialization); - } -} - -void Sema::DefineAmpCpuSerializeFunction(SourceLocation CurrentLocation, - CXXMethodDecl *Serialization) { - Serialization->setIsUsed(); - // Avoid overriding user-defined serialization - if (Serialization->hasBody()||Serialization->hasInlineBody()|| - Serialization->isOutOfLine()) { - return; - } - SourceLocation Loc = Serialization->getLocation(); - SynthesizedFunctionScope Scope(*this, Serialization); - CXXRecordDecl *ClassDecl = Serialization->getParent(); - - // The statements that form the synthesized function body. - SmallVector Statements; - - // Construct the "this" pointer. - Expr *This = ActOnCXXThis(Loc).getAs(); - - // Construct the Expr of parameter. - ParmVarDecl *S = Serialization->getParamDecl(0); - QualType SRefType = S->getType(); - if (const LValueReferenceType *SRef = SRefType->getAs()) { - SRefType = SRef->getPointeeType(); - } - Expr *SRef = BuildDeclRefExpr(S, SRefType, VK_LValue, Loc).get(); - assert(SRef && "Reference to parameter cannot fail!"); - - // Call direct base-class serialize. - for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), - BEnd = ClassDecl->bases_end(); - B != BEnd; ++B) { - if (B->isVirtual()) // Cannot Handled VirtualBaseSpec. - continue; - if (const RecordType *BaseType = B->getType()->getAs()) { - CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); - for (CXXRecordDecl::method_iterator Method = BaseClassDecl->method_begin(), - MethodEnd = BaseClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if((*Method)->getNameInfo().getAsString() == "__cxxamp_serialize") { - LookupResult Methodlookup(*this, - (*Method)->getNameInfo(),LookupOrdinaryName); - LookupQualifiedName(Methodlookup, BaseClassDecl, false); - CXXCastPath BasePath; - BasePath.push_back(B); - - // Dereference "this". - ExprResult Base = CreateBuiltinUnaryOp(Loc, UO_Deref, This); - - // Implicitly cast "this" to the appropriately-qualified base type. - Base = ImpCastExprToType(Base.get(), - Context.getQualifiedType(B->getType().getUnqualifiedType(), - Serialization->getTypeQualifiers()), - CK_UncheckedDerivedToBase, - VK_LValue, &BasePath); - CXXScopeSpec SS; - ExprResult BaseSerializeFunctionRef - = BuildMemberReferenceExpr(Base.getAs(), - B->getType().getNonReferenceType(), Loc, - /*isArrow=*/false, SS, - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - Methodlookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - assert(!BaseSerializeFunctionRef.isInvalid() && - "BaseSerializeFunctionRef cannot fail"); - MultiExprArg MEArg(&SRef, 1); - ExprResult Call = BuildCallToMemberFunction(/*Scope=*/0, - BaseSerializeFunctionRef.getAs(), - Loc, /*&SRef*/MEArg, /*1,*/ Loc); - StmtResult SerializeResult = Call.getAs(); - Statements.push_back(SerializeResult.getAs()); - } - } - } - } - - //Do the fields serialize. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - QualType FieldType = Field->getType().getNonReferenceType(); - - // Skip fields that are not supposed to be marshalled to GPU space - if (Field->hasAttr() && - !Field->hasAttr()) { - continue; - } - const RecordType *RecordTy = FieldType->getAs(); - - // hc::array shall be serialized as normal C++AMP objects even in HC mode - if (!getLangOpts().HSAExtension || FieldType.getTypePtr()->isGPUArrayType()) { - - if (RecordTy) { - CXXRecordDecl *FieldClassDecl = cast(RecordTy->getDecl()); - for (CXXRecordDecl::method_iterator Method = FieldClassDecl->method_begin(), - MethodEnd = FieldClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if((*Method)->getNameInfo().getAsString() == "__cxxamp_serialize") { - // Intentionally empty - CXXScopeSpec CSS; - LookupResult MemberLookup(*this, Field->getDeclName(), Loc, - LookupMemberName); - MemberLookup.addDecl(*Field); - MemberLookup.resolveKind(); - ExprResult FRef = BuildMemberReferenceExpr(This, This->getType(), - Loc, /*IsArrow=*/true, - CSS, SourceLocation(), 0, - MemberLookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - LookupResult Methodlookup(*this, - (*Method)->getNameInfo(),LookupOrdinaryName); - LookupQualifiedName(Methodlookup, FieldClassDecl, false); - CXXScopeSpec SS; - const Type *CanonicalT = Context.getCanonicalType(FieldType.getTypePtr()); - SS.MakeTrivial(Context, - NestedNameSpecifier::Create(Context, 0, - false, CanonicalT), - Loc); - ExprResult SerializeFunctionRef - = BuildMemberReferenceExpr(FRef.get(), FieldType, Loc, - /*isArrow=*/false, SS, - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - Methodlookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - assert(!SerializeFunctionRef.isInvalid() && - "SerializeFunctionRef cannot fail"); - MultiExprArg MEArg(&SRef, 1); - ExprResult Call = BuildCallToMemberFunction(/*Scope=*/0, - SerializeFunctionRef.getAs(), - Loc, /*&SRef*/MEArg, /*1,*/ Loc); - StmtResult SerializeResult = Call.getAs(); - Statements.push_back(SerializeResult.getAs()); - } - } - } - else if(FieldType->isScalarType()){ - if (Field->getType()->isReferenceType()) { - Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); - Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_member_synthesized_at) - << Serialization << Context.getTagDeclType(ClassDecl); - continue; - } - const RecordType *SRecordTy - = (S->getType().getNonReferenceType())->getAs(); - CXXRecordDecl *SClassDecl = cast(SRecordTy->getDecl()); - assert(SClassDecl && "SClassDecl cannot fail!"); - for (CXXRecordDecl::method_iterator Method = SClassDecl->method_begin(), - MethodEnd = SClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if((*Method)->getNameInfo().getAsString() == "Append") { - CXXScopeSpec CSS; - LookupResult MemberLookup(*this, Field->getDeclName(), Loc, - LookupMemberName); - MemberLookup.addDecl(*Field); - MemberLookup.resolveKind(); - ExprResult FRef = BuildMemberReferenceExpr(This, This->getType(), - Loc, /*IsArrow=*/true, - CSS, SourceLocation(), 0, - MemberLookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - - // Construct the parameter "const void *" for Append. - ExprResult T = CreateBuiltinUnaryOp(Loc, UO_AddrOf, FRef.getAs()); - - // Construct the parameter "size_t" for Append. - QualType SizeType = Context.getSizeType(); - llvm::APInt Size(Context.getTypeSize(SizeType), - Context.getTypeSizeInChars(Field->getType()).getQuantity()); - - LookupResult Methodlookup(*this, - (*Method)->getNameInfo(),LookupOrdinaryName); - LookupQualifiedName(Methodlookup, SClassDecl, false); - CXXScopeSpec SS; - const Type *CanonicalT = Context.getCanonicalType(SRefType.getTypePtr()); - SS.MakeTrivial(Context, - NestedNameSpecifier::Create(Context, 0, - false, CanonicalT), - Loc); - ExprResult AppendFunctionRef - = BuildMemberReferenceExpr(SRef, SRefType, Loc, - /*isArrow=*/false, SS, - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - Methodlookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - Expr* CallArgs[2] - = {IntegerLiteral::Create(Context, Size, SizeType, Loc),T.getAs()}; - MultiExprArg MEArg(CallArgs, 2); - ExprResult Call = BuildCallToMemberFunction(/*Scope=*/0, - AppendFunctionRef.getAs(), - Loc, /*CallArgs*/MEArg, /*2,*/ Loc); - Statements.push_back(Call/*.getAs()*/.getAs()); - } - } - } - - } else { // HSA extension check - - const RecordType *HSARecordTy = Field->getType()->getAs(); - CXXRecordDecl *FieldClassDecl = NULL; - NamespaceDecl* FieldNamespaceDecl = NULL; - if (RecordTy) { - FieldClassDecl = cast(RecordTy->getDecl()); - FieldNamespaceDecl = dyn_cast(FieldClassDecl->getEnclosingNamespaceContext()); - } - - // call __cxxamp_serialize for the following cases: - // a) under Concurrency namespace - // b) is a lambda/class/union (RecordType) by itself - // for all other classes, directly push pointer as kernel argument - if (HSARecordTy && - ( (FieldNamespaceDecl && FieldNamespaceDecl->getName() == "Concurrency") || - (FieldClassDecl) ) ) { - CXXRecordDecl *FieldClassDecl = cast(HSARecordTy->getDecl()); - for (CXXRecordDecl::method_iterator Method = FieldClassDecl->method_begin(), - MethodEnd = FieldClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if((*Method)->getNameInfo().getAsString() == "__cxxamp_serialize") { - // Intentionally empty - CXXScopeSpec CSS; - LookupResult MemberLookup(*this, Field->getDeclName(), Loc, - LookupMemberName); - MemberLookup.addDecl(*Field); - MemberLookup.resolveKind(); - ExprResult FRef = BuildMemberReferenceExpr(This, This->getType(), - Loc, /*IsArrow=*/true, - CSS, SourceLocation(), 0, - MemberLookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - LookupResult Methodlookup(*this, - (*Method)->getNameInfo(),LookupOrdinaryName); - LookupQualifiedName(Methodlookup, FieldClassDecl, false); - CXXScopeSpec SS; - const Type *CanonicalT = Context.getCanonicalType(FieldType.getTypePtr()); - SS.MakeTrivial(Context, - NestedNameSpecifier::Create(Context, 0, - false, CanonicalT), - Loc); - ExprResult SerializeFunctionRef - = BuildMemberReferenceExpr(FRef.get(), FieldType, Loc, - /*isArrow=*/false, SS, - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - Methodlookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - assert(!SerializeFunctionRef.isInvalid() && - "SerializeFunctionRef cannot fail"); - MultiExprArg MEArg(&SRef, 1); - ExprResult Call = BuildCallToMemberFunction(/*Scope=*/0, - SerializeFunctionRef.getAs(), - Loc, /*&SRef*/MEArg, /*1,*/ Loc); - StmtResult SerializeResult = Call.getAs(); - Statements.push_back(SerializeResult.getAs()); - } - } - } else { - // HSA capture by reference - // use AppendPtr to push pointer to the object - const RecordType *SRecordTy - = (S->getType().getNonReferenceType())->getAs(); - - CXXRecordDecl *SClassDecl = cast(SRecordTy->getDecl()); - assert(SClassDecl && "SClassDecl cannot fail!"); - - std::string AppendFuncName; - if (Field->getType()->isReferenceType()) { - AppendFuncName = "AppendPtr"; - } else { - AppendFuncName = "Append"; - } - - for (CXXRecordDecl::method_iterator Method = SClassDecl->method_begin(), - MethodEnd = SClassDecl->method_end(); - Method != MethodEnd; ++Method) { - if((*Method)->getNameInfo().getAsString() == AppendFuncName) { - CXXScopeSpec CSS; - LookupResult MemberLookup(*this, Field->getDeclName(), Loc, - LookupMemberName); - MemberLookup.addDecl(*Field); - MemberLookup.resolveKind(); - ExprResult FRef = BuildMemberReferenceExpr(This, This->getType(), - Loc, /*IsArrow=*/true, - CSS, SourceLocation(), 0, - MemberLookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - - // Construct the parameter "const void *" for Append. - ExprResult T = CreateBuiltinUnaryOp(Loc, UO_AddrOf, FRef.getAs()); - - // Construct the parameter "size_t" for Append. - QualType SizeType = Context.getSizeType(); - llvm::APInt Size(Context.getTypeSize(SizeType), - Context.getTypeSizeInChars(Field->getType()).getQuantity()); - - LookupResult Methodlookup(*this, - (*Method)->getNameInfo(),LookupOrdinaryName); - LookupQualifiedName(Methodlookup, SClassDecl, false); - CXXScopeSpec SS; - const Type *CanonicalT = Context.getCanonicalType(SRefType.getTypePtr()); - SS.MakeTrivial(Context, - NestedNameSpecifier::Create(Context, 0, - false, CanonicalT), - Loc); - ExprResult AppendFunctionRef - = BuildMemberReferenceExpr(SRef, SRefType, Loc, - /*isArrow=*/false, SS, - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - Methodlookup, - /*TemplateArgs=*/nullptr,/*S*/nullptr); - Expr* CallArgs[2] - = {IntegerLiteral::Create(Context, Size, SizeType, Loc),T.getAs()}; - MultiExprArg MEArg(CallArgs, 2); - ExprResult Call = BuildCallToMemberFunction(/*Scope=*/0, - AppendFunctionRef.getAs(), - Loc, /*CallArgs*/MEArg, /*2,*/ Loc); - Statements.push_back(Call/*.getAs()*/.getAs()); - } - } - } - - } // HSA extension check - - } - StmtResult Body; - { - CompoundScopeRAII CompoundScope(*this); - Body = ActOnCompoundStmt(Loc, Loc, (Statements), - /*isStmtExpr=*/false); - assert(!Body.isInvalid() && "Compound statement creation cannot fail"); - } - Serialization->setBody(Body.getAs()); - - if (ASTMutationListener *L = getASTMutationListener()) { - L->CompletedImplicitDefinition(Serialization); - } -} - Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) { CXXRecordDecl *ClassDecl = MD->getParent(); @@ -13400,6 +12254,10 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { /* ConstRHS */ false, /* Diagnose */ false); } + if (getLangOpts().CPlusPlusAMP) { + MoveAssignment->addAttr(HCRestrictCPUAttr::CreateImplicit(Context)); + MoveAssignment->addAttr(HCRestrictHCAttr::CreateImplicit(Context)); + } // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = @@ -13777,6 +12635,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /* ConstRHS */ Const, /* Diagnose */ false); } + if (getLangOpts().CPlusPlusAMP) { + CopyConstructor->addAttr(HCRestrictCPUAttr::CreateImplicit(Context)); + CopyConstructor->addAttr(HCRestrictHCAttr::CreateImplicit(Context)); + } // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = @@ -13907,6 +12769,10 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( /* ConstRHS */ false, /* Diagnose */ false); } + if (getLangOpts().CPlusPlusAMP) { + MoveConstructor->addAttr(HCRestrictCPUAttr::CreateImplicit(Context)); + MoveConstructor->addAttr(HCRestrictHCAttr::CreateImplicit(Context)); + } // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 140e9dd66f4..e6a244c3b04 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3213,9 +3213,9 @@ ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) { Context.IntTy, Loc); } -void DiagnoseCXXAMPFloatingLiteral(Sema &S, NumericLiteralParser &Literal, - QualType Ty, SourceLocation Loc) { - if(!S.IsInAMPRestricted() || !Literal.isFloatingLiteral()) +void DiagnoseHCFloatingLiteral(Sema &S, NumericLiteralParser &Literal, + QualType Ty, SourceLocation Loc) { + if(!S.IsInHCRestricted() || !Literal.isFloatingLiteral()) return; const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty); @@ -3257,9 +3257,11 @@ void DiagnoseCXXAMPFloatingLiteral(Sema &S, NumericLiteralParser &Literal, } } -void DiagnoseCXXAMPIntergerLiteral(Sema &S, NumericLiteralParser &Literal, - QualType Ty, SourceLocation Loc, unsigned MaxWidth ) { - if(!S.IsInAMPRestricted() || !Literal.isFloatingLiteral()) +// TODO: Fix for winter cleanup +void DiagnoseHCIntergerLiteral(Sema &S, NumericLiteralParser &Literal, + QualType Ty, SourceLocation Loc, + unsigned MaxWidth) { + if(!S.IsInHCRestricted() || !Literal.isFloatingLiteral()) return; llvm::APInt ResultVal(MaxWidth, 0); @@ -3277,10 +3279,10 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal, APFloat::opStatus result = Literal.GetFloatValue(Val); - // C++AMP - // Note that we suppress normal diagnositic + // HC + // Note that we suppress normal diagnostic if(S.getLangOpts().CPlusPlusAMP && result != APFloat::opOK) { - DiagnoseCXXAMPFloatingLiteral(S, Literal, Ty, Loc); + DiagnoseHCFloatingLiteral(S, Literal, Ty, Loc); } // Overflow is always an error, but underflow is only an error if @@ -3410,11 +3412,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else { llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0); if (Literal.GetIntegerValue(ResultVal)) { - // C++AMP + // HC // Note that this suppress normal diagnostic if(getLangOpts().CPlusPlusAMP) - DiagnoseCXXAMPIntergerLiteral(*this, Literal, CookedTy, Tok.getLocation(), - Context.getTargetInfo().getLongLongWidth()); + DiagnoseHCIntergerLiteral(*this, Literal, CookedTy, + Tok.getLocation(), + Context.getTargetInfo().getLongLongWidth()); else Diag(Tok.getLocation(), diag::err_integer_literal_too_large) << /* Unsigned */ 1; @@ -3565,7 +3568,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // If this value didn't fit into uintmax_t, error and force to ull. // C++AMP if(getLangOpts().CPlusPlusAMP) - DiagnoseCXXAMPIntergerLiteral(*this, Literal, Ty, Tok.getLocation(), MaxWidth); + DiagnoseHCIntergerLiteral(*this, Literal, Ty, Tok.getLocation(), MaxWidth); else Diag(Tok.getLocation(), diag::err_integer_literal_too_large) << /* Unsigned */ 1; @@ -5661,64 +5664,11 @@ ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc); } -void Sema::DiagnoseCXXAMPMethodCallExpr(SourceLocation LParenLoc, - CXXMethodDecl *Callee) { - if(!Callee || Callee->isConstexpr() || Callee->getBuiltinID() != 0u) - return; - - FunctionDecl* Caller = this->getCurFunctionDecl(); - LambdaScopeInfo* LambdaInfo = this->getCurLambda(); - bool CallerAMP = (LambdaInfo && LambdaInfo->CallOperator)? - LambdaInfo->CallOperator->hasAttr(): - (Caller?Caller->hasAttr():false); - bool CallerCPU= (LambdaInfo && LambdaInfo->CallOperator)? - LambdaInfo->CallOperator->hasAttr(): - (Caller?Caller->hasAttr():false); - bool CalleeAMP = Callee->hasAttr(); - bool CalleeCPU = Callee->hasAttr(); - - // Logic for auto-compile-for-accelerator: - // In device path, if auto-compile-for-accelerator flag is on, - // and caller method has GPU attribute (CXXAMPRestrictAMPAttr), - // and callee method doesn't have GPU attribute (CXXAMPRestrictAMPAttr), - // then annotate it with one, and recalculate related boolean flags - if (getLangOpts().DevicePath && getLangOpts().AutoCompileForAccelerator) { - if (CallerAMP && !CalleeAMP) { - //llvm::errs() << "add [[hc]] to callee: " << Callee->getName() << "\n"; - Callee->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Callee->getLocation(), Context, 0)); - CalleeAMP = Callee->hasAttr(); - } - } - - // Case by case - if((LambdaInfo && LambdaInfo->CallOperator) && !getLangOpts().AMPCPU) { - // caller: __GPU, lambda; callee: non __GPU, lambda - // int i = 0; - // auto l2 = []() { i = 1; }; - // auto l = []() __GPU { - // l2(); // Error - // }; - if(getLangOpts().DevicePath && Callee->getParent() && Callee->getParent()->isLambda() && - (CallerAMP && CallerCPU) && (!CalleeAMP && !CalleeCPU) ) - // FIXME: Need a mangled lambda name as ' operator()' - Diag(LParenLoc, diag::err_amp_overloaded_member_function) - << Callee->getQualifiedNameAsString() - << LambdaInfo->CallOperator->getQualifiedNameAsString(); - } else if(Caller && ! (LambdaInfo && LambdaInfo->CallOperator) && !getLangOpts().AMPCPU) { - // caller: __GPU, global; callee: non __GPU, class static - // class C1 { - // public: - // static void foo(int &flag) {flag = 1;} - // }; - // bool test() __GPU { - // int flag = 0; - // C1::foo(flag); // Error - // } - if(getLangOpts().DevicePath && Callee->isStatic() && (CallerAMP && CallerCPU) && - (!CalleeAMP && !CalleeCPU) ) - Diag(LParenLoc, diag::err_amp_overloaded_member_function) - << Callee->getQualifiedNameAsString() << Caller->getNameAsString(); - } +// TODO: Fix for winter cleanup; this should be collapsed with +// DiagnoseHCOverloadedCallExpr. +void Sema::DiagnoseHCMethodCallExpr(SourceLocation LParenLoc, + CXXMethodDecl *Callee) { + DiagnoseHCOverloadedCallExpr(LParenLoc, Callee); } /// BuildResolvedCallExpr - Build a call to a resolved expression, @@ -5924,12 +5874,14 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, } } - // C++AMP - if(getLangOpts().CPlusPlusAMP) { + // TODO - Fix for winter cleanup; this is already done in + // FinishOverloadedCallExpr. + // HC + if (getLangOpts().CPlusPlusAMP) { if (CXXMethodDecl *Method = dyn_cast_or_null(FDecl)) - DiagnoseCXXAMPMethodCallExpr(LParenLoc, Method); + DiagnoseHCMethodCallExpr(LParenLoc, Method); else - DiagnoseCXXAMPOverloadedCallExpr(LParenLoc, FDecl); + DiagnoseHCOverloadedCallExpr(LParenLoc, FDecl); } if (CXXMethodDecl *Method = dyn_cast_or_null(FDecl)) @@ -10089,70 +10041,18 @@ static ValueDecl *getCompareDecl(Expr *E) { return nullptr; } -// The following are not allowed in amp restricted codes +// The following are not allowed in hc restricted code // Recursion. - // Variables declared with the volatile keyword. // Virtual functions. - // Pointers to functions. - // Pointers to member functions. - // Pointers in structures. - // Pointers to pointers. - // goto statements. - // Labeled statements. // try , catch, or throw statements. - // Global variables. - // Static variables. Use tile_static Keyword instead. - //>>>>>>>>>>>>>>>> - // Refering to [2.4.3.2] Primary Expressions (C++11 5.1) - // An identifier or qualified identifier that refers to an object shall refer only to: - // (1) a parameter to the function, or - // (2) a local variable declared at a block scope within the function, or - // (3) a non-static member of the class of which this function is a member, or - // (4) a static const type that can be reduced to a integer literal and is only used as an rvalue, or - // (5) a global const type that can be reduced to a integer literal and is only used as an rvalue, or - // (6) a captured variable in a lambda expression. - //<<<<<<<<<<<<<<<< // dynamic_cast casts. // The typeid operator. - // asm declarations. // Varargs. -void Sema::DiagnoseCXXAMPExpr(Expr* Stripped, ExprResult &HS, bool DiagnoseWhenStatic) { - if(IsInAMPRestricted()) { - if (DeclRefExpr* DRL = dyn_cast(Stripped)) - if (VarDecl *var = dyn_cast(DRL->getDecl())) { - QualType Type = var->getType(); - if(!var->hasLocalStorage() || var->isStaticDataMember()) { - if (var->hasAttr()) { - // Skip tile_static - } else if(Type.isConstQualified() /*&& LHS.get()->isRValue()*/) { - // Skip a static const type and global const type that is rvalue - if((var->getStorageClass() == SC_Static && - isa(HS.get()->IgnoreParens()) && - cast(HS.get()->IgnoreParens())->getOpcode()== UO_AddrOf) || - DiagnoseWhenStatic) { - //Still diagnose pointer to static and/or member, e.g - // static const int flagxxx = 2; - // void foo(bool set) __GPU - // { - // int n = flagxxx + 3; - // const int *p = &flagxxx; // error - // } - // Or sometimes HS is not a UnaryOperator, we use manually-set flag - // 'DiagnoseWhenStatic' to determine - // - Diag(HS.get()->getBeginLoc(), diag::err_amp_using_static_or_global_variables) - << var->getName(); - } - } else - if (getLangOpts().HSAExtension || getLangOpts().AMPCPU) { - ; // hsa extention - } else { - Diag(HS.get()->getBeginLoc(), diag::err_amp_using_static_or_global_variables) - << var->getName(); - } - } - } - } +void Sema::DiagnoseHCExpr( + Expr* Stripped, ExprResult &HS, bool DiagnoseWhenStatic) { + if(!IsInHCRestricted()) return; + + // TODO: figure if we actually need to do anything here. } /// Diagnose some forms of syntactically-obvious tautological comparison. @@ -10506,11 +10406,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc); // C++AMP - if (getLangOpts().CPlusPlusAMP ) { + if (getLangOpts().CPlusPlusAMP) { Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts(); Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts(); - DiagnoseCXXAMPExpr(LHSStripped, LHS); - DiagnoseCXXAMPExpr(RHSStripped, RHS); + DiagnoseHCExpr(LHSStripped, LHS); + DiagnoseHCExpr(RHSStripped, RHS); } // The result of comparisons is 'bool' in C++, 'int' in C. @@ -11673,13 +11573,14 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, CheckForNullPointerDereference(*this, LHSExpr); - // C++AMP + // HC + // TODO: Fix for winter cleanup. // Primary Expression: " const int *p = &flag; // where flag is a 'static int' if(getLangOpts().CPlusPlusAMP) { ExprResult ER = LHSExpr; - DiagnoseCXXAMPExpr(LHSExpr->IgnoreParenImpCasts(), ER); - DiagnoseCXXAMPExpr(RHS.get()->IgnoreParenImpCasts(), RHS); + DiagnoseHCExpr(LHSExpr->IgnoreParenImpCasts(), ER); + DiagnoseHCExpr(RHS.get()->IgnoreParenImpCasts(), RHS); } // C99 6.5.16p3: The type of an assignment expression is the type of the @@ -11871,17 +11772,6 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); - // C++AMP [2.4.3.7] - if (S.getLangOpts().CPlusPlusAMP && S.IsInAMPRestricted() && !S.getLangOpts().HSAExtension) { - if(ResType->isPointerType() && ResType->getPointeeType()->isBooleanType()) { - // No matter IsPrefix or not. We only care about the opcode string - StringRef OpcString = (IsInc)?UnaryOperator::getOpcodeStr(UnaryOperatorKind(UO_PreInc)) - :UnaryOperator::getOpcodeStr(UnaryOperatorKind(UO_PreDec)); - S.Diag(Op->getExprLoc(), diag::err_amp_arithmetic_operation_on_pointer_to_bool) - << OpcString; - } - } - // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. @@ -12138,9 +12028,9 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { AddressOfError = AO_Register_Variable; } - // C++AMP - if(getLangOpts().CPlusPlusAMP) { - DiagnoseCXXAMPExpr(op, OrigOp, true); + // HC + if (getLangOpts().CPlusPlusAMP) { + DiagnoseHCExpr(op, OrigOp, true); } } else if (isa(dcl)) { AddressOfError = AO_Property_Expansion; @@ -12694,19 +12584,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, CheckArrayAccess(LHS.get()); CheckArrayAccess(RHS.get()); - // C++AMP [2.4.3.7] - // FIXME: Should check if there are allowed Pointer arithmetic - if (getLangOpts().CPlusPlusAMP && IsInAMPRestricted() && !getLangOpts().HSAExtension) { - QualType L = LHS.get()->getType(); - QualType R = RHS.get()->getType(); - if(L->isPointerType() && L->getPointeeType()->isBooleanType()) - Diag(LHS.get()->getExprLoc(), diag::err_amp_arithmetic_operation_on_pointer_to_bool) - << BinaryOperator::getOpcodeStr(Opc); - if(R->isPointerType() && R->getPointeeType()->isBooleanType()) - Diag(RHS.get()->getExprLoc(), diag::err_amp_arithmetic_operation_on_pointer_to_bool) - << BinaryOperator::getOpcodeStr(Opc); - } - if (const ObjCIsaExpr *OISA = dyn_cast(LHS.get()->IgnoreParenCasts())) { NamedDecl *ObjectSetClass = LookupSingleName(TUScope, &Context.Idents.get("object_setClass"), @@ -14987,26 +14864,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } else if (Constructor->isMoveConstructor()) { DefineImplicitMoveConstructor(Loc, Constructor); } - } else if (Constructor->getInheritedConstructor()) { - DefineInheritingConstructor(Loc, Constructor); - } else if (LangOpts.CPlusPlusAMP) { - if (Constructor->hasAttr() && - Constructor->hasAttr() && - Constructor->getAttr()->getAnnotation() == - "auto_deserialize") { -#if 0 - DeclarationNameInfo AmpFunInfo = Func -> getNameInfo(); - std::string MethodFunName = AmpFunInfo.getAsString(); - llvm::errs() << "Definiting Function = " << MethodFunName << "\n"; -#endif - - // do not generate deserializer in case there are previous errors - if (!this->getDiagnostics().hasErrorOccurred()) - DefineAmpGpuDeSerializeFunction(Loc, Constructor); + } else if (Constructor->getInheritedConstructor()) { + DefineInheritingConstructor(Loc, Constructor); } - } - } else if (CXXDestructorDecl *Destructor = - dyn_cast(Func)) { + } else if (CXXDestructorDecl *Destructor = + dyn_cast(Func)) { Destructor = cast(Destructor->getFirstDecl()); if (Destructor->isDefaulted() && !Destructor->isDeleted()) { if (Destructor->isTrivial() && !Destructor->hasAttr()) @@ -15016,16 +14878,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (Destructor->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast(Func)) { - // C++AMP - DeclarationNameInfo AmpFunInfo = Func -> getNameInfo(); - std::string MethodFunName = AmpFunInfo.getAsString(); - std::string AmpFunName = "__cxxamp_serialize"; - if (AmpFunName == MethodFunName) { - DefineAmpCpuSerializeFunction(Loc, MethodDecl); - } else if (MethodFunName == "__cxxamp_trampoline"|| - MethodFunName == "__cxxamp_trampoline_name") { - DefineAMPTrampoline(Loc, MethodDecl); - } else if (MethodDecl->isOverloadedOperator()) { + if (MethodDecl->isOverloadedOperator()) { if (isHIPFunctor(MethodDecl)) { // TODO: temporary. auto t = findCall(MethodDecl->getBody()); if (t) { @@ -15053,7 +14906,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, MethodDecl->getParent()); } - + // Recursive functions should be marked when used from another function. // FIXME: Is this really right? if (CurContext == Func) return; @@ -17185,4 +17038,4 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); -} +} \ No newline at end of file diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index f530502c5b9..bd9e1ca3308 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -5738,8 +5738,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // C++AMP if(getLangOpts().CPlusPlusAMP) { - DiagnoseCXXAMPExpr(LHS.get()->IgnoreParenImpCasts(), LHS); - DiagnoseCXXAMPExpr(RHS.get()->IgnoreParenImpCasts(), RHS); + DiagnoseHCExpr(LHS.get()->IgnoreParenImpCasts(), LHS); + DiagnoseHCExpr(RHS.get()->IgnoreParenImpCasts(), RHS); } // Either of the arguments dependent? diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index c88d4cbae5b..4d57286bd8c 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1120,72 +1120,48 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } if (CXXMethodDecl *MemberFn = dyn_cast(MemberDecl)) { - // C++AMP + // HC + // TODO: Fix for winter cleanup if(getLangOpts().CPlusPlusAMP) { bool ParentCPU = false; - bool ParentAMP = false; + bool ParentHC = false; std::string name; if(getCurFunctionDecl()) { - ParentCPU = getCurFunctionDecl()->hasAttr(); - ParentAMP = getCurFunctionDecl()->hasAttr(); + ParentCPU = getCurFunctionDecl()->hasAttr(); + ParentHC = getCurFunctionDecl()->hasAttr(); name = getCurFunctionDecl()->getNameAsString(); } - if(ParentCPU || ParentAMP) { - // Lambda if any will inheritate AMP restrictions from Parent RECURSIVELY + if(ParentCPU || ParentHC) { + // Lambda if any will inheritate HC restrictions from Parent RECURSIVELY } else if(getCurLambda() && getCurLambda()->CallOperator) { // Suppress the restrictions - ParentCPU = getCurLambda()->CallOperator->hasAttr(); - ParentAMP = getCurLambda()->CallOperator->hasAttr(); + ParentHC = getCurLambda()->CallOperator->hasAttr(); + ParentHC = getCurLambda()->CallOperator->hasAttr(); name = getCurLambda()->CallOperator->getNameAsString(); } // Check local - // FIXME: the class should inheritate AMP restriction from parent RECURSIVELY - // especially the class.local. Any missing of that can cause unexpected errors - bool MemberAMP = MemberFn->hasAttr(); - bool MemberCPU = MemberFn->hasAttr() || !MemberAMP; + // FIXME: the class should inherit HC restriction from parent RECURSIVELY + // especially the class.local. Any missing of that can cause + // unexpected errors + bool MemberHC = MemberFn->hasAttr(); + bool MemberCPU = MemberFn->hasAttr() || !MemberHC; const CXXRecordDecl * RDecl = MemberFn->getParent(); - // Logic for auto-compile-for-accelerator: - // In both CPU and device path, if auto-compile-for-accelerator flag is on, - // and caller has GPU attribute (CXXAMPRestrictAMPAttr), - // and callee method doesn't have GPU attribute (CXXAMPRestrictAMPAttr), - // and callee is not within C++ or HCC default library, - // then annotate callee with one, and recalculate related boolean flags - - if (getLangOpts().AutoCompileForAccelerator) { - if (ParentAMP && !MemberAMP) { - std::string QualifiedName = MemberDecl->getQualifiedNameAsString(); - // Skip self implementation and unwanted - if(QualifiedName.find("Kalmar::")!=std::string::npos || - QualifiedName.find("hc::")!=std::string::npos || - QualifiedName.find("Concurrency::")!=std::string::npos || - QualifiedName.find("std::")!=std::string::npos || - QualifiedName.find("__cxxamp_serialize")!=std::string::npos || - QualifiedName.find("__cxxamp_trampoline_name")!=std::string::npos) { - } else { - //llvm::errs() << "add [[hc]] to member: " << MemberFn->getName() << "\n"; - MemberFn->addAttr(::new (Context) CXXAMPRestrictAMPAttr(MemberFn->getLocation(), Context, 0)); - MemberAMP = MemberFn->hasAttr(); - MemberCPU = MemberFn->hasAttr() || !MemberAMP; - } - } - } - if(RDecl && RDecl->isLocalClass()) { // Do nothing - } else if(ParentCPU== MemberCPU && ParentAMP== MemberAMP) { + } else if(ParentCPU == MemberCPU && ParentHC == MemberHC) { // The function is not overloaded - } else if((!MemberCPU &&!MemberAMP && (ParentCPU ||ParentAMP)) || - (!ParentCPU&&!ParentAMP && (!MemberCPU && MemberAMP)) || - (ParentCPU== (!ParentAMP) && MemberCPU == (!MemberAMP) && ParentCPU!=MemberCPU)) { + } else if((!MemberCPU &&!MemberHC && (ParentCPU ||ParentHC)) || + (!ParentCPU&&!ParentHC && (!MemberCPU && MemberHC)) || + (ParentCPU == (!ParentHC) && MemberCPU == (!MemberHC) && + ParentCPU != MemberCPU)) { std::string QualifiedName = MemberDecl->getQualifiedNameAsString(); // Skip self implementation and unwanted if(QualifiedName.find("::accelerator_view")!=std::string::npos || QualifiedName.find("array_view<")!=std::string::npos || QualifiedName.find("::accelerator")!=std::string::npos || - QualifiedName.find("Concurrency::")!=std::string::npos || - QualifiedName.find("std::")!=std::string::npos || - QualifiedName.find("__cxxamp_serialize")!=std::string::npos) { + QualifiedName.find("hc::")!=std::string::npos || + QualifiedName.find("std::")!=std::string::npos) { // TODO: likely bogus. } else { Diag(MemberLoc, diag::err_amp_overloaded_member_function) << MemberDecl->getQualifiedNameAsString() << name; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 6dfbd900b1c..4f642d41ac2 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3803,48 +3803,49 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, return CandidateSet.BestViableFunction(S, DeclLoc, Best); } +// TODO: Fix for winter cleanup // Specially diagnose dtor case: "no dtor possible thus no default ctor possible" // struct A3_base_1 { // int i; -// ~A3_base_1() restrict(cpu) {} +// ~A3_base_1() [[cpu]] {} // }; // class A3_member_1 { // public: -// ~A3_member_1() restrict(amp) {} +// ~A3_member_1() [[hc]] {} // }; // struct A3 : A3_base_1 { // A3_member_1 m1; // // no dtor possible thus no default ctor possible // }; -static void CheckCXXAMPHasPossibleSMF(Sema&S, CXXRecordDecl* RDecl, - bool OrgCPU, bool OrgAMP, - bool NewCPU, bool NewAMP, unsigned DiagID) { - if((OrgCPU && OrgAMP) || (NewCPU && NewAMP)) +static void CheckHCHasPossibleSMF(Sema &S, CXXRecordDecl *RDecl, + bool OrgCPU, bool OrgHC, + bool NewCPU, bool NewHC, unsigned DiagID) { + if ((OrgCPU && OrgHC) || (NewCPU && NewHC)) return; - if(OrgCPU || OrgAMP) { - if((OrgCPU !=NewCPU) &&(OrgAMP !=NewAMP)) + if (OrgCPU || OrgHC) { + if ((OrgCPU !=NewCPU) && (OrgHC !=NewHC)) S.Diag(RDecl->getInnerLocStart(), DiagID) << RDecl->getName(); } } -#define INTERSECT_ATTR(OrgCPU, OrgAMP, NewCPU, NewAMP) \ - if(!(OrgCPU && OrgAMP) && (OrgCPU!= OrgAMP)) { \ - if(NewCPU && NewAMP) \ +#define INTERSECT_ATTR(OrgCPU, OrgHC, NewCPU, NewHC) \ + if(!(OrgCPU && OrgHC) && (OrgCPU!= OrgHC)) { \ + if(NewCPU && NewHC) \ ; \ - else if((OrgCPU!=NewCPU) && (OrgAMP!=NewAMP)) { \ + else if((OrgCPU!=NewCPU) && (OrgHC != NewHC)) { \ /* Mutex situation. Throw exceptions about "Wrong Restrictions" */\ ; \ } \ - } else if (OrgCPU && OrgAMP) { \ - if(!(NewCPU && NewAMP)) { \ + } else if (OrgCPU && OrgHC) { \ + if(!(NewCPU && NewHC)) { \ OrgCPU = NewCPU; \ - OrgAMP = NewAMP; \ + OrgHC = NewHC; \ } \ } else { \ OrgCPU |= NewCPU; \ - OrgAMP |= NewAMP; \ + OrgHC |= NewHC; \ } // Using locally @@ -3856,16 +3857,18 @@ static void CheckCXXAMPHasPossibleSMF(Sema&S, CXXRecordDecl* RDecl, #define SMF_Destructor 0x20 #define SMF_All 0x3f -void Sema::InheritSMFDtorIntersections(CXXRecordDecl* RDecl, - bool& CPUAttr, bool& AMPAttr, - bool& ParentCPUAttr, bool& ParentAMPAttr) { +// TODO: Fix for winter cleanup +void Sema::InheritSMFDtorIntersections(CXXRecordDecl *RDecl, + bool &CPUAttr, bool &HCAttr, + bool &ParentCPUAttr, bool &ParentHCAttr) { // Step1 - // The compiler sets the restrictions of compiler-generated destructors to the - // intersection of the restrictions on all of the destructors of the data members - // [able to destroy all data members] and all of the base classes.destructors - // [able to call all base classes destructors]. If there are no such destructors, - // then all possible restrictions are used [able to destroy in any context]. - // However, any restriction that would result in an error is not set. + // The compiler sets the restrictions of compiler-generated destructors to + // the intersection of the restrictions on all of the destructors of the data + // members [able to destroy all data members] and all of the base + // classes.destructors [able to call all base classes destructors]. If there + // are no such destructors, then all possible restrictions are used [able to + // destroy in any context]. However, any restriction that would result in an + // `error is not set. if(RDecl->getQualifiedNameAsString().find("std::")!=std::string::npos) return; @@ -3882,17 +3885,19 @@ void Sema::InheritSMFDtorIntersections(CXXRecordDecl* RDecl, continue; if(CXXDestructorDecl * BaseDtor = BaseRDecl ->getDestructor()) { if(!BaseDtor->isUserProvided()) - InheritSMFDtorIntersections(BaseRDecl, CPUAttr, AMPAttr, ParentCPUAttr, ParentAMPAttr); + InheritSMFDtorIntersections(BaseRDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr); else{ - CheckCXXAMPHasPossibleSMF(*this, RDecl, CPUAttr, AMPAttr, - BaseDtor->hasAttr(), - BaseDtor->hasAttr(), + CheckHCHasPossibleSMF(*this, RDecl, CPUAttr, HCAttr, + BaseDtor->hasAttr(), + BaseDtor->hasAttr(), diag::err_amp_has_no_default_ctor); - INTERSECT_ATTR(CPUAttr, AMPAttr, BaseDtor->hasAttr(), - BaseDtor->hasAttr()); + INTERSECT_ATTR(CPUAttr, HCAttr, BaseDtor->hasAttr(), + BaseDtor->hasAttr()); } } else { - InheritSMFDtorIntersections(BaseRDecl, CPUAttr, AMPAttr, ParentCPUAttr, ParentAMPAttr); + InheritSMFDtorIntersections(BaseRDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr); } } } @@ -3903,7 +3908,7 @@ void Sema::InheritSMFDtorIntersections(CXXRecordDecl* RDecl, const FieldDecl *FD = *It; const RecordType *RT = Context.getBaseElementType(FD->getType())->getAs(); if (!RT) { - if(ParentAMPAttr) { + if(ParentHCAttr) { const Type* Ty = FD->getType().getTypePtrOrNull(); // FIXME:The following codes might not work since the in-compatible scalar types of // struct/union/class are diagnosed in advance, e.g. ActOnDeclarator @@ -3917,34 +3922,38 @@ void Sema::InheritSMFDtorIntersections(CXXRecordDecl* RDecl, continue; } CXXRecordDecl *MemberDecl = cast(RT->getDecl()); - InheritSMFDtorIntersections(MemberDecl, CPUAttr, AMPAttr, ParentCPUAttr, ParentAMPAttr); + InheritSMFDtorIntersections(MemberDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr); } // Check the member methods if any for ( CXXRecordDecl::method_iterator MethodIt = RDecl->method_begin(), MethodItE = RDecl->method_end(); MethodIt != MethodItE; ++MethodIt) { if(dyn_cast(*MethodIt)) { - CheckCXXAMPHasPossibleSMF(*this, RDecl, CPUAttr, AMPAttr, - MethodIt->hasAttr(), - MethodIt->hasAttr(), - diag::err_amp_has_no_default_ctor); - INTERSECT_ATTR(CPUAttr, AMPAttr, MethodIt->hasAttr(), - MethodIt->hasAttr()); + CheckHCHasPossibleSMF(*this, RDecl, CPUAttr, HCAttr, + MethodIt->hasAttr(), + MethodIt->hasAttr(), + diag::err_amp_has_no_default_ctor); + INTERSECT_ATTR(CPUAttr, HCAttr, MethodIt->hasAttr(), + MethodIt->hasAttr()); } } } -void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, - bool& CPUAttr, bool& AMPAttr, - bool& ParentCPUAttr, bool& ParentAMPAttr, int flag, bool ConstParam) { +// TODO: Fix for winter cleanup +void Sema::InheritSMFCtorIntersections(CXXRecordDecl *RDecl, bool &CPUAttr, + bool &HCAttr, bool &ParentCPUAttr, + bool &ParentHCAttr, int flag, + bool ConstParam) { // Step2 - // The compiler sets the restrictions of compiler-generated default constructors - // to the intersection of the restrictions on all of the default constructors of the member - // fields [able to construct all member fields], all of the base classes default constructors - // [able to call all base classes default constructors], and the destructor of the class - // [able to destroy in any context constructed]. However, any restriction that would result - // in an error is not set. + // The compiler sets the restrictions of compiler-generated default + // constructors to the intersection of the restrictions on all of the default + // constructors of the member fields [able to construct all member fields], + // all of the base classes default constructors [able to call all base classes + // default constructors], and the destructor of the class [able to destroy in + // any context constructed]. However, any restriction that would result in an + // error is not set. if(RDecl->getQualifiedNameAsString().find("std::")!=std::string::npos) return; @@ -3959,11 +3968,11 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, if(BaseRDecl->getQualifiedNameAsString().find("std::")!=std::string::npos) continue; if(BaseRDecl->ctor_end() == BaseRDecl->ctor_begin()) - InheritSMFCtorIntersections(BaseRDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, flag, ConstParam); + InheritSMFCtorIntersections(BaseRDecl, CPUAttr, HCAttr, ParentCPUAttr, + ParentHCAttr, flag, ConstParam); else { bool BaseMergedCPU = false; - bool BaseMergedAMP = false; + bool BaseMergedHC = false; bool DoIt = false; unsigned DiagID; for(CXXRecordDecl::ctor_iterator CtorIt = BaseRDecl->ctor_begin(); @@ -3975,8 +3984,8 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, DiagID = diag::err_amp_has_no_default_ctor; if(CXXDestructorDecl * CDD = BaseRDecl->getDestructor()) { if(CDD->isUserProvided()) { - BaseMergedCPU |= CDD->hasAttr(); - BaseMergedAMP |= CDD->hasAttr(); + BaseMergedCPU |= CDD->hasAttr(); + BaseMergedHC |= CDD->hasAttr(); DoIt = true; } } @@ -3990,8 +3999,8 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, DiagID = diag::err_amp_has_no_copy_constructor; if(CXXDestructorDecl * CDD = BaseRDecl->getDestructor()) { if(CDD->isUserProvided()) { - BaseMergedCPU |= CDD->hasAttr(); - BaseMergedAMP |= CDD->hasAttr(); + BaseMergedCPU |= CDD->hasAttr(); + BaseMergedHC |= CDD->hasAttr(); DoIt = true; } } @@ -4004,24 +4013,25 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, continue; } if(!CD->isUserProvided()) - InheritSMFCtorIntersections(BaseRDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, flag, ConstParam); + InheritSMFCtorIntersections(BaseRDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr, flag, + ConstParam); else { // At this point, multiple restrictions might not be merged yet, e.g // struct A8_base { - // A8_base() restrict(cpu,amp) {} - // A8_base(A8_base&) restrict(cpu) {} // #1 CopyCtor - // A8_base(A8_base&) restrict(amp) {} // #2 CopyCotr + // A8_base() [[cpu, hc]] {} + // A8_base(A8_base&) [[cpu]] {} // #1 CopyCtor + // A8_base(A8_base&) [[hc]] {} // #2 CopyCtor // }; - BaseMergedCPU |= CD->hasAttr(); - BaseMergedAMP |= CD->hasAttr(); + BaseMergedCPU |= CD->hasAttr(); + BaseMergedHC |= CD->hasAttr(); DoIt = true; } } if(DoIt) { - CheckCXXAMPHasPossibleSMF(*this, RDecl, CPUAttr, AMPAttr, - BaseMergedCPU, BaseMergedAMP, DiagID); - INTERSECT_ATTR(CPUAttr, AMPAttr, BaseMergedCPU, BaseMergedAMP); + CheckHCHasPossibleSMF(*this, RDecl, CPUAttr, HCAttr, + BaseMergedCPU, BaseMergedHC, DiagID); + INTERSECT_ATTR(CPUAttr, HCAttr, BaseMergedCPU, BaseMergedHC); } } @@ -4036,20 +4046,20 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, if (!RT) continue; CXXRecordDecl *MemberDecl = cast(RT->getDecl()); - InheritSMFCtorIntersections(MemberDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, flag, ConstParam); + InheritSMFCtorIntersections(MemberDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr, flag, ConstParam); } // Empty class with user-defined dtor // class A1 { // public: - // ~A1() restrict(amp) {} - // // defaulted: A1() restrict(amp) + // ~A1() [[hc]] {} + // // defaulted: A1() [[hc]] // }; // Check own ctors { bool BaseMergedCPU = false; - bool BaseMergedAMP = false; + bool BaseMergedHC = false; bool DoIt = false; unsigned DiagID; for(CXXRecordDecl::ctor_iterator CtorIt = RDecl->ctor_begin(); @@ -4061,8 +4071,8 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, DiagID = diag::err_amp_has_no_default_ctor; if(CXXDestructorDecl * CDD = RDecl->getDestructor()) { if(CDD->isUserProvided()) { - BaseMergedCPU |= CDD->hasAttr(); - BaseMergedAMP |= CDD->hasAttr(); + BaseMergedCPU |= CDD->hasAttr(); + BaseMergedHC |= CDD->hasAttr(); DoIt = true; } } @@ -4076,8 +4086,8 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, DiagID = diag::err_amp_has_no_copy_constructor; if(CXXDestructorDecl * CDD = RDecl->getDestructor()) { if(CDD->isUserProvided()) { - BaseMergedCPU |= CDD->hasAttr(); - BaseMergedAMP |= CDD->hasAttr(); + BaseMergedCPU |= CDD->hasAttr(); + BaseMergedHC |= CDD->hasAttr(); DoIt = true; } } @@ -4093,26 +4103,26 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, if(CD->isUserProvided()) { // At this point, multiple restrictions might not be merged yet, e.g // struct A8_base { - // A8_base() restrict(cpu,amp) {} - // A8_base(A8_base&) restrict(cpu) {} // #1 CopyCtor - // A8_base(A8_base&) restrict(amp) {} // #2 CopyCotr + // A8_base() [[cpu, hc]] {} + // A8_base(A8_base&) [[cpu]] {} // #1 CopyCtor + // A8_base(A8_base&) [[hc]] {} // #2 CopyCotr // }; - BaseMergedCPU |= CD->hasAttr(); - BaseMergedAMP |= CD->hasAttr(); + BaseMergedCPU |= CD->hasAttr(); + BaseMergedHC |= CD->hasAttr(); DoIt = true; } } if(DoIt) { - CheckCXXAMPHasPossibleSMF(*this, RDecl, CPUAttr, AMPAttr, - BaseMergedCPU, BaseMergedAMP, DiagID); - INTERSECT_ATTR(CPUAttr, AMPAttr, BaseMergedCPU, BaseMergedAMP); + CheckHCHasPossibleSMF(*this, RDecl, CPUAttr, HCAttr, + BaseMergedCPU, BaseMergedHC, DiagID); + INTERSECT_ATTR(CPUAttr, HCAttr, BaseMergedCPU, BaseMergedHC); } } // Check the member methods if any { bool BaseMergedCPU = false; - bool BaseMergedAMP = false; + bool BaseMergedHC = false; bool DoIt = false; for ( CXXRecordDecl::method_iterator MethodIt = RDecl->method_begin(), MethodItE = RDecl->method_end(); MethodIt != MethodItE; ++MethodIt) { @@ -4129,31 +4139,31 @@ void Sema::InheritSMFCtorIntersections(CXXRecordDecl* RDecl, if(!MethodIt->isUserProvided()) { } else { - BaseMergedCPU |= MethodIt->hasAttr(); - BaseMergedAMP |= MethodIt->hasAttr(); + BaseMergedCPU |= MethodIt->hasAttr(); + BaseMergedHC |= MethodIt->hasAttr(); DoIt = true; } } if(DoIt) { // FIXME: Comment out this point since no idea of what DiagID it should be #if 0 - CheckCXXAMPHasPossibleSMF(*this, RDecl, CPUAttr, AMPAttr, BaseMergedCPU, BaseMergedAMP); + CheckHCHasPossibleSMF(*this, RDecl, CPUAttr, HCAttr, BaseMergedCPU, BaseMergedHC); #endif - INTERSECT_ATTR(CPUAttr, AMPAttr, BaseMergedCPU, BaseMergedAMP); + INTERSECT_ATTR(CPUAttr, HCAttr, BaseMergedCPU, BaseMergedHC); } } } -static void CheckCXXAMPHasPossibleSMFMethod(Sema&S, - CXXRecordDecl* RDecl, CXXMethodDecl* Method, - bool OrgCPU, bool OrgAMP, - bool NewCPU, bool NewAMP, unsigned DiagID) { - if((OrgCPU && OrgAMP) || (NewCPU && NewAMP)) +static void CheckHCHasPossibleSMFMethod(Sema &S, CXXRecordDecl *RDecl, + CXXMethodDecl *Method, bool OrgCPU, + bool OrgHC, bool NewCPU, bool NewHC, + unsigned DiagID) { + if((OrgCPU && OrgHC) || (NewCPU && NewHC)) return; - if(OrgCPU || OrgAMP) { - if((OrgCPU !=NewCPU) &&(OrgAMP !=NewAMP)) + if(OrgCPU || OrgHC) { + if((OrgCPU != NewCPU) &&(OrgHC != NewHC)) S.Diag(Method->getInnerLocStart(), DiagID) << Method->getNameAsString() <getName(); @@ -4161,9 +4171,10 @@ static void CheckCXXAMPHasPossibleSMFMethod(Sema&S, } // Defaulted CopyAssign and MoveAssign -void Sema::InheritSMFMethodIntersections(CXXRecordDecl* RDecl, - bool& CPUAttr, bool& AMPAttr, - bool& ParentCPUAttr, bool& ParentAMPAttr, int flag, bool ConstParam) { +void Sema::InheritSMFMethodIntersections(CXXRecordDecl *RDecl, bool &CPUAttr, + bool &HCAttr, bool &ParentCPUAttr, + bool &ParentHCAttr, int flag, + bool ConstParam) { // Step3 // The compiler sets the restrictions of compiler-generated copy constructors to // the intersection of the restrictions on all of the copy constructors of the member fields @@ -4188,14 +4199,14 @@ void Sema::InheritSMFMethodIntersections(CXXRecordDecl* RDecl, cast(BaseIt->getType()->getAs()->getDecl()); if(!BaseRDecl) continue; if(BaseRDecl->ctor_end() == BaseRDecl->ctor_begin()) - InheritSMFMethodIntersections(BaseRDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, flag); + InheritSMFMethodIntersections(BaseRDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr, flag); else { bool BaseMergedCPU = false; - bool BaseMergedAMP = false; + bool BaseMergedHC = false; bool DoIt = false; unsigned DiagID; - CXXMethodDecl* Method = NULL; + CXXMethodDecl* Method = nullptr; for ( CXXRecordDecl::method_iterator MethodIt = RDecl->method_begin(), MethodItE = RDecl->method_end(); MethodIt != MethodItE; ++MethodIt) { if(flag == SMF_CopyAssignment) { @@ -4216,18 +4227,19 @@ void Sema::InheritSMFMethodIntersections(CXXRecordDecl* RDecl, continue; } if( !MethodIt->isUserProvided()) { - InheritSMFMethodIntersections(BaseRDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, flag, ConstParam); + InheritSMFMethodIntersections(BaseRDecl, CPUAttr, HCAttr, + ParentCPUAttr, ParentHCAttr, flag, + ConstParam); } else { - BaseMergedCPU |= MethodIt->hasAttr(); - BaseMergedAMP |= MethodIt->hasAttr(); + BaseMergedCPU |= MethodIt->hasAttr(); + BaseMergedHC |= MethodIt->hasAttr(); DoIt = true; } } if(DoIt) { - CheckCXXAMPHasPossibleSMFMethod(*this, RDecl, Method, CPUAttr, AMPAttr, - BaseMergedCPU, BaseMergedAMP, DiagID); - INTERSECT_ATTR(CPUAttr, AMPAttr, BaseMergedCPU, BaseMergedAMP); + CheckHCHasPossibleSMFMethod(*this, RDecl, Method, CPUAttr, HCAttr, + BaseMergedCPU, BaseMergedHC, DiagID); + INTERSECT_ATTR(CPUAttr, HCAttr, BaseMergedCPU, BaseMergedHC); } } } @@ -4241,14 +4253,14 @@ void Sema::InheritSMFMethodIntersections(CXXRecordDecl* RDecl, if (!RT) continue; CXXRecordDecl *MemberDecl = cast(RT->getDecl()); - InheritSMFMethodIntersections(MemberDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, flag, ConstParam); + InheritSMFMethodIntersections(MemberDecl, CPUAttr, HCAttr, ParentCPUAttr, + ParentHCAttr, flag, ConstParam); } // Check the member methods if any { bool BaseMergedCPU = false; - bool BaseMergedAMP = false; + bool BaseMergedHC = false; bool DoIt = false; unsigned DiagID; CXXMethodDecl* Method = NULL; @@ -4273,40 +4285,44 @@ void Sema::InheritSMFMethodIntersections(CXXRecordDecl* RDecl, } if(MethodIt->isUserProvided()) { - BaseMergedCPU |= MethodIt->hasAttr(); - BaseMergedAMP |= MethodIt->hasAttr(); + BaseMergedCPU |= MethodIt->hasAttr(); + BaseMergedHC |= MethodIt->hasAttr(); DoIt = true; } } if(DoIt) { - CheckCXXAMPHasPossibleSMFMethod(*this, RDecl, Method, CPUAttr, AMPAttr, - BaseMergedCPU, BaseMergedAMP, DiagID); - INTERSECT_ATTR(CPUAttr, AMPAttr, BaseMergedCPU, BaseMergedAMP); + CheckHCHasPossibleSMFMethod(*this, RDecl, Method, CPUAttr, HCAttr, + BaseMergedCPU, BaseMergedHC, DiagID); + INTERSECT_ATTR(CPUAttr, HCAttr, BaseMergedCPU, BaseMergedHC); } } } -static void CheckCXXAMPSMFDestructor(Sema &S, CXXRecordDecl* RDecl, - bool& ParentCPUAttr, bool& ParentAMPAttr) { +// TODO: Fix for winter cleanup +static void CheckHCSMFDestructor(Sema &S, CXXRecordDecl *RDecl, + bool &ParentCPUAttr, bool &ParentHCAttr) { if(!RDecl || S.getLangOpts().HSAExtension) return; ASTContext &Context = S.Context; SourceLocation Loc = RDecl->getLocation(); CXXDestructorDecl * DD = RDecl ->getDestructor(); - if(DD && !DD->isUserProvided() && !DD->hasAttr() && - !DD->hasAttr()) { + if (DD && + !DD->isUserProvided() && + !DD->hasAttr() && + !DD->hasAttr()) { bool CPUAttr = false; - bool AMPAttr = false; - S.InheritSMFDtorIntersections(RDecl, CPUAttr, AMPAttr, ParentCPUAttr, ParentAMPAttr); - if(!DD->hasAttr() && - !DD->hasAttr()) { - if(CPUAttr && !DD->hasAttr()) - DD->addAttr(::new (Context) CXXAMPRestrictCPUAttr(Loc, Context, 0)); - - if(AMPAttr && !DD->hasAttr()) { - DD->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Loc, Context, 0)); + bool HCAttr = false; + S.InheritSMFDtorIntersections(RDecl, CPUAttr, HCAttr, ParentCPUAttr, + ParentHCAttr); + if (!DD->hasAttr() && + !DD->hasAttr()) { + if (CPUAttr && !DD->hasAttr()) + DD->addAttr(::new (Context) HCRestrictCPUAttr(Loc, Context, 0)); + + if (HCAttr && !DD->hasAttr()) { + DD->addAttr(::new (Context) HCRestrictHCAttr(Loc, Context, 0)); } } else { // FIXME: @@ -4315,195 +4331,9 @@ static void CheckCXXAMPSMFDestructor(Sema &S, CXXRecordDecl* RDecl, } } - if(DD && (DD->hasAttr() || - DD->hasAttr())) - S.DiagnoseCXXAMPOverloadedCallExpr(DD->getInnerLocStart(), DD); -} - -static void CheckCXXAMPSMFConstructor(Sema &S, CXXRecordDecl* RDecl, - bool& ParentCPUAttr, bool& ParentAMPAttr) { - if (!RDecl || S.getLangOpts().HSAExtension) - return; - - ASTContext &Context = S.Context; - SourceLocation Loc = RDecl->getLocation(); - - if(RDecl->hasDefaultConstructor() || RDecl->needsImplicitDefaultConstructor()) { - bool CPUAttr = false; - bool AMPAttr = false; - CXXConstructorDecl* DefaultCtor = NULL; - if(!RDecl->needsImplicitDefaultConstructor()) { - for(CXXRecordDecl::ctor_iterator CtorIt = RDecl->ctor_begin(); - CtorIt!=RDecl->ctor_end(); CtorIt++) - if((*CtorIt)->isDefaultConstructor() && !(*CtorIt)->isUserProvided() && - (*CtorIt)->isDefaulted()) { - DefaultCtor = (*CtorIt);} - } else { - DefaultCtor = S.DeclareImplicitDefaultConstructor(RDecl); - } - if(DefaultCtor && !DefaultCtor->hasAttr() && - !DefaultCtor->hasAttr()) { - S.InheritSMFCtorIntersections(RDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, SMF_DefaultConstructor); - if(DefaultCtor && CPUAttr && !DefaultCtor->hasAttr()) - DefaultCtor->addAttr(::new (Context) CXXAMPRestrictCPUAttr(Loc, Context, 0)); - - if(DefaultCtor && AMPAttr && !DefaultCtor->hasAttr()) - DefaultCtor->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Loc, Context, 0)); - } - if(DefaultCtor && (DefaultCtor->hasAttr() || - DefaultCtor->hasAttr())) - S.DiagnoseCXXAMPOverloadedCallExpr(DefaultCtor->getInnerLocStart(), DefaultCtor); - - } - - if(!RDecl->hasUserDeclaredCopyConstructor()) { - bool CPUAttr = false; - bool AMPAttr = false; - CXXConstructorDecl* CopyCtor = NULL; - bool ConstParam = RDecl->implicitCopyConstructorHasConstParam(); - if(!RDecl->needsImplicitCopyConstructor()) { - for(CXXRecordDecl::ctor_iterator CtorIt = RDecl->ctor_begin(); - CtorIt!=RDecl->ctor_end(); CtorIt++) - if((*CtorIt)->isCopyConstructor() && !(*CtorIt)->isUserProvided() && - (*CtorIt)->isDefaulted()){ - CopyCtor = (*CtorIt); - ConstParam = RDecl->hasCopyConstructorWithConstParam(); - } - } else { - CopyCtor = S.DeclareImplicitCopyConstructor(RDecl); - } - - if(CopyCtor && !CopyCtor->hasAttr() && - !CopyCtor->hasAttr()) { - S.InheritSMFCtorIntersections(RDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, SMF_CopyConstructor, ConstParam); - if(CopyCtor && CPUAttr && !CopyCtor->hasAttr()) - CopyCtor->addAttr(::new (Context) CXXAMPRestrictCPUAttr(Loc, Context, 0)); - - if(CopyCtor && AMPAttr && !CopyCtor->hasAttr()) - CopyCtor->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Loc, Context, 0)); - - if(CopyCtor && (CopyCtor->hasAttr() || - CopyCtor->hasAttr())) - S.DiagnoseCXXAMPOverloadedCallExpr(CopyCtor->getInnerLocStart(), CopyCtor); - } - } - - if(!RDecl->hasUserDeclaredMoveConstructor()) { - bool CPUAttr = false; - bool AMPAttr = false; - CXXConstructorDecl* MoveCtor = NULL; - if(!RDecl->needsImplicitMoveConstructor()) { - for(CXXRecordDecl::ctor_iterator CtorIt = RDecl->ctor_begin(); - CtorIt!=RDecl->ctor_end(); CtorIt++) - if((*CtorIt)->isMoveConstructor() && !(*CtorIt)->isUserProvided() && - (*CtorIt)->isDefaulted()){ - MoveCtor = (*CtorIt); - } - } else { - MoveCtor = S.DeclareImplicitMoveConstructor(RDecl); - } - - if(MoveCtor && !MoveCtor->hasAttr() && - !MoveCtor->hasAttr()) { - S.InheritSMFCtorIntersections(RDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, SMF_MoveConstructor); - if(MoveCtor && CPUAttr && !MoveCtor->hasAttr()) - MoveCtor->addAttr(::new (Context) CXXAMPRestrictCPUAttr(Loc, Context, 0)); - - if(MoveCtor && AMPAttr && !MoveCtor->hasAttr()) - MoveCtor->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Loc, Context, 0)); - - if(MoveCtor && (MoveCtor->hasAttr() || - MoveCtor->hasAttr())) - S.DiagnoseCXXAMPOverloadedCallExpr(MoveCtor->getInnerLocStart(), MoveCtor); - } - } - -} - -static void CheckCXXAMPSMFMethod(Sema& S, CXXRecordDecl* RDecl, - bool& ParentCPUAttr, bool& ParentAMPAttr) { - if (!RDecl || S.getLangOpts().HSAExtension) - return; - - ASTContext &Context = S.Context; - SourceLocation Loc = RDecl->getLocation(); - if(!RDecl->hasUserDeclaredCopyAssignment()) { - bool CPUAttr = false; - bool AMPAttr = false; - CXXMethodDecl* CopyAssign = NULL; - bool ConstParam = RDecl->implicitCopyAssignmentHasConstParam(); - if(!RDecl->needsImplicitCopyAssignment()) { - for(CXXRecordDecl::method_iterator MethodIt = RDecl->method_begin(); - MethodIt!=RDecl->method_end(); MethodIt++) - if((*MethodIt)->isCopyAssignmentOperator() && !(*MethodIt)->isUserProvided() && - (*MethodIt)->isDefaulted()){ - CopyAssign = (*MethodIt); - ConstParam = RDecl->hasCopyAssignmentWithConstParam(); - } - } else { - CopyAssign = S.DeclareImplicitCopyAssignment(RDecl); - } - - if(CopyAssign && !CopyAssign->hasAttr() && - !CopyAssign->hasAttr()) { - S.InheritSMFMethodIntersections(RDecl, CPUAttr, AMPAttr, - ParentCPUAttr, ParentAMPAttr, SMF_CopyAssignment, ConstParam); - if(CopyAssign && CPUAttr && !CopyAssign->hasAttr()) - CopyAssign->addAttr(::new (Context) CXXAMPRestrictCPUAttr(Loc, Context, 0)); - - if(CopyAssign && AMPAttr && !CopyAssign->hasAttr()) - CopyAssign->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Loc, Context, 0)); - - if(CopyAssign && (CopyAssign->hasAttr() || - CopyAssign->hasAttr())) - S.DiagnoseCXXAMPOverloadedCallExpr(CopyAssign->getInnerLocStart(), CopyAssign); - } - } - // No test cases for move assign - -} - -static void CheckCXXAMPSMF(Sema& S, CXXRecordDecl *RDecl, bool& Checking) { - if (!RDecl || S.getLangOpts().HSAExtension) - return; - - assert(RDecl); - - bool ParentCPUAttr = false; - bool ParentAMPAttr = false; - if(S.getCurFunctionDecl() && (S.getCurFunctionDecl()->hasAttr() || - S.getCurFunctionDecl()->hasAttr())) { - ParentCPUAttr = S.getCurFunctionDecl()->hasAttr(); - ParentAMPAttr = S.getCurFunctionDecl()->hasAttr(); - } else if(S.getCurLambda() && S.getCurLambda()->CallOperator && - (S.getCurLambda()->CallOperator ->hasAttr() || - S.getCurLambda()->CallOperator ->hasAttr())) { - ParentCPUAttr = S.getCurLambda()->CallOperator ->hasAttr(); - ParentAMPAttr = S.getCurLambda()->CallOperator ->hasAttr(); - } else if(RDecl->isLocalClass ()) { - // FIXME: Need to initiate ParentCPU and ParentAMP here - ParentCPUAttr = true; - ParentAMPAttr = true; - } - - if(!ParentCPUAttr && !ParentAMPAttr) { - Checking = true; - return; - } - - Checking = false; - - // Virtual bases are not allowed - if(!S.getLangOpts().HSAExtension && RDecl->isClass() && RDecl->getNumVBases()) - S.Diag(RDecl->getBeginLoc(), diag::err_amp_virtual_base_class_unsupported) - << RDecl->getDeclName().getAsString(); - - CheckCXXAMPSMFDestructor(S, RDecl, ParentCPUAttr, ParentAMPAttr); - CheckCXXAMPSMFConstructor(S, RDecl, ParentCPUAttr, ParentAMPAttr); - CheckCXXAMPSMFMethod(S, RDecl, ParentCPUAttr, ParentAMPAttr); + if (DD && + (DD->hasAttr() || DD->hasAttr())) + S.DiagnoseHCOverloadedCallExpr(DD->getInnerLocStart(), DD); } /// Attempt initialization by constructor (C++ [dcl.init]), which @@ -4628,12 +4458,6 @@ static void TryConstructorInitialization(Sema &S, return; } - // C++AMP Open Spec [2.3.2 Function Overloading] - bool NotCXXAMPSpec = true; - if(DestRecordDecl && S.getLangOpts().CPlusPlusAMP) { - CheckCXXAMPSMF(S, DestRecordDecl, NotCXXAMPSpec); - } - bool HadMultipleCandidates = (CandidateSet.size() > 1); // In C++17, ResolveConstructorOverload can select a conversion function @@ -4664,7 +4488,7 @@ static void TryConstructorInitialization(Sema &S, if (Kind.getKind() == InitializationKind::IK_Default && Entity.getType().isConstQualified()) { if (!CtorDecl->getParent()->allowConstDefaultInit()) { - if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity) && NotCXXAMPSpec) + if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); return; } @@ -5245,7 +5069,8 @@ static void TryReferenceInitializationCore(Sema &S, = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion); - // C++AMP + // TODO: Fix for winter cleanup + // HC if(S.getLangOpts().CPlusPlusAMP && isLValueRef && InitCategory.isLValue() && T2->isFunctionType()) { // Case by case @@ -5263,15 +5088,15 @@ static void TryReferenceInitializationCore(Sema &S, const DeclRefExpr* Decl = dyn_cast(Initializer); // FIXME: better to check source & target signature and invoke function conversion error // when implement amp restriction into signature - if(Decl && Decl->getDecl()) { + if (Decl && Decl->getDecl()) { bool EntityCPU = false; bool EntityAMP = false; if(Entity.getDecl()) { - EntityCPU = Entity.getDecl()->hasAttr(); - EntityAMP = Entity.getDecl()->hasAttr(); + EntityCPU = Entity.getDecl()->hasAttr(); + EntityAMP = Entity.getDecl()->hasAttr(); } - if(!(EntityCPU ==Decl->getDecl()->hasAttr() && - EntityAMP == Decl->getDecl()->hasAttr())){ + if(!(EntityCPU ==Decl->getDecl()->hasAttr() && + EntityAMP == Decl->getDecl()->hasAttr())){ if(!(EntityAMP && EntityCPU) && (EntityAMP ||EntityCPU)) S.Diag(DeclLoc, diag::err_amp_function_conversion); } @@ -6198,7 +6023,7 @@ void InitializationSequence::InitializeFrom(Sema &S, // Handle default initialization. if (Kind.getKind() == InitializationKind::IK_Default) { - // C++ AMP specific + // HC specific // Prevent tile_static variables being initialized if (S.getLangOpts().CPlusPlusAMP && Entity.getDecl() && @@ -9339,13 +9164,14 @@ bool InitializationSequence::Diagnose(Sema &S, // it was implicitly deleted. Make it clear that the deletion was // implicit. if (S.isImplicitlyDeleted(Best->Function)) { - // C++AMP + // TODO: Fix for winter cleanup + // HC bool check = true; - if(S.getLangOpts().CPlusPlusAMP) { + if (S.getLangOpts().CPlusPlusAMP) { FunctionDecl* F = S.getCurFunctionDecl(); - // FIXME:Best->Function loses C++AMP restriction after getting candidate - if(F && (F->hasAttr() || - F->hasAttr())){ + // FIXME:Best->Function loses [[hc]] after getting candidate + if (F && (F->hasAttr() || + F->hasAttr())){ check = false; } } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 17a94680829..5d5c1a34742 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1623,85 +1623,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CaptureInits.push_back(Init); } - // C++AMP - std::vector > FoundVec; - if (getLangOpts().CPlusPlusAMP && CallOperator->hasAttr()) { - for (unsigned K = 0, N = LSI->Captures.size(); K != N; ++K) { - Capture From = LSI->Captures[K]; - assert(!From.isBlockCapture() && "Cannot capture __block variables"); - if (From.isThisCapture()) continue; - // Handle [Var] - if(From.getCaptureType()->isPointerType()) { - if (getLangOpts().HSAExtension) { - // relax this rule in HSA to allow capturing raw pointers - } else { - FoundVec.push_back(std::make_pair(From, (unsigned)diag::err_amp_captured_variable_type)); - } - } - - if(From.getCaptureType()->isClassType() && From.isCopyCapture()) { - // hc::array and Concurrency::array can't be captured by copy - if (From.getCaptureType()->isGPUArrayType()) { - FoundVec.push_back(std::make_pair(From, (unsigned)diag::err_amp_captured_variable_type)); - } - } - // Handle [This], [&] - if(From.isReferenceCapture() || From.isThisCapture()) { - if(const ReferenceType* RT = dyn_cast(From.getCaptureType())) { - const PrintingPolicy PrintPolicy = Context.getPrintingPolicy(); - std::string Info = QualType::getAsString(From.getCaptureType()->getPointeeType().split(), PrintPolicy); - if (!getLangOpts().HSAExtension) { - if(RT->getPointeeType()->isPointerType()) { - #if 0 - // Add the skipped type here - if(!Info.empty() && (Info.find("array<")!=std::string::npos || - Info.find("array_view<")!=std::string::npos)) - #endif - FoundVec.push_back(std::make_pair(From, - (unsigned)diag::err_amp_captured_by_reference_for_variables)); - } else { - // Boolean type is allowed in capture - // FIXME: Ugly codes. Need reliable methods to skip amp compatible types - if(Info.find("array<")!=std::string::npos || Info.find("array_view<")!=std::string::npos || - Info.find("texture<")!=std::string::npos || - RT->getPointeeType()->isBooleanType()){ - // amp-compatible types - } else - FoundVec.push_back(std::make_pair(From, - (unsigned)diag::err_amp_captured_by_reference_for_variables)); - } - } // HSA extension check - } - } - } - } - // Capture a restrict-amp function pointer by value in a restrict(cpu) lambda - if (getLangOpts().CPlusPlusAMP && - (((!CallOperator->hasAttr() && - CallOperator->hasAttr()) || - (!CallOperator->hasAttr() && - !CallOperator->hasAttr())))) { - for (unsigned K = 0, N = LSI->Captures.size(); K != N; ++K) { - Capture From = LSI->Captures[K]; - assert(!From.isBlockCapture() && "Cannot capture __block variables"); - if (From.isThisCapture()) continue; - QualType CaptureType = From.getCaptureType(); - if(!CaptureType.isNull() && CaptureType->isFunctionPointerType()) { - if( From.getVariable() && From.getVariable()->hasAttr()) - FoundVec.push_back(std::make_pair(From, (unsigned)diag::err_amp_captured_variable_type)); - } - } - } - if(FoundVec.size()) { - for( std::vector >::iterator iter = FoundVec.begin(); - iter!=FoundVec.end(); iter++) - if(iter->first.getVariable()) - Diag(iter->first.getLocation(), iter->second) << iter->first.getVariable()->getName(); - else - Diag(iter->first.getLocation(), iter->second); - return ExprError(); - } - // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function @@ -1729,12 +1650,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, Cleanup.mergeFrom(LambdaCleanup); - // C++AMP - if (getLangOpts().CPlusPlusAMP && NeedAMPDeserializer(Class)) { - DeclareAMPDeserializer(Class, NULL); - } - - LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, + LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, CaptureDefaultLoc, Captures, ExplicitParams, ExplicitResultType, @@ -1756,6 +1672,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // Emit delayed shadowing warnings now that the full capture list is known. DiagnoseShadowingLambdaDecls(LSI); + // HC-specific. + MaybeAddHCAttr(getLangOpts(), CallOperator); + if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { // C++11 [expr.prim.lambda]p2: diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8ab636a89ce..5ff98a86d24 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -818,24 +818,6 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, } break; - case DeclarationName::Identifier: - if (S.getLangOpts().CPlusPlusAMP) { - if (const CXXRecordDecl *Record = dyn_cast(DC)) { - CXXRecordDecl *Class = const_cast(Record); - if (!Class->getDefinition() || !CanDeclareSpecialMemberFunction(Record)) { - break; - } - if (Name.getAsString() == "__cxxamp_trampoline") { - S.DeclareAMPTrampoline(Class, Name); - } else if (Name.getAsString() == "__cxxamp_trampoline_name") { - S.DeclareAMPTrampolineName(Class, Name); - } else if (Name.getAsString() == "__cxxamp_serialize") { - S.DeclareAMPSerializer(Class, Name); - } - } - } - break; - case DeclarationName::CXXDeductionGuideName: S.DeclareImplicitDeductionGuides(Name.getCXXDeductionGuideTemplate(), Loc); break; @@ -3108,97 +3090,12 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(Class); } - // C++AMP - if (getLangOpts().CPlusPlusAMP && NeedAMPDeserializer(Class)) { - DeclareAMPDeserializer(Class, NULL); - } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); DeclContext::lookup_result result = Class->lookup(Name); - if (!getLangOpts().CPlusPlusAMP) { - return result; - } else { - // C++AMP-specific logic - // We need to trim the result for constructors found - bool isAMP = false; - bool isCPU = false; - if (FunctionDecl *FD = dyn_cast(CurContext)) { - isAMP = FD->hasAttr(); - isCPU = FD->hasAttr(); - // In case the current context is restrict(amp, cpu), we simply - // return the result - if (isAMP && isCPU) - return result; - } - - // walkthrough the result and see if there is anything to be trimmed - bool to_trim_result = false; - for (DeclContext::lookup_iterator I = result.begin(), E = result.end(); - I != E; ++I) { - if (FunctionDecl *MD = dyn_cast(*I)) { - if (!isAMP) { - // for host codes (!isAMP) - // strip compiler-injected restrict(amp) constructors such as - // deserialize functions - if (!MD->hasAttr() && - MD->hasAttr() && - MD->getAttr()->getAnnotation() - .find("auto_deserialize") != StringRef::npos) { - to_trim_result = true; - break; - } - } else { - // for kernel codes (!isCPU) - // strip constructors which don't have restrict(amp) - if (!isCPU && - !MD->hasAttr() && - !MD->isImplicit()) { - to_trim_result = true; - break; - } - } - } - } - - // directly return the result if there is nothing to trim - if (!to_trim_result) { - return result; - } - - // FIXME: TrimmedLookupResult is allocated from heap, but it's not deleted - SmallVector *TrimmedLookupResult = new SmallVector; - for (DeclContext::lookup_iterator I = result.begin(), E = result.end(); - I != E; ++I) { - bool delete_this = false; - if (FunctionDecl *MD = dyn_cast(*I)) { - if (!isAMP) { - // for host codes (!isAMP) - // strip compiler-injected restrict(amp) constructors such as - // deserialize functions - if (!MD->hasAttr() && - MD->hasAttr() && - MD->getAttr()->getAnnotation() - .find("auto_deserialize") != StringRef::npos) { - delete_this = true; - } - } else { - // for kernel codes (!isCPU) - // strip constructors which don't have restrict(amp) - if (!isCPU && - !MD->hasAttr() && - !MD->isImplicit()) { - delete_this = true; - } - } - } - if (!delete_this) { - TrimmedLookupResult->push_back(*I); - } - } - return DeclContext::lookup_result(*TrimmedLookupResult); - } + return result; } /// Look up the copying assignment operator for the given class. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 140c9198169..7c7d0a23d27 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -930,8 +930,9 @@ static bool checkArgPlaceholdersForOverload(Sema &S, return false; } -void Sema::DiagnoseCXXAMPDtorOverload(FunctionDecl *New, - const LookupResult &Old) { +// TODO: Fix for winter cleanup +void Sema::DiagnoseHCDtorOverload(FunctionDecl *New, + const LookupResult &Old) { CXXMethodDecl *NewMethod = dyn_cast(New); if(!NewMethod ||!isa(NewMethod)) return; @@ -939,8 +940,8 @@ void Sema::DiagnoseCXXAMPDtorOverload(FunctionDecl *New, // class A // { // public: - // ~A() restrict(cpu) {} - // ~A() restrict(amp) {} // Error + // ~A() [[cpu]] {} + // ~A() [[hc]] {} // Error // }; if(!Old.empty()) { std::vector > FoundVec; @@ -961,8 +962,8 @@ void Sema::DiagnoseCXXAMPDtorOverload(FunctionDecl *New, // is the same, the only reason for overloadable is that they have different restrction if(Old && Old->getType() == New->getType()) // Make sure they are only different from restrictions - if(New->hasAttr()!=(*PreDecl)->hasAttr() || - New->hasAttr()!=(*PreDecl)->hasAttr()) + if (New->hasAttr()!=(*PreDecl)->hasAttr() || + New->hasAttr()!=(*PreDecl)->hasAttr()) FoundVec.push_back(std::make_pair((*PreDecl)->getLocation(), PrevDiag)); } if(FoundVec.size()) { @@ -1085,9 +1086,9 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, } } - // C++AMP + // HC if(getLangOpts().CPlusPlusAMP && dyn_cast(New)) - DiagnoseCXXAMPDtorOverload(New, Old); + DiagnoseHCDtorOverload(New, Old); // C++ [temp.friend]p1: // For a friend function declaration that is not a template declaration: @@ -1141,23 +1142,24 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, if ((OldTemplate == nullptr) != (NewTemplate == nullptr)) return true; - // C++AMP + // HC + // TODO: fix for winter cleanup if(getLangOpts().CPlusPlusAMP) { // allow this case: - // void fun(...) restrict(amp) - // void fun(...) restrict(cpu) - bool OldisAMP = Old->hasAttr(); - bool OldisCPU = Old->hasAttr(); - bool NewisAMP = New->hasAttr(); - bool NewisCPU = New->hasAttr(); + // void fun(...) [[hc]] + // void fun(...) [[cpu]] + bool OldisHC = Old->hasAttr(); + bool OldisCPU = Old->hasAttr(); + bool NewisHC = New->hasAttr(); + bool NewisCPU = New->hasAttr(); //support restrict overload - if (NewisAMP && !NewisCPU && !OldisAMP && OldisCPU) + if (NewisHC && !NewisCPU && !OldisHC && OldisCPU) return true; - if (!NewisAMP && NewisCPU && OldisAMP && !OldisCPU) + if (!NewisHC && NewisCPU && OldisHC && !OldisCPU) return true; - if (!NewisAMP && !NewisCPU && (OldisAMP ^ OldisCPU)) + if (!NewisHC && !NewisCPU && (OldisHC ^ OldisCPU)) return true; - if ((NewisAMP ^ NewisCPU) && !OldisAMP && !OldisCPU) + if ((NewisHC ^ NewisCPU) && !OldisHC && !OldisCPU) return true; } @@ -9062,28 +9064,29 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, } } +// TODO: Fix for winter cleanup // FIXME: should consider decltype trailing return type -bool Sema::IsInAMPRestricted() { - return ((getCurFunctionDecl() && getCurFunctionDecl()->hasAttr()) || +bool Sema::IsInHCRestricted() { + return ((getCurFunctionDecl() && getCurFunctionDecl()->hasAttr()) || (getCurLambda() && getCurLambda()->CallOperator && - getCurLambda()->CallOperator->hasAttr())); + getCurLambda()->CallOperator->hasAttr())); } // Determine if in CPU and/or AMP restricted codes // FIXME: should consider decltype trailing return type bool Sema::IsInAnyExplicitRestricted() { - return ((getCurFunctionDecl() && (getCurFunctionDecl()->hasAttr() || - getCurFunctionDecl()->hasAttr())) || + return ((getCurFunctionDecl() && (getCurFunctionDecl()->hasAttr() || + getCurFunctionDecl()->hasAttr())) || (getCurLambda() && getCurLambda()->CallOperator && - (getCurLambda()->CallOperator->hasAttr() || - getCurLambda()->CallOperator->hasAttr()))); + (getCurLambda()->CallOperator->hasAttr() || + getCurLambda()->CallOperator->hasAttr()))); } -static bool IsInAMPFunction(Scope *scope) { +static bool IsInHCFunction(Scope *scope) { while (scope) { if (scope->getFlags() & Scope::FnScope) { FunctionDecl *FD = dyn_cast_or_null(static_cast(scope->getEntity())); - if (FD && FD->hasAttr()) { + if (FD && FD->hasAttr()) { return true; } } @@ -9096,7 +9099,7 @@ static bool IsInExplicitCPUFunction(Scope *scope) { while (scope) { if (scope->getFlags() & Scope::FnScope) { FunctionDecl *FD = dyn_cast_or_null(static_cast(scope->getEntity())); - if (FD && FD->hasAttr()) { + if (FD && FD->hasAttr()) { return true; } } @@ -9106,28 +9109,21 @@ static bool IsInExplicitCPUFunction(Scope *scope) { } // FIXME: is it a reliable way? -void Sema::GetCXXAMPParentRestriction(Scope* SC, - bool& ParentCPU, bool& ParentAMP, bool&ParentAUTO) { +void Sema::GetHCParentRestriction(Scope *SC, bool &ParentCPU, bool &ParentHC) { if(getCurLambda() && getCurLambda()->CallOperator) { - ParentCPU = getCurLambda()->CallOperator->hasAttr(); - ParentAMP = getCurLambda()->CallOperator->hasAttr(); - // Will deduce in 'auto' inferring, however make the overload resolution happy for now - if(getCurLambda()->CallOperator->hasAttr()) - ParentAUTO = true; + ParentCPU = getCurLambda()->CallOperator->hasAttr(); + ParentHC = getCurLambda()->CallOperator->hasAttr(); } - if(!ParentCPU && !ParentAMP) { + if(!ParentCPU && !ParentHC) { if(getCurFunctionDecl()) { - ParentCPU = getCurFunctionDecl()->hasAttr(); - ParentAMP = getCurFunctionDecl()->hasAttr(); - // Will deduce in 'auto' inferring, however make the overload resolution happy for now - if(getCurFunctionDecl()->hasAttr()) - ParentAUTO = true; + ParentCPU = getCurFunctionDecl()->hasAttr(); + ParentHC = getCurFunctionDecl()->hasAttr(); } } - // To determine class member if it is in AMP restricted + // To determine class member if it is in HC restricted // - // void wrap_test_mem_2() restrict(amp) { + // void wrap_test_mem_2() [[hc]] { // // struct test_mem_2 { // decltype(f()) member; // expect: amp_t member @@ -9135,11 +9131,10 @@ void Sema::GetCXXAMPParentRestriction(Scope* SC, // // } if(!getCurFunctionDecl() && !getCurLambda() && SC) { - ParentAMP = SC->isAMPScope(); + ParentHC = SC->isHCScope(); ParentCPU = SC->isCPUScope(); - ParentAUTO = SC->isAUTOScope(); - if(IsInAMPFunction(SC)) - ParentAMP = true; + if(IsInHCFunction(SC)) + ParentHC = true; if(IsInExplicitCPUFunction(SC)) ParentCPU = true; @@ -9149,74 +9144,27 @@ void Sema::GetCXXAMPParentRestriction(Scope* SC, } } -static int getCXXAMPPrio(FunctionDecl *Func, bool isDevice, - bool ParentCPU, bool ParentAMP, bool ParentAUTO) +static int getHCPrio( + FunctionDecl *Func, bool isDevice, bool ParentCPU, bool ParentHC) { - bool isAMP = Func->hasAttr(); - bool isCPU = Func->hasAttr(); - // Ensure that the callee's 'auto' has been inferred before, otherwise no way to recursively - // resolve its overload without any explicit restrictions on it - if(Func->hasAttr()) { - llvm::errs()<<"The function should have been inferred at this point!\n"; - exit(1); - } - // Deduce to normal case - if(ParentCPU && ParentAMP) - ParentAUTO = false; - - int NonAutoSpec = 0; - if(ParentAUTO) { - NonAutoSpec = clang::CPPAMP_AMP | clang::CPPAMP_CPU ; - if(ParentCPU) - NonAutoSpec &=~clang::CPPAMP_CPU; - if(ParentAMP) - NonAutoSpec &=~clang::CPPAMP_AMP; - } - - if (!isAMP) isCPU = true; + bool isHC = Func->hasAttr(); + bool isCPU = Func->hasAttr(); + + if (!isHC) isCPU = true; int Prio = 0; // Specially handle auto restricted caller - if(NonAutoSpec) { - if (isAMP && isCPU) - Prio = 2; - else if (isDevice && isAMP) { - Prio = 2; // If the caller is CPU only, this callee will be diagnosed later - } else if (!isDevice && isCPU) { - Prio = 2; - } + if (isHC && isCPU) + Prio = 2; + else if (isDevice && isHC) { + Prio = 2; // If the caller is CPU only, this callee will be diagnosed later + } else if (!isDevice && isCPU) { + Prio = 2; + } // unreachable - else if (!isAMP && !isCPU) - Prio = 2; + else if (!isHC && !isCPU) + Prio = 2; return Prio; - - } else { - if (isAMP && isCPU) - Prio = 2; - else if (isDevice && isAMP) - Prio = 2; // If the caller is CPU only, this callee will be diagnosed later - else if (!isDevice && isCPU) { - // FIXME: proposition:use amp context in CPU fallback - // If the pro. is true, we should not allow any explicitly cpu-restricted - // in an amp context even in CPU path, i.e. !isDevice - if(ParentAMP && !ParentCPU) - return Prio; - Prio = 2; - } else if (!isDevice && isAMP) { - // FIXME: We can still select amp restricted function in CPU path - // since we don't emit it in code generation phase - if(ParentAMP && !ParentCPU) - return 2; - } - // unreachable - else if (!isAMP && !isCPU) - Prio = 2; - } - - // Can't resolve - // (1) isDevice && !isAMP - // (2) !isDevice && isAMP - return Prio; } namespace { @@ -9332,43 +9280,45 @@ bool clang::isBetterOverloadCandidate( else if (!Cand1.Viable) return false; - // C++AMP + // TODO: Fix for winter cleanup + // HC if (S.getLangOpts().CPlusPlusAMP && Cand1.Function && Cand2.Function) { bool ParentCPUAttr = false; - bool ParentAMPAttr = false; - bool ParentAUTOAttr = false; - S.GetCXXAMPParentRestriction(SC, ParentCPUAttr, ParentAMPAttr, ParentAUTOAttr); + bool ParentHCAttr = false; + S.GetHCParentRestriction(SC, ParentCPUAttr, ParentHCAttr); FunctionDecl *First = Cand1.Function; FunctionDecl *Second = Cand2.Function; if (!First->isImplicit() && !Second->isImplicit()) { - int CurPrio = getCXXAMPPrio(First, S.getLangOpts().DevicePath, - ParentCPUAttr, ParentAMPAttr, ParentAUTOAttr); - int FunPrio = getCXXAMPPrio(Second, S.getLangOpts().DevicePath, - ParentCPUAttr, ParentAMPAttr, ParentAUTOAttr); + int CurPrio = getHCPrio(First, S.getLangOpts().DevicePath, + ParentCPUAttr, ParentHCAttr); + int FunPrio = getHCPrio(Second, S.getLangOpts().DevicePath, + ParentCPUAttr, ParentHCAttr); if (CurPrio > FunPrio) return true; if (CurPrio < FunPrio) return false; } else if (!First->isImplicit()) { - if(ParentAMPAttr) { + if(ParentHCAttr) { // GPU path - if (First->hasAttr()) + if (First->hasAttr()) return true; } else { // CPU path - if (First->hasAttr() || !First->hasAttr()) + if (First->hasAttr() || + !First->hasAttr()) return true; } if(!S.getCurFunctionDecl() && !S.getCurLambda()) { if (S.getLangOpts().DevicePath) { // GPU path - if (First->hasAttr()) + if (First->hasAttr()) return true; } else { // CPU path - if (First->hasAttr() || !First->hasAttr()) + if (First->hasAttr() || + !First->hasAttr()) return true; } } @@ -9719,25 +9669,26 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); - // C++ AMP-specific + // TODO - Fix for winter cleanup + // HC-specific if (S.getLangOpts().CPlusPlusAMP) { // Diagnose err_amp_call_from_both_amp_and_cpu_to_disctint // TODO: Will consider implementation dependent, e.g. opencl_fabs. #if 0 bool ParentHasBoth = false; if(S.getCurLambda() && S.getCurLambda()->CallOperator) - ParentHasBoth = S.getCurLambda()->CallOperator->hasAttr() && - S.getCurLambda()->CallOperator->hasAttr(); + ParentHasBoth = S.getCurLambda()->CallOperator->hasAttr() && + S.getCurLambda()->CallOperator->hasAttr(); else if(S.getCurFunctionDecl()) - ParentHasBoth = S.getCurFunctionDecl()->hasAttr() && - S.getCurFunctionDecl()->hasAttr(); + ParentHasBoth = S.getCurFunctionDecl()->hasAttr() && + S.getCurFunctionDecl()->hasAttr(); bool BestFoundHasDistinct = false; if(Best->Function) - BestFoundHasDistinct = !Best->Function->hasAttr() || - !Best->Function->hasAttr(); + BestFoundHasDistinct = !Best->Function->hasAttr() || + !Best->Function->hasAttr(); if(ParentHasBoth && BestFoundHasDistinct) { - // There are a lot of overloaded, e.g. with different AMP restrictions + // There are a lot of overloaded, e.g. with different HC restrictions if(end()- begin() > 1) { for (iterator Cand = begin(); Cand != end(); ++Cand) Cand->Function->dump(); @@ -9746,40 +9697,45 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, } #endif // Implementation dependent - if (S.getLangOpts().DevicePath && !S.getLangOpts().AMPCPU) { + if (S.getLangOpts().DevicePath) { // in GPU path, check if calling from AMP to CPU - bool ParentAMP = false; - if(S.getCurFunctionDecl() && S.getCurFunctionDecl()->hasAttr()) - ParentAMP = true; + bool ParentHC = false; + if (S.getCurFunctionDecl() && + S.getCurFunctionDecl()->hasAttr()) + ParentHC = true; // Superess the restrictions - if(S.getCurLambda() && S.getCurLambda()->CallOperator) { - if(S.getCurLambda()->CallOperator->hasAttr()) - ParentAMP = true; + if (S.getCurLambda() && S.getCurLambda()->CallOperator) { + if (S.getCurLambda()->CallOperator->hasAttr()) + ParentHC = true; else - ParentAMP = false; + ParentHC = false; } - if (ParentAMP && Best->Function && Best->Function->hasAttr() && - !Best->Function->hasAttr()) { + if (ParentHC && + Best->Function && + Best->Function->hasAttr() && + !Best->Function->hasAttr()) { S.Diag(Loc, diag::err_amp_call_from_amp_to_cpu); } } - // in CPU path, check if calling from CPU to AMP + // in CPU path, check if calling from CPU to HC // SMF's restriction intersections might take place after selecting best function. // Disable the following semantic checking if (0 && !S.getLangOpts().DevicePath) { bool ParentCPU = false; - if(S.getCurFunctionDecl() && !S.getCurFunctionDecl()->hasAttr()) + if (S.getCurFunctionDecl() && + !S.getCurFunctionDecl()->hasAttr()) ParentCPU = true; - // Superess the restrictions - if(S.getCurLambda() && S.getCurLambda()->CallOperator) { - if(!S.getCurLambda()->CallOperator->hasAttr()) + // Supress the restrictions + if (S.getCurLambda() && S.getCurLambda()->CallOperator) { + if (!S.getCurLambda()->CallOperator->hasAttr()) ParentCPU = true; else ParentCPU = false; } - if (ParentCPU && Best->Function && !Best->Function->hasAttr() && - Best->Function->hasAttr()) { + if (ParentCPU && Best->Function && + !Best->Function->hasAttr() && + Best->Function->hasAttr()) { S.Diag(Loc, diag::err_amp_call_from_cpu_to_amp); } } @@ -11484,35 +11440,38 @@ class AddressOfFunctionResolver { if (!S.checkAddressOfFunctionIsAvailable(Specialization)) return false; + // TODO: Fix for winter cleanup // C++AMP if (S.getLangOpts().CPlusPlusAMP) { FunctionDecl *Current = S.getCurFunctionDecl(); - // fall back to normal non C++ AMP logic in case we are not in FunctionDecl + // fall back to normal non HC logic in case we are not in FunctionDecl if (!Current) { Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } - bool hasAMP = Current->hasAttr(); - bool hasCPU = Current->hasAttr(); + bool hasHC = Current->hasAttr(); + bool hasCPU = Current->hasAttr(); - if (!hasAMP) { + if (!hasHC) { hasCPU = true; } - if (hasAMP && FunctionTemplate->hasAttr()) { + if (hasHC && FunctionTemplate->hasAttr()) { Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } - if (hasCPU && (FunctionTemplate->hasAttr() || !FunctionTemplate->hasAttr())) { + if (hasCPU && + (FunctionTemplate->hasAttr() || + !FunctionTemplate->hasAttr())) { Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } return false; - } else { // non C++ AMP + } else { // non HC Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } @@ -11554,11 +11513,12 @@ class AddressOfFunctionResolver { // If we're in C, we need to support types that aren't exactly identical. if (!S.getLangOpts().CPlusPlus || candidateHasExactlyCorrectType(FunDecl)) { - // C++AMP + // TODO: Fix for winter cleanup + // HC if (S.getLangOpts().CPlusPlusAMP) { FunctionDecl *Current = S.getCurFunctionDecl(); - // fall back to normal non C++ AMP logic in case we are not in a FunctionDecl + // fall back to normal non HC logic in case we are not in a FunctionDecl if (!Current) { Matches.push_back(std::make_pair(CurAccessFunPair, cast(FunDecl->getCanonicalDecl()))); @@ -11566,26 +11526,28 @@ class AddressOfFunctionResolver { return true; } - bool hasAMP = Current->hasAttr(); - bool hasCPU = Current->hasAttr(); - if (!hasAMP) + bool hasHC = Current->hasAttr(); + bool hasCPU = Current->hasAttr(); + if (!hasHC) hasCPU = true; - if (hasAMP && FunDecl->hasAttr()) { + if (hasHC && FunDecl->hasAttr()) { Matches.push_back(std::make_pair(CurAccessFunPair, cast(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; return true; } - if (hasCPU && (FunDecl->hasAttr() || !FunDecl->hasAttr())) { + if (hasCPU && + (FunDecl->hasAttr() || + !FunDecl->hasAttr())) { Matches.push_back(std::make_pair(CurAccessFunPair, cast(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; return true; } return false; - } else { // non C++ AMP + } else { // non HC Matches.push_back(std::make_pair( CurAccessFunPair, cast(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; @@ -12530,76 +12492,72 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, return false; } -void Sema::DiagnoseCXXAMPOverloadedCallExpr(SourceLocation LParenLoc, - FunctionDecl* Callee) { +// TODO: Fix for winter cleanup +void Sema::DiagnoseHCOverloadedCallExpr(SourceLocation LParenLoc, + FunctionDecl *Callee) { if(!Callee || Callee->isConstexpr() || Callee->getBuiltinID() != 0u) return; - if(Callee->getQualifiedNameAsString().find("std::")!=std::string::npos) + if (Callee->getQualifiedNameAsString().find("std::")!=std::string::npos) // TODO: this is bogus. return; FunctionDecl* Caller = this->getCurFunctionDecl(); LambdaScopeInfo* LambdaInfo = this->getCurLambda(); - bool CallerAMP = (LambdaInfo && LambdaInfo->CallOperator)? - LambdaInfo->CallOperator->hasAttr(): - (Caller?Caller->hasAttr():false); + + // TODO: this should be generalised to all local classes, so that they + // transitively carry [[hc]] on operator() iff defined in a [[hc]] + // context. + if (LambdaInfo) MaybeAddHCAttr(getLangOpts(), LambdaInfo->CallOperator); + + bool CallerHC = (LambdaInfo && LambdaInfo->CallOperator)? + LambdaInfo->CallOperator->hasAttr(): + (Caller?Caller->hasAttr():false); bool CallerCPU= (LambdaInfo && LambdaInfo->CallOperator)? - LambdaInfo->CallOperator->hasAttr(): - (Caller?Caller->hasAttr():false); - bool CalleeAMP = Callee->hasAttr(); - bool CalleeCPU = Callee->hasAttr(); - - // Logic for auto-compile-for-accelerator: - // In device path, if auto-compile-for-accelerator flag is on, - // and caller has GPU attribute (CXXAMPRestrictAMPAttr), - // and callee function doesn't have GPU attribute (CXXAMPRestrictAMPAttr), - // and callee function is a global function, or a static function, - // then annotate it with one, and recalculate related boolean flags - if (getLangOpts().DevicePath && getLangOpts().AutoCompileForAccelerator) { - if ((CallerAMP && !CalleeAMP) && - (Callee->isGlobal() || Callee->getStorageClass() == SC_Static)) { - //llvm::errs() << "add [[hc]] to callee: " << Callee->getName() << "\n"; - Callee->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Callee->getLocation(), Context, 0)); - CalleeAMP = Callee->hasAttr(); - } - } + LambdaInfo->CallOperator->hasAttr(): + (Caller?Caller->hasAttr():false); + bool CalleeHC = Callee->hasAttr(); + bool CalleeCPU = Callee->hasAttr(); // Case by case - if (LambdaInfo && LambdaInfo->CallOperator && !getLangOpts().AMPCPU) { + if (LambdaInfo && LambdaInfo->CallOperator) { // caller: __GPU, lambda; callee: non __GPU, global // void f(int &flag) { flag = 1; } // auto l = [](int &flag) __GPU { // f(); // Error // }; - if(getLangOpts().DevicePath && Callee->isGlobal() && (CallerAMP && CallerCPU) && - (!CalleeAMP &&!CalleeCPU)) + if (getLangOpts().DevicePath && + Callee->isGlobal() && + (CallerHC && CallerCPU) && + (!CalleeHC &&!CalleeCPU)) // FIXME: Need a mangled lambda name as ' operator()' Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << LambdaInfo->CallOperator->getQualifiedNameAsString(); - if(getLangOpts().DevicePath && CallerAMP && !CalleeAMP) + if (getLangOpts().DevicePath && CallerHC && !CalleeHC) // FIXME: Need a mangled lambda name as ' operator()' Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << LambdaInfo->CallOperator->getQualifiedNameAsString(); // caller: CPU_Only; callee: has GPU - if(!getLangOpts().DevicePath && (!CallerAMP && CalleeAMP && !CalleeCPU)) + if (!getLangOpts().DevicePath && (!CallerHC && CalleeHC && !CalleeCPU)) Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << LambdaInfo->CallOperator->getQualifiedNameAsString(); } - else if(Caller && ! (LambdaInfo && LambdaInfo->CallOperator) && !getLangOpts().AMPCPU) { + else if (Caller && !(LambdaInfo && LambdaInfo->CallOperator)) { // caller: __GPU, global; callee: non __GPU, global // void fooxxx(int &flag) { flag = 1; } // bool test() __GPU { // int flag = 0; // fooxxx(flag); // Error // } - if(getLangOpts().DevicePath && Caller->isGlobal() && Callee->isGlobal() && - (CallerAMP && CallerCPU) && (!CalleeAMP && !CalleeCPU) ) + if (getLangOpts().DevicePath && + Caller->isGlobal() && + Callee->isGlobal() && + (CallerHC && CallerCPU) && (!CalleeHC && !CalleeCPU)) Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << Caller->getNameAsString(); @@ -12609,8 +12567,10 @@ void Sema::DiagnoseCXXAMPOverloadedCallExpr(SourceLocation LParenLoc, // int flag = 0; // fooxxx(flag); // Error // } - if(getLangOpts().DevicePath && Caller->isGlobal() && Callee->getStorageClass() == SC_Static && - (CallerAMP && CallerCPU) && (!CalleeAMP&&!CalleeCPU) ) + if (getLangOpts().DevicePath && + Caller->isGlobal() && + Callee->getStorageClass() == SC_Static && + (CallerHC && CallerCPU) && (!CalleeHC && !CalleeCPU)) Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << Caller->getNameAsString(); @@ -12619,35 +12579,37 @@ void Sema::DiagnoseCXXAMPOverloadedCallExpr(SourceLocation LParenLoc, // void foo(int &flag) __GPU { // ::foo(flag); // Error // } - if(getLangOpts().DevicePath && Callee->isGlobal() && dyn_cast(Caller) && - (CallerAMP && CallerCPU) && (!CalleeAMP&&!CalleeCPU) ) + if (getLangOpts().DevicePath && + Callee->isGlobal() && + dyn_cast(Caller) && + (CallerHC && CallerCPU) && (!CalleeHC && !CalleeCPU)) Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << Caller->getNameAsString(); // Handle SMF case by case // Empty class with base class having user-defined default ctor // struct A2_base { - // A2_base() restrict(cpu) {} + // A2_base() [[cpu]] {} // }; // class A2 : public A2_base { - // // defaulted: A2() restrict(cpu) + // // defaulted: A2() [[cpu]] // } // - // void test() restrict(amp) { + // void test() [[hc]] { // A2 a2; // Error test() is amp restricted, while A2() is cpu restricted // } CXXMethodDecl* CM = dyn_cast(Callee); if((dyn_cast(Callee) ||dyn_cast(Callee) || (CM && CM ->isCopyAssignmentOperator())) && - (((CallerAMP && !CallerCPU) && (CalleeCPU&&!CalleeAMP)) || - ((!CallerAMP && CallerCPU) && (!CalleeCPU&&CalleeAMP)))) + (((CallerHC && !CallerCPU) && (CalleeCPU && !CalleeHC)) || + ((!CallerHC && CallerCPU) && (!CalleeCPU && CalleeHC)))) Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << Caller->getQualifiedNameAsString(); // caller: CPU_Only or non __GPU; callee: GPU_Only // Note that GPU path is already checked in Overload Resolution. We only check CPU path // right after that in here. - if(!getLangOpts().DevicePath && (!CallerAMP) && (CalleeAMP && !CalleeCPU)) + if(!getLangOpts().DevicePath && (!CallerHC) && (CalleeHC && !CalleeCPU)) Diag(LParenLoc, diag::err_amp_overloaded_member_function) << Callee->getQualifiedNameAsString() << Caller->getNameAsString(); } @@ -12680,7 +12642,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, return ExprError(); // C++AMP if(SemaRef.getLangOpts().CPlusPlusAMP) - SemaRef.DiagnoseCXXAMPOverloadedCallExpr(LParenLoc, FDecl); + SemaRef.DiagnoseHCOverloadedCallExpr(LParenLoc, FDecl); Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, @@ -13931,7 +13893,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // parameter is placed at the beginning of the list). // C++AMP if(getLangOpts().CPlusPlusAMP && Method && Method->getParent()->isLambda()) - DiagnoseCXXAMPMethodCallExpr(LParenLoc, Method); + DiagnoseHCMethodCallExpr(LParenLoc, Method); SmallVector MethodArgs(NumArgsSlots); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 2bd18bdf201..9788e84d871 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4669,7 +4669,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, TempTempParm->getDefaultArgument().getTemplateNameLoc()); } -void Sema::DiagnoseCXXAMPTemplateArgument(NamedDecl *Param, +void Sema::DiagnoseHCTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &AL, NamedDecl *Template, SourceLocation TemplateLoc) { @@ -4679,7 +4679,7 @@ void Sema::DiagnoseCXXAMPTemplateArgument(NamedDecl *Param, // Check array's template type parameters. IdentifierInfo* Info = Template->getIdentifier(); if(Info && Info->isStr("array") && - Template->getQualifiedNameAsString().find("Concurrency::array")!=std::string::npos) { + Template->getQualifiedNameAsString().find("hc::array")!=std::string::npos) { // For a declaration: // template class array; // And a usage, @@ -4769,7 +4769,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, CheckTemplateArgumentKind CTAK) { // C++AMP if(getLangOpts().CPlusPlusAMP && Template) { - DiagnoseCXXAMPTemplateArgument(Param, Arg, Template, TemplateLoc); + DiagnoseHCTemplateArgument(Param, Arg, Template, TemplateLoc); } // Check template type parameters. @@ -8226,7 +8226,7 @@ bool Sema::CheckFunctionTemplateSpecialization( continue; } - // C++ AMP + // HC // Check if the specialization has the same or more restriction specifiers // Truth table (row: restriction specifier of the input, column: restriction specifier of the candidate. // +---------+------+-----+-----+---------+ @@ -8241,14 +8241,16 @@ bool Sema::CheckFunctionTemplateSpecialization( // | cpu/amp | NG | NG | NG | OK | // +---------+------+-----+-----+---------+ if (getLangOpts().CPlusPlusAMP) { - if (FD->hasAttr()) { - if (!Specialization->hasAttr()) { + if (FD->hasAttr()) { + if (!Specialization->hasAttr()) { continue; - } else if (FD->hasAttr() && !Specialization->hasAttr()) { + } else if (FD->hasAttr() && + !Specialization->hasAttr()) { continue; } } else { - if (Specialization->hasAttr() && !Specialization->hasAttr()) { + if (Specialization->hasAttr() && + !Specialization->hasAttr()) { continue; } } @@ -8366,20 +8368,21 @@ bool Sema::CheckFunctionTemplateSpecialization( MarkUnusedFileScopedDecl(Specialization); } - // C++ AMP + // HC if (getLangOpts().CPlusPlusAMP) { + // TODO: Fix for winter cleanup. SourceLocation Loc = FD->getLocation(); - if (FD->hasAttr()) { - if (!Specialization->hasAttr()) - Specialization->addAttr(::new (Context) CXXAMPRestrictAMPAttr(Loc, Context, 0)); + if (FD->hasAttr()) { + if (!Specialization->hasAttr()) + Specialization->addAttr(::new (Context) HCRestrictHCAttr(Loc, Context, 0)); } else - Specialization->dropAttr(); + Specialization->dropAttr(); - if (FD->hasAttr()) { - if (!Specialization->hasAttr()) - Specialization->addAttr(::new (Context) CXXAMPRestrictCPUAttr(Loc, Context, 0)); + if (FD->hasAttr()) { + if (!Specialization->hasAttr()) + Specialization->addAttr(::new (Context) HCRestrictCPUAttr(Loc, Context, 0)); } else - Specialization->dropAttr(); + Specialization->dropAttr(); } // Turn the given function declaration into a function template diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index a749b26f121..bf22e6902df 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -239,6 +239,52 @@ static void instantiateDependentDiagnoseIfAttr( DIA->getSpellingListIndex())); } +static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) { + EnterExpressionEvaluationContext Unevaluated{ + S, Sema::ExpressionEvaluationContext::ConstantEvaluated}; + + ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs); + if (Result.isInvalid()) return; + Expr *MinExpr = Result.getAs(); + + Expr *MaxExpr = Attr.getMax(); + + if (!MaxExpr) return; + + Result = S.SubstExpr(Attr.getMax(), TemplateArgs); + if (Result.isInvalid()) return; + MaxExpr = Result.getAs(); + + New->addAttr(new (S.Context) + AMDGPUFlatWorkGroupSizeAttr{Attr.getLocation(), S.Context, MinExpr, MaxExpr, + "", Attr.getSpellingListIndex()}); +} + +static void instantiateDependentAMDGPUWavesPerEUAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AMDGPUWavesPerEUAttr &Attr, Decl *New) { + EnterExpressionEvaluationContext Unevaluated{ + S, Sema::ExpressionEvaluationContext::ConstantEvaluated}; + + ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs); + if (Result.isInvalid()) return; + Expr *MinExpr = Result.getAs(); + + Expr *MaxExpr = Attr.getMax(); + + if (!MaxExpr) return; + + Result = S.SubstExpr(Attr.getMax(), TemplateArgs); + if (Result.isInvalid()) return; + MaxExpr = Result.getAs(); + + New->addAttr(new (S.Context) + AMDGPUWavesPerEUAttr{Attr.getLocation(), S.Context, MinExpr, MaxExpr, "", + Attr.getSpellingListIndex()}); +} + // Constructs and adds to New a new instance of CUDALaunchBoundsAttr using // template A as the base and arguments from TemplateArgs. static void instantiateDependentCUDALaunchBoundsAttr( @@ -428,6 +474,22 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWGSize = + dyn_cast(TmplAttr)) { + instantiateDependentAMDGPUFlatWorkGroupSizeAttr(*this, TemplateArgs, + *AMDGPUFlatWGSize, New); + + continue; + } + + if (const AMDGPUWavesPerEUAttr *AMDGPUWavesPerEU = + dyn_cast(TmplAttr)) { + instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs, + *AMDGPUWavesPerEU, New); + + continue; + } + if (const ModeAttr *Mode = dyn_cast(TmplAttr)) { instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New); continue; @@ -3886,6 +3948,32 @@ static void InstantiateDefaultCtorDefaultArgs(Sema &S, } } +static void MaybeCheckArrayCaptureInPFE(Sema &S, FunctionDecl *Function) +{ + if (!Function) return; + if (!Function->hasAttr()) return; + + static constexpr const char HCPfe[]{"__HC_PFE__"}; + if (Function->getAttr()->getAnnotation().find(HCPfe) == + StringRef::npos) return; + + static constexpr unsigned int CallableIdx{2u}; + auto Callable = Function->parameters()[CallableIdx] + ->getOriginalType() + .getNonReferenceType() + ->getAsCXXRecordDecl(); + + for (auto &&Field : Callable->fields()) { + QualType FieldT = Field->getType(); + if (FieldT->isPointerType()) FieldT = FieldT->getPointeeType(); + + if (!FieldT->isGPUArrayType()) continue; + + S.Diag(Field->getLocation(), diag::err_amp_captured_array_type_by_value) + << Field->getName(); + } +} + /// Instantiate the definition of the given function from its /// template. /// @@ -4113,6 +4201,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, LocalInstantiations.perform(); Scope.Exit(); GlobalInstantiations.perform(); + + MaybeCheckArrayCaptureInPFE(*this, Function); } VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( diff --git a/lib/Sema/StmtResInfer.cpp b/lib/Sema/StmtResInfer.cpp deleted file mode 100755 index 5a30b125664..00000000000 --- a/lib/Sema/StmtResInfer.cpp +++ /dev/null @@ -1,1052 +0,0 @@ -//===---- StmtResInfer.cpp - Inferring implementation for auto-restricted FunctionDecl-- ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Sema::TryCXXAMPRestrictionInferring method, which tries to -// automatically infer CXXAMP specific auto-restricted FunctionDecl with any eligible -// non-auto implicit restrictions onto it. -// -//===----------------------------------------------------------------------===// - -#include "clang/Sema/SemaInternal.h" -#include "TypeLocBuilder.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/CharUnits.h" -#include "clang/AST/CommentDiagnostic.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/EvaluatedExprVisitor.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/StmtCXX.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Sema/Scope.h" -#include "clang/AST/Attr.h" -#include "clang/AST/CommentVisitor.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Basic/Module.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -using namespace clang::comments; - -using namespace clang; -using namespace sema; - - -//===----------------------------------------------------------------------===// -// StmtResInfer Visitor -//===----------------------------------------------------------------------===// - -namespace { - class StmtResInfer - : public ConstDeclVisitor, public ConstStmtVisitor { - const SourceManager *SM; - unsigned CppAMPSpec; - Sema& TheSema; - - private: - inline void ClearResAMP() { CppAMPSpec &=~CPPAMP_AMP;} - inline void ClearResCPU() { CppAMPSpec &=~CPPAMP_CPU;} - - public: - StmtResInfer(Sema& S, unsigned& NonAutoSpec, const SourceManager *SM) - : SM(SM), CppAMPSpec(NonAutoSpec), TheSema(S) { } - - ~StmtResInfer() { - } - unsigned Infer(const Stmt* Node); - -//private: - void dumpDecl(const Decl *D); - void dumpStmt(const Stmt *S); - void dumpFullComment(const FullComment *C); - - // Formatting - void indent(); - void unindent(); - void lastChild(); - bool hasMoreChildren(); - void setMoreChildren(bool Value); - - // Utilities - void dumpPointer(const void *Ptr); - void dumpSourceRange(SourceRange R); - void dumpLocation(SourceLocation Loc); - void dumpBareType(QualType T); - void dumpType(QualType T); - void dumpBareDeclRef(const Decl *Node); - void dumpDeclRef(const Decl *Node, const char *Label = 0); - void dumpName(const NamedDecl *D); - bool hasNodes(const DeclContext *DC); - void dumpDeclContext(const DeclContext *DC); - void dumpAttr(const Attr *A); - - // C++ Utilities - void dumpAccessSpecifier(AccessSpecifier AS); - void dumpCXXCtorInitializer(const CXXCtorInitializer *Init); - void dumpTemplateParameters(const TemplateParameterList *TPL); - void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI); - void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A); - void dumpTemplateArgumentList(const TemplateArgumentList &TAL); - void dumpTemplateArgument(const TemplateArgument &A, - SourceRange R = SourceRange()); - - // Decls - void VisitLabelDecl(const LabelDecl *D); - void VisitTypedefDecl(const TypedefDecl *D); - void VisitEnumDecl(const EnumDecl *D); - void VisitRecordDecl(const RecordDecl *D); - void VisitEnumConstantDecl(const EnumConstantDecl *D); - void VisitIndirectFieldDecl(const IndirectFieldDecl *D); - void VisitFunctionDecl(const FunctionDecl *D); - void VisitFieldDecl(const FieldDecl *D); - void VisitVarDecl(const VarDecl *D); - void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D); - void VisitImportDecl(const ImportDecl *D); - - // C++ Decls - void VisitNamespaceDecl(const NamespaceDecl *D); - void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D); - void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); - void VisitTypeAliasDecl(const TypeAliasDecl *D); - void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); - void VisitCXXRecordDecl(const CXXRecordDecl *D); - void VisitStaticAssertDecl(const StaticAssertDecl *D); - void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); - void VisitClassTemplateDecl(const ClassTemplateDecl *D); - void VisitClassTemplateSpecializationDecl( - const ClassTemplateSpecializationDecl *D); - void VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D); - void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); - void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); - void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); - void VisitUsingDecl(const UsingDecl *D); - void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); - void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); - void VisitUsingShadowDecl(const UsingShadowDecl *D); - void VisitLinkageSpecDecl(const LinkageSpecDecl *D); - void VisitAccessSpecDecl(const AccessSpecDecl *D); - void VisitFriendDecl(const FriendDecl *D); - - // ObjC Decls - void VisitObjCIvarDecl(const ObjCIvarDecl *D); - void VisitObjCMethodDecl(const ObjCMethodDecl *D); - void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); - void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); - void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); - void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); - void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); - void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); - void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); - void VisitBlockDecl(const BlockDecl *D); - - // Stmts. - void VisitStmt(const Stmt *Node); - void VisitDeclStmt(const DeclStmt *Node); - void VisitAttributedStmt(const AttributedStmt *Node); - void VisitLabelStmt(const LabelStmt *Node); - void VisitGotoStmt(const GotoStmt *Node); - void VisitCXXTryStmt(const CXXTryStmt* Node); - - // Exprs - void VisitExpr(const Expr *Node); - void VisitCastExpr(const CastExpr *Node); - void VisitDeclRefExpr(const DeclRefExpr *Node); - void VisitPredefinedExpr(const PredefinedExpr *Node); - void VisitCharacterLiteral(const CharacterLiteral *Node); - void VisitIntegerLiteral(const IntegerLiteral *Node); - void VisitFloatingLiteral(const FloatingLiteral *Node); - void VisitStringLiteral(const StringLiteral *Str); - void VisitUnaryOperator(const UnaryOperator *Node); - void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node); - void VisitMemberExpr(const MemberExpr *Node); - void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node); - void VisitBinaryOperator(const BinaryOperator *Node); - void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); - void VisitAddrLabelExpr(const AddrLabelExpr *Node); - void VisitBlockExpr(const BlockExpr *Node); - void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); - - // C++ - void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node); - void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node); - void VisitCXXThisExpr(const CXXThisExpr *Node); - void VisitCXXThrowExpr(const CXXThrowExpr *Node); - void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); - void VisitCXXConstructExpr(const CXXConstructExpr *Node); - void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); - void VisitExprWithCleanups(const ExprWithCleanups *Node); - void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); - void dumpCXXTemporary(const CXXTemporary *Temporary); - void VisitCXXTypeidExpr(const CXXTypeidExpr* Node); - void VisitCXXDynamicCastExpr(const CXXDynamicCastExpr* Node); - - // ObjC - void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); - void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); - void VisitObjCMessageExpr(const ObjCMessageExpr *Node); - void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node); - void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node); - void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node); - void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node); - void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); - void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); - void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); - - // Comments. - const char *getCommandName(unsigned CommandID); - void dumpComment(const Comment *C); - - // Inline comments. - void visitTextComment(const TextComment *C); - void visitInlineCommandComment(const InlineCommandComment *C); - void visitHTMLStartTagComment(const HTMLStartTagComment *C); - void visitHTMLEndTagComment(const HTMLEndTagComment *C); - - // Block comments. - void visitBlockCommandComment(const BlockCommandComment *C); - void visitParamCommandComment(const ParamCommandComment *C); - void visitTParamCommandComment(const TParamCommandComment *C); - void visitVerbatimBlockComment(const VerbatimBlockComment *C); - void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); - void visitVerbatimLineComment(const VerbatimLineComment *C); - }; -} -void StmtResInfer::dumpPointer(const void *Ptr) { -} - -void StmtResInfer::dumpLocation(SourceLocation Loc) { -} - -void StmtResInfer::dumpSourceRange(SourceRange R) { -} - -void StmtResInfer::dumpBareType(QualType T) { -} - -void StmtResInfer::dumpType(QualType T) { - dumpBareType(T); -} - -void StmtResInfer::dumpBareDeclRef(const Decl *D) { - { - // C++AMP - if(D->getKind() == Decl::Function){ - if(TheSema.getLangOpts().DevicePath && (CppAMPSpec & CPPAMP_AMP) && - !D->hasAttr()) - ClearResAMP(); - if(!TheSema.getLangOpts().DevicePath && (CppAMPSpec & CPPAMP_CPU) && - D->hasAttr() && !D->hasAttr()) - ClearResCPU(); - } - } - - if (const ValueDecl *VD = dyn_cast(D)) - dumpType(VD->getType()); -} - -void StmtResInfer::dumpDeclRef(const Decl *D, const char *Label) { - if (!D) - return; - - dumpBareDeclRef(D); -} - -void StmtResInfer::dumpName(const NamedDecl *ND) { -} - -bool StmtResInfer::hasNodes(const DeclContext *DC) { - if (!DC) - return false; - - return DC->decls_begin() != DC->decls_end(); -} - -void StmtResInfer::dumpDeclContext(const DeclContext *DC) { - if (!DC) - return; - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); - I != E; ++I) { - dumpDecl(*I); - } -} - -//===----------------------------------------------------------------------===// -// Decl dumping methods. -//===----------------------------------------------------------------------===// - -void StmtResInfer::dumpDecl(const Decl *D) { - if (!D) { - return; - } - - // Decls within functions are visited by the body - bool HasDeclContext = !isa(*D) && !isa(*D) && - hasNodes(dyn_cast(D)); - - ConstDeclVisitor::Visit(D); - if (HasDeclContext) - dumpDeclContext(cast(D)); -} - -void StmtResInfer::VisitLabelDecl(const LabelDecl *D) { -} - -void StmtResInfer::VisitTypedefDecl(const TypedefDecl *D) { - dumpType(D->getUnderlyingType()); -} - -void StmtResInfer::VisitEnumDecl(const EnumDecl *D) { - if (D->isFixed()) - dumpType(D->getIntegerType()); -} - -void StmtResInfer::VisitRecordDecl(const RecordDecl *D) { -} - -void StmtResInfer::VisitEnumConstantDecl(const EnumConstantDecl *D) { - dumpType(D->getType()); - if (const Expr *Init = D->getInitExpr()) { - dumpStmt(Init); - } -} - -void StmtResInfer::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { - dumpType(D->getType()); - for (IndirectFieldDecl::chain_iterator I = D->chain_begin(), - E = D->chain_end(); - I != E; ++I) { - if (I + 1 == E) - dumpDeclRef(*I); - } -} - -void StmtResInfer::VisitFunctionDecl(const FunctionDecl *D) { -} - -void StmtResInfer::VisitFieldDecl(const FieldDecl *D) { - dumpName(D); - dumpType(D->getType()); - // Resue in BuildMemInitializer for err_amp_unsupported_reference_or_pointer - const Type* Ty = D->getType().getTypePtrOrNull(); - QualType TheType = D->getType(); - - if(Ty) { - // Case by case - if(Ty->isPointerType()) - TheType = Ty->getPointeeType(); - if(Ty->isArrayType()) - TheType = dyn_cast(Ty)->getElementType(); - if(!TheType.isNull() && TheType->isRecordType()) { - CXXRecordDecl* RDecl = TheType->getAsCXXRecordDecl(); - if (RDecl->getName() == "array") - ClearResAMP(); - } - } - // Checke if it is array_view's reference or pointer - if(Ty && (Ty->isPointerType() ||Ty->isReferenceType())) { - const Type* TargetTy = Ty->getPointeeType().getTypePtrOrNull(); - if(const TemplateSpecializationType* TST = TargetTy->getAs()) { - // Check if it is a TemplateSpecializationType - // FIXME: should consider alias Template - // Get its underlying template decl* - if(ClassTemplateDecl* CTDecl = dyn_cast_or_null( - TST->getTemplateName().getAsTemplateDecl())) { - if(CXXRecordDecl* RDecl = CTDecl->getTemplatedDecl()) - if(RDecl->getName() == "array_view") - ClearResAMP(); - } - } - } - - bool IsBitField = D->isBitField(); - Expr *Init = D->getInClassInitializer(); - bool HasInit = Init; - - if (IsBitField) { - dumpStmt(D->getBitWidth()); - } - if (HasInit) { - dumpStmt(Init); - } -} - -void StmtResInfer::VisitVarDecl(const VarDecl *D) { - if(TheSema.IsIncompatibleType(D->getType().getTypePtrOrNull(), false, true)) { - ClearResAMP(); - return; - } - - if(D->getType().isVolatileQualified()) - ClearResAMP(); - - if(D->getType()->isCharType() || D->getType()->isWideCharType() || - D->getType()->isSpecificBuiltinType(BuiltinType::Short) || - D->getType()->isSpecificBuiltinType(BuiltinType::LongLong) || - D->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) - ClearResAMP(); - - //var's type - dumpType(D->getType()); - - // TODO: Should infer if it is static -#if 0 - StorageClass SC = D->getStorageClass(); -#endif - - if (D->hasInit()) { - dumpStmt(D->getInit()); - } -} - -void StmtResInfer::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { - dumpStmt(D->getAsmString()); -} - -void StmtResInfer::VisitImportDecl(const ImportDecl *D) { -} - -//===----------------------------------------------------------------------===// -// C++ Declarations -//===----------------------------------------------------------------------===// - -void StmtResInfer::VisitNamespaceDecl(const NamespaceDecl *D) { - if (!D->isOriginalNamespace()) - dumpDeclRef(D->getOriginalNamespace(), "original"); -} - -void StmtResInfer::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { - dumpBareDeclRef(D->getNominatedNamespace()); -} - -void StmtResInfer::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { - dumpDeclRef(D->getAliasedNamespace()); -} - -void StmtResInfer::VisitTypeAliasDecl(const TypeAliasDecl *D) { - dumpType(D->getUnderlyingType()); -} - -void StmtResInfer::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { - // TODO - #if 0 - dumpTemplateParameters(D->getTemplateParameters()); - #endif - dumpDecl(D->getTemplatedDecl()); -} - -void StmtResInfer::VisitCXXRecordDecl(const CXXRecordDecl *D) { - VisitRecordDecl(D); - if (!D->isCompleteDefinition()) - return; - - for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(), - E = D->bases_end(); - I != E; ++I) { - dumpType(I->getType()); - } -} - -void StmtResInfer::VisitStaticAssertDecl(const StaticAssertDecl *D) { - dumpStmt(D->getAssertExpr()); - dumpStmt(D->getMessage()); -} - -void StmtResInfer::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { -} - -void StmtResInfer::VisitClassTemplateDecl(const ClassTemplateDecl *D) { -} - -void StmtResInfer::VisitClassTemplateSpecializationDecl( - const ClassTemplateSpecializationDecl *D) { - VisitCXXRecordDecl(D); - // TODO - #if 0 - dumpTemplateArgumentList(D->getTemplateArgs()); - #endif -} - -void StmtResInfer::VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); - // TODO - #if 0 - dumpTemplateParameters(D->getTemplateParameters()); - #endif -} - -void StmtResInfer::VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D) { - dumpDeclRef(D->getSpecialization()); - // TODO - #if 0 - if (D->hasExplicitTemplateArgs()) - dumpTemplateArgumentListInfo(D->templateArgs()); - #endif -} - -void StmtResInfer::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { - if (D->hasDefaultArgument()) - dumpType(D->getDefaultArgument()); -} - -void StmtResInfer::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { - dumpType(D->getType()); - if (D->hasDefaultArgument()) - dumpStmt(D->getDefaultArgument()); -} - -void StmtResInfer::VisitTemplateTemplateParmDecl( - const TemplateTemplateParmDecl *D) { - // TODO - #if 0 - dumpTemplateParameters(D->getTemplateParameters()); - if (D->hasDefaultArgument()) - dumpTemplateArgumentLoc(D->getDefaultArgument()); - #endif -} - -void StmtResInfer::VisitUsingDecl(const UsingDecl *D) { -} - -void StmtResInfer::VisitUnresolvedUsingTypenameDecl( - const UnresolvedUsingTypenameDecl *D) { -} - -void StmtResInfer::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { - dumpType(D->getType()); -} - -void StmtResInfer::VisitUsingShadowDecl(const UsingShadowDecl *D) { - dumpBareDeclRef(D->getTargetDecl()); -} - -void StmtResInfer::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { -} - -void StmtResInfer::VisitAccessSpecDecl(const AccessSpecDecl *D) { -} - -void StmtResInfer::VisitFriendDecl(const FriendDecl *D) { - if (TypeSourceInfo *T = D->getFriendType()) - dumpType(T->getType()); - else - dumpDecl(D->getFriendDecl()); -} - -//===----------------------------------------------------------------------===// -// Obj-C Declarations -//===----------------------------------------------------------------------===// - -void StmtResInfer::VisitObjCIvarDecl(const ObjCIvarDecl *D) { - dumpType(D->getType()); -} - -void StmtResInfer::VisitObjCMethodDecl(const ObjCMethodDecl *D) { - dumpType(D->getReturnType()); - - bool HasBody = D->hasBody(); - - if (D->isThisDeclarationADefinition()) { - dumpDeclContext(D); - } else { - for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), - E = D->param_end(); - I != E; ++I) { - if (I + 1 == E) - dumpDecl(*I); - } - } - - if (HasBody) { - dumpStmt(D->getBody()); - } -} - -void StmtResInfer::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { - dumpDeclRef(D->getClassInterface()); - if (D->protocol_begin() == D->protocol_end()) - dumpDeclRef(D->getImplementation()); - for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); - I != E; ++I) { - if (I + 1 == E) - dumpDeclRef(*I); - } -} - -void StmtResInfer::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { - dumpDeclRef(D->getClassInterface()); - dumpDeclRef(D->getCategoryDecl()); -} - -void StmtResInfer::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { - for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); - I != E; ++I) { - if (I + 1 == E) - dumpDeclRef(*I); - } -} - -void StmtResInfer::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { - dumpDeclRef(D->getSuperClass(), "super"); - if (D->protocol_begin() == D->protocol_end()) - dumpDeclRef(D->getImplementation()); - for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); - I != E; ++I) { - if (I + 1 == E) - dumpDeclRef(*I); - } -} - -void StmtResInfer::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { - dumpDeclRef(D->getSuperClass(), "super"); - dumpDeclRef(D->getClassInterface()); - for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), - E = D->init_end(); - I != E; ++I) { - } -} - -void StmtResInfer::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { - dumpDeclRef(D->getClassInterface()); -} - -void StmtResInfer::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { - dumpType(D->getType()); - - ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); - if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { - if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) { - if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter)) - dumpDeclRef(D->getGetterMethodDecl(), "getter"); - } - if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) { - dumpDeclRef(D->getSetterMethodDecl(), "setter"); - } - } -} - -void StmtResInfer::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { - dumpDeclRef(D->getPropertyDecl()); - dumpDeclRef(D->getPropertyIvarDecl()); -} - -void StmtResInfer::VisitBlockDecl(const BlockDecl *D) { - for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); - I != E; ++I) - dumpDecl(*I); - - if (D->isVariadic()) { - } - - if (D->capturesCXXThis()) { - } - for (BlockDecl::capture_const_iterator I = D->capture_begin(), E = D->capture_end(); - I != E; ++I) { - if (I->getVariable()) { - dumpBareDeclRef(I->getVariable()); - } - if (I->hasCopyExpr()) - dumpStmt(I->getCopyExpr()); - } - dumpStmt(D->getBody()); -} - -//===----------------------------------------------------------------------===// -// Stmt dumping methods. -//===----------------------------------------------------------------------===// - -void StmtResInfer::dumpStmt(const Stmt *S) { - if (!S) { - return; - } - - if (const DeclStmt *DS = dyn_cast(S)) { - VisitDeclStmt(DS); - return; - } - - ConstStmtVisitor::Visit(S); - for (Stmt::const_child_iterator CI = S->child_begin(); CI != S->child_end(); ++CI) { - dumpStmt(*CI); - } -} - -// Perform the inferring -unsigned StmtResInfer::Infer(const Stmt* Node) { - dumpStmt(Node); - return CppAMPSpec; -} -void StmtResInfer::VisitStmt(const Stmt *Node) { -} - -void StmtResInfer::VisitDeclStmt(const DeclStmt *Node) { - VisitStmt(Node); - for (DeclStmt::const_decl_iterator I = Node->decl_begin(), - E = Node->decl_end(); - I != E; ++I) { - dumpDecl(*I); - } -} - -void StmtResInfer::VisitAttributedStmt(const AttributedStmt *Node) { - VisitStmt(Node); -} - -void StmtResInfer::VisitLabelStmt(const LabelStmt *Node) { - VisitStmt(Node); - - // label statement is not valid in C++AMP - // but is valid in HSA extension mode - if(!TheSema.getLangOpts().HSAExtension) { - ClearResAMP(); - } -} - -void StmtResInfer::VisitGotoStmt(const GotoStmt *Node) { - VisitStmt(Node); - - // goto statement is not valid in C++AMP - // but is valid in HSA extension mode - if(!TheSema.getLangOpts().HSAExtension) { - ClearResAMP(); - } -} -void StmtResInfer::VisitCXXTryStmt(const CXXTryStmt* Node) { - VisitStmt(Node); - ClearResAMP(); -} -void StmtResInfer::VisitCXXTypeidExpr(const CXXTypeidExpr* Node) { - VisitStmt(Node); - ClearResAMP(); -} -void StmtResInfer::VisitCXXDynamicCastExpr(const CXXDynamicCastExpr* Node) { - VisitStmt(Node); - ClearResAMP(); -} - - -//===----------------------------------------------------------------------===// -// Expr dumping methods. -//===----------------------------------------------------------------------===// - -void StmtResInfer::VisitExpr(const Expr *Node) { - VisitStmt(Node); - dumpType(Node->getType()); -} - -void StmtResInfer::VisitCastExpr(const CastExpr *Node) { - VisitExpr(Node); - //TODO: infer if any -} - -void StmtResInfer::VisitDeclRefExpr(const DeclRefExpr *Node) { - //Format: DeclRefExpr 0x3eca4e8 'int (void)' lvalue - VisitExpr(Node); - dumpBareDeclRef(Node->getDecl()); - if (Node->getDecl() != Node->getFoundDecl()) { - dumpBareDeclRef(Node->getFoundDecl()); - } -} - -void StmtResInfer::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitPredefinedExpr(const PredefinedExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitCharacterLiteral(const CharacterLiteral *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitIntegerLiteral(const IntegerLiteral *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitFloatingLiteral(const FloatingLiteral *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitStringLiteral(const StringLiteral *Str) { - VisitExpr(Str); -} - -void StmtResInfer::VisitUnaryOperator(const UnaryOperator *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitUnaryExprOrTypeTraitExpr( - const UnaryExprOrTypeTraitExpr *Node) { - VisitExpr(Node); - if (Node->isArgumentType()) - dumpType(Node->getArgumentType()); -} - -void StmtResInfer::VisitMemberExpr(const MemberExpr *Node) { - VisitExpr(Node); - ValueDecl* VD = Node->getMemberDecl(); - if((CppAMPSpec & CPPAMP_AMP) && !VD->hasAttr()) - ClearResAMP(); - if((CppAMPSpec & CPPAMP_CPU) && VD->hasAttr() && - !VD->hasAttr()) - ClearResCPU();; -} - -void StmtResInfer::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitBinaryOperator(const BinaryOperator *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitCompoundAssignOperator( - const CompoundAssignOperator *Node) { - VisitExpr(Node); - dumpBareType(Node->getComputationLHSType()); - dumpBareType(Node->getComputationResultType()); -} - -void StmtResInfer::VisitBlockExpr(const BlockExpr *Node) { - VisitExpr(Node); - dumpDecl(Node->getBlockDecl()); -} - -void StmtResInfer::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { - VisitExpr(Node); - if (Expr *Source = Node->getSourceExpr()) { - dumpStmt(Source); - } -} - -// GNU extensions. - -void StmtResInfer::VisitAddrLabelExpr(const AddrLabelExpr *Node) { - VisitExpr(Node); -} - -//===----------------------------------------------------------------------===// -// C++ Expressions -//===----------------------------------------------------------------------===// - -void StmtResInfer::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitCXXThisExpr(const CXXThisExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitCXXThrowExpr(const CXXThrowExpr *Node) { - VisitExpr(Node); - ClearResAMP(); -} - -void StmtResInfer::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitCXXConstructExpr(const CXXConstructExpr *Node) { - VisitExpr(Node); - // TODO: infer if any -#if 0 - CXXConstructorDecl *Ctor = Node->getConstructor(); -#endif -} - -void StmtResInfer::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { - VisitExpr(Node); - dumpCXXTemporary(Node->getTemporary()); -} - -void StmtResInfer::VisitExprWithCleanups(const ExprWithCleanups *Node) { - VisitExpr(Node); - for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) - dumpDeclRef(Node->getObject(i), "cleanup"); -} - -void StmtResInfer::dumpCXXTemporary(const CXXTemporary *Temporary) { -} - -//===----------------------------------------------------------------------===// -// Obj-C Expressions -//===----------------------------------------------------------------------===// - -void StmtResInfer::VisitObjCMessageExpr(const ObjCMessageExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) { - VisitExpr(Node); -} -void StmtResInfer::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { - VisitStmt(Node); -} - -void StmtResInfer::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) { - VisitExpr(Node); -} - -void StmtResInfer::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) { - VisitExpr(Node); -} - -static void InferFunctionType(FunctionDecl* FD, unsigned& Spec) { - //check function return type - { - QualType ResultType = FD->getReturnType(); - if(ResultType->isPointerType()) - ResultType = ResultType->getPointeeType(); - // double* is allowed, while double** is not allowed - if(ResultType->isPointerType()) { - Spec &=~CPPAMP_AMP; - return; - } - } - // check if there's incompatible parameters in the function declarator - for (FunctionDecl::param_iterator PIt = FD->param_begin(); - PIt != FD->param_end(); ++PIt) { - ParmVarDecl *pvDecl = (*PIt); - if(!pvDecl) - continue; - - QualType Ty = pvDecl->getOriginalType(); - if (Ty->isCharType() || Ty->isWideCharType() || Ty->isSpecificBuiltinType(BuiltinType::Short) || - Ty->isSpecificBuiltinType(BuiltinType::LongLong) || - Ty->isSpecificBuiltinType(BuiltinType::LongDouble) || Ty.isVolatileQualified()) { - Spec &=~CPPAMP_AMP; - return; - } - - if (Ty->isEnumeralType()) { - const EnumType* ETy = dyn_cast(Ty); - if (ETy && ETy->getDecl()) { - const Type* UTy = ETy->getDecl()->getIntegerType().getTypePtrOrNull(); - if (UTy->isCharType() || UTy->isWideCharType() || - UTy->isSpecificBuiltinType(BuiltinType::Short) || - UTy->isSpecificBuiltinType(BuiltinType::LongLong) || - UTy->isSpecificBuiltinType(BuiltinType::LongDouble)) { - Spec &=~CPPAMP_AMP; - return; - } - } - } - - // Pointer's pointer - QualType TheType = Ty; - if(Ty->isPointerType()) - TheType = Ty->getPointeeType(); - // double* is allowed, while double** is not allowed - if(TheType->isPointerType()) { - Spec &=~CPPAMP_AMP; - return; - } - } - - QualType ResultType = FD->getReturnType(); - // check if the return type is of incompatible type - if (ResultType->isCharType() || ResultType->isSpecificBuiltinType(BuiltinType::Short)) { - Spec &=~CPPAMP_AMP; - return; - } - - if(FD->getType().isVolatileQualified()) - Spec &=~CPPAMP_AMP; - - return; -} - -// FIXME: Once all statements of the declaration are passed, the restricitons -// inferring can be performed. This is only allowed in auto-restricted declaration -// Top down -void Sema::TryCXXAMPRestrictionInferring(Decl *dcl, Stmt *S) { - if (!getLangOpts().CPlusPlusAMP ||!dcl ||!dcl->hasAttr()) - return; - - // Only allow on funtion definition - assert(isa(*dcl) && dcl->hasBody()); - - unsigned OtherSpec = CPPAMP_AMP | CPPAMP_CPU; - if(dcl->hasAttr()) - OtherSpec &= ~CPPAMP_AMP; - if(dcl->hasAttr()) - OtherSpec &= ~CPPAMP_CPU; - - // Inferring process - // skip method in a lambda class (ex: kernel function in parallel_for_each) - if (isa(dcl) && dyn_cast(dcl)->getParent()->isLambda()) { - } else if(OtherSpec & CPPAMP_AMP) { - // Assuming that 'auto' has been already inferred in parent scope if any - // Contained in any CPU only caller? - if(!IsInAMPRestricted() && dcl->getParentFunctionOrMethod()) - OtherSpec &= ~CPPAMP_AMP; - else if(FunctionDecl* FD = dyn_cast(dcl)) - InferFunctionType(FD, OtherSpec); - } - - if(OtherSpec) { - StmtResInfer SRI(*this, OtherSpec, &this->getSourceManager()); - OtherSpec = SRI.Infer(S); - } - - // Update non-auto restriction specifiers if any - if(OtherSpec) { - - //Place all manually created Attr in where 'auto' physically is - CXXAMPRestrictAUTOAttr *AUTOAttr = dcl->getAttr(); - assert(AUTOAttr); - if(OtherSpec & CPPAMP_AMP) - dcl->addAttr(::new (Context) CXXAMPRestrictAMPAttr(AUTOAttr->getRange(), Context, 0)); - if(OtherSpec & CPPAMP_CPU) - dcl->addAttr(::new (Context) CXXAMPRestrictCPUAttr(AUTOAttr->getRange(), Context, 0)); - } - - // The inferring process is done. Drop AUTO Attribute in this compilation path - dcl->dropAttr(); - -} - diff --git a/test/CodeGenHCC/register-control.cpp b/test/CodeGenHCC/register-control.cpp index 3f311e4d756..f4a60e314fa 100755 --- a/test/CodeGenHCC/register-control.cpp +++ b/test/CodeGenHCC/register-control.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -famp-is-device -fhsa-ext -std=c++amp -x hc-kernel -triple amdgcn -target-cpu fiji -emit-llvm -disable-llvm-passes -o - %s| FileCheck %s +// RUN: %clang_cc1 -fhc-is-device -fhsa-ext -std=c++11 -x hc-kernel -triple amdgcn -target-cpu fiji -emit-llvm -disable-llvm-passes -o - %s| FileCheck %s // // This test emulates parallel-for-each without relying on HCC header files. // By using pseudo definitions of some HCC types this test can generate the trampoline functions which are @@ -8,13 +8,13 @@ class accelerator_view { int dummy; }; class extent { int dummy; }; struct index { - index() __attribute__((annotate("__cxxamp_opencl_index"))){} + index() {} int x; }; struct array { int x; - void foo() restrict(amp) {} + void foo() [[hc]] {} }; template @@ -36,7 +36,7 @@ int main() { // Test parallel-for-each with functor. class A { public: - void foo()restrict(amp){} + void foo() [[hc]] {} // CHECK-LABEL: define internal amdgpu_kernel void @_ZZ4mainEN1A19__cxxamp_trampolineEi(i32) // CHECK-SAME: #[[ATTR2:[0-9]+]] void operator()(index& i)