diff --git a/README.md b/README.md index 1273ba17c2fa0..4645fdb40c122 100644 --- a/README.md +++ b/README.md @@ -120,3 +120,19 @@ Join [LLVM Discourse forums](https://discourse.llvm.org/), [discord chat](https: The LLVM project has adopted a [code of conduct](https://llvm.org/docs/CodeOfConduct.html) for participants to all modes of communication within the project. + +## Build Procedural-Parametric Extension + +It is not differs from mainstream llvm build. +But you can use the recommended command line for debug build +``` +cmake -DCMAKE_BUILD_TYPE:STRING=Debug -DBUILD_SHARED_LIBS:STRING=ON "-DLLVM_TARGETS_TO_BUILD:STRING=X86" -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE "-DLLVM_ENABLE_PROJECTS:STRING=clang" -DLLVM_OPTIMIZED_TABLEGEN:STRING=ON -DLLVM_CCACHE_BUILD:STRING=ON -DCMAKE_C_COMPILER:FILEPATH= -DCMAKE_CXX_COMPILER:FILEPATH= -S -B -G Ninja +``` +After that it is needed to build clang: +``` +cmake --build --config Debug --target all -- +``` +And check if it is actually works: +``` +/bin/llvm-lit /clang/test/CodeGen/pp-linked.c +``` diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index fb87a75a1241f..e457d16127a84 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1830,6 +1830,11 @@ class ParmVarDecl : public VarDecl { static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ParmVar; } + /// Setter and checker for ident type + /// used in multimethods (pp-extension) + bool PPExtIsGenAsSpecIdType() const { return identType == PPExtIdentType::GenAsSpecForMM; } + void PPExtSetIdentType(PPExtIdentType t) { identType = t; } + private: enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 }; @@ -1849,6 +1854,8 @@ class ParmVarDecl : public VarDecl { void setParameterIndexLarge(unsigned parameterIndex); unsigned getParameterIndexLarge() const; + + PPExtIdentType identType = PPExtIdentType::Default; }; enum class MultiVersionKind { @@ -2546,6 +2553,24 @@ class FunctionDecl : public DeclaratorDecl, setParams(getASTContext(), NewParamInfo); } + struct PPMMParam { + RecordDecl* RD; + ParmVarDecl* PVD; + int IdxOfTypeTag; // of __pp_specialization_type + int ParamIdx; //- index of this parameter + RecordDecl* BaseRD; // base of generalization + }; + + struct MMParams + { + std::vector ParamsList; + bool IsSpecialization = false; + }; + + MMParams getRecordDeclsGenArgsForPPMM() const; + + static int getNumOfSpecializationsPPMM(StringRef Name); + /// Returns the minimum number of arguments needed to call this function. This /// may be fewer than the number of function parameters, if some of the /// parameters have default arguments (in C++). diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index aaf1297c1a648..55812f76d9159 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -561,6 +561,7 @@ class IdentifierInfoLookup { /// piece of the code, as each occurrence of every identifier goes through /// here when lexed. class IdentifierTable { +public: // Shark shows that using MallocAllocator is *much* slower than using this // BumpPtrAllocator! using HashTableTy = llvm::StringMap; diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 7657ae36d21bb..b4f5d1d125bf7 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -390,6 +390,22 @@ namespace clang { } llvm_unreachable("Unknown AccessSpecifier"); } + + // PP-EXT + // Enum describes ppstruct identifier type + enum class PPExtIdentType + { + // Default ident type - generalization + // or any specialization + // (including recursive ones) + Default, + // Special ident type - generalization with ".void" postfix + // It is used in multimethod specializations + // to show that this method should be specialized + // for generalization (instead of one of specializations) + GenAsSpecForMM + }; + } // end namespace clang #endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 41bfc9f48eccf..53033b7743fe9 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -252,6 +252,70 @@ class Parser : public CodeCompletionHandler { /// Current kind of OpenMP clause OpenMPClauseKind OMPClauseKind = llvm::omp::OMPC_unknown; + /// Part of PP-EXT + /// When true, we are in parsing base types of pp multimethod invocation + /// (between '<' and '>') + /// MultiMethod<...here...>(); + bool IsInPPMM = false; + + /// PP-EXT + using NameAndPtr = std::pair; + + std::string PPExtConstructGenName( + StringRef BaseName, + NameAndPtr SpecName, + bool AddPrefix = true + ); + + std::string PPExtConstructGenName( + std::vector Names, + ParsedAttributes& PAttrs + ); + + RecordDecl* PPExtCreateGeneralization( + StringRef Name, + RecordDecl* Head, + RecordDecl* Tail, + SourceLocation Loc, + ParsedAttributes& PAttrs); + + RecordDecl* PPExtGetTypeByName(StringRef Name); + + using PPIdDescription = std::pair; + PPIdDescription PPExtGetIdForExistingOrNewlyCreatedGen( + StringRef BaseName, + ParsedAttributes& PAttrs, + bool NeedToAddLParen = true, + bool SaveLastIdent = false + ); + + enum class PPStructType { + Default, + Generalization, + Specialization + }; + + PPStructType PPExtGetStructType(const RecordDecl* RD) const; + + struct PPStructInitDesc { + NamedDecl* VD; + const RecordDecl* RD; + const PPStructType Type; + }; + + std::vector PPExtGetRDListToInit(const RecordDecl* RD) const; + + std::string PPExtConstructTagName(StringRef GenName); + + struct PPMemberInitData { + Expr* Assign; + Expr* MemberAccess; + }; + + PPMemberInitData PPExtInitPPStruct(PPStructInitDesc IDesc, Expr* MemberAccess); + + static DeclSpec::TST PPExtGetFieldTypeByTokKind(tok::TokenKind TK); + /// RAII class that manages the template parameter depth. class TemplateParameterDepthRAII { unsigned &Depth; @@ -483,6 +547,16 @@ class Parser : public CodeCompletionHandler { return ParseTopLevelDecl(Result, IS); } + std::vector m_PPTypedefs; + std::vector m_PPCtors; + std::vector m_PPGlobalVars; + // PP-EXT TODO: Combine these two fields + bool IsInPPMultimethod = false; + StringRef PPMultimethodNameStr; + Declarator* PPMMDecl; + int NumberOfPPSpecilizations = 0; + void FinalizePPArgsParsing(); + /// ConsumeToken - Consume the current 'peek token' and lex the next one. /// This does not work with special tokens: string literals, code completion, /// annotation tokens and balanced tokens must be handled using the specific @@ -2172,6 +2246,93 @@ class Parser : public CodeCompletionHandler { StmtResult ParseSEHFinallyBlock(SourceLocation Loc); StmtResult ParseSEHLeaveStatement(); +//===--------------------------------------------------------------------===// + // Procedural-parametric extension + + struct SpecsDescr { + std::string VariantName; + IdentifierInfo* FullNameIInfo = nullptr; + bool IsPtr = false; + }; + using SpecsVec = SmallVector; + Optional TryParsePPExt(Decl *TagDecl, + SmallVector& FieldDecls); + + void PPExtAddAlign8Attr(ParsedAttributes &Attrs); + + void FieldGenerator(const char* FieldName, + DeclSpec::TST FieldType, + Decl *TagDecl, + RecordDecl* RD, + SmallVector& FieldDecls, + const ParsedAttributes& Attrs, + bool IsPointer); + enum class PPFuncMode { + Ctor, + Init, + Increment, + CreateSpec, + MMDefault + }; + + struct PPMangledNames { + struct PPVariant { + std::string VariantName; + std::string VariantInitFuncName; + std::string VariantTagVariableName; + std::string VariantCreateSpecFuncName; + }; + + std::string BaseStructName; + std::string BaseTagVariableName; + std::string BaseCtorName; + std::string BaseIncFuncName; + std::vector VariantStructNames; + + void setBaseName(std::string BaseName); + + void addVariantName(std::string VariantName); + + std::string MMName; + std::string MMArrayName; + + void setMMName(std::string Name); + + LLVM_ATTRIBUTE_NOINLINE + void dump(); + }; + + static void dumpPPNames(PPMangledNames& p); + + void AddStmts(StmtVector& Stmts, + PPFuncMode Mode, + std::string StrVarName, + PPMangledNames& ppMNames); + + void AddFunc(std::string FuncName, + PPFuncMode Mode, + std::string TagNameToInit, + PPMangledNames& ppMNames, + DeclSpec::TST ReturnType = DeclSpec::TST_void, + SmallVector *ParamInfo = nullptr); + + void FieldGenerator(const char* FieldName, + DeclSpec::TST FieldType, + RecordDecl* RD, + bool IsPointer, + const ParsedAttributes& TestAttrs, + Decl *TestDecl, + SmallVector& FieldDecls); + + Sema::DeclGroupPtrTy VarGenerate(std::string TypeVarName, + bool IsPointer = false, + std::string TypeNameStr = ""); + Sema::DeclGroupPtrTy TypedefGenerate(std::string TypeVarName, + DeclSpec::TST ReturnTypeSpecifier, + SmallVector& ParamInfo); + + bool PPExtNextTokIsLParen = false; + //===--------------------------------------------------------------------===// // Objective-C Statements diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 21d4a53d8e22b..318e1b694516b 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -399,6 +399,8 @@ class DeclSpec { ObjCDeclSpec *ObjCQualifiers; + PPExtIdentType identType = PPExtIdentType::Default; + static bool isTypeRep(TST T) { return (T == TST_typename || T == TST_typeofType || T == TST_underlyingType || T == TST_atomic); @@ -816,6 +818,11 @@ class DeclSpec { /// /// Only tag declspecs can stand alone. bool isMissingDeclaratorOk(); + + /// Setter and getter for ident type + /// used in multimethods (pp-extension) + PPExtIdentType PPExtGetIdentType() const { return identType; } + void PPExtSetIdentType(PPExtIdentType t) { identType = t; } }; /// Captures information about "declaration specifiers" specific to diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 3749d925b106c..d5a7279060147 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -147,10 +147,12 @@ class Scope { /// scope. Scope *AnyParent; +public: /// Flags - This contains a set of ScopeFlags, which indicates how the scope /// interrelates with other control flow statements. unsigned Flags; +private: /// Depth - This is the depth of this scope. The translation-unit scope has /// depth 0. unsigned short Depth; @@ -161,10 +163,12 @@ class Scope { unsigned short MSCurManglingNumber; +public: /// PrototypeDepth - This is the number of function prototype scopes /// enclosing this scope, including this scope. unsigned short PrototypeDepth; +private: /// PrototypeIndex - This is the number of parameters currently /// declared in this scope. unsigned short PrototypeIndex; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cfd7bf6045422..07266ad24e1cd 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11588,6 +11588,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return true; if (const auto *FD = dyn_cast(D)) { + + if (FD->getName().startswith("__pp_mm_")) { + // PP-EXT: Always emit bodies for multimethods + // even if they are marked as `static` + return true; + } + // Forward declarations aren't required. if (!FD->doesThisDeclarationHaveABody()) return FD->doesDeclarationForceExternallyVisibleDefinition(); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index aaba4345587b2..b54fcd57698f5 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3461,6 +3461,84 @@ void FunctionDecl::setParams(ASTContext &C, } } +int FunctionDecl::getNumOfSpecializationsPPMM(StringRef Name) +{ + if (!Name.startswith("__pp_mm_")) { + return -1; + } + + auto PrefixSize = sizeof("__pp_mm_") - 1; + auto PosAfterNum = Name.find_first_of("_", PrefixSize); + auto NumStr = Name.substr(PrefixSize, + PosAfterNum - PrefixSize); + llvm::APInt Num; + NumStr.getAsInteger(10, Num); + auto NumInt = Num.getSExtValue(); + return NumInt; +} + + +auto FunctionDecl::getRecordDeclsGenArgsForPPMM() const -> MMParams +{ + std::vector Result; + int ParamIdx = 0; + auto NumInt = getNumOfSpecializationsPPMM(getName()); + bool IsSpec = false; + + for (auto p = param_begin(); + (p != param_end()) && (NumInt-- > 0); + ++p, ++ParamIdx) { + +#ifdef PPEXT_DUMP + auto Param = *p; + Param->dump(); +#endif + + auto PT = dyn_cast_or_null( + (*p)->getType().getTypePtr()); + if (PT) { + auto RD = PT->getPointeeType().getTypePtr()->getAsRecordDecl(); + if (RD) { + int Idx = 0; + + bool isGenAsSpec = (*p)->PPExtIsGenAsSpecIdType(); + bool startsWithPPStruct = RD->getName().startswith("__pp_struct_"); + assert(!(isGenAsSpec && startsWithPPStruct)); + if (isGenAsSpec || startsWithPPStruct) { + IsSpec = true; + } else { + // If we meet a generalization parameter + // then it should not be specialization + assert(IsSpec == false); + } + + RecordDecl* BaseRD = nullptr; + if (IsSpec) { + if (isGenAsSpec) { + BaseRD = RD; + } + else { + auto F = *RD->field_begin(); + assert(F->getName().equals("__pp_head")); + assert(F->getType().getTypePtr() && + F->getType().getTypePtr()->getAsRecordDecl()); + BaseRD = F->getType().getTypePtr()->getAsRecordDecl(); + } + } + + auto RecordToIterate = (IsSpec ? BaseRD : RD); + for (auto F = RecordToIterate->field_begin(); + F != RecordToIterate->field_end(); + ++F, ++Idx) { + if (F->getName().equals("__pp_specialization_type")) + Result.push_back({RD, *p, Idx, ParamIdx, BaseRD}); + } + } + } + } + return { Result, IsSpec }; +} + /// getMinRequiredArguments - Returns the minimum number of arguments /// needed to call this function. This may be fewer than the number of /// function parameters, if some of the parameters have default diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index d87692face2a9..82ce5f0ede637 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -53,6 +53,8 @@ #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -66,6 +68,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/X86TargetParser.h" +#include "llvm/Transforms/Utils/Cloning.h" using namespace clang; using namespace CodeGen; @@ -96,6 +99,76 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) { llvm_unreachable("invalid C++ ABI kind"); } +namespace +{ + +enum class PPStructType { + Default, + Generalization, + Specialization +}; + +struct PPStructInitDesc { + NamedDecl* VD; + const RecordDecl* RD; + const PPStructType Type; + int Idx; +}; + +PPStructType +PPExtGetStructType(const RecordDecl* RD) +{ + StringRef TagFieldName("__pp_specialization_type"); + for (auto FieldIter = RD->field_begin(); + FieldIter != RD->field_end(); ++FieldIter) { + if (FieldIter->getName().equals(TagFieldName)) { + return PPStructType::Generalization; + } + } + + if (RD->getName().startswith("__pp_struct")) { + return PPStructType::Specialization; + } + + return PPStructType::Default; +} + + +std::vector +PPExtGetRDListToInit(const RecordDecl* RD) +{ + std::vector Result; + assert(!RD->field_empty()); + auto HeadElem = *RD->field_begin(); + auto HeadType = HeadElem->getType(); + const RecordDecl* RDHead = HeadType.getCanonicalType().getTypePtr()-> + getAsRecordDecl(); + + if (!RDHead || + !HeadElem->getName().equals("__pp_head")) { + RDHead = RD; + } + + int Index = 0; + for (auto FieldIter = RDHead->field_begin(); + FieldIter != RDHead->field_end(); ++Index, ++FieldIter) { + auto FieldType = FieldIter->getType(); + RecordDecl* RDField = FieldType.getCanonicalType().getTypePtr()-> + getAsRecordDecl(); + if (RDField) { + auto StrTy = PPExtGetStructType(RDField); + if (StrTy != PPStructType::Default) { + Result.emplace_back( + PPStructInitDesc{*FieldIter, RDField, StrTy, Index}); + } + } + } + + return Result; +} + +} + CodeGenModule::CodeGenModule(ASTContext &C, IntrusiveRefCntPtr FS, const HeaderSearchOptions &HSO, @@ -1246,6 +1319,25 @@ void CodeGenModule::setDLLImportDLLExport(llvm::GlobalValue *GV, } } +void CodeGenModule::adjustPPLinkage(llvm::Function* F) { + StringRef FName = F->getName(); + if (FName.startswith("__pp_") || + FName.startswith("create_spec") || + FName.startswith("get_spec_ptr") || + FName.startswith("get_spec_size") || + FName.startswith("spec_index_cmp") || + FName.startswith("init_spec")) { + F->setLinkage(llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage); + } +} + +void CodeGenModule::adjustPPLinkage(llvm::GlobalVariable* GV) { + StringRef GVName = GV->getName(); + if (GVName.startswith("__pp_")) { + GV->setLinkage(llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage); + } +} + void CodeGenModule::setGVProperties(llvm::GlobalValue *GV, GlobalDecl GD) const { setDLLImportDLLExport(GV, GD); @@ -3201,8 +3293,23 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { if (const auto *FD = dyn_cast(Global)) { // Forward declarations are emitted lazily on first use. if (!FD->doesThisDeclarationHaveABody()) { - if (!FD->doesDeclarationForceExternallyVisibleDefinition()) + if (!FD->doesDeclarationForceExternallyVisibleDefinition()) { + if (FD->getName().startswith("create_spec")) { + // PP-EXT: It is an empty-generated create_spec + // Compute the function info and LLVM type. + // TODO: Avoid it by moving declaration of create_spec + // to CodeGenModule instead of AST + const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); + llvm::Type *Ty = getTypes().GetFunctionType(FI); + + // Here it implicitly will be added to + // PPCreateSpecsToDefine + GetOrCreateLLVMFunction(FD->getName(), Ty, GD, /*ForVTable=*/false, + /*DontDefer=*/false); + } return; + } + StringRef MangledName = getMangledName(GD); @@ -3838,6 +3945,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { return Resolver; } +static std::vector PPCreateSpecsToDefine; + /// GetOrCreateLLVMFunction - If the specified mangled name is not in the /// module, create and return an llvm Function with the specified type. If there /// is something in the module with the specified name, return it potentially @@ -4017,6 +4126,14 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( } } + if (F->getName().startswith("create_spec") || + F->getName().startswith("get_spec_ptr") || + F->getName().startswith("get_spec_size") || + F->getName().startswith("spec_index_cmp") || + F->getName().startswith("init_spec")) { + PPCreateSpecsToDefine.push_back(F); + } + // Make sure the result is of the requested type. if (!IsIncompleteFunction) { assert(F->getFunctionType() == Ty); @@ -4379,6 +4496,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, *this, GV, DAddrSpace, ExpectedAS, Ty->getPointerTo(TargetAS)); } + PPExtInitGlobVar(GV); + return GV; } @@ -4903,6 +5022,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (CGDebugInfo *DI = getModuleDebugInfo()) if (getCodeGenOpts().hasReducedDebugInfo()) DI->EmitGlobalVariable(GV, D); + + adjustPPLinkage(GV); } void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) { @@ -5225,6 +5346,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, auto *Fn = cast(GV); setFunctionLinkage(GD, Fn); + adjustPPLinkage(Fn); + // FIXME: this is redundant with part of setFunctionDefinitionAttributes setGVProperties(Fn, GD); @@ -5246,6 +5369,1420 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, AddGlobalDtor(Fn, DA->getPriority(), true); if (D->hasAttr()) AddGlobalAnnotations(D, Fn); + + HandlePPExtensionMethods(Fn, GD); +} + +void CodeGenModule::AddPPSpecialization( + llvm::Function* F, + const FunctionDecl::MMParams& Gens) +{ + auto FName = F->getName(); + std::string RDName; + for (auto FuncParam : Gens.ParamsList) { + if (FuncParam.PVD->PPExtIsGenAsSpecIdType()) { + RDName += "__0"; + } + RDName += FuncParam.RD->getNameAsString(); + } + + auto initArrName = std::string("__pp_mminitarr") + + FName.substr(0, FName.size() + - RDName.size() + - sizeof("__pp_spec") + + 1).str(); + StringRef Nm(initArrName); + + llvm::Function *FRecorder = PPExtCreateMMRecorder(F); + FRecorder->setName(std::string("__pp_record") + F->getName().str()); + FRecorder->deleteBody(); + auto* BB = llvm::BasicBlock::Create( + getLLVMContext(), "entry", FRecorder); + + CreateCallPrintf( + BB, "[PP-EXT] FRecorder start\n"); + + auto* DecrIdx64 = PPExtGetIndexForMM(BB, Gens); + + CreateCallPrintf( + BB, + "[PP-EXT] FRecorder. Will write to index %lld\n", + DecrIdx64); + + auto* FnTy = F->getFunctionType()->getPointerTo(); + auto* FnPtrType = llvm::PointerType::get(FnTy, 0); + auto* InitArrPtr = + getModule().getOrInsertGlobal(Nm, FnPtrType); + auto* LoadInitArr = new llvm::LoadInst( + FnPtrType, + InitArrPtr, "", BB); + llvm::Value* Idxs[] = {DecrIdx64}; + auto* Elem = llvm::GetElementPtrInst::CreateInBounds( + FnTy, LoadInitArr, Idxs, "", BB); + new llvm::StoreInst(F, Elem, BB); + + llvm::ReturnInst::Create(getLLVMContext(), BB); + AddGlobalCtor(FRecorder, 103); +} + +void CodeGenModule::PPExtInitCreateSpecArray( + StringRef GenName, + llvm::Module& Parent) +{ + // Create initializer declaration + std::vector ArgTypes; + auto* ResultType = llvm::Type::getVoidTy(getLLVMContext()); + llvm::FunctionType *FnTy = + llvm::FunctionType::get(ResultType, + ArgTypes, false); + llvm::FunctionType *FnCSTy = + llvm::FunctionType::get( + llvm::PointerType::get( + llvm::Type::getInt8Ty(getLLVMContext()), 0), + ArgTypes, false + ); + std::string FName = std::string("__pp_init_cs_arr_") + GenName.str(); + auto* FnInitCSArr = + llvm::Function::Create(FnTy, + llvm::GlobalValue::LinkageTypes::WeakAnyLinkage, + 0, // AddressSpace + FName, + &Parent); + + // Add body to initializer + auto* BB = llvm::BasicBlock::Create( + getLLVMContext(), "entry", FnInitCSArr); + + // Get tags value + auto tagsName = std::string("__pp_tags_") + + GenName.str(); + auto *GV = getModule().getGlobalVariable(tagsName); + auto ASTIntTy = getContext().IntTy; + auto ASTLongLongTy = getContext().LongLongTy; + auto MyIntTy = getTypes().ConvertTypeForMem(ASTIntTy); + auto MyLongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + auto MyAlignment = getContext().getAlignOfGlobalVarInChars(ASTIntTy); + auto* LoadGV = new llvm::LoadInst(MyIntTy, GV, Twine(), + false, MyAlignment.getAsAlign(), BB); + + // Increment + llvm::APInt api1(32, 1); + auto* OneVal = llvm::ConstantInt::get(getLLVMContext(), api1); + auto* IncrementedTags = llvm::BinaryOperator::CreateNSWAdd( + LoadGV, OneVal, "", BB); + + // Multiply Tags * sizeof(Ptr) + llvm::APInt apint8(64, 8); + auto Int8_Number = llvm::ConstantInt::get(getLLVMContext(), apint8); + auto* CInstr = llvm::CastInst::Create( + llvm::Instruction::CastOps::SExt, + IncrementedTags, + MyLongLongTy, + "", BB); + auto MulInstr = llvm::BinaryOperator::Create(llvm::BinaryOperator::BinaryOps::Mul, + Int8_Number, CInstr, "", BB); + + // Get Malloc Fn + // TODO: Reuse HandlePPExtensionMethods + // (use function, which will return ptr to malloc) + StringRef MallocName = "malloc"; + llvm::Function *FnMalloc = getModule().getFunction(MallocName); + if (!FnMalloc) { + auto* PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); + auto* MallocResultType = llvm::PointerType::get(PointeeType, 0); + auto* Arg1Type = llvm::IntegerType::get(getLLVMContext(), + static_cast(64)); + SmallVector ArgTypes(1); + ArgTypes[0] = Arg1Type; + auto* FTy = llvm::FunctionType::get(MallocResultType, + ArgTypes, false); + FnMalloc = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, + MallocName, &getModule()); + } + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + llvm::AttrBuilder RetAttrs(getLLVMContext()); + Optional NumElemsParam; + FuncAttrs.addAllocSizeAttr(0, NumElemsParam); + getDefaultFunctionAttributes(MallocName, false, false, FuncAttrs); + std::vector Features; + Features = getTarget().getTargetOpts().Features; + FuncAttrs.addAttribute("target-cpu", "x86-64"); + FuncAttrs.addAttribute("tune-cpu", "generic"); + llvm::sort(Features); + FuncAttrs.addAttribute("target-features", llvm::join(Features, ",")); + llvm::AttrBuilder Attrs(getLLVMContext()); + Attrs.addAttribute(llvm::Attribute::NoUndef); + Attrs.addStackAlignmentAttr(llvm::MaybeAlign(0)); + SmallVector ArgAttrs(1); + ArgAttrs[0] = ArgAttrs[0].addAttributes( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs)); + llvm::AttributeList PAL; + PAL = llvm::AttributeList::get( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs), + llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs); + FnMalloc->setAttributes(PAL); + FnMalloc->setCallingConv(static_cast(0)); + FnMalloc->setDSOLocal(false); + // -- end of block which should be extracted to separate function + + // Call malloc + SmallVector BundleListBundleList; + SmallVector IRCallArgs(1); + IRCallArgs[0] = MulInstr; + auto* CI = llvm::CallInst::Create(FnMalloc->getFunctionType(), + FnMalloc, IRCallArgs, "call_malloc", BB); + CI->setAttributes(PAL); + + // Get array + auto arrName = std::string("__pp_cs_arr_") + GenName.str(); + StringRef TmpDbg(arrName); + auto* FnPtrType = llvm::PointerType::get(FnCSTy, 0); + auto* InitArrPtr = + getModule().getGlobalVariable(arrName); + if (!InitArrPtr) { + InitArrPtr = new llvm::GlobalVariable(getModule(), + FnPtrType, + false, + llvm::GlobalValue::LinkageTypes::WeakAnyLinkage, + nullptr, arrName); + InitArrPtr->setAlignment(llvm::MaybeAlign(8)); + InitArrPtr->setDSOLocal(true); + InitArrPtr->setInitializer( + llvm::Constant::getNullValue(FnPtrType)); + } + + new llvm::StoreInst(CI, InitArrPtr, BB); + + // auto* LoadInitArr = new llvm::LoadInst( + // FnPtrType, + // InitArrPtr, "", BB); + + llvm::ReturnInst::Create(getLLVMContext(), BB); + AddGlobalCtor(FnInitCSArr, 102); +} + +llvm::Function* +CodeGenModule::PPExtCreateMMRecorder(llvm::Function* BaseF) +{ + std::vector ArgTypes; + + assert(!BaseF->getFunctionType()->isVarArg() && + "VarArgs wiil be handle later"); + llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), + ArgTypes, + BaseF->getFunctionType()->isVarArg()); + auto* Res = + llvm::Function::Create(FTy, BaseF->getLinkage(), + BaseF->getAddressSpace(), + BaseF->getName(), + BaseF->getParent()); + return Res; +} + +clang::Type* +CodeGenModule::PPExtGetTypeByName(StringRef TypeNameExtracted) { + clang::Type* Result = nullptr; + auto& Ts = Context.getTypes(); + for (auto Ty : Ts) { + if (Ty->isRecordType() && + Ty->getAsRecordDecl() + ->getName().equals(TypeNameExtracted)) { + Result = Ty; + break; + } + } + return Result; +} + +template +void CodeGenModule::PPExtInitGenOrSpec( + TInsertPoint* IPoint, + StringRef Name, + llvm::Value* ParentObject) +{ + const bool IsFullGeneralization = Name.startswith("__pp_struct"); + std::string TagPrefix = + IsFullGeneralization ? + "__pp_tag_" : "__pp_tags_"; + auto* GVTag = getModule().getGlobalVariable( + TagPrefix + Name.str()); + + // Load ptr to tag field + auto* Ty = PPExtGetTypeByName(Name); + assert(Ty); + auto Qty = Ty->getCanonicalTypeInternal(); + auto* GenRecTy = getTypes().ConvertTypeForMem(Qty); + llvm::APInt Apint0(32, 0); + auto* Number0 = + llvm::ConstantInt::get( + getLLVMContext(), Apint0); + llvm::Value* IdxsHead[] = {Number0, Number0}; + auto* HeadElem = llvm::GetElementPtrInst::CreateInBounds( + GenRecTy, ParentObject, IdxsHead, "pp_head", IPoint); + auto* RecordTy = Ty->getAsRecordDecl(); + assert(RecordTy); + auto HeadRecordTy = IsFullGeneralization ? + RecordTy->field_begin()->getType()->getAsRecordDecl() : + RecordTy; + int FieldIdx = 0; + for (auto* Field : HeadRecordTy->fields()) { + if (Field->getName().equals("__pp_specialization_type")) { + break; + } + ++FieldIdx; + } + llvm::APInt ApintIdx(32, FieldIdx); + auto* NumberIdx = + llvm::ConstantInt::get( + getLLVMContext(), ApintIdx); + llvm::Value* IdxsTagField[] = {Number0, NumberIdx}; + auto HeadQTy = HeadRecordTy->getTypeForDecl()->getCanonicalTypeInternal(); + auto* HeadRecTy = getTypes().ConvertTypeForMem(HeadQTy); + + auto* SpecTypeField = llvm::GetElementPtrInst::CreateInBounds( + HeadRecTy, HeadElem, IdxsTagField, "pp_spec_type", IPoint); + + // Store tag + auto ASTIntTy = getContext().IntTy; + auto IntTy = getTypes().ConvertTypeForMem(ASTIntTy); + llvm::Value* InitVal = + IsFullGeneralization ? + (llvm::Value*)new llvm::LoadInst(IntTy, GVTag, "", IPoint) : + (llvm::Value*)llvm::Constant::getNullValue(IntTy); + new llvm::StoreInst(InitVal, SpecTypeField, IPoint); +} + +void CodeGenModule::PPExtInitStackAllocatedVars(llvm::Function* F) +{ + for (llvm::inst_iterator I = llvm::inst_begin(F), + E = llvm::inst_end(F); I != E; ++I) + { + auto& Inst = *I; + if (isa(Inst)) { + auto AInst = dyn_cast(&Inst); + auto ATy = AInst->getAllocatedType(); + if (!ATy->isStructTy()) { + continue; + } + auto ATyName = ATy->getStructName(); + StringRef Name = ATyName.split(".").second; + auto* Ty = PPExtGetTypeByName(Name); + if (!Ty) { + // Anonimous type + continue; + } + auto* RecordTy = Ty->getAsRecordDecl(); + assert(RecordTy); + auto RDType = PPExtGetStructType(RecordTy); + if (RDType == PPStructType::Default) { + continue; + } + + auto TmpIter = I; + auto NextInstr = &*(++TmpIter); + PPExtInitTypeTagsRecursively(Name, AInst, NextInstr); + } + } +} + +void CodeGenModule::PPExtInitGlobVar(llvm::GlobalVariable* GV) +{ + auto *VTy = GV->getValueType(); + if (!VTy->isStructTy()) { + return; + } + + auto VTyName = VTy->getStructName(); + StringRef Name = VTyName.split(".").second; + auto* Ty = PPExtGetTypeByName(Name); + if (!Ty) { + // Anonimous type + return; + } + auto* RecordTy = Ty->getAsRecordDecl(); + assert(RecordTy); + auto RDType = PPExtGetStructType(RecordTy); + if (RDType == PPStructType::Default) { + return; + } + + std::string MangledName = "__pp_gvinit__" + GV->getName().str(); + llvm::Function *F = getModule().getFunction(MangledName); + if (!F) { + auto* ResType = llvm::Type::getVoidTy(getLLVMContext()); + SmallVector ArgTypes; + auto* FTy = llvm::FunctionType::get(ResType, + ArgTypes, false); + F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, + MangledName, &getModule()); + auto* BB = llvm::BasicBlock::Create(getLLVMContext(), "entry", F); + + PPExtInitTypeTagsRecursively(Name, GV, BB); + + llvm::ReturnInst::Create(getLLVMContext(), BB); + + // PPEXT TODO: Check priority value + AddGlobalCtor(F, 104); + } +} + + +void CodeGenModule::PPExtRecordCreateSpec( + llvm::Function* FnCreateSpec, + RecordDecl* RDSpec, + llvm::Module& Parent) +{ + // Create initializer declaration + std::vector ArgTypes; + // auto* PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); + // auto* ResultType = llvm::PointerType::get(PointeeType, 0); + auto* ResultType = llvm::Type::getVoidTy(getLLVMContext()); + llvm::FunctionType *FnTy = + llvm::FunctionType::get(ResultType, + ArgTypes, false); + llvm::FunctionType *FnCSTy = + llvm::FunctionType::get( + llvm::PointerType::get( + llvm::Type::getInt8Ty(getLLVMContext()), 0), + ArgTypes, false + ); + + // Extract generalization name + auto SpecName = RDSpec->getName(); + constexpr auto SzPPstruct = sizeof("__pp_struct_") - 1; + const auto DoubleUnderscore = SpecName.find("__", SzPPstruct); + const bool IsGeneralization = (DoubleUnderscore == StringRef::npos); + auto GenName = IsGeneralization ? + SpecName : + SpecName.substr( + SzPPstruct, + DoubleUnderscore - SzPPstruct + ); + + // Check that SpecName is not like Figure.Decor.Figure.Something + // because in this fucntion we register create_spec + // which will be invoked by get_spec_ptr(Figure, N) + // not by get_spec_ptr(Figure.Decor, N), which is not supported + // (and maybe do not need at all, it is a research question) + assert((SpecName.count("____") == 0) && + "Trying to record decorated struct for get_spec_ptr usage"); + std::string FName = std::string("__pp_record_cs_") + SpecName.str(); + StringRef FNameRef(FName); // Degub purpose + auto* FnRecordCSArr = + llvm::Function::Create(FnTy, + llvm::GlobalValue::LinkageTypes::WeakAnyLinkage, + 0, // AddressSpace + FName, + &Parent); + + // Add body to initializer + auto* BB = llvm::BasicBlock::Create( + getLLVMContext(), "entry", FnRecordCSArr); + + // Decremented specialization tag + auto specTagName = + std::string("__pp_tag_") + + SpecName.str(); + StringRef TmpDbg2(specTagName); + auto ASTIntTy = getContext().IntTy; + auto CGIntTy = getTypes().ConvertTypeForMem(ASTIntTy); + llvm::Value* SpecTagPtr = + getModule().getGlobalVariable(specTagName); + + auto CGAlignment = getContext().getAlignOfGlobalVarInChars(ASTIntTy); + llvm::Value* LoadGV; + if (IsGeneralization) { + LoadGV = llvm::Constant::getNullValue(CGIntTy); + } + else { + LoadGV = new llvm::LoadInst(CGIntTy, SpecTagPtr, Twine(), + false, CGAlignment.getAsAlign(), BB); + } + + auto ASTLongLongTy = getContext().LongLongTy; + auto CGLongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + auto DecrIdx64 = llvm::CastInst::Create( + llvm::Instruction::CastOps::SExt, + LoadGV, + CGLongLongTy, "", BB); + + // Array of create_spec + auto initArrName = + std::string("__pp_cs_arr_") + + GenName.str(); + StringRef TmpDbg(initArrName); + auto* InitArrPtr = + getModule().getGlobalVariable(initArrName); + auto* FnPtrType = llvm::PointerType::get(FnCSTy, 0); + if (!InitArrPtr) { + InitArrPtr = new llvm::GlobalVariable(getModule(), + FnPtrType, + false, + llvm::GlobalValue::LinkageTypes::WeakAnyLinkage, + nullptr, initArrName); + InitArrPtr->setAlignment(llvm::MaybeAlign(8)); + InitArrPtr->setDSOLocal(true); + InitArrPtr->setInitializer( + llvm::Constant::getNullValue(FnPtrType)); + } + + auto* LoadInitArr = new llvm::LoadInst( + FnPtrType, + InitArrPtr, "", BB); + + // Store function pointer + llvm::Value* Idxs[] = {DecrIdx64}; + auto* Elem = llvm::GetElementPtrInst::CreateInBounds( + FnPtrType, LoadInitArr, Idxs, "", BB); + new llvm::StoreInst(FnCreateSpec, Elem, BB); + + // InitArrPtr->dump(); + printf("%s\n", GenName.str().c_str()); + + llvm::ReturnInst::Create(getLLVMContext(), BB); + AddGlobalCtor(FnRecordCSArr, 103); +} + +void CodeGenModule::HandlePPExtensionMethods( + llvm::Function* F, GlobalDecl GD) +{ + PPExtInitStackAllocatedVars(F); + + if (F->getName().startswith("__pp_inc_tags")) { + StringRef GenName(F->getName().substr(sizeof("__pp_inc_tags"))); + PPExtInitCreateSpecArray(GenName, *F->getParent()); + return; + } + + for (auto* FSpec : PPCreateSpecsToDefine) { + const bool IsInitSpec = FSpec->getName().startswith("init_spec"); + const bool IsGetSpecPtr = FSpec->getName().startswith("get_spec_ptr"); + const bool IsGetSpecSize = FSpec->getName().startswith("get_spec_size"); + const bool IsSpecIdxCmp = FSpec->getName().startswith("spec_index_cmp"); + + if(FSpec->getBasicBlockList().empty()) { + auto TypeNameExtracted = IsInitSpec ? + FSpec->getName().substr(sizeof("init_spec") - 1) : + (IsGetSpecPtr ? + FSpec->getName().substr(sizeof("get_spec_ptr") - 1) : + (IsGetSpecSize ? + FSpec->getName().substr(sizeof("get_spec_size") - 1) : + FSpec->getName().substr(sizeof("create_spec") - 1))); + + // TODO: Refactor + if (IsSpecIdxCmp) { + StringRef PPStructPrefix("__pp_struct_"); + TypeNameExtracted = FSpec->getName().substr(sizeof("spec_index_cmp") - 1); + // TypeNameExtracted should be a name of generalization + // if it is not - then extract it from specialization name + if (TypeNameExtracted.startswith(PPStructPrefix)) { + TypeNameExtracted = TypeNameExtracted.substr(PPStructPrefix.size()); + auto Pos = TypeNameExtracted.find("__"); + TypeNameExtracted = TypeNameExtracted.substr(0, Pos); + assert(!TypeNameExtracted.empty()); + } + auto* Ty = PPExtGetTypeByName(TypeNameExtracted); + assert(Ty); + + auto* RecordTy = Ty->getAsRecordDecl(); + assert(RecordTy); + + int FieldIdx = 0; + for (auto* Field : RecordTy->fields()) { + if (Field->getName().equals("__pp_specialization_type")) { + break; + } + ++FieldIdx; + } + llvm::APInt ApintIdx(32, FieldIdx); + auto* NumberIdx = + llvm::ConstantInt::get( + getLLVMContext(), ApintIdx); + llvm::APInt Apint0(32, 0); + llvm::APInt ApintM1(32, -1); + auto* Number0 = + llvm::ConstantInt::get( + getLLVMContext(), Apint0); + auto* NumberM1 = + llvm::ConstantInt::get( + getLLVMContext(), ApintM1); + llvm::Value* IdxsTagField[] = {Number0, NumberIdx}; + auto HeadQTy = RecordTy->getTypeForDecl()->getCanonicalTypeInternal(); + auto* HeadRecTy = getTypes().ConvertTypeForMem(HeadQTy); + + auto* Arg1 = FSpec->getArg(0); + auto* Arg2 = FSpec->getArg(1); + auto* BB = llvm::BasicBlock::Create(getLLVMContext(), "entry", FSpec); + auto ASTIntTy = getContext().IntTy; + auto CGIntTy = getTypes().ConvertTypeForMem(ASTIntTy); + auto* RetVal = new llvm::AllocaInst(CGIntTy, 0, "retval", BB); + auto* Tag1 = llvm::GetElementPtrInst::CreateInBounds( + HeadRecTy, Arg1, IdxsTagField, "pp_spec_type", BB); + auto* Tag2 = llvm::GetElementPtrInst::CreateInBounds( + HeadRecTy, Arg2, IdxsTagField, "pp_spec_type", BB); + auto* LTag1 = new llvm::LoadInst(CGIntTy, Tag1, "", BB); + auto* LTag2 = new llvm::LoadInst(CGIntTy, Tag2, "", BB); + auto* Cmp = llvm::CmpInst::Create( + llvm::Instruction::OtherOps::ICmp, + llvm::CmpInst::Predicate::ICMP_EQ, + LTag1, LTag2, "", BB); + auto* BBIfThen = llvm::BasicBlock::Create(getLLVMContext(), "if.then", FSpec); + auto* BBIfEnd = llvm::BasicBlock::Create(getLLVMContext(), "if.end", FSpec); + auto* BBRet = llvm::BasicBlock::Create(getLLVMContext(), "return", FSpec); + llvm::BranchInst::Create(BBIfThen, BBIfEnd, + Cmp, BB); + new llvm::StoreInst(LTag1, RetVal, BBIfThen); + llvm::BranchInst::Create(BBRet, BBIfThen); + + new llvm::StoreInst(NumberM1, RetVal, BBIfEnd); + llvm::BranchInst::Create(BBRet, BBIfEnd); + + auto* Ret = new llvm::LoadInst(CGIntTy, RetVal, "", BBRet); + llvm::ReturnInst::Create(getLLVMContext(), Ret, BBRet); + continue; + } + +#ifdef PPEXT_DUMP + printf("Need to generate body for %s [%s]\n", + FSpec->getName().data(), + TypeNameExtracted.data()); +#endif + + int64_t BytesToAlloc = 0; + + auto* Ty = PPExtGetTypeByName(TypeNameExtracted); + assert(Ty); + + auto* RecordTy = Ty->getAsRecordDecl(); + assert(RecordTy); + BytesToAlloc = Context.getTypeSizeInChars(Ty).getQuantity(); + +#ifdef PPEXT_DUMP + printf("Found Record = [%s][%d][%d]\n", + RecordTy->getName().data(), + (int)Context.getTypeSize(Ty), + (int)Context.getTypeSizeInChars(Ty).getQuantity()); + RecordTy->dump(); +#endif + + if (IsGetSpecPtr) { + auto* BB = llvm::BasicBlock::Create(getLLVMContext(), "entry", FSpec); + llvm::Value* Idx = FSpec->getArg(0); + StringRef GenName(FSpec->getName().substr(sizeof("get_spec_ptr") - 1)); + auto arrName = std::string("__pp_cs_arr_") + GenName.str(); + auto* InitArr = getModule().getGlobalVariable(arrName); + std::vector ArgTypes; + auto* ResultType = llvm::Type::getInt8PtrTy(getLLVMContext()); + llvm::FunctionType *FnTy = + llvm::FunctionType::get(ResultType, + ArgTypes, false); + + auto* FnPtrType = llvm::PointerType::get(FnTy, 0); + + // Extend parameter to i64 + // TODO PP-EXT: Change type in function signature + // (from get_spec_ptr(i32) to get_spec_ptr(i64)) + auto ASTLongLongTy = getContext().LongLongTy; + auto MyLongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + auto* IdxExt = llvm::CastInst::Create( + llvm::Instruction::CastOps::SExt, + Idx, + MyLongLongTy, + "", BB); + + // Load pointer to necessary create_spec + llvm::Value* TypeTagsIdxs[] = {IdxExt}; + auto* LoadInitArr = new llvm::LoadInst( + FnPtrType, + InitArr, "", BB); + auto* Elem = llvm::GetElementPtrInst::CreateInBounds( + FnPtrType, + LoadInitArr, TypeTagsIdxs, "", BB); + auto LoadElem = new llvm::LoadInst( + FnTy->getPointerTo(), + Elem, "", BB); + + // Execute create_spec + SmallVector VecArgs; + ArrayRef Args (VecArgs); + auto *CI = llvm::CallInst::Create(FnTy, + LoadElem, Args, "call_res", BB); + llvm::ReturnInst::Create(getLLVMContext(), CI, BB); + continue; + } + + if (IsGetSpecSize) { + auto* BB = llvm::BasicBlock::Create(getLLVMContext(), "entry", FSpec); + StringRef GenName(FSpec->getName().substr(sizeof("get_spec_size") - 1)); + auto gvName = std::string("__pp_tags_") + GenName.str(); + auto* GV = getModule().getGlobalVariable(gvName); + auto ASTIntTy = getContext().IntTy; + auto IntTy = getTypes().ConvertTypeForMem(ASTIntTy); + auto* LoadGlobalTag = + new llvm::LoadInst(IntTy, GV, + "tags", BB); + llvm::APInt api1(32, 1); + auto* OneVal = llvm::ConstantInt::get(getLLVMContext(), api1); + auto* IncrementedTags = llvm::BinaryOperator::CreateNSWAdd( + LoadGlobalTag, OneVal, "", BB); + llvm::ReturnInst::Create(getLLVMContext(), + IncrementedTags, BB); + continue; + } + + auto* BB = llvm::BasicBlock::Create(getLLVMContext(), "entry", FSpec); + llvm::Value* PtrToObjForGEP = IsInitSpec ? FSpec->getArg(0) : nullptr; + llvm::CallInst* MallocRes = nullptr; + { + if (!IsInitSpec) + { + StringRef MangledName = "malloc"; + llvm::Function *F = getModule().getFunction(MangledName); + if (!F) { + auto* PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); + auto* MallocResultType = llvm::PointerType::get(PointeeType, 0); + auto* Arg1Type = llvm::IntegerType::get(getLLVMContext(), + static_cast(64)); + SmallVector ArgTypes(1); + ArgTypes[0] = Arg1Type; + auto* FTy = llvm::FunctionType::get(MallocResultType, + ArgTypes, false); + F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, + MangledName, &getModule()); + } + + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + llvm::AttrBuilder RetAttrs(getLLVMContext()); + Optional NumElemsParam; + FuncAttrs.addAllocSizeAttr(0, NumElemsParam); + getDefaultFunctionAttributes(MangledName, false, false, FuncAttrs); + std::vector Features; + Features = getTarget().getTargetOpts().Features; + FuncAttrs.addAttribute("target-cpu", "x86-64"); + FuncAttrs.addAttribute("tune-cpu", "generic"); + llvm::sort(Features); + FuncAttrs.addAttribute("target-features", llvm::join(Features, ",")); + llvm::AttrBuilder Attrs(getLLVMContext()); + Attrs.addAttribute(llvm::Attribute::NoUndef); + Attrs.addStackAlignmentAttr(llvm::MaybeAlign(0)); + SmallVector ArgAttrs(1); + ArgAttrs[0] = ArgAttrs[0].addAttributes( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs)); + llvm::AttributeList PAL; + PAL = llvm::AttributeList::get( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs), + llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs); + F->setAttributes(PAL); + F->setCallingConv(static_cast(0)); + F->setDSOLocal(false); + + SmallVector BundleListBundleList; + SmallVector IRCallArgs(1); + auto ASTLongLongTy = getContext().LongLongTy; + auto LongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + auto* SizeAlloca = new llvm::AllocaInst(LongLongTy, 0, "Size", BB); + llvm::APInt ApintAlloc(64, BytesToAlloc); + auto* NumberAllocBytes = + llvm::ConstantInt::get(getLLVMContext(), ApintAlloc); + new llvm::StoreInst(NumberAllocBytes, SizeAlloca, BB); + auto* LoadTmp = + new llvm::LoadInst(LongLongTy, SizeAlloca, "", BB); + IRCallArgs[0] = LoadTmp; + + MallocRes = llvm::CallInst::Create(F->getFunctionType(), + F, IRCallArgs, "call_malloc", BB); + MallocRes->setAttributes(PAL); + + PtrToObjForGEP = MallocRes; + } + + PPExtInitTypeTagsRecursively(TypeNameExtracted, + PtrToObjForGEP, + BB); + + if (IsInitSpec) { + llvm::ReturnInst::Create(getLLVMContext(), BB); + } + else { + assert(MallocRes); + llvm::ReturnInst::Create(getLLVMContext(), + MallocRes, BB); + } + + adjustPPLinkage(FSpec); + + if (FSpec->getName().count("____") == 0) { + // Do not register decorated generalization + // Now we support only `get_spec_ptr(Figure, N)` + // not `get_spec_ptr(Figure.Decor, N)` + // (and maybe we do not need it at all, it is a question for further research) + PPExtRecordCreateSpec(FSpec, RecordTy, *FSpec->getParent()); + } + } + } + } + + auto FName = F->getName(); + + if (not FName.startswith("__pp_mm")) { + if (FName.equals("main")) { + auto& BB = F->getEntryBlock(); + CreateCallPrintf( + &BB, "[PP-EXT] === main start ===\n", + nullptr, InsertPrintfPos::BeforeFirstInstr); + } + return; + } + + if (F->empty()) { + return; + } + + auto FD = dyn_cast_or_null(GD.getDecl()); + auto Generalizations = FD->getRecordDeclsGenArgsForPPMM(); + + assert(not Generalizations.ParamsList.empty()); + + bool IsSpecialization = + Generalizations.IsSpecialization; + + if (IsSpecialization) { + +#ifdef PPEXT_DUMP + printf("Found MM Specialization: %s\n", FName.str().c_str()); +#endif + AddPPSpecialization(F, Generalizations); + return; + } + else { + +#ifdef PPEXT_DUMP + printf("Found MM Handler: %s\n", FName.substr(sizeof("__pp_mm")).str().c_str()); +#endif + + } + + auto* DefaultHandler = ExtractDefaultPPMMImplementation(F, FD); + + llvm::ArrayRef Params; + auto AllocaFTy = llvm::FunctionType::get( + VoidTy, Params, false); + auto* NewF = llvm::Function::Create(AllocaFTy, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + std::string("__pp_alloc") + FName.str(), + &getModule()); + + auto* BB = llvm::BasicBlock::Create(getLLVMContext(), "entry", NewF); + CreateCallPrintf(BB, "[PP-EXT] Allocation start\n"); + auto genName = std::string("__pp_tags_") + + Generalizations.ParamsList[0].RD->getNameAsString(); + auto ASTIntTy = getContext().IntTy; + auto ASTLongLongTy = getContext().LongLongTy; + auto MyIntTy = getTypes().ConvertTypeForMem(ASTIntTy); + auto MyLongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + auto *GV = getModule().getGlobalVariable(genName); + auto MyAlignment = getContext().getAlignOfGlobalVarInChars(ASTIntTy); + auto* LoadGVDef = new llvm::LoadInst(MyIntTy, GV, Twine(), + false, MyAlignment.getAsAlign(), BB); + + llvm::APInt apint1_32(32, 1); + auto Int1_Number32 = llvm::ConstantInt::get(getLLVMContext(), apint1_32); + auto* LoadGV = llvm::BinaryOperator::CreateNSWAdd(LoadGVDef, Int1_Number32, "Increment", BB); + llvm::APInt apint8(64, 8); + auto Int8_Number = llvm::ConstantInt::get(getLLVMContext(), apint8); + + auto* CInstr = llvm::CastInst::Create( + llvm::Instruction::CastOps::SExt, + LoadGV, + MyLongLongTy, + "", BB); + auto MulInstr = llvm::BinaryOperator::Create(llvm::BinaryOperator::BinaryOps::Mul, + Int8_Number, CInstr, "", BB); + // TODO: Make loop starting with i = 0 + for (auto i = 1UL; i < Generalizations.ParamsList.size(); ++i) { + auto nextGenName = std::string("__pp_tags_") + + Generalizations.ParamsList[i].RD->getNameAsString(); + auto *nextGV = getModule().getGlobalVariable(nextGenName); + auto* LoadNextGVRaw = new llvm::LoadInst(MyIntTy, nextGV, Twine(), + false, MyAlignment.getAsAlign(), BB); + auto* LoadNextGV = + llvm::BinaryOperator::CreateNSWAdd(LoadNextGVRaw, Int1_Number32, "Increment", BB); + auto* nextCInstr = llvm::CastInst::Create( + llvm::Instruction::CastOps::SExt, + LoadNextGV, + MyLongLongTy, + "", BB); + MulInstr = llvm::BinaryOperator::Create(llvm::BinaryOperator::BinaryOps::Mul, + MulInstr, nextCInstr, "", BB); + } + + // Construct and invoke malloc + auto initArrName = std::string("__pp_mminitarr") + FName.str(); + StringRef initArrNameRef(initArrName); // For debug purpose + { + StringRef MangledName = "malloc"; + llvm::Function *F = getModule().getFunction(MangledName); + if (!F) { + auto* PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); + auto* MallocResultType = llvm::PointerType::get(PointeeType, 0); + auto* Arg1Type = llvm::IntegerType::get(getLLVMContext(), + static_cast(64)); + SmallVector ArgTypes(1); + ArgTypes[0] = Arg1Type; + auto* FTy = llvm::FunctionType::get(MallocResultType, + ArgTypes, false); + F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, + MangledName, &getModule()); + } + + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + llvm::AttrBuilder RetAttrs(getLLVMContext()); + Optional NumElemsParam; + FuncAttrs.addAllocSizeAttr(0, NumElemsParam); + getDefaultFunctionAttributes(MangledName, false, false, FuncAttrs); + std::vector Features; + Features = getTarget().getTargetOpts().Features; + FuncAttrs.addAttribute("target-cpu", "x86-64"); + FuncAttrs.addAttribute("tune-cpu", "generic"); + llvm::sort(Features); + FuncAttrs.addAttribute("target-features", llvm::join(Features, ",")); + llvm::AttrBuilder Attrs(getLLVMContext()); + Attrs.addAttribute(llvm::Attribute::NoUndef); + Attrs.addStackAlignmentAttr(llvm::MaybeAlign(0)); + SmallVector ArgAttrs(1); + ArgAttrs[0] = ArgAttrs[0].addAttributes( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs)); + llvm::AttributeList PAL; + PAL = llvm::AttributeList::get( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs), + llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs); + F->setAttributes(PAL); + F->setCallingConv(static_cast(0)); + F->setDSOLocal(false); + + SmallVector BundleListBundleList; + SmallVector IRCallArgs(1); + IRCallArgs[0] = MulInstr; + CreateCallPrintf(BB, + "[PP-EXT] Allocation size for malloc (bytes): %lld\n", + MulInstr); + auto* CI = llvm::CallInst::Create(F->getFunctionType(), + F, IRCallArgs, "call_malloc", BB); + CI->setAttributes(PAL); + auto* Ptr = getModule().getGlobalVariable(initArrName); + assert(Ptr && + "[PP-EXT] Asked for unnallocated array of handlers"); + + CreateCallPrintf(BB, + "[PP-EXT] Allocation Set InitArr %p\n", + Ptr); + new llvm::StoreInst(CI, Ptr, BB); + auto* LoadTmp = + new llvm::LoadInst(Int64Ty, Ptr, "", BB); + CreateCallPrintf(BB, + "[PP-EXT] Allocation Set InitArr First 64bits: %p\n", + LoadTmp); + } + + auto* HandlersArray = getModule().getGlobalVariable(initArrName); + auto* BBEnd = InitPPHandlersArray(BB, + MulInstr, + HandlersArray, + DefaultHandler); + + CreateCallPrintf(BBEnd, "[PP-EXT] Allocation end\n"); + llvm::ReturnInst::Create(getLLVMContext(), BBEnd); + AddGlobalCtor(NewF, 102); +} + +template +void CodeGenModule::PPExtInitTypeTagsRecursively( + StringRef NameOfVariable, + llvm::Value* PtrToObjForGEP, + TInsertPoint* IPoint) +{ + auto* Ty = PPExtGetTypeByName(NameOfVariable); + do { + auto Qty = Ty->getCanonicalTypeInternal(); + auto* GenRecTy = getTypes().ConvertTypeForMem(Qty); + auto* RecordTy = Ty->getAsRecordDecl(); + assert(RecordTy); + llvm::APInt Apint0(32, 0); + llvm::APInt Apint1(32, 1); + auto* Number0 = + llvm::ConstantInt::get( + getLLVMContext(), Apint0); + auto* Number1 = + llvm::ConstantInt::get( + getLLVMContext(), Apint1); + llvm::Value* IdxsHead[] = {Number0, Number0}; + llvm::Value* IdxsTail[] = {Number0, Number1}; + auto* HeadElem = llvm::GetElementPtrInst::CreateInBounds( + GenRecTy, PtrToObjForGEP, IdxsHead, "pp_head", IPoint); + assert(!RecordTy->fields().empty()); + auto firstField = *RecordTy->field_begin(); + auto HeadRecordTy = RecordTy->field_begin()->getType()->getAsRecordDecl(); + if (!firstField->getName().equals("__pp_head")) { + // It is a generalization + HeadRecordTy = RecordTy; + } + + int FieldIdx = 0; + bool SpecTypeWasFound = false; + for (auto* Field : HeadRecordTy->fields()) { + if (Field->getName().equals("__pp_specialization_type")) { + SpecTypeWasFound = true; + break; + } + ++FieldIdx; + } + assert(SpecTypeWasFound); + llvm::APInt ApintIdx(32, FieldIdx); + auto* NumberIdx = + llvm::ConstantInt::get( + getLLVMContext(), ApintIdx); + llvm::Value* IdxsTagField[] = {Number0, NumberIdx}; + auto HeadQTy = HeadRecordTy->getTypeForDecl()->getCanonicalTypeInternal(); + auto* HeadRecTy = getTypes().ConvertTypeForMem(HeadQTy); + + auto* TagElem = llvm::GetElementPtrInst::CreateInBounds( + HeadRecTy, HeadElem, IdxsTagField, "pp_spec_type", IPoint); + + auto genName = std::string("__pp_tag_") + + NameOfVariable.str(); + + auto fourUnderscorePos = NameOfVariable.find("____"); + if (fourUnderscorePos != StringRef::npos) { + auto GenName = NameOfVariable; + char PPStructPrefix[] = "__pp_struct_"; + auto Sz = sizeof(PPStructPrefix); + auto NextPos = GenName.find(PPStructPrefix, Sz); + StringRef SpecName(""); + if (NextPos != StringRef::npos) { + auto EndOfTypePos = GenName.find("__", fourUnderscorePos + 4); + assert(EndOfTypePos != StringRef::npos); + auto StartPos = NextPos + Sz - 1; + SpecName = GenName.substr(StartPos, + EndOfTypePos - StartPos); + auto BaseName = GenName.substr(0, fourUnderscorePos); + genName = std::string("__pp_tag_") + BaseName.str(); + +#ifdef PPEXT_DUMP + StringRef GN(genName); + printf("%s\n", GN.data()); +#endif + + PtrToObjForGEP = llvm::GetElementPtrInst::CreateInBounds( + GenRecTy, PtrToObjForGEP, IdxsTail, "pp_tail", IPoint); + } + } + + StringRef DbgStr(genName); + auto *GV = getModule().getGlobalVariable(genName); + auto ASTIntTy = getContext().IntTy; + auto IntTy = getTypes().ConvertTypeForMem(ASTIntTy); + if (GV) { + auto* LoadGlobalTag = + new llvm::LoadInst(IntTy, GV, + "global_spec_tag", IPoint); + new llvm::StoreInst(LoadGlobalTag, TagElem, IPoint); + } + else { + new llvm::StoreInst( + llvm::Constant::getNullValue(IntTy), TagElem, IPoint); + } + + // tag for the current struct is inited + // next step: init tags for direct fields + auto FieldsToInit = PPExtGetRDListToInit(RecordTy); + for (auto& F : FieldsToInit) { + llvm::APInt Apint0(32, 0); + llvm::APInt ApintIdx(32, F.Idx); + auto* Number0 = + llvm::ConstantInt::get( + getLLVMContext(), Apint0); + auto* NumberIdx = + llvm::ConstantInt::get( + getLLVMContext(), ApintIdx); + llvm::Value* FieldIdxs[] = {Number0, NumberIdx}; + auto Qty = Ty->getCanonicalTypeInternal(); + auto* GenRecTy = getTypes().ConvertTypeForMem(Qty); + auto* HeadElem = llvm::GetElementPtrInst::CreateInBounds( + GenRecTy, PtrToObjForGEP, FieldIdxs, "pp_struct_field_to_init", IPoint); + PPExtInitGenOrSpec(IPoint, F.RD->getName(), HeadElem); + } + + auto Pos = NameOfVariable.find("____"); + if (Pos != StringRef::npos) { + NameOfVariable = NameOfVariable.substr(Pos + 2); + Ty = PPExtGetTypeByName(NameOfVariable); + } else { + Ty = nullptr; + } + } while(Ty); +} + + +llvm::BasicBlock* CodeGenModule::InitPPHandlersArray( + llvm::BasicBlock* BB, + llvm::Value* AllocatedBytes, + llvm::Value* HandlersArray, + llvm::Value* DefaultHandler) +{ + auto ASTLongLongTy = getContext().LongLongTy; + auto LongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + + auto* SizeAlloca = new llvm::AllocaInst(LongLongTy, 0, "Size", BB); + auto* IterAlloca = new llvm::AllocaInst(LongLongTy, 0, "Iter", BB); + + llvm::APInt apint8(64, 8); + auto* Int8_Number = llvm::ConstantInt::get(getLLVMContext(), apint8); + llvm::APInt apint0(64, 0); + auto* Int0_Number = llvm::ConstantInt::get(getLLVMContext(), apint0); + llvm::APInt apint1(64, 1); + auto* Int1_Number = llvm::ConstantInt::get(getLLVMContext(), apint1); + + CreateCallPrintf(BB, + "[PP-EXT] InitPPHandlersArray\n"); + auto* NumOfHandlers = llvm::BinaryOperator::Create( + llvm::Instruction::BinaryOps::UDiv, + AllocatedBytes, Int8_Number, "", BB); + + { + CreateCallPrintf(BB, + "[PP-EXT] InitPPHandlersArray Addr: %p\n", + HandlersArray); + auto* LoadTmp = + new llvm::LoadInst(Int64Ty, HandlersArray, "", BB); + CreateCallPrintf(BB, + "[PP-EXT] InitPPHandlersArray First 64bit: %p\n", + LoadTmp); + } + + CreateCallPrintf(BB, + "[PP-EXT] InitPPHandlersArray NumOfHandlers %d\n", + NumOfHandlers); + CreateCallPrintf(BB, + "[PP-EXT] InitPPHandlersArray DefaultHandler %p\n", + DefaultHandler); + new llvm::StoreInst(NumOfHandlers, SizeAlloca, BB); + new llvm::StoreInst(Int0_Number, IterAlloca, BB); + + auto* BBCond = llvm::BasicBlock::Create( + getLLVMContext(), "for.cond", BB->getParent()); + llvm::BranchInst::Create(BBCond, BB); + + // Condition BB + auto* CurIter = new llvm::LoadInst( + LongLongTy, + IterAlloca, "", BBCond); + // TODO: Load it only once in entry BB + auto* CurSize = new llvm::LoadInst( + LongLongTy, + SizeAlloca, "", BBCond); + auto* CurCmp = llvm::CmpInst::Create( + llvm::Instruction::OtherOps::ICmp, + llvm::CmpInst::Predicate::ICMP_ULT, + CurIter, CurSize, "", BBCond); + + auto* BBBody = llvm::BasicBlock::Create( + getLLVMContext(), "for.body", BB->getParent()); + auto* BBInc = llvm::BasicBlock::Create( + getLLVMContext(), "for.inc", BB->getParent()); + auto* BBEnd = llvm::BasicBlock::Create( + getLLVMContext(), "for.end", BB->getParent()); + + llvm::BranchInst::Create(BBBody, BBEnd, + CurCmp, BBCond); + + // Body BB + auto* FnTy = cast(DefaultHandler) + ->getFunctionType(); + + auto* ArrayPtr = HandlersArray; + auto* CurIdx = new llvm::LoadInst( + LongLongTy, + IterAlloca, "", BBBody); + CreateCallPrintf(BBBody, + "[PP-EXT] InitPPHandlersArray CurIdx %lld\n", + CurIdx); + auto* FnPtrType = llvm::PointerType::get(FnTy, 0); + auto* LoadInitArr = new llvm::LoadInst( + FnPtrType, + ArrayPtr, "", BBBody); + llvm::Value* Idxs[] = {CurIdx}; + auto* Elem = llvm::GetElementPtrInst::CreateInBounds( + FnPtrType, LoadInitArr, Idxs, "", BBBody); + CreateCallPrintf(BBBody, + "[PP-EXT] InitPPHandlersArray Elem ptr: %p\n", + Elem); + auto* ElemValB = new llvm::LoadInst(LongLongTy, + Elem, "", BBBody); + CreateCallPrintf(BBBody, + "[PP-EXT] InitPPHandlersArray ElemVal before init: %p\n", + ElemValB); + new llvm::StoreInst(DefaultHandler, Elem, BBBody); + auto* ElemValA = new llvm::LoadInst(LongLongTy, + Elem, "", BBBody); + CreateCallPrintf(BBBody, + "[PP-EXT] InitPPHandlersArray ElemVal after init: %p\n", + ElemValA); + llvm::BranchInst::Create(BBInc, BBBody); + + // Inc BB + auto* IterForInc = new llvm::LoadInst( + LongLongTy, + IterAlloca, "", BBInc); + auto* IncrementedIter = llvm::BinaryOperator::CreateAdd( + IterForInc, + Int1_Number, "", BBInc); + new llvm::StoreInst(IncrementedIter, IterAlloca, BBInc); + llvm::BranchInst::Create(BBCond, BBInc); + + { + auto* LoadTmp = + new llvm::LoadInst(Int64Ty, HandlersArray, "", BBEnd); + CreateCallPrintf(BBEnd, + "[PP-EXT] InitPPHandlersArray First 64bit after init: %p\n", + LoadTmp); + } + return BBEnd; +} + +llvm::Value* +CodeGenModule::PPExtGetIndexForMM( + llvm::BasicBlock* BB, + const FunctionDecl::MMParams& Gens) +{ + assert(BB); + auto GetIdxForGen = + [&](const FunctionDecl::PPMMParam& g) -> llvm::Value* { + auto Qty = g.RD->getTypeForDecl() + ->getCanonicalTypeInternal(); + auto* GenRecTy = getTypes().ConvertTypeForMem(Qty); + + auto* GenRecPtr = new llvm::AllocaInst( + GenRecTy->getPointerTo(), 0, "", BB); + auto CurIdxInt = g.IdxOfTypeTag; + auto ParamIdxInt = g.ParamIdx; + auto* F = BB->getParent(); + auto* GenRecParamPtr = F->getArg(ParamIdxInt); + new llvm::StoreInst(GenRecParamPtr, GenRecPtr, BB); + + llvm::APInt api0(32, 0); + llvm::APInt apiIndx(32, CurIdxInt); + auto* ZeroVal = llvm::ConstantInt::get(getLLVMContext(), api0); + auto* CurIdx = llvm::ConstantInt::get(getLLVMContext(), apiIndx); + CreateCallPrintf(BB, + "[PP-EXT] MM Index of typetag %d\n", CurIdx); + + llvm::Value* Idxs[] = {ZeroVal, CurIdx}; + + auto* TypeTagPtr = llvm::GetElementPtrInst::CreateInBounds( + GenRecTy, GenRecParamPtr, Idxs, "", BB); + +#ifdef PPEXT_DUMP + TypeTagPtr->dump(); +#endif + + auto* TypeTag = new llvm::LoadInst(IntTy, TypeTagPtr, "", BB); + + CreateCallPrintf(BB, + "[PP-EXT] MM TypeTag %d\n", + TypeTag); + + return TypeTag; + }; + + auto ASTIntTy = getContext().IntTy; + auto ASTLongLongTy = getContext().LongLongTy; + auto MyIntTy = getTypes().ConvertTypeForMem(ASTIntTy); + + auto GetTagForType = + [&](const FunctionDecl::PPMMParam& g) -> llvm::Value* { + if (g.PVD->PPExtIsGenAsSpecIdType()) { + return llvm::Constant::getNullValue(MyIntTy); + } + auto genName = std::string("__pp_tag_") + + g.RD->getNameAsString(); + StringRef StrRefTagsName(genName); + auto *GV = getModule().getGlobalVariable(genName); + auto MyAlignment = getContext().getAlignOfGlobalVarInChars(ASTIntTy); + auto* LoadGV = new llvm::LoadInst(MyIntTy, GV, Twine(), + false, MyAlignment.getAsAlign(), BB); + return LoadGV; + }; + + auto Getter = [&](const FunctionDecl::PPMMParam& g) -> llvm::Value* + { + // If we have a Recorder for Specialization, then + // we take indexes from typenames + // which are mangled in specialized multimethod name + // If we have a default dispatch function, then + // then we take indexes from multimethod's arguments + return Gens.IsSpecialization ? + GetTagForType(g) : + GetIdxForGen(g); + }; + + llvm::APInt apint1_32(32, 1); + auto Int1_Number32 = llvm::ConstantInt::get(getLLVMContext(), apint1_32); + llvm::Value* CurIdx = llvm::Constant::getNullValue(Int32Ty); + llvm::Value* TagsProduct = Int1_Number32; + for (auto FuncParam : Gens.ParamsList) { + // Get type tag + auto* TypeTagIdx = Getter(FuncParam); + + // Multiply + auto* Mul = llvm::BinaryOperator::Create( + llvm::BinaryOperator::BinaryOps::Mul, + TypeTagIdx, TagsProduct, "", BB); + + // And Add CurIdx to it + // Now we have valid index for this iteration + CurIdx = llvm::BinaryOperator::CreateAdd( + CurIdx, Mul, "", BB); + + // Get tags number + auto BaseRD = FuncParam.BaseRD ? + FuncParam.BaseRD : + FuncParam.RD; + auto genName = std::string("__pp_tags_") + + BaseRD->getNameAsString(); + auto *TagsCount = getModule().getGlobalVariable(genName); + + // Increment tags number + auto TagsCountAlignment = getContext().getAlignOfGlobalVarInChars(ASTIntTy); + auto* LoadTagsCountRaw = new llvm::LoadInst(MyIntTy, TagsCount, Twine(), + false, TagsCountAlignment.getAsAlign(), BB); + auto* LoadTagsCount = llvm::BinaryOperator::CreateNSWAdd( + LoadTagsCountRaw, Int1_Number32, "Increment", BB); + + // Update TagsProduct to use in next iteration + TagsProduct = llvm::BinaryOperator::Create( + llvm::BinaryOperator::BinaryOps::Mul, + LoadTagsCount, TagsProduct, "", BB); + } + + // Extend index to i64 + auto LongLongTy = getTypes().ConvertTypeForMem(ASTLongLongTy); + auto* CurIdxExt = llvm::CastInst::Create( + llvm::Instruction::CastOps::SExt, + CurIdx, + LongLongTy, + "", BB); + return CurIdxExt; +} + +llvm::Function* +CodeGenModule::ExtractDefaultPPMMImplementation( + llvm::Function* F, + const clang::FunctionDecl* FD) +{ + // Create default handler function + // TODO: Check if multimethod is empty + // and then do not clone it + llvm::ValueToValueMapTy VMap; + llvm::Function *NewFn = llvm::CloneFunction(F, VMap); + NewFn->setName(std::string("__pp_default") + F->getName().str()); + + // Add dispatch + F->deleteBody(); + auto* BB = llvm::BasicBlock::Create( + getLLVMContext(), "entry", F); + + auto Gens = FD->getRecordDeclsGenArgsForPPMM(); + assert(!Gens.ParamsList.empty()); + + llvm::AttributeList PAL; + { + // Add attributes to parameters + llvm::AttrBuilder Attrs(getLLVMContext()); + Attrs.addAttribute(llvm::Attribute::NoUndef); + Attrs.addStackAlignmentAttr(llvm::MaybeAlign(0)); + SmallVector ArgAttrs(1); + ArgAttrs[0] = ArgAttrs[0].addAttributes( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs)); + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + llvm::AttrBuilder RetAttrs(getLLVMContext()); + PAL = llvm::AttributeList::get( + getLLVMContext(), + F->getAttributes().getFnAttrs(), + F->getAttributes().getRetAttrs(), + ArgAttrs); + F->setAttributes(PAL); + } + + auto* TypeTagIdxExt = PPExtGetIndexForMM(&F->getEntryBlock(), Gens); + CreateCallPrintf(BB, + "[PP-EXT] MM TypeTagIdxExt %lld\n", + TypeTagIdxExt); + + auto FName = F->getName(); + auto FnTy = F->getFunctionType(); + auto initArrName = std::string("__pp_mminitarr") + FName.str(); + StringRef initArrNameRef(initArrName); // For debug purpose + auto* InitArr = getModule().getGlobalVariable(initArrName); + auto* FnPtrType = llvm::PointerType::get(FnTy, 0); + if (!InitArr) { + InitArr = new llvm::GlobalVariable(getModule(), + FnPtrType, + false, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + nullptr, initArrName); + InitArr->setAlignment(llvm::MaybeAlign(8)); + InitArr->setDSOLocal(true); + InitArr->setInitializer( + llvm::Constant::getNullValue(FnPtrType)); + +#ifdef PPEXT_DUMP + InitArr->dump(); +#endif + } + + llvm::Value* TypeTagsIdxs[] = {TypeTagIdxExt}; + CreateCallPrintf(BB, + "[PP-EXT] MM InitArr ptr %p\n", + InitArr); + auto* LoadInitArr = new llvm::LoadInst( + FnPtrType, + InitArr, "", BB); + auto* Elem = llvm::GetElementPtrInst::CreateInBounds( + FnPtrType, + LoadInitArr, TypeTagsIdxs, "", BB); + CreateCallPrintf(BB, + "[PP-EXT] MM InitArr elem %p\n", + Elem); + auto LoadElem = new llvm::LoadInst( + FnTy->getPointerTo(), + Elem, "", BB); + CreateCallPrintf(BB, + "[PP-EXT] MM InitArr LoadElem (to be executed): %p\n", + LoadElem); + + SmallVector VecArgs; + for (auto& arg: F->args()) { + VecArgs.push_back(&arg); + } + ArrayRef Args (VecArgs); + auto *CI = llvm::CallInst::Create(FnTy, + LoadElem, Args, "", BB); + CI->setAttributes(PAL); + if (FnTy->getReturnType()->isVoidTy()) { + llvm::ReturnInst::Create(getLLVMContext(), BB); + } + else { + llvm::ReturnInst::Create(getLLVMContext(), CI, BB); + } + + if (NewFn->getBasicBlockList().empty()) { + auto* NewBB = llvm::BasicBlock::Create( + getLLVMContext(), "entry", NewFn); + CreateCallPrintf(NewBB, "[PP-EXT] Default handler executed\n"); + llvm::ReturnInst::Create(getLLVMContext(), NewBB); + } + return NewFn; } void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { @@ -5733,6 +7270,97 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT, return GV; } +llvm::CallInst* +CodeGenModule::CreateCallPrintf(llvm::BasicBlock* BB, + StringRef FormatStr, + llvm::Value* Arg, + CodeGenModule::InsertPrintfPos Pos) +{ + +#ifndef PPEXT_DUMP + return nullptr; +#endif + + StringRef MangledName = "printf"; + llvm::Function *F = getModule().getFunction(MangledName); + if (!F) { + auto* IntType = llvm::Type::getInt32Ty(getLLVMContext()); + auto* PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); + auto* StrType = llvm::PointerType::get(PointeeType, 0); + SmallVector ArgTypes(1); + ArgTypes[0] = StrType; + auto* FTy = llvm::FunctionType::get(IntType, + ArgTypes, true); + F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, + MangledName, &getModule()); + } + + llvm::AttrBuilder FuncAttrs(getLLVMContext()); + llvm::AttrBuilder RetAttrs(getLLVMContext()); + getDefaultFunctionAttributes(MangledName, false, false, FuncAttrs); + std::vector Features; + Features = getTarget().getTargetOpts().Features; + FuncAttrs.addAttribute("target-cpu", "x86-64"); + FuncAttrs.addAttribute("tune-cpu", "generic"); + llvm::sort(Features); + FuncAttrs.addAttribute("target-features", llvm::join(Features, ",")); + llvm::AttrBuilder Attrs(getLLVMContext()); + Attrs.addAttribute(llvm::Attribute::NoUndef); + Attrs.addStackAlignmentAttr(llvm::MaybeAlign(0)); + SmallVector ArgAttrs(1); + ArgAttrs[0] = ArgAttrs[0].addAttributes( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), Attrs)); + llvm::AttributeList PAL; + PAL = llvm::AttributeList::get( + getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs), + llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs); + F->setAttributes(PAL); + F->setCallingConv(static_cast(0)); + F->setDSOLocal(false); + + SmallString<64> Str(FormatStr); + auto NewSize = FormatStr.size(); + Str.resize(NewSize + 1); + auto* C = llvm::ConstantDataArray::getString( + getLLVMContext(), + Str, + false + ); + auto* GV = GenerateStringLiteral( + C, + llvm::GlobalValue::LinkageTypes::PrivateLinkage, + *this, + "SomeStrName", + CharUnits::One() + ); + + SmallVector BundleListBundleList; + SmallVector IRCallArgs(Arg ? 2 : 1); + IRCallArgs[0] = GV; + if (Arg) IRCallArgs[1] = Arg; + + llvm::CallInst* CI = nullptr; + if (Pos == InsertPrintfPos::BeforeFirstInstr) { + assert(not BB->getInstList().empty()); + auto* I = &*BB->getInstList().begin(); + CI = llvm::CallInst::Create(F->getFunctionType(), + F, IRCallArgs, "call_printf", I); + } + else if (Pos == InsertPrintfPos::BeforeRet) { + auto* I = &BB->getInstList().back(); + CI = llvm::CallInst::Create(F->getFunctionType(), + F, IRCallArgs, "call_printf", I); + } + else { + CI = llvm::CallInst::Create(F->getFunctionType(), + F, IRCallArgs, "call_printf", BB); + } + + CI->setAttributes(PAL); + + return CI; +} + /// GetAddrOfConstantStringFromLiteral - Return a pointer to a /// constant array for the given string literal. ConstantAddress diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 5fbcc5ad1f5fe..e841381dff6a7 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1290,6 +1290,11 @@ class CodeGenModule : public CodeGenTypeCache { F->setLinkage(getFunctionLinkage(GD)); } + // PP-EXT + // TODO: Use one method instead of 2 + void adjustPPLinkage(llvm::Function* F); + void adjustPPLinkage(llvm::GlobalVariable* GV); + /// Return the appropriate linkage for the vtable, VTT, and type information /// of the given class. llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD); @@ -1565,6 +1570,46 @@ class CodeGenModule : public CodeGenTypeCache { void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); + // PP-Extension + clang::Type* PPExtGetTypeByName(StringRef TypeNameExtracted); + void HandlePPExtensionMethods(llvm::Function* F, GlobalDecl GD); + void PPExtInitGlobVar(llvm::GlobalVariable* GV); + void PPExtInitStackAllocatedVars(llvm::Function* F); + + template + void PPExtInitGenOrSpec(TInsertPoint* IPoint, StringRef Name, llvm::Value* ParentObject); + void PPExtRecordCreateSpec(llvm::Function* FnCreateSpec, RecordDecl* RDSpec, llvm::Module& Parent); + + void AddPPSpecialization(llvm::Function* F, + const FunctionDecl::MMParams& Gens); + void PPExtInitCreateSpecArray(StringRef GenName, llvm::Module& Parent); + llvm::Function* PPExtCreateMMRecorder(llvm::Function* BaseF); + llvm::Function* ExtractDefaultPPMMImplementation(llvm::Function* F, + const clang::FunctionDecl* FD); + llvm::Value* PPExtGetIndexForMM(llvm::BasicBlock* BB, + const FunctionDecl::MMParams& Gens); + + template + void PPExtInitTypeTagsRecursively(StringRef NameOfVariable, + llvm::Value* PtrToObjForGEP, + TInsertPoint* IPoint); + + llvm::BasicBlock* + InitPPHandlersArray(llvm::BasicBlock* BB, + llvm::Value* AllocatedBytes, + llvm::Value* HandlersArray, + llvm::Value* DefaultHandler); + enum class InsertPrintfPos { + Default, + BeforeFirstInstr, + BeforeRet + }; + llvm::CallInst* CreateCallPrintf( + llvm::BasicBlock* BB, + StringRef FormatStr, + llvm::Value* Arg = nullptr, + InsertPrintfPos Pos = InsertPrintfPos::Default); + void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); void EmitExternalVarDeclaration(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index a4cff403e739c..95cd1dd4041f5 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -4205,11 +4205,15 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) { break; case '@': - // Objective C support. - if (CurPtr[-1] == '@' && LangOpts.ObjC) - Kind = tok::at; - else - Kind = tok::unknown; + { + const bool IsPPExt = true; // TODO: Add it to LangOpts + // Objective C support. + if (CurPtr[-1] == '@' && + (LangOpts.ObjC || IsPPExt)) + Kind = tok::at; + else + Kind = tok::unknown; + } break; // UCNs (C99 6.4.3, C++11 [lex.charset]p2) diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index 5fca029a42668..e2be6d34f2b8d 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -165,6 +165,21 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { // skipping something. if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) return; + + for (auto Elem : P.m_PPTypedefs) { + Consumer->HandleTopLevelDecl(Elem.get()); + } + P.m_PPTypedefs.clear(); + + for (auto Elem : P.m_PPGlobalVars) { + Consumer->HandleTopLevelDecl(Elem.get()); + } + P.m_PPGlobalVars.clear(); + + for (auto Elem : P.m_PPCtors) { + Consumer->HandleTopLevelDecl(Elem.get()); + } + P.m_PPCtors.clear(); } } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index aef9909a7c971..214ad3ed204b8 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -13,11 +13,13 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/Expr.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -25,6 +27,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" @@ -2099,16 +2102,25 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); } + + // TODO PP-EXT: Pass this variable to + // Parser::ParseFunctionDefinition + const bool IsPPExtMMDefaultEq0 = + (Tok.is(tok::equal) && + D.getIdentifier() && + D.getIdentifier()->getName().startswith("__pp_mm_")); + // Look at the next token to make sure that this isn't a function // declaration. We have to check this because __attribute__ might be the // start of a function definition in GCC-extended K&R C. - if (!isDeclarationAfterDeclarator()) { + if (!isDeclarationAfterDeclarator() || IsPPExtMMDefaultEq0) { // Function definitions are only allowed at file scope and in C++ classes. // The C++ inline method definition case is handled elsewhere, so we only // need to handle the file scope definition case. if (Context == DeclaratorContext::File) { - if (isStartOfFunctionDefinition(D)) { + if (isStartOfFunctionDefinition(D) + || IsPPExtMMDefaultEq0) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(Tok, diag::err_function_declared_typedef); @@ -2183,8 +2195,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); - if (FirstDecl) + if (FirstDecl) { DeclsInGroup.push_back(FirstDecl); + } bool ExpectSemi = Context != DeclaratorContext::ForInit; @@ -3191,7 +3204,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); - switch (Tok.getKind()) { + bool PPEXTUsesTypedef = IsInPPMultimethod && Tok.is(tok::identifier); + auto TokKind = PPEXTUsesTypedef ? tok::kw_struct : Tok.getKind(); + switch (TokKind) { default: DoneWithDeclSpec: if (!AttrsLastTime) @@ -3472,6 +3487,40 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___super: case tok::kw_decltype: case tok::identifier: { + if (Tok.is(tok::identifier)) { + if (PP.LookAhead(0).is(tok::plus) && + PP.LookAhead(1).is(tok::less)) { + // PP-EXT: Parse extension like: Figure + < Circle; > + // PP-EXT TODO: Check if Tok is typedef to generalization + // e.g. check existance of __pp_spec_type field + auto Kind = tok::kw_struct; + ParsedAttributes Attributes(AttrFactory); + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, + EnteringContext, DSContext, Attributes); + continue; + } + else if (PP.LookAhead(0).is(tok::period) && + PP.LookAhead(1).is(tok::identifier)) { + // Check if it is a specializatoin + auto TokIdentName = Tok.getIdentifierInfo()->getName(); + auto* IdentRDecl = PPExtGetTypeByName(TokIdentName); + if (IdentRDecl) { + auto RDType = PPExtGetStructType(IdentRDecl); + if (RDType == PPStructType::Generalization) { + ParsedAttributes Attributes(AttrFactory); + ConsumeToken(); + auto* II = PPExtGetIdForExistingOrNewlyCreatedGen( + TokIdentName, Attributes, false, true).second; + Tok.setIdentifierInfo(II); + auto Kind = tok::kw_struct; + ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, + EnteringContext, DSContext, Attributes); + continue; + } + } + } + } + // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. @@ -4133,7 +4182,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); + if (PPEXTUsesTypedef) { + Kind = tok::kw_struct; + } + else { + ConsumeToken(); + } // These are attributes following class specifiers. // To produce better diagnostic, we parse them when @@ -4413,6 +4467,747 @@ void Parser::ParseStructDeclaration( } } +static std::string GetMangledName(const std::string& Base, const std::string& Variant) { + return std::string("__pp_struct_") + + Base + "__" + + Variant; +} + +static std::string GetVariantName(Parser& P, std::string CurTokName, const Token& NextTok) { + if (!P.getCurToken().isOneOf(tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_float, + tok::kw_char)) { + llvm_unreachable("pp-ext-expected-token-identifier"); + return ""; + } + + bool IsPtr = false; + auto TokKind = NextTok.getKind(); + if (NextTok.is(tok::star)) { + IsPtr = true; + P.ConsumeAnyToken(); + TokKind = P.NextToken().getKind(); + } + + std::string MangledName; + switch (TokKind) + { + case tok::semi: + case tok::greater: + case tok::colon: + case tok::comma: + if (IsPtr) { + CurTokName += "_pp_ptr"; + } + return CurTokName; + break; + case tok::less: + P.ConsumeToken(); // gen identifier + P.ConsumeToken(); // less + MangledName = GetMangledName(CurTokName, GetVariantName(P, CurTokName, P.NextToken())); + P.ConsumeToken(); // variant identifier + return MangledName; + default: + llvm_unreachable("pp-ext-error-name"); + break; + } + return ""; +} + +void Parser::FieldGenerator(const char* FieldName, + DeclSpec::TST FieldType, + Decl *TagDecl, + RecordDecl* RD, + SmallVector& FieldDecls, + const ParsedAttributes& Attrs, + bool IsPointer) +{ + // TODO PPEXT: Combine with other Parser::FieldGenerator method + // assert(false && + // "Check where is it used, and why we have two FieldGenerator"); + ParsingDeclSpec DS(*this); + auto Policy = Actions.getPrintingPolicy(); + auto Loc = Tok.getLocation(); + unsigned int DiagID = 0; + const char *PrevSpec = nullptr; + if (FieldType != DeclSpec::TST::TST_struct) { + bool isInvalid = DS.SetTypeSpecType(FieldType, Loc, PrevSpec, DiagID, Policy); + assert(!isInvalid); + } + else { + bool isInvalid = DS.SetTypeSpecType(FieldType, Loc, Loc, PrevSpec, DiagID, RD, false, Policy); + assert(!isInvalid); + } + ParsingFieldDeclarator DeclaratorInfo(*this, DS, Attrs); + SourceLocation CommaLoc; + DeclaratorInfo.D.setCommaLoc(CommaLoc); + auto ID = PP.getIdentifierInfo(FieldName); + DeclaratorInfo.D.SetIdentifier(ID, Loc); + DeclaratorInfo.D.SetRangeBegin(Loc); + DeclaratorInfo.D.SetRangeEnd(Loc); + if (IsPointer) { + DeclaratorInfo.D.AddTypeInfo( + DeclaratorChunk::getPointer( + DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), + DS.getVolatileSpecLoc(), DS.getRestrictSpecLoc(), + DS.getAtomicSpecLoc(), DS.getUnalignedSpecLoc()), + std::move(DS.getAttributes()), SourceLocation()); + } + Decl *Field = + Actions.ActOnField(getCurScope(), TagDecl, + DeclaratorInfo.D.getDeclSpec().getSourceRange().getBegin(), + DeclaratorInfo.D, + DeclaratorInfo.BitfieldSize); + FieldDecls.push_back(Field); + DeclaratorInfo.complete(Field); +} + +void Parser::AddStmts(StmtVector& Stmts, + PPFuncMode Mode, + std::string StrVarName, + PPMangledNames& ppMNames) +{ + if (Mode == PPFuncMode::Increment) { + IdentifierInfo* II = &PP.getIdentifierTable().get(StrVarName); + UnqualifiedId VarName; + VarName.setIdentifier(II, SourceLocation()); + DeclarationNameInfo DNI; + DNI.setName(VarName.Identifier); + LookupResult R(Actions, DNI, + Sema::LookupOrdinaryName); + getActions().LookupName(R, getCurScope(), true); + auto* D = cast(R.getFoundDecl()); + auto* Res = DeclRefExpr::Create(getActions().Context, + NestedNameSpecifierLoc(), SourceLocation(), + D, + false, + R.getLookupNameInfo(), + D->getType(), + clang::VK_LValue, + D); + getActions().MarkDeclRefReferenced(Res); + + auto ResPreInc = UnaryOperator::Create(getActions().Context, Res, clang::UO_PreInc, + Res->getType(), clang::VK_PRValue, clang::OK_Ordinary, + SourceLocation(), false, Actions.CurFPFeatureOverrides()); + + Stmts.push_back(ResPreInc); + } + else if (Mode == PPFuncMode::Init) { + StmtVector IfStmts; + IdentifierInfo* II = + &PP.getIdentifierTable().get(ppMNames.BaseIncFuncName); + LookupResult Result(getActions(), II, SourceLocation(), + clang::Sema::LookupOrdinaryName); + CXXScopeSpec CSS; + getActions().LookupParsedName(Result, getCurScope(), &CSS, true); + Decl* D = Result.getFoundDecl(); + ValueDecl* VD = cast(D); + auto& Actions = getActions(); + auto& NameInfo = Result.getLookupNameInfo(); + auto Ty = VD->getType(); + auto TmpLoc = SourceLocation(); + NestedNameSpecifierLoc NNS; + + DeclRefExpr *E = DeclRefExpr::Create( + Actions.Context, NNS, + TmpLoc, VD, false, NameInfo, Ty, + clang::VK_PRValue, VD); + Actions.MarkDeclRefReferenced(E); + Parser::ExprVector ArgExprs; + Expr* NullExpr = nullptr; + ExprResult CallExpr = Actions.ActOnCallExpr(getCurScope(), E, SourceLocation(), ArgExprs, + SourceLocation(), NullExpr); + IfStmts.push_back(CallExpr.get()); + + { + DeclRefExpr* LHSRes, *RHSRes; + + // TODO: Reuse code for LHS and RHS + { // LHS + IdentifierInfo* II = &PP.getIdentifierTable().get(StrVarName); + UnqualifiedId VarName; + VarName.setIdentifier(II, SourceLocation()); + DeclarationNameInfo DNI; + DNI.setName(VarName.Identifier); + LookupResult R(Actions, DNI, + Sema::LookupOrdinaryName); + getActions().LookupName(R, getCurScope(), true); + auto* D = cast(R.getFoundDecl()); + LHSRes = DeclRefExpr::Create(getActions().Context, + NestedNameSpecifierLoc(), SourceLocation(), + D, + false, + R.getLookupNameInfo(), + D->getType(), + clang::VK_LValue, + D); + getActions().MarkDeclRefReferenced(LHSRes); + } // LHS + + { // RHS + IdentifierInfo* II = &PP.getIdentifierTable().get(ppMNames.BaseTagVariableName); + UnqualifiedId VarName; + VarName.setIdentifier(II, SourceLocation()); + DeclarationNameInfo DNI; + DNI.setName(VarName.Identifier); + LookupResult R(Actions, DNI, + Sema::LookupOrdinaryName); + getActions().LookupName(R, getCurScope(), true); + auto* D = cast(R.getFoundDecl()); + RHSRes = DeclRefExpr::Create(getActions().Context, + NestedNameSpecifierLoc(), SourceLocation(), + D, + false, + R.getLookupNameInfo(), + D->getType(), + clang::VK_LValue, + D); + getActions().MarkDeclRefReferenced(RHSRes); + } // RHS + + auto AssignmentExprOp = Actions.ActOnBinOp( + getCurScope(), + SourceLocation(), + clang::tok::equal, + LHSRes, RHSRes + ); + + IfStmts.push_back(AssignmentExprOp.get()); + + { + // Create If Stmt + // Condition + { // LHS + IdentifierInfo* II = &PP.getIdentifierTable().get(StrVarName); + UnqualifiedId VarName; + VarName.setIdentifier(II, SourceLocation()); + DeclarationNameInfo DNI; + DNI.setName(VarName.Identifier); + LookupResult R(Actions, DNI, + Sema::LookupOrdinaryName); + getActions().LookupName(R, getCurScope(), true); + auto* D = cast(R.getFoundDecl()); + LHSRes = DeclRefExpr::Create(getActions().Context, + NestedNameSpecifierLoc(), SourceLocation(), + D, + false, + R.getLookupNameInfo(), + D->getType(), + clang::VK_LValue, + D); + getActions().MarkDeclRefReferenced(LHSRes); + + // RHS + // llvm::APInt ZeroInt(32, 0); + Expr* ZeroIntExpr = IntegerLiteral::Create(Actions.Context, + llvm::APInt(32, 0), Actions.Context.IntTy, SourceLocation()); + + // Conditions + SourceLocation Loc; + ExprResult ComparisonExprRes = Actions.ActOnBinOp(getCurScope(), Loc, + clang::tok::equalequal, LHSRes, ZeroIntExpr); + + Sema::ConditionResult Cond = Actions.ActOnCondition(getCurScope(), + Loc, ComparisonExprRes.get(), clang::Sema::ConditionKind::Boolean, false); + + // Statements + StmtResult InitStmt, ThenStmt, ElseStmt; + +#ifdef PPEXT_DUMP + fprintf(stderr, "!!! IfStmts size %d\n", (int)IfStmts.size()); +#endif + + ThenStmt = Actions.ActOnCompoundStmt(Loc, Loc, IfStmts, false); + + StmtResult IfBody = Actions.ActOnIfStmt(Loc, clang::IfStatementKind::Ordinary, + Loc, InitStmt.get(), Cond, Loc, ThenStmt.get(), Loc, ElseStmt.get()); + Stmts.push_back(IfBody.get()); + } + } + } + } +} + + +Optional Parser::TryParsePPExt(Decl *TagDecl, + SmallVector& FieldDecls) { + if (Tok.isNot(clang::tok::less)) { + return {}; + } + + auto DeclGenerator = [&](std::string BaseName, + std::string VarName, + bool IsPtr) { + Parser::SpecsDescr Res; + Res.VariantName = BaseName; + Res.FullNameIInfo = &PP.getIdentifierTable().get(VarName); + Res.IsPtr = IsPtr; + return Res; + }; + +#ifdef PPEXT_DUMP + printf("\n[PPMC] Parse extension\n"); +#endif + + ConsumeAnyToken(); + auto* RD = cast(TagDecl); + const auto GenName = RD->getDeclName().getAsString(); + SpecsVec Result; + while (Tok.isNot(clang::tok::greater)) { + +#ifdef PPEXT_DUMP + printf(" Token -> Kind: [%s]", Tok.getName()); +#endif + if (Tok.isOneOf(tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_float, + tok::kw_char)) { + auto TokName = Tok.getIdentifierInfo()->getName().str(); + SmallVector Names; + do { + auto Name = GetVariantName(*this, + GetMangledName(GenName, TokName), + NextToken()); + Names.push_back(Name); + if (NextToken().isNot(tok::comma)) { + break; + } + ConsumeToken(); + ConsumeToken(); + assert(Tok.isOneOf(tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_float, + tok::kw_char)); + TokName = Tok.getIdentifierInfo()->getName().str(); + } while(true); + +#ifdef PPEXT_DUMP + printf(", Name:[%s]", TokName.c_str()); +#endif + + bool IsPtr = false; + + if (NextToken().is(tok::colon)) { + ConsumeToken(); + ConsumeToken(); + assert(Tok.isOneOf(tok::identifier, + tok::kw_void, + tok::kw_int, + tok::kw_double, + tok::kw_float, + tok::kw_char)); + + TokName = Tok.getIdentifierInfo()->getName().str(); + if (NextToken().is(tok::star)) { + IsPtr = true; + ConsumeToken(); + } + } + + for (auto& Name : Names) { + auto D = DeclGenerator(TokName, Name, IsPtr); + Result.push_back(D); + } + } + +#ifdef PPEXT_DUMP + printf("\n"); +#endif + + ConsumeAnyToken(); + } +#ifdef PPEXT_DUMP + printf("[PPMC] Finish parse extension\n\n"); +#endif + ConsumeAnyToken(); + + ParsedAttributes FieldAttrs(AttrFactory); + FieldGenerator("__pp_specialization_type", + DeclSpec::TST_int, TagDecl, + nullptr, + FieldDecls, + FieldAttrs, + false); + + return Result; +} + +void Parser::PPExtAddAlign8Attr(ParsedAttributes &Attrs) +{ + auto* II = &PP.getIdentifierTable().get("aligned"); + ArgsVector ArgExprs; + StringRef TokSpelling = "8"; + clang::NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), + PP.getSourceManager(), PP.getLangOpts(), + PP.getTargetInfo(), PP.getDiagnostics()); + llvm::APInt PriorityValue(64, 0); + Literal.GetIntegerValue(PriorityValue); + PriorityValue = PriorityValue.trunc(32); + QualType Ty = Actions.Context.IntTy; + auto* Expr = IntegerLiteral::Create(Actions.Context, PriorityValue, Ty, SourceLocation()); + ArgExprs.push_back(Expr); + + Attrs.addNew(II,SourceRange(), nullptr, SourceLocation(), + ArgExprs.data(), ArgExprs.size(), + ParsedAttr::Syntax::AS_GNU); +} + +void Parser::AddFunc(std::string FuncName, + PPFuncMode Mode, + std::string TagNameToInit, + PPMangledNames& ppMNames, + DeclSpec::TST ReturnType, + SmallVector *ParamInfo) +{ + ParsingDeclSpec DS(*this); + unsigned DiagID = 0; + const char *PrevSpec = nullptr; + PrintingPolicy Policy = Actions.getPrintingPolicy(); + DS.SetTypeSpecType(ReturnType, SourceLocation(), PrevSpec, + DiagID, Policy); + + ParsedAttributes& Attrs = DS.getAttributes(); + // --- Attr --- + ArgsVector ArgExprs; + IdentifierInfo* AttrName = &PP.getIdentifierTable().get("constructor"); + bool isCtor = (Mode == PPFuncMode::Init); + if (isCtor) { + StringRef TokSpelling = "101"; + clang::NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), + PP.getSourceManager(), PP.getLangOpts(), + PP.getTargetInfo(), PP.getDiagnostics()); + llvm::APInt PriorityValue(64, 0); + Literal.GetIntegerValue(PriorityValue); + PriorityValue = PriorityValue.trunc(32); + QualType Ty = Actions.Context.IntTy; + auto* Expr = IntegerLiteral::Create(Actions.Context, PriorityValue, Ty, SourceLocation()); + ArgExprs.push_back(Expr); + } + + IdentifierInfo* ScopeId = nullptr; + + DS.Finish(Actions, Policy); + + ParsedAttributes LocalAttrs(AttrFactory); + DeclaratorContext Context = DeclaratorContext::File; + ParsingDeclarator D(*this, DS, LocalAttrs, Context); + + DeclSpec DSPtr(AttrFactory); + const bool IsCreateSpec = (Mode == PPFuncMode::CreateSpec); + if (IsCreateSpec) { + DSPtr.Finish(Actions, Actions.getASTContext().getPrintingPolicy()); + D.ExtendWithDeclSpec(DSPtr); + } + + auto FuncNameIdentifier = &PP.getIdentifierTable().get(FuncName); + D.SetIdentifier(FuncNameIdentifier, SourceLocation()); + D.SetRangeEnd(SourceLocation()); + Actions.ActOnStartFunctionDeclarationDeclarator(D, 0); + { + bool HasProto = false; + bool IsAmbiguous = false; + bool RefQualifierIsLValueRef = true; + SourceLocation LParenLoc, EllipsisLoc, + RParenLoc, RefQualifierLoc, StartLoc, + LocalEndLoc, EndLoc; + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + SmallVector DynamicExceptions; + SmallVector DynamicExceptionRanges; + ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens = nullptr; + SmallVector DeclsInPrototype; + TypeResult TrailingReturnType; + SourceLocation TrailingReturnTypeLoc; + ParsedAttributes FnAttrs(AttrFactory); + SmallVector TmpParamInfo; + if (ParamInfo == nullptr) { + ParamInfo = &TmpParamInfo; + } + DeclaratorChunk DCh = DeclaratorChunk::getFunction( + HasProto, IsAmbiguous, LParenLoc, ParamInfo->data(), + ParamInfo->size(), EllipsisLoc, RParenLoc, + RefQualifierIsLValueRef, RefQualifierLoc, + /*MutableLoc=*/SourceLocation(), + ESpecType, ESpecRange, DynamicExceptions.data(), + DynamicExceptionRanges.data(), DynamicExceptions.size(), + NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, + ExceptionSpecTokens, DeclsInPrototype, StartLoc, + LocalEndLoc, D, TrailingReturnType, TrailingReturnTypeLoc, + &DS); + D.AddTypeInfo(DCh, std::move(FnAttrs), EndLoc); + + if (isCtor) { + Attrs.addNew(AttrName, SourceRange(), ScopeId, SourceLocation(), + ArgExprs.data(), ArgExprs.size(), clang::AttributeCommonInfo::AS_GNU); + } + + Actions.ActOnFinishFunctionDeclarationDeclarator(D); + + if (IsCreateSpec) { + SourceLocation Loc = Tok.getLocation(); + D.AddTypeInfo( + DeclaratorChunk::getPointer( + DSPtr.getTypeQualifiers(), Loc, DSPtr.getConstSpecLoc(), + DSPtr.getVolatileSpecLoc(), DSPtr.getRestrictSpecLoc(), + DSPtr.getAtomicSpecLoc(), DSPtr.getUnalignedSpecLoc()), + std::move(DSPtr.getAttributes()), SourceLocation()); + } + + Sema::SkipBodyInfo SkipBody; + Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other; + ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); + + Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D, + MultiTemplateParamsArg(), + &SkipBody, BodyKind); + D.complete(Res); + D.getMutableDeclSpec().abort(); + + // ParseCompoundStatementBody + StmtVector Stmts; + SourceLocation CloseLoc; + bool isStmtExpr = false; + StmtResult FnBody; + Actions.ActOnStartOfCompoundStmt(false); + if (Mode != PPFuncMode::CreateSpec) { + AddStmts(Stmts, Mode, TagNameToInit, ppMNames); + Sema::CompoundScopeRAII CompoundScope(Actions, isStmtExpr); + Actions.ActOnAfterCompoundStatementLeadingPragmas(); + Sema::FPFeaturesStateRAII SaveFPFeatures(Actions); + FnBody = Actions.ActOnCompoundStmt(SourceLocation(), CloseLoc, + Stmts, isStmtExpr); + } + // ParseDeclGroup + BodyScope.Exit(); + Decl *TheDecl = Actions.ActOnFinishFunctionBody(Res, FnBody.get()); + m_PPCtors.push_back(Actions.ConvertDeclToDeclGroup(TheDecl)); + } +} + +void Parser::FieldGenerator(const char* FieldName, + DeclSpec::TST FieldType, + RecordDecl* RD, + bool IsPointer, + const ParsedAttributes& TestAttrs, + Decl *TestDecl, + SmallVector& FieldDecls) +{ + if (FieldType == DeclSpec::TST::TST_void + && !IsPointer) { + return; + } + + ParsingDeclSpec DS(*this); + auto Policy = Actions.getPrintingPolicy(); + auto Loc = Tok.getLocation(); + unsigned int DiagID = 0; + const char *PrevSpec = nullptr; + if (FieldType != DeclSpec::TST::TST_struct) { + bool isInvalid = DS.SetTypeSpecType(FieldType, Loc, PrevSpec, DiagID, Policy); + assert(!isInvalid); + } + else { + bool isInvalid = DS.SetTypeSpecType(FieldType, Loc, Loc, PrevSpec, DiagID, RD, false, Policy); + assert(!isInvalid); + } + ParsingFieldDeclarator DeclaratorInfo(*this, DS, TestAttrs); + SourceLocation CommaLoc; + DeclaratorInfo.D.setCommaLoc(CommaLoc); + auto ID = PP.getIdentifierInfo(FieldName); + DeclaratorInfo.D.SetIdentifier(ID, Loc); + DeclaratorInfo.D.SetRangeBegin(Loc); + DeclaratorInfo.D.SetRangeEnd(Loc); + if (IsPointer) { + DeclaratorInfo.D.AddTypeInfo( + DeclaratorChunk::getPointer( + DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), + DS.getVolatileSpecLoc(), DS.getRestrictSpecLoc(), + DS.getAtomicSpecLoc(), DS.getUnalignedSpecLoc()), + std::move(DS.getAttributes()), SourceLocation()); + } + Decl *Field = + Actions.ActOnField(getCurScope(), TestDecl, + DeclaratorInfo.D.getDeclSpec().getSourceRange().getBegin(), + DeclaratorInfo.D, + DeclaratorInfo.BitfieldSize); + FieldDecls.push_back(Field); + DeclaratorInfo.complete(Field); +} + +void Parser::PPMangledNames::setBaseName(std::string BaseName) +{ + BaseStructName = "__pp_struct_" + BaseName; + BaseTagVariableName = "__pp_tags_" + BaseName; + BaseCtorName = "__pp_ctor_" + BaseName; + BaseIncFuncName = "__pp_inc_tags_" + BaseName; +} + +void Parser::PPMangledNames::addVariantName(std::string VariantName) +{ + VariantStructNames.emplace_back( + PPMangledNames::PPVariant{ + VariantName, + "__pp_init_" + VariantName, + "__pp_tag_" + VariantName, + "create_spec" + VariantName} + ); +} + +void Parser::PPMangledNames::setMMName(std::string Name) +{ + MMName = std::move(Name); + auto PrefixSize = sizeof("__pp_mm_"); + assert(MMName.size() > PrefixSize); + std::string BaseName = MMName.substr(PrefixSize); + MMArrayName = std::string("__pp_mminitarr_") + BaseName; +} + +__attribute__((noinline)) +void Parser::PPMangledNames::dump() { +#ifdef PPEXT_DUMP + fprintf(stderr, "=== ppmnames ===\n" + "BaseStructName = %s\n" + "BaseTagVariableName = %s\n" + "BaseCtorName = %s\n" + "BaseIncFuncName = %s\n" + "VariantStructNames size: %d\n", + BaseStructName.c_str(), + BaseTagVariableName.c_str(), + BaseCtorName.c_str(), + BaseIncFuncName.c_str(), + (int)VariantStructNames.size()); + int i = 0; + for (auto& V : VariantStructNames) { + fprintf(stderr, " [%d] " + "VariantName: %s\n VariantTagVariableName: %s\n", + i++, V.VariantName.c_str(), V.VariantTagVariableName.c_str()); + } + fprintf(stderr, "=== ppmnames end dump ===\n"); +#endif +} + +void Parser::dumpPPNames(PPMangledNames& p) { + p.dump(); +} + +Sema::DeclGroupPtrTy Parser::VarGenerate(std::string TypeVarName, + bool IsPointer, + std::string TypeNameStr) +{ + SourceLocation Loc; + const char* Null = nullptr; + unsigned int DiagID = 0; + auto PrintPolicy = Actions.getPrintingPolicy(); + ParsingDeclSpec DS(*this); + const bool IsTypedef = (not TypeNameStr.empty()); + if (IsTypedef) { + auto TypeIdentifier = &PP.getIdentifierTable().get(TypeNameStr); + LookupResult Result(Actions, + TypeIdentifier, + SourceLocation(), + clang::Sema::LookupOrdinaryName); + Actions.LookupName(Result, getCurScope()); + assert(Result.getResultKind() == LookupResult::Found); + NamedDecl* IIDecl = Result.getFoundDecl(); + TypeDecl* TD = dyn_cast(IIDecl); + auto T = Actions.Context.getTypeDeclType(TD); + Actions.MarkAnyDeclReferenced(Tok.getLocation(), TD, false); + ParsedType TypeRep = ParsedType::make(T); + //--- + // All Above can be replaced with + // Note 1 + // --- + DS.SetTypeSpecType(TST_typename, Loc, Null, DiagID, TypeRep, PrintPolicy); + DS.SetRangeEnd(Tok.getLocation()); + } + else { + DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Null, + DiagID, PrintPolicy); + } + DS.Finish(Actions, PrintPolicy); + + ParsedAttributes attrs(AttrFactory); + ParsingDeclarator D(*this, + DS, attrs, DeclaratorContext::File); + auto VarIdentifier = &PP.getIdentifierTable().get(TypeVarName); + D.SetIdentifier(VarIdentifier, Loc); + if (IsPointer) { + D.AddTypeInfo( + DeclaratorChunk::getPointer( + DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), + DS.getVolatileSpecLoc(), DS.getRestrictSpecLoc(), + DS.getAtomicSpecLoc(), DS.getUnalignedSpecLoc()), + std::move(DS.getAttributes()), Loc + ); + } + Decl* ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + Actions.ActOnUninitializedDecl(ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); + D.complete(ThisDecl); + SmallVector DeclsInGroup; + DeclsInGroup.push_back(ThisDecl); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); +} + +Sema::DeclGroupPtrTy Parser::TypedefGenerate(std::string TypeVarName, + DeclSpec::TST ReturnTypeSpecifier, + SmallVector& ParamInfo) +{ + ParsingDeclSpec DS(*this); + SourceLocation TokLoc = Tok.getLocation(); + const char* TmpNull = nullptr; + unsigned int DiagID = 0; + auto PPolicy = Actions.getPrintingPolicy(); + DS.SetStorageClassSpec(Actions, + DeclSpec::SCS_typedef, + TokLoc, TmpNull, DiagID, PPolicy); + DS.SetRangeEnd(TokLoc); + DS.SetTypeSpecType(ReturnTypeSpecifier, TokLoc, TmpNull, DiagID, PPolicy); + DS.Finish(Actions, PPolicy); + ParsedAttributes LocalAttrs(AttrFactory); + auto Ctx = DeclaratorContext::File; + ParsingDeclarator D(*this, DS, LocalAttrs, Ctx); + D.SetRangeBegin(TokLoc); + D.SetRangeEnd(TokLoc); + auto VarIdentifier = &PP.getIdentifierTable().get(TypeVarName); + D.SetIdentifier(VarIdentifier, TokLoc); + D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), TokLoc, TokLoc, + TokLoc, TokLoc, TokLoc, TokLoc), TokLoc); + D.AddTypeInfo(DeclaratorChunk::getParen(TokLoc, TokLoc), std::move(LocalAttrs), TokLoc); + D.setGroupingParens(false); + + ParsedAttributes PPattr(AttrFactory); + clang::ParsedType ExceptionTmpEmpty; + clang::SourceRange RangeEmpty; + llvm::ArrayRef ArrayEmpty; + clang::TypeResult TRes(false); + + D.AddTypeInfo(DeclaratorChunk::getFunction(true, false, TokLoc, ParamInfo.data(), ParamInfo.size(), + SourceLocation(), TokLoc, true, SourceLocation(), TokLoc, clang::EST_None, SourceRange(), &ExceptionTmpEmpty, + &RangeEmpty, 0, nullptr, nullptr, ArrayEmpty, SourceLocation(), SourceLocation(), D, TRes, + SourceLocation(), &DS), std::move(PPattr), TokLoc); + + auto* ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + +#ifdef PPEXT_DUMP + ThisDecl->dump(); +#endif + + Actions.ActOnUninitializedDecl(ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); + D.complete(ThisDecl); + SmallVector DeclsInGroup; + DeclsInGroup.push_back(ThisDecl); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); +} + /// ParseStructUnionBody /// struct-contents: /// struct-declaration-list @@ -4537,10 +5332,139 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SmallVector FieldDecls(TagDecl->fields()); + Optional PPExtSpecs = TryParsePPExt(TagDecl, FieldDecls); + if (PPExtSpecs) { + PPExtAddAlign8Attr(attrs); + } + Actions.ActOnFields(getCurScope(), RecordLoc, TagDecl, FieldDecls, T.getOpenLocation(), T.getCloseLocation(), attrs); StructScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, T.getRange()); + + if (PPExtSpecs) { + +#ifdef PPEXT_DUMP + TagDecl->dump(); +#endif + + PPMangledNames ppMNames; + + ppMNames.setBaseName(TagDecl->getNameAsString()); + + m_PPGlobalVars.push_back(VarGenerate(ppMNames.BaseTagVariableName)); + + AddFunc(ppMNames.BaseCtorName, PPFuncMode::Ctor, "", ppMNames); + AddFunc(ppMNames.BaseIncFuncName, PPFuncMode::Increment, + ppMNames.BaseTagVariableName, ppMNames); + + // TODO: Merge with next loop + for (auto S : *PPExtSpecs) { + std::string VarName = std::string("__pp_tag_") + + S.FullNameIInfo->getName().str(); + m_PPGlobalVars.push_back(VarGenerate(VarName)); + } + + AddFunc("create_spec" + TagDecl->getNameAsString(), + PPFuncMode::CreateSpec, + ppMNames.BaseStructName, ppMNames); + + for (auto S : *PPExtSpecs) { + Sema::SkipBodyInfo TestSkipBody; + CXXScopeSpec TestSS; + MultiTemplateParamsArg TestTParams; + bool TestOwned = true; + bool TestIsDependent = false; + auto TestLocation = TagDecl->getLocation(); + ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); + ParsedAttributes TestAttrs(AttrFactory); + const bool IsVariantVoid = (S.VariantName == "void"); + auto VariantNameIdentifier = (IsVariantVoid ? + nullptr : &PP.getIdentifierTable().get(S.VariantName)); +#ifdef PPEXT_DUMP + printf("[] Test name: %s, Variant Name: %s\n", S.FullNameIInfo->getNameStart(), S.VariantName.c_str()); +#endif + ppMNames.addVariantName(S.FullNameIInfo->getName().str()); + ParsingDeclSpec PDS(*this); + assert((!IsVariantVoid && VariantNameIdentifier) || + (IsVariantVoid && !VariantNameIdentifier)); + auto VariantDecl = IsVariantVoid ? + nullptr : + Actions.ActOnTag(getCurScope(), clang::TST_struct, clang::Sema::TUK_Reference, + TestLocation, TestSS, VariantNameIdentifier, TestLocation, TestAttrs, clang::AS_none, TestLocation, + TestTParams, TestOwned, TestIsDependent, SourceLocation(), false, clang::TypeResult(), + false, false, &TestSkipBody); + auto TestDecl = Actions.ActOnTag(getCurScope(), clang::TST_struct, clang::Sema::TUK_Definition, + TestLocation, TestSS, S.FullNameIInfo, TestLocation, TestAttrs, clang::AS_none, TestLocation, + TestTParams, TestOwned, TestIsDependent, SourceLocation(), false, clang::TypeResult(), + false, false, &TestSkipBody); + Actions.ActOnTagStartDefinition(getCurScope(), TestDecl); + + FieldGenerator("__pp_head", DeclSpec::TST_struct, TagDecl, false, + TestAttrs, TestDecl, FieldDecls); + if (!IsVariantVoid) { + assert(VariantDecl); + auto VariantRecordDecl = cast(VariantDecl); + + // If there is a specialization like Figure var; then + // then it has "_pp_ptr" in the end (to distiguish it from Figure var;) + // In other case, if there is a tagged specialization, like Figure var; + // where some_tag has an pointer underlying type (e.g. Figure {} ) + // then full name does not have "_pp_ptr" in the end (it is not needed), + // instead Parser::SpecsDescr::IsPtr has this information + const bool IsPtr = + (S.FullNameIInfo->getName().endswith("_pp_ptr") || S.IsPtr); + + auto GetTST = [](StringRef VarName) { + auto Result = DeclSpec::TST::TST_struct; + if (VarName.equals("int")) { + Result = DeclSpec::TST::TST_int; + } + else if (VarName.equals("double")) { + Result = DeclSpec::TST::TST_double; + } + else if (VarName.equals("float")) { + Result = DeclSpec::TST::TST_float; + } + else if (VarName.equals("char")) { + Result = DeclSpec::TST::TST_char; + } + + return Result; + }; + + FieldGenerator("__pp_tail", + GetTST(VariantRecordDecl->getName()), + VariantRecordDecl, + IsPtr, TestAttrs, TestDecl, FieldDecls); + } + + SmallVector TestFieldDecls(cast(TestDecl)->fields()); + Actions.ActOnFields(getCurScope(), RecordLoc, TestDecl, TestFieldDecls, + SourceLocation(), SourceLocation(), attrs); + + StructScope.Exit(); + Actions.ActOnTagFinishDefinition(getCurScope(), TestDecl, SourceRange()); + unsigned DiagID; + const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); + const char *PrevSpec = nullptr; + PDS.SetTypeSpecType( + DeclSpec::TST_struct, SourceLocation(), SourceLocation(), PrevSpec, + DiagID, TestDecl, true, Policy); + +#ifdef PPEXT_DUMP + TestDecl->dump(); +#endif + + auto& V = ppMNames.VariantStructNames.back(); + AddFunc(V.VariantCreateSpecFuncName, + PPFuncMode::CreateSpec, + V.VariantTagVariableName, ppMNames); + AddFunc(V.VariantInitFuncName, + PPFuncMode::Init, + V.VariantTagVariableName, ppMNames); + } + } } /// ParseEnumSpecifier @@ -5652,6 +6576,18 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { return IsConstructor; } +void Parser::FinalizePPArgsParsing() +{ + IsInPPMultimethod = false; + ConsumeToken(); + assert(Tok.is(tok::l_paren)); + if (NextToken().is(tok::r_paren)) { + ConsumeAnyToken(); + } else { + Tok.setKind(tok::comma); + } +} + /// ParseTypeQualifierListOpt /// type-qualifier-list: [C99 6.7.5] /// type-qualifier @@ -5677,6 +6613,10 @@ void Parser::ParseTypeQualifierListOpt( SourceLocation EndLoc; + if (Tok.is(tok::greater)) { + FinalizePPArgsParsing(); + } + while (true) { bool isInvalid = false; const char *PrevSpec = nullptr; @@ -6378,6 +7318,26 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.hasName() && !D.getNumTypeObjects()) MaybeParseCXX11Attributes(D); + if (Tok.is(tok::less)) { + Tok.setKind(tok::l_paren); + IsInPPMultimethod = true; + NumberOfPPSpecilizations = 0; + PPMultimethodNameStr = D.getIdentifier()->getName(); + PPMMDecl = &D; + } + else if (IsInPPMultimethod && Tok.is(tok::greater)) { + auto NumOsSpecStr = std::to_string(NumberOfPPSpecilizations); + auto FNameStr = PPMultimethodNameStr.str(); + PPMultimethodNameStr = ""; + auto FullNameStr = NumOsSpecStr + "_" + FNameStr; + StringRef FuncName = FullNameStr; + SmallVector TmpOut; + StringRef Mangled = Twine("__pp_mm_" + FuncName).toStringRef(TmpOut); + IdentifierInfo* II = &PP.getIdentifierTable().get(Mangled); + PPMMDecl->getName().setIdentifier(II, D.getIdentifierLoc()); + FinalizePPArgsParsing(); + } + while (true) { if (Tok.is(tok::l_paren)) { bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration(); @@ -6822,20 +7782,76 @@ void Parser::ParseFunctionDeclarator(Declarator &D, } } + const bool IsMultimethod = + (D.getName().Identifier && + D.getName().Identifier->getName().startswith("__pp_mm_")); // Collect non-parameter declarations from the prototype if this is a function // declaration. They will be moved into the scope of the function. Only do // this in C and not C++, where the decls will continue to live in the // surrounding context. SmallVector DeclsInPrototype; + bool IsSpecialization = false; + StringRef FuncNameMM = D.getIdentifier()->getName(); + const int SpecNum = + FunctionDecl::getNumOfSpecializationsPPMM(FuncNameMM); + + // PP-EXT: Now it is needed to check if it is a Mono/MultiMethod (MM) + // and if so - if it is a specialized, or default one + // In order to do so, we check all first arguments, which are + // included in <...> brackets (SpecNum count). For default version there are expected + // only generalizations. If there will be specializations, then + // it is a specialized MM and we will add a "__pp_spec" postfix to its name if (getCurScope()->isFunctionDeclarationScope() && !getLangOpts().CPlusPlus) { + int SpecNumIter = SpecNum; for (Decl *D : getCurScope()->decls()) { NamedDecl *ND = dyn_cast(D); + auto PVD = cast(ND); + const bool IsArgInSpecNumCount = (SpecNumIter-- > 0); + if (PVD && IsMultimethod && IsArgInSpecNumCount) { + auto* ID = PVD->getType().getBaseTypeIdentifier(); + // If either type is specialization and it starts with "__pp_struct" + // or it is generalization but ends with ".void" + // then it is an argument for multimethod specialization + const bool startsWithPPStruct = + (ID && ID->getName().startswith("__pp_struct")); + const bool isGenAsSpec = PVD->PPExtIsGenAsSpecIdType(); + // It cannot be both true at the same time + assert(!(startsWithPPStruct && isGenAsSpec)); + if (startsWithPPStruct || isGenAsSpec) + IsSpecialization = true; + } + if (!ND || isa(ND)) continue; + if (IsMultimethod && IsArgInSpecNumCount && + ND->getName().startswith("__pp_struct")) + IsSpecialization = true; DeclsInPrototype.push_back(ND); } } + if (IsSpecialization) { + std::string strMangled = FuncNameMM.str(); + int SpecNumIter = SpecNum; + for(auto& PIn : ParamInfo) { + auto PVD = cast(PIn.Param); + auto typeName = PVD->getType() + .getBaseTypeIdentifier() + ->getName().str(); + const bool IsGenAsSpec = PVD->PPExtIsGenAsSpecIdType(); + // In case of IsGenAsSpec add 0 to the type + // to mark it as a specialized version of generalization + strMangled += (IsGenAsSpec ? "__0" : "") + typeName; + if (--SpecNumIter <= 0) { + break; + } + } + strMangled += std::string("__pp_spec"); + StringRef Mangled(strMangled); + IdentifierInfo* II = &PP.getIdentifierTable().get(Mangled); + D.getName().setIdentifier(II, D.getIdentifierLoc()); + } + // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction( HasProto, IsAmbiguous, LParenLoc, ParamInfo.data(), @@ -6874,7 +7890,7 @@ bool Parser::ParseRefQualifier(bool &RefQualifierIsLValueRef, /// abstract-declarators. bool Parser::isFunctionDeclaratorIdentifierList() { return !getLangOpts().requiresStrictPrototypes() - && Tok.is(tok::identifier) + && Tok.is(tok::identifier) && !IsInPPMultimethod && !TryAltiVecVectorToken() // K&R identifier lists can't have typedefs as identifiers, per C99 // 6.7.5.3p11. @@ -7042,6 +8058,7 @@ void Parser::ParseParameterDeclarationClause( : DeclaratorCtx == DeclaratorContext::LambdaExpr ? DeclaratorContext::LambdaExprParameter : DeclaratorContext::Prototype); + ++NumberOfPPSpecilizations; ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index bf73ddfd10311..55147e1a8fb2c 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1430,6 +1430,318 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { return false; } + +std::string Parser::PPExtConstructGenName( + StringRef BaseName, + NameAndPtr SpecName, + bool AddPrefix) +{ + return (AddPrefix ? std::string("__pp_struct_") : std::string("")) + + BaseName.str() + + std::string("__") + + SpecName.first.str() + + (SpecName.second ? "_pp_ptr" : ""); +} + +std::string Parser::PPExtConstructGenName( + std::vector Names, + ParsedAttributes& PAttrs +) +{ + if (Names.size() < 2) { + assert(false + && "Wrong number of specialization names"); + return ""; + } + + auto GetTypeNameIfTag = [&](std::string PrevName, + std::string NameToCheck) { + auto TypeToCheck = PPExtGetTypeByName(NameToCheck); + if (!TypeToCheck) { + // Create gen name. It should exist + auto GenName = + PPExtConstructGenName(PrevName, {NameToCheck, false}); + auto GenType = PPExtGetTypeByName(GenName); + assert(GenType); + for (auto f: GenType->fields()) { + if (f->getName().equals("__pp_tail")) { + auto S = f->getType().getAsString(); + StringRef SR(S); + SR = SR.split(" ").second; + NameToCheck = SR.str(); + TypeToCheck = PPExtGetTypeByName(SR); + assert(TypeToCheck); + break; + } + } + } + return std::make_pair(NameToCheck, TypeToCheck); + }; + + auto LastIdx = static_cast(Names.size()) - 1; + auto CurBaseName = Names[LastIdx - 1].first.str(); + if (LastIdx > 1) { + // Return type name if + // CurBaseName is a tag + auto P = GetTypeNameIfTag(Names[LastIdx - 2].first.str(), + CurBaseName); + CurBaseName = P.first; + } + std::string ResName = PPExtConstructGenName( + CurBaseName, + Names[LastIdx]); + auto* ResType = PPExtGetTypeByName(ResName); + assert(ResType); + + for (int i = LastIdx - 2; i >= 0; --i) { + auto CurBaseHeadName = Names[i].first; + auto CurBaseHeadType = PPExtGetTypeByName(CurBaseHeadName); + if (i != 0) { + // Return type name ifs + // CurBaseName is a tag + auto P = GetTypeNameIfTag(Names[i - 1].first.str(), + CurBaseHeadName.str()); + CurBaseHeadName = P.first; + CurBaseHeadType = P.second; + } + assert(CurBaseHeadType); + CurBaseName = PPExtConstructGenName(CurBaseHeadName, + Names[i + 1]); + // Construct new type (or get existing one + // if it is already constructed) + auto CurGenName = PPExtConstructGenName( + CurBaseName, + {ResName, false}, + false); + auto CurGenType = PPExtGetTypeByName(CurGenName); + if (!CurGenType) { + assert(CurBaseHeadType); + CurGenType = PPExtCreateGeneralization( + CurGenName, CurBaseHeadType, ResType, + Tok.getLocation(), PAttrs); + assert(CurGenType); + } + ResType = CurGenType; + ResName = CurGenName; + } + + assert(ResType); + return ResName; +} + + +RecordDecl* Parser::PPExtCreateGeneralization( + StringRef Name, + RecordDecl* Head, + RecordDecl* Tail, + SourceLocation Loc, + ParsedAttributes& PAttrs +) { + + Sema::SkipBodyInfo TestSkipBody; + CXXScopeSpec TestSS; + MultiTemplateParamsArg TestTParams; + bool TestOwned = true; + bool TestIsDependent = false; + + ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); + ParsedAttributes Attrs(AttrFactory); + auto BaseNameIdentifier = &PP.getIdentifierTable().get(Name); + + ParsingDeclSpec PDS(*this); + + auto ResultDecl = Actions.ActOnTag(getCurScope(), clang::TST_struct, clang::Sema::TUK_Definition, + Loc, TestSS, BaseNameIdentifier, Loc, Attrs, clang::AS_none, Loc, + TestTParams, TestOwned, TestIsDependent, SourceLocation(), false, clang::TypeResult(), + false, false, &TestSkipBody); + Actions.ActOnTagStartDefinition(getCurScope(), ResultDecl); + + SmallVector FieldDecls; + FieldGenerator("__pp_head", DeclSpec::TST_struct, Head, false, + Attrs, ResultDecl, FieldDecls); + FieldGenerator("__pp_tail", DeclSpec::TST_struct, Tail, false, + Attrs, ResultDecl, FieldDecls); + SmallVector TestFieldDecls(cast(ResultDecl)->fields()); + Actions.ActOnFields(getCurScope(), Loc, ResultDecl, TestFieldDecls, + SourceLocation(), SourceLocation(), PAttrs); + + StructScope.Exit(); + Actions.ActOnTagFinishDefinition(getCurScope(), ResultDecl, SourceRange()); + unsigned DiagID; + const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); + const char *PrevSpec = nullptr; + PDS.SetTypeSpecType( + DeclSpec::TST_struct, SourceLocation(), SourceLocation(), PrevSpec, + DiagID, ResultDecl, true, Policy); + +#ifdef PPEXT_DUMP + ResultDecl->dump(); +#endif + + auto* ResultRecordDecl = cast(ResultDecl); + assert(ResultRecordDecl); + return ResultRecordDecl; +} + +RecordDecl* Parser::PPExtGetTypeByName(StringRef Name) +{ + auto& TypesArr = getActions().getASTContext().getTypes(); + clang::RecordDecl* ResDecl = nullptr; + for (auto* Ty: TypesArr) { + if (Ty->isRecordType() && + Ty->getAsRecordDecl() + ->getName().equals(Name)) { + ResDecl = Ty->getAsRecordDecl(); + break; + } + } + return ResDecl; +} + + +auto Parser::PPExtGetIdForExistingOrNewlyCreatedGen( + StringRef BaseName, + ParsedAttributes& PAttrs, + bool NeedToAddLParen, + bool SaveLastIdent +) -> PPIdDescription +{ + assert(Tok.is(tok::l_paren) || + Tok.is(tok::period)); + ConsumeAnyToken(); + std::vector Names; + auto BaseNameStr = BaseName.str(); + if (!BaseName.empty()) { + if (Tok.is(tok::kw_void)) { + // Meet construction like + // "Generalization.void" + // It is used in multimethods specializations + // to exlicitly set multimethods with + // generalization parameters + BaseNameStr = "0" + BaseNameStr; + BaseName = BaseNameStr; + } + Names.push_back({BaseName, false}); + } + + assert(Tok.isOneOf(tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_float, + tok::kw_char, + tok::kw_void)); + + if (Tok.isOneOf(tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_float, + tok::kw_char)) { + Names.push_back({Tok.getIdentifierInfo()->getName(), false}); + } + + if (!SaveLastIdent && + (Names.size() != 1 || + !NextToken().is(tok::r_paren))) { + ConsumeToken(); + } + + assert(Tok.isOneOf( + tok::r_paren, + tok::identifier, + tok::period, + tok::star)); + + while (Tok.is(tok::period)) { + assert(NextToken().isOneOf( + tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_char + )); + auto IdentTok = NextToken(); + + Names.push_back({IdentTok.getIdentifierInfo()->getName(), false}); + + const bool IsLastIter = + PP.LookAhead(1).isOneOf(tok::r_paren, tok::comma); + + if (!IsLastIter) { + ConsumeToken(); + ConsumeToken(); + } else { + break; + } + } + + assert(Tok.isOneOf( + tok::comma, + tok::identifier, + tok::period, + tok::star, + tok::l_paren, + tok::r_paren)); + + if (NeedToAddLParen && + (Tok.is(tok::comma) || + NextToken().is(tok::r_paren))) { + Tok.setKind(tok::l_paren); + } + + auto MangledName = + Names.size() == 1 ? + Names[0].first.str() : + PPExtConstructGenName(Names, PAttrs); + + PPExtIdentType IdType = PPExtIdentType::Default; + auto& Tbl = PP.getIdentifierTable(); + StringRef MangledNameRef = MangledName; + if (MangledNameRef.startswith("0")) { + // It is an explicit generalization parameter + // like "generalization.void" + MangledNameRef = MangledNameRef.substr(1); + IdType = PPExtIdentType::GenAsSpecForMM; + } + assert(Tbl.find(MangledNameRef) != Tbl.end()); + return {IdType, &PP.getIdentifierTable().get(MangledNameRef)}; +} + + +std::string Parser::PPExtConstructTagName(StringRef GenName) +{ + char PPStructPrefix[] = "__pp_struct_"; + auto Sz = sizeof(PPStructPrefix); + auto NextPos = GenName.find(PPStructPrefix, Sz); + // 'NextPos-2' because there are 4 underscores + return std::string("__pp_tag_") + + GenName.substr(0, NextPos - 2).str(); +} + +DeclSpec::TST Parser::PPExtGetFieldTypeByTokKind(tok::TokenKind TK) +{ + auto Res = DeclSpec::TST::TST_struct; + switch (TK) { + case tok::kw_int: + Res = DeclSpec::TST::TST_int; + break; + case tok::kw_char: + Res = DeclSpec::TST::TST_char; + break; + case tok::kw_double: + Res = DeclSpec::TST::TST_double; + break; + case tok::kw_float: + Res = DeclSpec::TST::TST_float; + break; + case tok::kw_void: + Res = DeclSpec::TST::TST_void; + break; + default: + ; + } + + return Res; +} + /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that @@ -1648,6 +1960,151 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + // PP-EXT + if (Tok.is(tok::plus)) { + ConsumeToken(); + assert(Tok.is(tok::less)); + auto CurLoc = ConsumeToken(); + if (Tok.is(tok::kw_struct)) { + // PP-EXT TODO: If kw_struct is not used, + // then check if identifier is typedef + CurLoc = ConsumeToken(); + } + assert(Tok.isOneOf(tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_char)); + StringRef TagName; + if (NextToken().is(tok::colon)) { + TagName = Tok.getIdentifierInfo()->getName(); + ConsumeToken(); + ConsumeToken(); + assert(Tok.isOneOf(tok::identifier, + tok::kw_void, + tok::kw_int, + tok::kw_char, + tok::kw_double, + tok::kw_float)); + } +#ifdef PPEXT_DUMP + printf("!!! [%s] %s\n", + TagName.data(), + Tok.getIdentifierInfo()->getNameStart()); +#endif + + // Add struct + { + // TODO: Use functions for this functionality + // together with ParseDecl.cpp:5038 +#ifdef PPEXT_DUMP + printf("\n[!!!] TODO: Refactoring: reuse PPCreateGen\n"); +#endif + Sema::SkipBodyInfo TestSkipBody; + CXXScopeSpec TestSS; + MultiTemplateParamsArg TestTParams; + bool TestOwned = true; + bool TestIsDependent = false; + + ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); + ParsedAttributes TestAttrs(AttrFactory); + auto VariantName = Tok.getIdentifierInfo()->getName().str(); + auto VariantNameIdentifier = &PP.getIdentifierTable().get(VariantName); + const bool IsPtr = NextToken().is(tok::star); + auto TestNameStr = std::string("__pp_struct_") + Name->getName().str() + + "__" + + (TagName.empty() ? + VariantName + (IsPtr ? "_pp_ptr" : "") : + TagName.str()); + auto TestName = &PP.getIdentifierTable().get(TestNameStr); + + SmallVector Parts; + auto MainFileID = Actions.getSourceManager().getMainFileID(); + auto FullFileName = Actions.getSourceManager().getFileEntryForID(MainFileID)->getName(); + FullFileName.split(Parts, '/'); + auto ExactFileName = Parts.back(); + Parts.clear(); + ExactFileName.split(Parts, '.'); + auto OnlyFileName = Parts.front().str(); + const bool NeedCtorsDefinitions = true; +#ifdef PPEXT_DUMP + printf("!!! FullFilename:[%s], OnlyFileName:[%s], Name:[%s]\n", + FullFileName.str().c_str(), + OnlyFileName.c_str(), + Name->getName().str().c_str()); + printf("[+] Test name: %s, Variant Name: %s\n", TestName->getNameStart(), VariantName.c_str()); +#endif + auto TestLocation = SourceLocation(); + + PPMangledNames ppMNames; + ppMNames.setBaseName(Name->getName().str()); + ppMNames.addVariantName(TestName->getName().str()); + ParsingDeclSpec PDS(*this); + + auto BaseDecl = Actions.ActOnTag(getCurScope(), clang::TST_struct, clang::Sema::TUK_Reference, + TestLocation, TestSS, Name, TestLocation, TestAttrs, clang::AS_none, TestLocation, + TestTParams, TestOwned, TestIsDependent, SourceLocation(), false, clang::TypeResult(), + false, false, &TestSkipBody); + auto VariantDecl = Actions.ActOnTag(getCurScope(), clang::TST_struct, clang::Sema::TUK_Reference, + TestLocation, TestSS, VariantNameIdentifier, TestLocation, TestAttrs, clang::AS_none, TestLocation, + TestTParams, TestOwned, TestIsDependent, SourceLocation(), false, clang::TypeResult(), + false, false, &TestSkipBody); + auto TestDecl = Actions.ActOnTag(getCurScope(), clang::TST_struct, clang::Sema::TUK_Definition, + TestLocation, TestSS, TestName, TestLocation, TestAttrs, clang::AS_none, TestLocation, + TestTParams, TestOwned, TestIsDependent, SourceLocation(), false, clang::TypeResult(), + false, false, &TestSkipBody); + Actions.ActOnTagStartDefinition(getCurScope(), TestDecl); + + const DeclSpec::TST FieldType = PPExtGetFieldTypeByTokKind(Tok.getKind()); + // TODO PP-EXT: VariantDecl should not be casted to RecordDecl + auto VariantRecordDecl = cast(VariantDecl); + auto BaseRecordDecl = cast(BaseDecl); + SmallVector FieldDecls; + FieldGenerator("__pp_head", DeclSpec::TST_struct, BaseRecordDecl, false, + TestAttrs, TestDecl, FieldDecls); + FieldGenerator("__pp_tail", + FieldType, + VariantRecordDecl, IsPtr, + TestAttrs, TestDecl, FieldDecls); + SmallVector TestFieldDecls(cast(TestDecl)->fields()); + Actions.ActOnFields(getCurScope(), CurLoc, TestDecl, TestFieldDecls, + CurLoc, CurLoc, attrs); + + StructScope.Exit(); + Actions.ActOnTagFinishDefinition(getCurScope(), TestDecl, SourceRange()); + unsigned DiagID; + const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); + const char *PrevSpec = nullptr; + PDS.SetTypeSpecType( + DeclSpec::TST_struct, SourceLocation(), SourceLocation(), PrevSpec, + DiagID, TestDecl, true, Policy); + +#ifdef PPEXT_DUMP + TestDecl->dump(); +#endif + + std::string GVarName = std::string("__pp_tag_") + TestNameStr; + m_PPGlobalVars.push_back(VarGenerate(GVarName)); + + auto& V = ppMNames.VariantStructNames.back(); + if (NeedCtorsDefinitions) { + AddFunc(V.VariantCreateSpecFuncName, + PPFuncMode::CreateSpec, + V.VariantTagVariableName, ppMNames); + AddFunc(V.VariantInitFuncName, + PPFuncMode::Init, + V.VariantTagVariableName, ppMNames); + } + } + ConsumeToken(); + if (Tok.is(tok::star)) { + ConsumeToken(); + } + assert(Tok.is(tok::semi)); + ConsumeToken(); + assert(Tok.is(tok::greater)); + ConsumeToken(); + assert(Tok.is(tok::semi)); + } if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { // The name was supposed to refer to a template, but didn't. // Eat the template argument list and try to continue parsing this as @@ -1662,6 +2119,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } RecoverFromUndeclaredTemplateName( Name, NameLoc, SourceRange(LAngleLoc, RAngleLoc), false); + } else if (Tok.is(tok::period)) { + auto GenId = PPExtGetIdForExistingOrNewlyCreatedGen(Name->getName(), + attrs, + ParenCount == 0); + DS.PPExtSetIdentType(GenId.first); + Name = GenId.second; } } else if (Tok.is(tok::annot_template_id)) { TemplateId = takeTemplateIdAnnotation(Tok); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index a6a946d7f31b1..0c44c2a5f29ad 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/PrettyStackTrace.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" @@ -1041,6 +1042,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant + // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. if (getLangOpts().CPlusPlus) { @@ -1249,6 +1251,146 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, Validator.WantRemainingKeywords = Tok.isNot(tok::r_paren); } Name.setIdentifier(&II, ILoc); + + // Check create_spec + if (Name.Identifier->getName().equals("create_spec") || + Name.Identifier->getName().equals("get_spec_ptr") || + Name.Identifier->getName().equals("get_spec_size") || + Name.Identifier->getName().equals("spec_index_cmp") || + Name.Identifier->getName().equals("init_spec")) { + assert(Tok.is(tok::l_paren) && + "[PP-EXT] Expected l_paren after create_spec & init_spec"); + } + if (Tok.is(tok::l_paren)) { + if (Name.Identifier->getName().equals("create_spec") || + Name.Identifier->getName().equals("get_spec_ptr") || + Name.Identifier->getName().equals("get_spec_size") || + Name.Identifier->getName().equals("spec_index_cmp") || + Name.Identifier->getName().equals("init_spec")) { + + if (Name.Identifier + ->getName().equals("get_spec_size")) { + assert(NextToken().is(tok::identifier)); + const auto Mangled = + Name.Identifier->getName().str() + + NextToken().getIdentifierInfo()->getName().str(); + auto* IIMangled = &PP.getIdentifierTable().get(Mangled); + Name.setIdentifier(IIMangled, ILoc); + // Replace Tok kind to avoid + // balancing parens error in parser + Tok.setKind(tok::comma); + ConsumeToken(); + assert(NextToken().is(tok::r_paren)); + Tok.setKind(tok::l_paren); + } + else if (Name.Identifier + ->getName().equals("spec_index_cmp")) { + auto IdentTok = + PP.LookAhead(0).is(tok::identifier) ? + PP.LookAhead(0) : PP.LookAhead(1); + assert(IdentTok.is(tok::identifier)); + auto* II = IdentTok.getIdentifierInfo(); + LookupResult Result(Actions, II, Tok.getLocation(), + Sema::LookupOrdinaryName); + Actions.LookupName(Result, getCurScope()); + assert(Result.getResultKind() == LookupResult::Found); + auto FD = Result.getFoundDecl(); + assert(FD); + auto VD = cast(FD); + assert(VD); + clang::QualType QTT = VD->getType(); + auto Str = QTT.getAsString(); + StringRef SS(Str); + StringRef SpaceRef(" "); + auto SSPair = SS.split(SpaceRef); + auto StructName = SSPair.second; + if (StructName.equals("*")) { + StructName = SSPair.first; + } + else if (StructName.find(SpaceRef) != StringRef::npos) { + StructName = StructName.split(SpaceRef).first; + } + auto MangledName = "spec_index_cmp" + StructName.str(); + auto IIMangled = &PP.getIdentifierTable().get(MangledName); + Name.setIdentifier(IIMangled, ILoc); + } + else if (Name.Identifier + ->getName().equals("get_spec_ptr")) { + // Replace Tok kind to avoid + // balancing parens error in parser + Tok.setKind(tok::comma); + ConsumeToken(); + assert(Tok.is(tok::identifier)); + const auto Mangled = + Name.Identifier->getName().str() + + Tok.getIdentifierInfo()->getName().str(); + auto* IIMangled = &PP.getIdentifierTable().get(Mangled); + // Tok = IdentTok; + Name.setIdentifier(IIMangled, ILoc); + ConsumeToken(); + assert(Tok.is(tok::comma)); + Tok.setKind(tok::l_paren); + } + else { + ParsedAttributes attrs(AttrFactory); + auto* Id = PPExtGetIdForExistingOrNewlyCreatedGen("", attrs).second; + auto S = Name.Identifier->getName().str() + + Id->getName().str(); + StringRef Mangled(S); + IdentifierInfo* IIMangled = &PP.getIdentifierTable().get(Mangled); + Name.setIdentifier(IIMangled, ILoc); + assert(Tok.is(tok::period) + || Tok.is(tok::l_paren)); + if (!Tok.is(tok::l_paren)) { + ConsumeToken(); + assert(Tok.isOneOf( + tok::identifier, + tok::kw_int, + tok::kw_double, + tok::kw_char + )); + Tok.setKind(tok::l_paren); + } + } + } + } + + // Check if it is a multimethod call + if (Tok.is(tok::less)) { + TemplateArgumentListInfo TALI; + DeclarationNameInfo DNI; + const TemplateArgumentListInfo* SomeInfo = nullptr; + Actions.DecomposeUnqualifiedId(Name, TALI, DNI, SomeInfo); + LookupResult R(Actions, DNI, Sema::LookupAnyName); + if (R.getResultKind() == LookupResult::NotFound) { + auto AheadTok = PP.LookAhead(0); + int count = 1; + for (int i = 0; AheadTok.isNot(tok::greater); ++i) { + if (AheadTok.is(tok::comma)) { + ++count; + } else if (AheadTok.is(tok::semi)) { + count = -1; + break; + } + AheadTok = PP.LookAhead(i); + } + + if (count > 0) { + std::string S("__pp_mm_"); + S += std::to_string(count); + S.push_back('_'); + S += II.getName().str(); + StringRef Mangled(S); + auto& IDTbl = PP.getIdentifierTable(); + + if (IDTbl.find(Mangled) != IDTbl.end()) { + IdentifierInfo* IIMangled = &PP.getIdentifierTable().get(Mangled); + Tok.setIdentifierInfo(IIMangled); + Name.setIdentifier(IIMangled, ILoc); + } + } + } + } Res = Actions.ActOnIdExpression( getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand, &Validator, @@ -1859,10 +2001,90 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; auto SavedType = PreferredType; + bool IsNextVariantField = false; + auto IsGeneralization = [](Expr* E, bool IsNextVariant) { + assert(E); + if (!isa(E) && !isa(E)) + return false; + + if (isa(E) || isa(E)) { + if (auto TypeID = E->getType() + .getCanonicalType() + .getBaseTypeIdentifier()) { + auto TypeName = TypeID->getName(); + return TypeName.startswith("__pp_struct"); + } + return false; + } + + if (isa(E)) { + return IsNextVariant; + } + + return false; + }; + + auto* E = LHS.get(); + bool IsFunction = false; + if (E && isa(E)) { + if (auto X = cast_or_null(E)) { + IsFunction = X->getType().getTypePtr()->isFunctionType(); + } + } + while (true) { + if (IsInPPMM && Tok.is(tok::greater)) { + IsInPPMM = false; + ConsumeToken(); + if (NextToken().is(tok::r_paren)) { + ConsumeAnyToken(); + } + else { + Tok.setKind(tok::comma); + } + } + else if (IsFunction && Tok.is(tok::less)) { + Tok.setKind(tok::l_paren); + IsInPPMM = true; + } // Each iteration relies on preferred type for the whole expression. PreferredType = SavedType; switch (Tok.getKind()) { + case tok::at: + if (!LHS.isInvalid() && IsGeneralization(LHS.get(), IsNextVariantField)) { + IsNextVariantField = false; + Tok.startToken(); + Tok.clearFlag(Token::NeedsCleaning); + Tok.setIdentifierInfo(nullptr); + const char* pp_tail_name = "__pp_tail"; + Tok.setLength(strlen(pp_tail_name)); + Tok.setLocation(SourceLocation()); + Tok.setKind(tok::raw_identifier); + Tok.setRawIdentifierData(pp_tail_name); + + auto* NameId = PP.LookUpIdentifierInfo(Tok); + UnqualifiedId Name; + Name.setIdentifier(NameId, SourceLocation()); + CXXScopeSpec SS; + PreferredType.enterMemAccess(Actions, Tok.getLocation(), LHS.get()); + LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), SourceLocation(), + tok::identifier, SS, SourceLocation(), Name, nullptr); + + switch (NextToken().getKind()) + { + case tok::identifier: + Tok.startToken(); + Tok.clearFlag(Token::NeedsCleaning); + Tok.setIdentifierInfo(nullptr); + Tok.setKind(tok::period); + break; + default: + llvm_unreachable("Wrong token in <...> was met. Expected only identifier or '>'"); + } + + break; // handle next token + } + return LHS; case tok::code_completion: if (InMessageExpression) return LHS; @@ -2112,6 +2334,74 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } case tok::arrow: case tok::period: { + { + Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; + if (IsGeneralization(OrigLHS, IsNextVariantField)) { + // PP-EXT TODO: Handle IsNextVariantField + IsNextVariantField = false; + + auto OldTok = Tok; + const char* pp_field_name = "__pp_head"; + if (NextToken().is(tok::at)) { + ConsumeToken(); + pp_field_name = "__pp_tail"; + } + Tok.startToken(); + Tok.clearFlag(Token::NeedsCleaning); + Tok.setIdentifierInfo(nullptr); + + Tok.setLength(strlen(pp_field_name)); + Tok.setLocation(SourceLocation()); + Tok.setKind(tok::raw_identifier); + Tok.setRawIdentifierData(pp_field_name); + + auto* NameId = PP.LookUpIdentifierInfo(Tok); + UnqualifiedId Name; + Name.setIdentifier(NameId, SourceLocation()); + CXXScopeSpec SS; + PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); + LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), + SourceLocation(), + OldTok.is(tok::period) ? + tok::identifier : + tok::arrow, + SS, SourceLocation(), Name, nullptr); + + auto& NTok = NextToken(); + if (NTok.is(tok::period) + || NTok.is(tok::arrow)) { + ConsumeToken(); + } else { + assert(NTok.isOneOf( + tok::identifier, + tok::semi, + tok::equal, + tok::r_paren, + tok::comma, + tok::minus, + tok::plus, + tok::greater + )); + Tok.setKind(tok::period); + } + + assert(Tok.isOneOf(tok::period, tok::arrow)); + + if (NTok.isOneOf( + tok::plus, + tok::minus, + tok::semi, + tok::equal, + tok::greater, + tok::r_paren, + tok::comma)) { + // Return whole variant part + // var.@ or var->@ + ConsumeToken(); + } + break; + } + } // postfix-expression: p-e '->' template[opt] id-expression // postfix-expression: p-e '.' template[opt] id-expression tok::TokenKind OpKind = Tok.getKind(); @@ -2121,7 +2411,32 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { ParsedType ObjectType; bool MayBePseudoDestructor = false; Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; - + // if (isa(OrigLHS)) { + // if (auto X = cast_or_null(OrigLHS)) { + // auto type = X->getType().getAsString(); + // auto name = X->getNameInfo().getAsString(); + // auto just_type = X->getType().getCanonicalType().getTypePtr()-> + // getAsRecordDecl()->getName().str(); + // printf(">>> T:%s, N:%s, JT:%s\n", + // type.c_str(), // struct __pp_struct_... + // name.c_str(), // b + // just_type.c_str()); // + // // T:struct __pp_struct_Generalization__Base1, + // // N:gb, + // // JT:__pp_struct_Generalization__Base1 + + // // auto* NameId = &PP.getIdentifierTable().get("__pp_head"); + // // UnqualifiedId Name; + // // Name.setIdentifier(NameId, SourceLocation()); + // // PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); + // // LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, + // // OpKind, SS, SourceLocation(), Name, + // // CurParsedObjCImpl ? CurParsedObjCImpl->Dcl + // // : nullptr); + // // break; + // } + // } + PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 9bd89eddb4551..b6942ef39f0b5 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -564,6 +564,12 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, case tok::annot_non_type: { NamedDecl *ND = getNonTypeAnnotation(Tok); SourceLocation Loc = ConsumeAnnotationToken(); + + if (PPExtNextTokIsLParen) { + Tok.setKind(tok::l_paren); + PPExtNextTokIsLParen = false; + } + E = Actions.ActOnNameClassifiedAsNonType(getCurScope(), SS, ND, Loc, Tok); break; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 1f6c74aeae7e0..ca3949149e114 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -18,6 +18,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" @@ -189,7 +190,92 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( return StmtError(); case tok::identifier: { + if (Tok.getIdentifierInfo() + ->getName().equals("get_spec_ptr")) { + const auto IdentTok = Tok; + ConsumeToken(); + assert(Tok.is(tok::l_paren)); + // Replace Tok kind to avoid + // balancing parens error in parser + Tok.setKind(tok::comma); + ConsumeToken(); + assert(Tok.is(tok::identifier)); + const auto Mangled = + IdentTok.getIdentifierInfo()->getName().str() + + Tok.getIdentifierInfo()->getName().str(); + auto* IIMangled = &PP.getIdentifierTable().get(Mangled); + Tok.setIdentifierInfo(IIMangled); + PPExtNextTokIsLParen = true; + } + else if (Tok.getIdentifierInfo() + ->getName().equals("spec_index_cmp")) { + auto IdentTok = + PP.LookAhead(1).is(tok::identifier) ? + PP.LookAhead(1) : PP.LookAhead(2); + assert(IdentTok.is(tok::identifier)); + auto* II = IdentTok.getIdentifierInfo(); + LookupResult Result(Actions, II, Tok.getLocation(), + Sema::LookupOrdinaryName); + Actions.LookupName(Result, getCurScope()); + assert(Result.getResultKind() == LookupResult::Found); + auto FD = Result.getFoundDecl(); + assert(FD); + auto VD = cast(FD); + assert(VD); + clang::QualType QTT = VD->getType(); + auto Str = QTT.getAsString(); + StringRef SS(Str); + auto StructName = SS.split(" ").second; + auto MangledName = "spec_index_cmp" + StructName.str(); + auto IIMangled = &PP.getIdentifierTable().get(MangledName); + Tok.setIdentifierInfo(IIMangled); + } + else if (Tok.getIdentifierInfo() + ->getName().equals("create_spec") || + Tok.getIdentifierInfo() + ->getName().equals("get_spec_size") || + Tok.getIdentifierInfo() + ->getName().equals("init_spec")) { + + const bool IsGSS = Tok.getIdentifierInfo() + ->getName().equals("get_spec_size"); + + auto IdentTok = Tok; + ParsedAttributes Attrs(AttrFactory); + ConsumeToken(); + assert(Tok.is(tok::l_paren)); + + StringRef SuffixName; + if (IsGSS) { + assert(NextToken().is(tok::identifier)); + SuffixName = NextToken().getIdentifierInfo()->getName(); + } + else { + auto* TypeIdent = PPExtGetIdForExistingOrNewlyCreatedGen( + "", + Attrs).second; + SuffixName = TypeIdent->getName(); + } + + auto Mangled = + IdentTok.getIdentifierInfo()->getName().str() + + SuffixName.str(); + IdentifierInfo* IIMangled = &PP.getIdentifierTable().get(Mangled); + if (IIMangled->getName().startswith("init_spec")) { + ConsumeToken(); + } + + Tok = IdentTok; + Tok.setIdentifierInfo(IIMangled); + PPExtNextTokIsLParen = true; + } + Token Next = NextToken(); + + if (PPExtNextTokIsLParen) { + Next.setKind(tok::l_paren); + } + if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // Both C++11 and GNU attributes preceding the label appertain to the // label, so put them in a single list to pass on to @@ -1082,6 +1168,160 @@ StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult); } +Parser::PPStructType +Parser::PPExtGetStructType(const RecordDecl* RD) const +{ + StringRef TagFieldName("__pp_specialization_type"); + for (auto FieldIter = RD->field_begin(); + FieldIter != RD->field_end(); ++FieldIter) { + if (FieldIter->getName().equals(TagFieldName)) { + return PPStructType::Generalization; + } + } + + if (RD->getName().startswith("__pp_struct")) { + return PPStructType::Specialization; + } + + return PPStructType::Default; +} + + +std::vector +Parser::PPExtGetRDListToInit(const RecordDecl* RD) const +{ + std::vector Result; + assert(!RD->field_empty()); + auto HeadElem = *RD->field_begin(); + auto HeadType = HeadElem->getType(); + const RecordDecl* RDHead = HeadType.getCanonicalType().getTypePtr()-> + getAsRecordDecl(); + + if (!RDHead || + !HeadElem->getName().equals("__pp_head")) { + RDHead = RD; + } + + for (auto FieldIter = RDHead->field_begin(); + FieldIter != RDHead->field_end(); ++FieldIter) { + auto FieldType = FieldIter->getType(); + RecordDecl* RDField = FieldType.getCanonicalType().getTypePtr()-> + getAsRecordDecl(); + if (RDField) { + auto StrTy = PPExtGetStructType(RDField); + if (StrTy != PPStructType::Default) { + Result.emplace_back( + PPStructInitDesc{*FieldIter, RDField, StrTy}); + } + } + } + + return Result; +} + + +Parser::PPMemberInitData +Parser::PPExtInitPPStruct(PPStructInitDesc IDesc, Expr* MemberAccess) +{ + auto RDType = PPExtGetStructType(IDesc.RD); + auto TName = IDesc.RD->getName(); + StringRef TagFieldName("__pp_specialization_type"); + assert(RDType != PPStructType::Default); + // Initialize tag + CXXScopeSpec SS; + UnqualifiedId HeadFieldId; + { + // setup field name + IdentifierInfo* Id = &PP.getIdentifierTable().get("__pp_head"); + HeadFieldId.setIdentifier(Id, SourceLocation()); + } + + ExprResult ERes; + if (MemberAccess == nullptr) { + ERes = Actions.ActOnNameClassifiedAsNonType( + getCurScope(), + SS, + IDesc.VD, + SourceLocation(), + NextToken() + ); + } + else { + UnqualifiedId CurStructId; + CurStructId.setIdentifier( + &PP.getIdentifierTable().get(IDesc.VD->getName()), + SourceLocation()); + // Access from head to current struct + ERes = Actions.ActOnMemberAccessExpr(getCurScope(), + MemberAccess, SourceLocation(), + clang::tok::period, + SS, + SourceLocation(), + CurStructId, + nullptr); + } + + const bool isVariant = (PPStructType::Specialization == RDType); + auto HeadField = isVariant ? + Actions.ActOnMemberAccessExpr(getCurScope(), + ERes.get(), SourceLocation(), + clang::tok::period, + SS, + SourceLocation(), + HeadFieldId, + nullptr) + : ERes; + + IdentifierInfo* Id = &PP.getIdentifierTable().get(TagFieldName); + UnqualifiedId TagFieldId; + TagFieldId.setIdentifier(Id, SourceLocation()); + auto TagField = Actions.ActOnMemberAccessExpr(getCurScope(), + HeadField.get(), SourceLocation(), + clang::tok::period, + SS, + SourceLocation(), + TagFieldId, + nullptr); + + Expr* RHSRes; + // Prepare RHS + if (isVariant) { + std::string TagName = PPExtConstructTagName(TName); + IdentifierInfo* II = &PP.getIdentifierTable().get(TagName); + UnqualifiedId VarName; + VarName.setIdentifier(II, SourceLocation()); + DeclarationNameInfo DNI; + DNI.setName(VarName.Identifier); + LookupResult R(Actions, DNI, + Sema::LookupOrdinaryName); + getActions().LookupName(R, getCurScope(), true); + auto* D = cast(R.getFoundDecl()); + auto RHSResDeclRef = DeclRefExpr::Create(getActions().Context, + NestedNameSpecifierLoc(), SourceLocation(), + D, + false, + R.getLookupNameInfo(), + D->getType(), + clang::VK_LValue, + D); + getActions().MarkDeclRefReferenced(RHSResDeclRef); + RHSRes = RHSResDeclRef; + } + else { + RHSRes = Actions.ActOnIntegerConstant(Tok.getLocation(), 0).get(); + } + + ExprResult AssignmentOpExpr = + Actions.ActOnBinOp( + getCurScope(), + SourceLocation(), + clang::tok::equal, + TagField.get(), + RHSRes + ); + return PPMemberInitData{AssignmentOpExpr.get(), HeadField.get()}; +} + /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the /// ActOnCompoundStmt action. This expects the '{' to be the current token, and /// consume the '}' at the end of the block. It does not manipulate the scope @@ -1196,9 +1436,11 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { } } - if (R.isUsable()) + if (R.isUsable()) { Stmts.push_back(R.get()); + } } + // Warn the user that using option `-ffp-eval-method=source` on a // 32-bit target and feature `sse` disabled, or using // `pragma clang fp eval_method=source` and feature `sse` disabled, is not diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index fd044660845be..9e2d594d2a5dd 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1238,9 +1238,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (FTI.isKNRPrototype()) ParseKNRParamDeclarations(D); + const bool IsPPExtMMDefaultEq0 = + (Tok.is(tok::equal) && + D.getIdentifier() && + D.getIdentifier()->getName().startswith("__pp_mm_")); + // We should have either an opening brace or, in a C++ constructor, // we may have a colon. if (Tok.isNot(tok::l_brace) && + !IsPPExtMMDefaultEq0 && (!getLangOpts().CPlusPlus || (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) && Tok.isNot(tok::equal)))) { @@ -1326,7 +1332,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // ActOnStartOfFunctionDef needs to know whether the function is deleted. Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other; SourceLocation KWLoc; - if (TryConsumeToken(tok::equal)) { + if (!IsPPExtMMDefaultEq0 && TryConsumeToken(tok::equal)) { assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); if (TryConsumeToken(tok::kw_delete, KWLoc)) { @@ -1381,6 +1387,19 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // safe because we're always the sole owner. D.getMutableDeclSpec().abort(); + if (IsPPExtMMDefaultEq0) { + ConsumeToken(); + assert(Tok.is(tok::numeric_constant)); + // TODO PP-EXT: Check if it is 0 + ConsumeToken(); + StmtVector Stmts; + StmtResult FnBody = Actions.ActOnCompoundStmt( + Tok.getLocation(), NextToken().getLocation(), Stmts, false); + auto* ResFn = Actions.ActOnFinishFunctionBody( + Res, FnBody.get(), false); + return ResFn; + } + if (BodyKind != Sema::FnBodyKind::Other) { Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind); Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; @@ -1709,6 +1728,9 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { } Token Next = NextToken(); + if (PPExtNextTokIsLParen) { + Next.setKind(tok::l_paren); + } // Look up and classify the identifier. We don't perform any typo-correction // after a scope specifier, because in general we can't recover from typos diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 75ffa8b0a90ab..a586a5806b227 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -881,6 +881,93 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); + if (Result.getResultKind() == + clang::LookupResult::NotFound && + (Name->getName().startswith("create_spec") || + Name->getName().startswith("get_spec_ptr") || + Name->getName().startswith("get_spec_size") || + Name->getName().startswith("spec_index_cmp") || + Name->getName().startswith("init_spec"))) { + const bool IsInitSpec = Name->getName().startswith("init_spec"); + const bool IsGetSpecPtr = Name->getName().startswith("get_spec_ptr"); + const bool IsGetSpecSize = Name->getName().startswith("get_spec_size"); + const bool IsSpecIdxCmp = Name->getName().startswith("spec_index_cmp"); + + auto ResTy = Context.VoidPtrTy; + std::vector ArrTysVec; + if (IsInitSpec) { + ArrTysVec.push_back(Context.VoidPtrTy); + ResTy = Context.VoidTy; + } + else if (IsGetSpecPtr) { + ArrTysVec.push_back(Context.IntTy); + } + else if (IsGetSpecSize) { + ResTy = Context.IntTy; + } + else if (IsSpecIdxCmp) { + ResTy = Context.IntTy; + ArrTysVec.push_back(Context.VoidPtrTy); + ArrTysVec.push_back(Context.VoidPtrTy); + } + ArrayRef ArrTys(ArrTysVec); + + auto FPI = FunctionProtoType::ExtProtoInfo(); + auto QTy = Context.getFunctionType(ResTy,ArrTys, FPI); + + DeclContext *Parent = Context.getTranslationUnitDecl(); + FunctionDecl *NewD = FunctionDecl::Create(Context, Parent, NameLoc, NameLoc, + Name, QTy, + /*TInfo=*/nullptr, SC_Extern, + getCurFPFeatures().isFPConstrained(), + false, QTy->isFunctionProtoType()); + SmallVector Params; + if (IsInitSpec) { + auto tfi = Context.CreateTypeSourceInfo(Context.VoidPtrTy); + ParmVarDecl* PVDecl = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.VoidPtrTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + Params.push_back(PVDecl); + } + else if (IsSpecIdxCmp) { + auto tfi = Context.CreateTypeSourceInfo(Context.VoidPtrTy); + ParmVarDecl* PVDecl1 = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.VoidPtrTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + ParmVarDecl* PVDecl2 = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.VoidPtrTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + Params.push_back(PVDecl1); + Params.push_back(PVDecl2); + } + else if (IsGetSpecPtr) { + auto tfi = Context.CreateTypeSourceInfo(Context.IntTy); + ParmVarDecl* PVDecl = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.IntTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + Params.push_back(PVDecl); + } + + NewD->setParams(Params); + Result.addDecl(NewD); + } + if (SS.isInvalid()) return NameClassification::Error(); @@ -962,7 +1049,20 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, // Perform typo correction to determine if there is another name that is // close to this name. - if (!SecondTry && CCC) { + // PP-EXT TODO: Need to handle this case correctly + // if we have code like + // ``` + // struct Figure {} <>; + // void FigureIn() {} + // void foo() { + // struct Figure *sp; + // FigureIn(); + // } + // ``` + // then if remove `&& !NextToken.is(tok::less)` + // then parser will throw an error with proposal + // to replace FigureIn with Figure + if (!SecondTry && CCC && !NextToken.is(tok::less)) { SecondTry = true; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, @@ -14280,6 +14380,8 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { CheckParameter(Context.getTranslationUnitDecl(), D.getBeginLoc(), D.getIdentifierLoc(), II, parmDeclType, TInfo, SC); + New->PPExtSetIdentType(D.getDeclSpec().PPExtGetIdentType()); + if (D.isInvalidType()) New->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 83081bbf0aa0c..6d782c62ff237 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2543,6 +2543,87 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam) ? LookupObjCImplicitSelfParam : LookupOrdinaryName); + if (R.getResultKind() == + clang::LookupResult::NotFound && + (Name.getAsIdentifierInfo()->getName().startswith("create_spec") || + Name.getAsIdentifierInfo()->getName().startswith("get_spec_ptr") || + Name.getAsIdentifierInfo()->getName().startswith("get_spec_size") || + Name.getAsIdentifierInfo()->getName().startswith("spec_index_cmp") || + Name.getAsIdentifierInfo()->getName().startswith("init_spec"))) { + auto ResTy = Context.VoidPtrTy; + std::vector tmpvec; + const bool IsGetSpecPtr = Name.getAsIdentifierInfo() + ->getName().startswith("get_spec_ptr"); + const bool IsGetSpecSize = Name.getAsIdentifierInfo() + ->getName().startswith("get_spec_size"); + const bool IsSpecIdxCmp = Name.getAsIdentifierInfo() + ->getName().startswith("spec_index_cmp"); + if (IsGetSpecPtr) { + tmpvec.push_back(Context.IntTy); + } + else if (IsGetSpecSize) { + ResTy = Context.IntTy; + } + else if (IsSpecIdxCmp) { + ResTy = Context.IntTy; + tmpvec.push_back(Context.VoidPtrTy); + tmpvec.push_back(Context.VoidPtrTy); + } + ArrayRef ArrTys(tmpvec); + + auto FPI = FunctionProtoType::ExtProtoInfo(); + auto QTy = Context.getFunctionType(ResTy,ArrTys, FPI); + + DeclContext *Parent = Context.getTranslationUnitDecl(); + FunctionDecl *NewD = FunctionDecl::Create(Context, Parent, NameLoc, NameLoc, + Name, QTy, + /*TInfo=*/nullptr, SC_Extern, + getCurFPFeatures().isFPConstrained(), + false, QTy->isFunctionProtoType()); + SmallVector Params; + if (IsGetSpecPtr) { + auto tfi = Context.CreateTypeSourceInfo(Context.VoidPtrTy); + ParmVarDecl* PVDecl = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.IntTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + Params.push_back(PVDecl); + } + else if (IsSpecIdxCmp) { + auto tfi = Context.CreateTypeSourceInfo(Context.VoidPtrTy); + ParmVarDecl* PVDecl1 = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.VoidPtrTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + ParmVarDecl* PVDecl2 = ParmVarDecl::Create(Context, + Context.getTranslationUnitDecl(), + NameLoc, NameLoc, nullptr, + Context.VoidPtrTy, + tfi, + clang::StorageClass::SC_None, + nullptr); + Params.push_back(PVDecl1); + Params.push_back(PVDecl2); + } + NewD->setParams(Params); + // TODO: Remove it + auto X = DeclRefExpr::Create(Context, + NestedNameSpecifierLoc(), SourceLocation(), + NewD, + false, + R.getLookupNameInfo(), + NewD->getType(), + clang::VK_LValue, + NewD); + R.addDecl(X->getDecl()); + } + if (TemplateKWLoc.isValid() || TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the diff --git a/clang/test/CodeGen/Inputs/Figure.c b/clang/test/CodeGen/Inputs/Figure.c new file mode 100644 index 0000000000000..8dd7d64b9b755 --- /dev/null +++ b/clang/test/CodeGen/Inputs/Figure.c @@ -0,0 +1,40 @@ +#include "pp-linked-figure.h" +#include + +void test_create_spec_linkage_from_diff_compilation_units_2() { + struct Figure.Circle* fc = create_spec(Figure.Circle); +} + +void printCircle() +{ + struct Figure.Circle fc; + fc.@r = 42; + fc.color = 0xffffffff; + + printf("FigCircle: %d %u\n", fc.@r, fc.color); + printf("Circle tags check: [%d]\n", + (int)(fc.__pp_specialization_type == __pp_tag___pp_struct_Figure__Circle)); +} + +void printRectangle() +{ + struct Figure.Rectangle fr; + fr.@w = 5; + fr.@h = 7; + fr.color = 0x000000ff; + + printf("FigRect: %d %d %u\n", fr.@w, fr.@h, fr.color); + printf("Rectangle tags check: [%d]\n", + (int)(fr.__pp_specialization_type == __pp_tag___pp_struct_Figure__Rectangle)); +} + +void PrintFigure() +{ + printf("PrintFigure Default body\n"); +} + +void PrintFigure() { + struct Figure.Rectangle r = *p; + printf(">>> Rectangle: color = %d, w = %d, h = %d\n", + r.color, r.@w, r.@h); +} diff --git a/clang/test/CodeGen/Inputs/Triangle.c b/clang/test/CodeGen/Inputs/Triangle.c new file mode 100644 index 0000000000000..166dcece9f478 --- /dev/null +++ b/clang/test/CodeGen/Inputs/Triangle.c @@ -0,0 +1,21 @@ +#include "pp-linked-triangle.h" +#include + +void printTriangle() +{ + struct Figure.Triangle ft; + ft.@a = 1; + ft.@b = 2; + ft.@c = 3; + ft.color = 0x00000001; + + printf("FigTriangle: %d %d %d %u\n", ft.@a, ft.@b, ft.@c, ft.color); + printf("Triangle tags check: [%d]\n", + (int)(ft.__pp_specialization_type == __pp_tag___pp_struct_Figure__Triangle)); +} + +void PrintFigure() { + struct Figure.Triangle t = *p; + printf(">>> Triangle: color = %d, a = %d, b = %d, c = %d\n", + t.color, t.@a, t.@b, t.@c); +} diff --git a/clang/test/CodeGen/Inputs/pp-linked-figure.h b/clang/test/CodeGen/Inputs/pp-linked-figure.h new file mode 100644 index 0000000000000..a1c408b68031b --- /dev/null +++ b/clang/test/CodeGen/Inputs/pp-linked-figure.h @@ -0,0 +1,11 @@ +#pragma once + +struct Circle { int r; }; +struct Rectangle { int w, h; }; +struct Figure { unsigned color; } < struct Circle; struct Rectangle; >; + +void printRectangle(); +void printCircle(); + + +void PrintFigure(); diff --git a/clang/test/CodeGen/Inputs/pp-linked-triangle.h b/clang/test/CodeGen/Inputs/pp-linked-triangle.h new file mode 100644 index 0000000000000..0960031d2f7af --- /dev/null +++ b/clang/test/CodeGen/Inputs/pp-linked-triangle.h @@ -0,0 +1,8 @@ +#pragma once + +#include "pp-linked-figure.h" + +struct Triangle { int a, b, c; }; +struct Figure + ; + +void printTriangle(); diff --git a/clang/test/CodeGen/Monomethod.c b/clang/test/CodeGen/Monomethod.c new file mode 100644 index 0000000000000..245528d33d228 --- /dev/null +++ b/clang/test/CodeGen/Monomethod.c @@ -0,0 +1,56 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +// {workspace}/build/bin/clang {workspace}/clang/test/CodeGen/Monomethod.c -g -O0 -o {workspace}/clang/test/CodeGen/a1.out +// {workspace}/clang/test/CodeGen/a1.out + +#include + +struct Circle { int r; }; +struct Rectangle { int w, h; }; +struct Figure { int color; } < struct Circle; struct Rectangle; >; + + +struct Triangle { int a, b, c; }; +struct Figure + < struct Triangle; >; + + +void PrintFigure1() +{ + printf(">>> [Default] PrintFigure1 color = %d\n", f->color); +} + +void PrintFigure1 *p>() { + struct Figure c = *p; + printf(">>> Circle: color = %d, r = %d\n", c.color, c); +} + +void PrintFigure1 *p>() { + struct Figure r = *p; + printf(">>> Rectangle: color = %d, h = %d, w = %d\n", + r.color, r, r); +} + + +int main() +{ + struct Figure fc; + fc.color = 111; + fc = 100; + +// CHECK-RT: >>> Circle: color = 111, r = 100 + PrintFigure1<&fc>(); + + struct Figure fr; + fr.color = 555; + fr = 300; + fr = 1000; + +// CHECK-RT: >>> Rectangle: color = 555, h = 300, w = 1000 + PrintFigure1<&fr>(); + + struct Figure ft; + ft.color = -1; + +// CHECK-RT: >>> [Default] PrintFigure1 color = -1 + PrintFigure1<&ft>(); +} diff --git a/clang/test/CodeGen/check_all.py b/clang/test/CodeGen/check_all.py new file mode 100755 index 0000000000000..32a8415325b26 --- /dev/null +++ b/clang/test/CodeGen/check_all.py @@ -0,0 +1,70 @@ +#!/usr/bin/python3 + +import os + +cur_dir = os.getcwd() +bin_dir = "/build/bin/" +path_to_clang = cur_dir + bin_dir + "clang-15" + +if not os.path.isfile(path_to_clang): + print("[ERROR] Clang not found: " + path_to_clang) + exit() + +command_list = [ + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-base.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-init.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-linked.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-tagged-generalization.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-tagged-create_spec.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-mm.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-mm-tag.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-spec-ptr.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-spec-base-types.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-mm-3d.c " + "-v" + , + "./build/bin/llvm-lit " + "clang/test/CodeGen/pp-mm-5d.c " + "-v" +] + +idx = 1 +for cmd in command_list: + print("\n===========") + str_test = "[TEST][" + str(idx) + "]" + idx = idx + 1 + print("***", str_test, "***\nRun command: ", cmd) + retval = os.system(cmd) + if retval != 0: + print("***", str_test, "Error with: ", cmd) + break + else: + print("***", str_test, "OK ***") diff --git a/clang/test/CodeGen/pp-base.c b/clang/test/CodeGen/pp-base.c new file mode 100644 index 0000000000000..fded341a99d4c --- /dev/null +++ b/clang/test/CodeGen/pp-base.c @@ -0,0 +1,347 @@ +// RUN~: %clang -S -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-LOGS +// RUN~: %clang -S -Xclang -ast-dump -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-AST +// RUN~: %clang -S -emit-llvm %s 2>&1 -o - | FileCheck %s -check-prefix=CHECK-IR +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +// CHECK-LOGS: [PPMC] Parse extension +// CHECK-LOGS-NEXT: Token -> Kind: [struct] +// CHECK-LOGS-NEXT: Token -> Kind: [identifier], Name:[Circle] +// CHECK-LOGS-NEXT: Token -> Kind: [semi] +// CHECK-LOGS-NEXT: Token -> Kind: [struct] +// CHECK-LOGS-NEXT: Token -> Kind: [identifier], Name:[Rectangle] +// CHECK-LOGS-NEXT: Token -> Kind: [semi] +// CHECK-LOGS-NEXT: [PPMC] Finish parse extension + +// CHECK-LL: struct Generalization definition +// CHECK-LL: load 'double' +// CHECK-LL: __pp_specialization_type 'int' + +// CHECK-LL: %struct.Base1 = type { i32 } +// CHECK-LL: %struct.Base2 = type { i32 } +// CHECK-LL: %struct.Generalization = type { double, i32 } +// CHECK-LL: %struct.__pp_struct_Generalization__Base1 = type { %struct.Generalization, %struct.Base1 } +// CHECK-LL: %struct.__pp_struct_Generalization__Base2 = type { %struct.Generalization, %struct.Base2 } + +// CHECK-LL: @__pp_tags_Figure = dso_local global i32 0, align 4 +// CHECK-LL: @__pp_tag___pp_struct_Figure__Circle = dso_local global i32 0, align 4 +// CHECK-LL: @__pp_tag___pp_struct_Figure__Rectangle = dso_local global i32 0, align 4 +// CHECK-LL: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @__pp_tag__pp_struct_Figure__Circle, ptr null }, { i32, ptr, ptr } { i32 101, ptr @__pp_tag__pp_struct_Figure__Rectangle, ptr null }] + +// CHECK-LL: double @check_gen_b1(ptr noundef byval(%struct.__pp_struct_Generalization__Base1) align 8 %gb) +// CHECK-LL: double @check_gen_b2(ptr noundef byval(%struct.__pp_struct_Generalization__Base2) align 8 %gb) + +// CHECK-LL: ; Function Attrs: noinline nounwind optnone uwtable +// CHECK-LL: define dso_local void @__pp_tag__pp_struct_Figure__Circle() #0 { +// CHECK-LL: entry: +// CHECK-LL: %0 = load i32, ptr @__pp_tags_Figure, align 4 +// CHECK-LL: %inc = add nsw i32 %0, 1 +// CHECK-LL: store i32 %inc, ptr @__pp_tags_Figure, align 4 +// CHECK-LL: %1 = load i32, ptr @__pp_tags_Figure, align 4 +// CHECK-LL: store i32 %1, ptr @__pp_tag__pp_struct_Figure__Circle, align 4 +// CHECK-LL: ret void +// CHECK-LL: } + +// CHECK-LL: ; Function Attrs: noinline nounwind optnone uwtable +// CHECK-LL: define dso_local void @__pp_tag__pp_struct_Figure__Rectangle() #0 { +// CHECK-LL: entry: +// CHECK-LL: %0 = load i32, ptr @__pp_tags_Figure, align 4 +// CHECK-LL: %inc = add nsw i32 %0, 1 +// CHECK-LL: store i32 %inc, ptr @__pp_tags_Figure, align 4 +// CHECK-LL: %1 = load i32, ptr @__pp_tags_Figure, align 4 +// CHECK-LL: store i32 %1, ptr @__pp_tag__pp_struct_Figure__Rectangle, align 4 +// CHECK-LL: ret void +// CHECK-LL: } + +// CHECK-AST: |-RecordDecl {{.*}} struct Base1 definition +// CHECK-AST-NEXT:| `-FieldDecl {{.*}} i 'int' +// CHECK-AST-NEXT:|-RecordDecl {{.*}} struct Base2 definition +// CHECK-AST-NEXT:| `-FieldDecl {{.*}} j 'int' +// CHECK-AST-NEXT:|-RecordDecl {{.*}} struct Generalization definition +// CHECK-AST-NEXT:| |-FieldDecl {{.*}} referenced load 'double' +// CHECK-AST-NEXT:| `-FieldDecl {{.*}} referenced __pp_specialization_type 'int' +// CHECK-AST-NEXT:|-RecordDecl {{.*}} struct __pp_struct_Generalization__Base1 definition +// CHECK-AST-NEXT:| |-FieldDecl {{.*}} referenced __pp_head 'struct Generalization':'struct Generalization' +// CHECK-AST-NEXT:| `-FieldDecl {{.*}} referenced __pp_tail 'struct Base1':'struct Base1' +// CHECK-AST-NEXT:|-FunctionDecl {{.*}} __pp_ctor__pp_struct_Generalization__Base1 'void ()' +// CHECK-AST-NEXT:| `-CompoundStmt {{.*}} +// CHECK-AST-NEXT:|-RecordDecl {{.*}} struct __pp_struct_Generalization__Base2 definition +// CHECK-AST-NEXT:| |-FieldDecl {{.*}} referenced __pp_head 'struct Generalization':'struct Generalization' +// CHECK-AST-NEXT:| `-FieldDecl {{.*}} referenced __pp_tail 'struct Base2':'struct Base2' +// CHECK-AST-NEXT:|-FunctionDecl {{.*}} __pp_ctor__pp_struct_Generalization__Base2 'void ()' +// CHECK-AST-NEXT:| `-CompoundStmt {{.*}} + + +//--------------------------------------- + +// typedef void(*ftype)(int); +// ftype* my_ptr; + +#include + +typedef struct Circle { int r; } Circle; +typedef struct Rectangle { int w, h; } Rectangle; +struct Figure { unsigned color; } < struct Circle; struct Rectangle; >; + +typedef struct Triangle { int a, b, c; } Triangle; +Figure + < Triangle; >; +Figure + ; + +typedef struct BaseObject { int a; }<> BaseObject; +typedef struct NewObject { int b; } NewObject; +BaseObject + < NewObject; >; +BaseObject + ; +BaseObject + < Circle; >; + +void PrintFigure() { + printf("Default\n"); +} + +void PrintFigure() { + printf("Circle\n"); +} + +void PrintFigure() { + printf("Rectangle\n"); +} + +void PrintFigure() { + printf("Triangle\n"); +} + +// void PrintFigureWithArg(unsigned i); +// void MultiMethod(); +// void MultiMethodWithArgs(unsigned c1, unsigned c2); + +// CHECK-IR: @__pp_mminitarr__pp_mm_PrintFigure = dso_local global [1 x ptr] zeroinitializer, align 8 +// C HECK-IR-NEXT: @__pp_mminitarr__pp_mm_PrintFigureWithArg = dso_local global [1 x ptr] zeroinitializer, align 8 +// C HECK-IR-NEXT: @__pp_mminitarr__pp_mm_MultiMethod = dso_local global [1 x ptr] zeroinitializer, align 8 +// C HECK-IR-NEXT: @__pp_mminitarr__pp_mm_MultiMethodWithArgs = dso_local global [1 x ptr] zeroinitializer, align 8 + +// CHECK-IR: @llvm.global_ctors = +// CHECK-IR: { i32 102, ptr @__pp_alloc__pp_mm_PrintFigure, ptr null } +// C HECK-IR: { i32 102, ptr @__pp_alloc__pp_mm_PrintFigureWithArg, ptr null } +// C HECK-IR: { i32 102, ptr @__pp_alloc__pp_mm_MultiMethod, ptr null } +// C HECK-IR: { i32 102, ptr @__pp_alloc__pp_mm_MultiMethodWithArgs, ptr null } + +// Allocate arrays and generate default handlers +// CHECK-IR: define void @__pp_alloc__pp_mm_PrintFigure(ptr %0) { +// CHECK-IR: @__pp_default__pp_mm_PrintFigure + +void test_type_tag(struct Figure* f) +{ + printf("[foo_test] f->__pp_specialization_type = %d\n", f->__pp_specialization_type); +} + +struct Figure.Circle gfc; + +struct RectangleCover { + struct Figure.Circle fc; + struct Figure.Triangle ft; + Rectangle r; +} <>; + +int main() { + struct Figure f; + // CHECK-RT: [foo_test] f->__pp_specialization_type = 0 + test_type_tag(&f); + + struct RectangleCover rc; + // CHECK-RT: RectangleCover tag: 0 + printf("RectangleCover tag: %d\n", + rc.__pp_specialization_type); + // CHECK-RT: [foo_test] f->__pp_specialization_type = 1 + test_type_tag(&rc.fc); + // CHECK-RT: [foo_test] f->__pp_specialization_type = 3 + test_type_tag(&rc.ft); + + struct Figure.Circle fc; + fc.@r = 42; + fc.color = 0xffffffff; + + // CHECK-RT: [foo_test] f->__pp_specialization_type = 1 + test_type_tag(&gfc); + + // CHECK-RT: [foo_test] f->__pp_specialization_type = 1 + test_type_tag(&fc); + + struct Figure.Rectangle fr; + fr.@w = 5; + fr.@h = 7; + fr.color = 0x000000ff; + + // CHECK-RT: [foo_test] f->__pp_specialization_type = 2 + test_type_tag(&fr); + + struct Figure.Triangle ft; + ft.@a = 1; + ft.@b = 2; + ft.@c = 3; + ft.color = 0x00000001; + + // CHECK-RT: FigCircle: 42 4294967295 + // CHECK-RT-NEXT: FigRect: 5 7 255 + // CHECK-RT-NEXT: FigTriangle: 1 2 3 1 + printf("FigCircle: %d %u\n", fc.@r, fc.color); + printf("FigRect: %d %d %u\n", fr.@w, fr.@h, fr.color); + printf("FigTriangle: %d %d %d %u\n", ft.@a, ft.@b, ft.@c, ft.color); + + // CHECK-IR: call void @__pp_mm_PrintFigure(ptr noundef %fc) + PrintFigure<&fc>(); + // TODO: Restore these invocations after + // it will be fixed + // PrintFigureWithArg<&fc>(42); + // MultiMethod<&fc, &fr>(); + // MultiMethodWithArgs<&fc, &fr>(7, 8); + + // CHECK-RT: Figure tags: 4 + // CHECK-RT-NEXT: Circle tag: 1 + // CHECK-RT-NEXT: Rectangle tag: 2 + // CHECK-RT-NEXT: Triangle tag: 3 + printf("Figure tags: %d\n", __pp_tags_Figure); + printf("Circle tag: %d\n", __pp_tag___pp_struct_Figure__Circle); + printf("Rectangle tag: %d\n", __pp_tag___pp_struct_Figure__Rectangle); + printf("Triangle tag: %d\n", __pp_tag___pp_struct_Figure__Triangle); + + // CHECK-RT-NEXT: get_spec_size = 5 + int numberOfSpecs = get_spec_size(Figure); + printf("get_spec_size = %d\n", numberOfSpecs); + + // CHECK-RT-NEXT: fc.__pp_specialization_type = 1 + // CHECK-RT-NEXT: fr.__pp_specialization_type = 2 + // CHECK-RT-NEXT: ft.__pp_specialization_type = 3 + printf("fc.__pp_specialization_type = %d\n", fc.__pp_specialization_type); + printf("fr.__pp_specialization_type = %d\n", fr.__pp_specialization_type); + printf("ft.__pp_specialization_type = %d\n", ft.__pp_specialization_type); + + struct Figure.Circle fc2; + struct Figure.Rectangle fr2; + struct Figure.Triangle ft2; + + // CHECK-RT-NEXT: fc2.__pp_specialization_type = 1 + // CHECK-RT-NEXT: fr2.__pp_specialization_type = 2 + // CHECK-RT-NEXT: ft2.__pp_specialization_type = 3 + printf("fc2.__pp_specialization_type = %d\n", fc2.__pp_specialization_type); + printf("fr2.__pp_specialization_type = %d\n", fr2.__pp_specialization_type); + printf("ft2.__pp_specialization_type = %d\n", ft2.__pp_specialization_type); + + struct BaseObject.NewObject obj; + obj.a = 101; + obj.@b = 102; + // CHECK-RT-NEXT: BaseObject.NewObject: 101 102 + printf("BaseObject.NewObject: %d %d\n", obj.a, obj.@b); + + struct BaseObject.int obj2; + obj2.@ = 777; + // CHECK-RT-NEXT: BaseObject.int: 777 + printf("BaseObject.int: %d\n", obj2.@); + + struct BaseObject.NewObject* obj3 = malloc(sizeof(struct BaseObject.NewObject)); + init_spec(BaseObject.NewObject, obj3); + // CHECK-RT-NEXT: obj3.__pp_specialization_type = 1 + printf("obj3.__pp_specialization_type = %d\n", obj3->__pp_specialization_type); + + init_spec(BaseObject.Circle, obj3); + // CHECK-RT-NEXT: obj3.__pp_specialization_type = 3 + printf("obj3.__pp_specialization_type = %d\n", obj3->__pp_specialization_type); + + // CHECK-RT-NEXT: fig_spec_count = 5 + int fig_spec_count = get_spec_size(Figure); + printf("fig_spec_count = %d\n", fig_spec_count); + + // CHECK-RT-NEXT: created_ptr->__pp_specialization_type = 0 + // CHECK-RT-NEXT: Default + // CHECK-RT-NEXT: created_ptr->__pp_specialization_type = 1 + // CHECK-RT-NEXT: Circle + // CHECK-RT-NEXT: created_ptr->__pp_specialization_type = 2 + // CHECK-RT-NEXT: Rectangle + // CHECK-RT-NEXT: created_ptr->__pp_specialization_type = 3 + // CHECK-RT-NEXT: Triangle + // Checking empty tag (with void*) + // CHECK-RT-NEXT: created_ptr->__pp_specialization_type = 4 + // CHECK-RT-NEXT: Default + for (int i = 0; i < fig_spec_count; ++i) { + struct Figure* created_ptr = get_spec_ptr(Figure, i); + printf("created_ptr->__pp_specialization_type = %d\n", + created_ptr->__pp_specialization_type); + PrintFigure(); + } + // CHECK-RT-NEXT: created_ptr->__pp_specialization_type = 1 + struct Figure* created_ptr = get_spec_ptr(Figure, 1); + printf("created_ptr->__pp_specialization_type = %d\n", + created_ptr->__pp_specialization_type); + + // CHECK-RT-NEXT: Trian+Trian cmp: 3 + int res_cmp1 = spec_index_cmp(&ft, &ft); + printf("Trian+Trian cmp: %d\n", res_cmp1); + + // CHECK-RT-NEXT: Rect+Rect cmp: 2 + int res_cmp2 = spec_index_cmp(&fr, &fr); + printf("Rect+Rect cmp: %d\n", res_cmp2); + + // CHECK-RT-NEXT: Circ+Circ2 cmp: 1 + int res_cmp3 = spec_index_cmp(&fc, &fc2); + printf("Circ+Circ2 cmp: %d\n", res_cmp3); + + // CHECK-RT-NEXT: Circ+Rect cmp: -1 + int res_cmp4 = spec_index_cmp(&fc, &fr); + printf("Circ+Rect cmp: %d\n", res_cmp4); + + // CHECK-RT-NEXT: Rect+Circ cmp: -1 + res_cmp4 = spec_index_cmp(&fr, &fc); + printf("Rect+Circ cmp: %d\n", res_cmp4); + + // CHECK-RT-NEXT: PtrToCirc+Circ cmp: 1 + res_cmp4 = spec_index_cmp(created_ptr, &fc); + printf("PtrToCirc+Circ cmp: %d\n", res_cmp4); + + // CHECK-RT-NEXT: PtrToCirc+Rect cmp: -1 + res_cmp4 = spec_index_cmp(created_ptr, &fr); + printf("PtrToCirc+Rect cmp: %d\n", res_cmp4); + + // CHECK-RT-NEXT: Checked usage spec_index_cmp in condition + if (spec_index_cmp(&fc, &fc) >= 0) { + printf("Checked usage spec_index_cmp in condition\n"); + } +} + +// This code just checking comilation +// of fields access through +// implicit __head and __tail + +struct NewCircle { int c; }; +struct NewFigure { int f; } < struct NewCircle; >; +NewFigure + < cptr: Circle*; >; + +__attribute__((weak)) +void not_called_bar(int*); + +__attribute__((weak)) +void not_called_bar2(int); + +__attribute__((weak)) +void not_called_cptr(Circle*, int*); + +int not_called_foo() { + struct NewFigure.NewCircle* fc; + struct NewFigure.NewCircle fcstack; + fcstack.@c = 41; + fcstack.f = 71; + fc->@c = 42; + fc->f = 72; + not_called_bar(&(fc->@c)); + not_called_bar(&(fcstack.@c)); + not_called_bar(&(fc->f)); + not_called_bar(&(fcstack.f)); + not_called_bar2(fc->@c); + not_called_bar2(fcstack.@c); + not_called_bar2(fc->f); + not_called_bar2(fcstack.f); + struct NewFigure.cptr* pfcptr = create_spec(NewFigure.cptr); + not_called_cptr(pfcptr->@, 0); + return fc->@c + fcstack.@c + fc->f + fcstack.f; +} + +// Check if casting works as expected +void foo_check_cast(void* ptr) { + struct Figure.Circle* fc = (struct Figure.Circle*)ptr; +} diff --git a/clang/test/CodeGen/pp-init.c b/clang/test/CodeGen/pp-init.c new file mode 100644 index 0000000000000..13b0782787f7a --- /dev/null +++ b/clang/test/CodeGen/pp-init.c @@ -0,0 +1,111 @@ + +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +#include + +typedef struct Circle { int r; } Circle; +typedef struct Rectangle { int w, h; } Rectangle; +struct Figure { + unsigned color; + int additional_workload; + double additional_workload2; + char additional_workload3; +} < struct Circle; struct Rectangle; >; + +typedef struct Triangle { int a, b, c; } Triangle; +Figure + < Triangle; >; + +struct RectangleCover { + struct Figure.Circle fc; + struct Figure.Triangle ft; + Rectangle r; +} <>; + +Figure + < struct RectangleCover; >; + +struct RectangleCover g_rc; +struct Figure g_figure; +struct Figure.Circle g_fc; +struct Figure.RectangleCover g_fig_rect; + +RectangleCover + < Triangle; >; + +struct Figure.RectangleCover.Triangle g_fig_rect_trian; + +int main() { + // CHECK-RT: pf_empty tag = 0 + struct Figure* pf_empty = create_spec(Figure); + printf("pf_empty tag = %d\n", + pf_empty->__pp_specialization_type); + + // CHECK-RT: prc tag = 0 + struct RectangleCover* prc = create_spec(RectangleCover); + printf("prc tag = %d\n", + prc->__pp_specialization_type); + + // CHECK-RT: prc->fc tag = 1 + printf("prc->fc tag = %d\n", + prc->fc.__pp_specialization_type); + + // CHECK-RT: prc->ft tag = 3 + printf("prc->ft tag = %d\n", + prc->ft.__pp_specialization_type); + + + // CHECK-RT: g_rc tag = 0 + printf("g_rc tag = %d\n", + g_rc.__pp_specialization_type); + + // CHECK-RT: g_rc.fc tag = 1 + printf("g_rc.fc tag = %d\n", + g_rc.fc.__pp_specialization_type); + + // CHECK-RT: g_rc.ft tag = 3 + printf("g_rc.ft tag = %d\n", + g_rc.ft.__pp_specialization_type); + + // Just check compilation + init_spec(Figure.Rectangle, &(g_rc.fc)); + // CHECK-RT: g_rc.fc tag = 2 + printf("g_rc.fc tag = %d\n", + g_rc.fc.__pp_specialization_type); + + // CHECK-RT: g_figure tag = 0 + printf("g_figure tag = %d\n", + g_figure.__pp_specialization_type); + + // CHECK-RT: g_fc tag = 1 + printf("g_fc tag = %d\n", + g_fc.__pp_specialization_type); + + // CHECK-RT: g_fig_rect tag = 4 + printf("g_fig_rect tag = %d\n", + g_fig_rect.__pp_specialization_type); + + // CHECK-RT: g_fig_rect_trian.@ tag = 1 + printf("g_fig_rect_trian.@ tag = %d\n", + g_fig_rect_trian.@.__pp_specialization_type); + + // CHECK-RT: g_fig_rect_trian.@.fc tag = 1 + printf("g_fig_rect_trian.@.fc tag = %d\n", + g_fig_rect_trian.@.fc.__pp_specialization_type); + + // TODO: Make it work + // C~HECK-RT: g_fig_rect_trian.@.ft tag = 3 + printf("g_fig_rect_trian.@.ft tag = %d\n", + g_fig_rect_trian.@.ft.__pp_specialization_type); + + struct RectangleCover rc; + // CHECK-RT: rc tag = 0 + printf("rc tag = %d\n", + rc.__pp_specialization_type); + + // CHECK-RT: rc.fc tag = 1 + printf("rc.fc tag = %d\n", + rc.fc.__pp_specialization_type); + + // CHECK-RT: rc.ft tag = 3 + printf("rc.ft tag = %d\n", + rc.ft.__pp_specialization_type); + return 0; +} diff --git a/clang/test/CodeGen/pp-linked.c b/clang/test/CodeGen/pp-linked.c new file mode 100644 index 0000000000000..870c9ef499069 --- /dev/null +++ b/clang/test/CodeGen/pp-linked.c @@ -0,0 +1,149 @@ + +// RUN: %clang -c %S/Inputs/Figure.c -o %S/f.o +// RUN: %clang -c %S/Inputs/Triangle.c -o %S/t.o +// RUN: %clang -c %s -o %S/a.o +// RUN: %clang %S/f.o %S/t.o %S/a.o -o %S/a.out +// RUN: %S/a.out | FileCheck %s -check-prefix=CHECK-RT +// RUN: rm %S/a.out %S/f.o %S/t.o %S/a.o + +#include "Inputs/pp-linked-figure.h" +#include "Inputs/pp-linked-triangle.h" +#include + +void test_create_spec_linkage_from_diff_compilation_units() { + struct Figure.Circle* fc = create_spec(Figure.Circle); +} + +typedef struct Rhombus { int a, b; } Rhombus; +// Check version without struct key word +Figure + < Rhombus; >; + +void PrintFigure() { + struct Figure.Rhombus r = *p; + printf(">>> Rhombus: color = %d, a = %d, b = %d\n", + r.color, r.@a, r.@b); +} + +void PrintFigureWithArg(int i) +{ + printf(">>> PrintFigureWithArg Default Color = %d, Param = %d\n", + f->color, + i); +} + +void PrintFigureWithArg(int i) +{ + struct Figure.Rhombus r = *p; + printf(">>> PrintFigureWithArg Rhombus Color = %d, \ + a = %d, b = %d, Param = %d\n", + r.color, + r.@a, + r.@b, + i); +} + + +struct Simple {} < >; + +struct Decorator { +} < struct Simple; >; + +struct Simple + < struct Decorator;> ; +struct Simple + < struct Circle;> ; + +int main() +{ + struct Simple.Decorator.Simple.Circle sd; + // CHECK-RT: [1 1 2] + printf("[%d %d %d]\n", + sd.__pp_specialization_type, + sd.@.__pp_specialization_type, + sd.@.@.__pp_specialization_type + ); + + sd.@.@.@r = 0; + struct Simple* s_ptr = create_spec(Simple.Decorator.Simple.Circle); + + // TODO: Make it work + // // C~HECK-RT: [1 1 2] + // printf("[%d %d %d]\n", + // s_ptr->__pp_specialization_type, + // s_ptr->@.__pp_specialization_type, + // s_ptr->@.@.__pp_specialization_type + // ); + + // CHECK-RT: FigCircle: 42 4294967295 + // CHECK-RT-NEXT: Circle tags check: [1] + printCircle(); + // CHECK-RT-NEXT: FigRect: 5 7 255 + // CHECK-RT-NEXT: Rectangle tags check: [1] + printRectangle(); + // CHECK-RT-NEXT: FigTriangle: 1 2 3 1 + // CHECK-RT-NEXT: Triangle tags check: [1] + printTriangle(); + + // CHECK-RT: Figure tags: 4 + // CHECK-RT: Circle tag: 1 + // CHECK-RT: Rectangle tag: 2 + // CHECK-RT: Triangle tag: 3 + // CHECK-RT: Rhombus tag: 4 + printf("Figure tags: %d\n", __pp_tags_Figure); + printf("Circle tag: %d\n", __pp_tag___pp_struct_Figure__Circle); + printf("Rectangle tag: %d\n", __pp_tag___pp_struct_Figure__Rectangle); + printf("Triangle tag: %d\n", __pp_tag___pp_struct_Figure__Triangle); + printf("Rhombus tag: %d\n", __pp_tag___pp_struct_Figure__Rhombus); + + struct Figure.Circle fc; + fc.color = 111; + fc.@r = 100; + + // CHECK-RT: PrintFigure Default body + PrintFigure<&fc>(); + + // CHECK-RT: >>> Triangle: color = 555, a = 10, b = 20, c = 30 + struct Figure.Triangle ft; + ft.color = 555; + ft.@a = 10; + ft.@b = 20; + ft.@c = 30; + PrintFigure<&ft>(); + + + // CHECK-RT: >>> Rectangle: color = 333, w = 22, h = 11 + struct Figure.Rectangle fr; + fr.color = 333; + fr.@w = 22; + fr.@h = 11; + PrintFigure<&fr>(); + + // CHECK-RT: >>> Rhombus: color = 999, a = 10000, b = 20000 + struct Figure.Rhombus frh; + frh.color = 999; + frh.@a = 10000; + frh.@b = 20000; + PrintFigure<&frh>(); + + // CHECK-RT: >>> PrintFigureWithArg Default Color = 333, Param = 111 + PrintFigureWithArg<&fr>(111); + + // CHECK-RT: >>> PrintFigureWithArg Rhombus Color = 999, a = 10000, b = 20000, Param = 42 + PrintFigureWithArg<&frh>(42); + + // CHECK-RT: >>> PrintFigureWithArg Rhombus + struct Figure* Ptr = create_spec(Figure.Rhombus); + PrintFigureWithArg(42); + + // Test access to tail part + struct Figure.Circle f_test; + struct Circle cc1 = f_test.@; + f_test.@ = cc1; + struct Circle* ptr_cc1 = &(f_test.@); + ptr_cc1->r = 66; + + struct Figure.Circle* f_ptr = &f_test; + struct Circle cc2 = f_ptr->@; + struct Circle* ptr_cc2 = &(f_ptr->@); + ptr_cc2->r = 55; + + return 0; +} diff --git a/clang/test/CodeGen/pp-mm-3d.c b/clang/test/CodeGen/pp-mm-3d.c new file mode 100644 index 0000000000000..5bc40a89b3f60 --- /dev/null +++ b/clang/test/CodeGen/pp-mm-3d.c @@ -0,0 +1,52 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +typedef struct Circle { int r; } Circle; +struct Figure1D { unsigned color; } < struct Circle; >; + +typedef struct Rectangle { int w, h; } Rectangle; +struct Figure2D { unsigned color; } < struct Circle; struct Rectangle; >; + +typedef struct Triangle { int a, b, c; } Triangle; +struct Figure3D { unsigned color; } < struct Circle; struct Rectangle; struct Triangle; >; + + +void PrintFigures() +{ + printf("default\n"); +} + +void PrintFigures() +{ + printf("circ + rect + trian\n"); +} + +void PrintFigures() +{ + printf("circ + circ + circ\n"); +} + + +int main() { + struct Figure1D.Circle f1c; + + struct Figure2D.Circle f2c; + struct Figure2D.Rectangle f2r; + + struct Figure3D.Circle f3c; + struct Figure3D.Triangle f3t; + + // CHECK-RT: default + PrintFigures<&f1c, &f2c, &f3t>(); + // CHECK-RT: circ + circ + circ + PrintFigures<&f1c, &f2c, &f3c>(); + // CHECK-RT: circ + rect + trian + PrintFigures<&f1c, &f2r, &f3t>(); + + return 0; +} \ No newline at end of file diff --git a/clang/test/CodeGen/pp-mm-5d.c b/clang/test/CodeGen/pp-mm-5d.c new file mode 100644 index 0000000000000..3e5303ea719e0 --- /dev/null +++ b/clang/test/CodeGen/pp-mm-5d.c @@ -0,0 +1,49 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + + +struct Circle {}; +struct Rectangle {}; +struct Figure { +} < struct Circle; struct Rectangle; >; + +struct RGB{}; +struct Format { +} < struct RGB; >; + +struct Builder{}; +struct Officer{}; +struct Doctor{}; +struct Worker { +} < struct Builder; + struct Officer; + struct Doctor; >; + +void Multimethod5() +{ + printf("Def_5\n"); +} + +void Multimethod5() +{ + printf("C-R-D-R-B\n"); +} + +int main() { + struct Figure.Circle fcircle; + struct Format.RGB frgb; + struct Worker.Doctor wdoctor; + struct Worker.Builder wbuilder; + + // CHECK-RT: Def_5 + Multimethod5<&fcircle, &frgb, &wdoctor, &frgb, &wdoctor>(); + // CHECK-RT: C-R-D-R-B + Multimethod5<&fcircle, &frgb, &wdoctor, &frgb, &wbuilder>(); +} diff --git a/clang/test/CodeGen/pp-mm-tag.c b/clang/test/CodeGen/pp-mm-tag.c new file mode 100644 index 0000000000000..4a7a0c107791c --- /dev/null +++ b/clang/test/CodeGen/pp-mm-tag.c @@ -0,0 +1,67 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + + +struct Circle { int c; }; +struct Rect { int h, w; }; +struct Trian { int a, b, c; }; + +struct Figure { int f; } < t0 : Circle; + t1 : Rect; + t2, t3 : Trian >; + +void PrintFigures() +{ + printf("default\n"); +} + + +void PrintFigures() +{ + printf("t0 + t0\n"); +} + +void PrintFigures() +{ + printf("t0 + t1\n"); +} + +void PrintFigures() +{ + printf("t1 + t2\n"); +} + +void PrintFigures() +{ + printf("t2 + t3\n"); +} + +void PrintFigures() +{ + printf("t3 + t0\n"); +} + +int main() { + struct Figure.t0 t0_obj; + struct Figure.t1 t1_obj; + struct Figure.t2 t2_obj; + struct Figure.t3 t3_obj; + + // CHECK-RT: t0 + t0 + PrintFigures<&t0_obj, &t0_obj>(); + // CHECK-RT: default + PrintFigures<&t1_obj, &t1_obj>(); + // CHECK-RT: t0 + t1 + PrintFigures<&t0_obj, &t1_obj>(); + // CHECK-RT: t1 + t2 + PrintFigures<&t1_obj, &t2_obj>(); + // CHECK-RT: t2 + t3 + PrintFigures<&t2_obj, &t3_obj>(); + // CHECK-RT: t3 + t0 + PrintFigures<&t3_obj, &t0_obj>(); +} diff --git a/clang/test/CodeGen/pp-mm.c b/clang/test/CodeGen/pp-mm.c new file mode 100644 index 0000000000000..b39d0efdb4ae3 --- /dev/null +++ b/clang/test/CodeGen/pp-mm.c @@ -0,0 +1,122 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + + +typedef struct Circle { int r; } Circle; +typedef struct Rectangle { int w, h; } Rectangle; +struct Figure { unsigned color; } < struct Circle; struct Rectangle; >; + + +void PrintFigures() +{ + printf("default\n"); +} + + +void PrintFigures() +{ + printf("circ + circ\n"); +} + +void PrintFigures() +{ + printf("rect + rect\n"); +} + +void PrintFigures() +{ + printf("circ + rect\n"); +} + +void PrintFigures() +{ + printf("rect + circ\n"); +} + +void MultimethodFirstRect(Figure.Rectangle* r1, int* ofst) {} + +void MultimethodFirstRect(Figure.Rectangle* r1, int* ofst) { + printf("Rectangle - Rectangle Combination\n"); +} + +void MultimethodFirstRect(Figure.Rectangle* r1, int* ofst) { + printf("Rectangle - Circle Combination\n"); +} + +static +void StaticPrintFigure() +{ + printf("static default\n"); +} + + +static +void StaticPrintFigure() +{ + printf("static circ\n"); +} + + +void CheckGenVoid() +{ + printf("Default\n"); +} + +void CheckGenVoid() +{ + printf("Figure + Circle\n"); +} + +void CheckGenVoid() +{ + printf("Rectangle + Figure\n"); +} + +void CheckGenVoid() +{ + printf("Rectangle + Circle\n"); +} + +int main() { + struct Figure.Circle fc; + struct Figure.Rectangle fr; + // CHECK-RT: circ + circ + PrintFigures<&fc, &fc>(); + // CHECK-RT: circ + rect + PrintFigures<&fc, &fr>(); + // CHECK-RT: rect + circ + PrintFigures<&fr, &fc>(); + // CHECK-RT: rect + rect + PrintFigures<&fr, &fr>(); + + struct Figure plain_f; + // CHECK-RT: Figure + Circle + CheckGenVoid<&plain_f, &fc>(); + // CHECK-RT: Default + CheckGenVoid<&plain_f, &fr>(); + // CHECK-RT: Rectangle + Figure + CheckGenVoid<&fr, &plain_f>(); + // CHECK-RT: Rectangle + Circle + CheckGenVoid<&fr, &fc>(); + // CHECK-RT: Default + CheckGenVoid<&fc, &fr>(); + + struct Figure* fp = get_spec_ptr(Figure, 0); + // CHECK-RT: default + PrintFigures(); + + int dummy = 0; + // CHECK-RT: Rectangle - Rectangle Combination + MultimethodFirstRect<&fr>(&fr, &dummy); + // CHECK-RT: Rectangle - Circle Combination + MultimethodFirstRect<&fc>(&fr, &dummy); + + // CHECK-RT: static default + StaticPrintFigure<&fr>(); + // CHECK-RT: static circ + StaticPrintFigure<&fc>(); +} diff --git a/clang/test/CodeGen/pp-spec-base-types.c b/clang/test/CodeGen/pp-spec-base-types.c new file mode 100644 index 0000000000000..7f9ebf124cf50 --- /dev/null +++ b/clang/test/CodeGen/pp-spec-base-types.c @@ -0,0 +1,130 @@ +// RUN: %clang -c %s -o %S/a.o +// RUN: %clang %S/a.o -o %S/a.out +// RUN: %S/a.out | FileCheck %s -check-prefix=CHECK-RT +// RUN: rm %S/a.out %S/a.o + + + +#include + + +struct Figure { int f; } < int; >; + +typedef struct FigureTag { } + < tag_c : int; > FigureTag; +FigureTag + < fourth_tag : int; >; +FigureTag + < void_tag : void; >; + +struct FigureD { } < double; >; +struct FigureF { } < float; >; +struct FigureC { } < char; >; +struct FigureD2 { } < tag: double; >; +struct FigureF2 { } < tag: float; >; +struct FigureC2 { } < tag: char; >; + +struct FigureFull { } < char; int; double; float; >; +FigureFull + < tag1 : char; >; +FigureFull + < tag2 : int; >; +FigureFull + < tag3 : double; >; +FigureFull + < tag4 : float; >; + +void PrintFF(){ + printf("PrintFF default version\n"); +} + +void PrintFF() { + printf("PrintFF tag1 version\n"); +} + +void PrintFF() { + printf("PrintFF tag2 version\n"); +} + +void Print1(){ + printf("Print1 default version\n"); +} + +void Print1() { + printf("Print1 tagged version\n"); +} + +void Print1() { + printf("Print1 void_tag version\n"); +} + +int main() { + struct Figure.int fc; + fc.@ = 5; + + // CHECK-RT: Field value: 5 + printf("Field value: %d\n", fc.@); + + struct FigureTag.tag_c tfc; + tfc.@ = 7; + + // CHECK-RT: Field value: 7 + printf("Field value: %d\n", tfc.@); + + struct FigureTag.fourth_tag tfc2; + tfc2.@ = 42; + + // CHECK-RT: Field value: 42 + printf("Field value: %d\n", tfc2.@); + + // CHECK-RT: Print1 tagged version + Print1<&tfc>(); + + // CHECK-RT: Print1 default version + Print1<&tfc2>(); + + struct FigureTag.void_tag tfv; + + // CHECK-RT: Print1 void_tag version + Print1<&tfv>(); + + struct FigureD.double fd1; + struct FigureF.float ff1; + struct FigureC.char fc1; + + fd1.@ = 1.0; + ff1.@ = 1.0f; + fc1.@ = 'A'; + + struct FigureD2.tag fd2; + struct FigureF2.tag ff2; + struct FigureC2.tag fc2; + + fd2.@ = 1.0; + ff2.@ = 1.0f; + fc2.@ = 'A'; + + struct FigureFull.int ffi; + struct FigureFull.char ffc; + struct FigureFull.double ffd; + struct FigureFull.float fff; + ffi.@ = 1; + ffc.@ = 'A'; + ffd.@ = 1.0; + fff.@ = 1.0f; + + struct FigureFull.tag1 fft1; + struct FigureFull.tag2 fft2; + struct FigureFull.tag3 fft3; + struct FigureFull.tag4 fft4; + + fft1.@ = ffc.@; + fft2.@ = ffi.@; + fft3.@ = ffd.@; + fft4.@ = fff.@; + + // CHECK-RT: PrintFF tag1 version + PrintFF<&fft1>(); + // CHECK-RT: PrintFF tag2 version + PrintFF<&fft2>(); + // CHECK-RT: PrintFF default version + PrintFF<&fft3>(); + // CHECK-RT: PrintFF default version + PrintFF<&fft4>(); + // CHECK-RT: PrintFF default version + PrintFF<&ffi>(); +} diff --git a/clang/test/CodeGen/pp-spec-ptr.c b/clang/test/CodeGen/pp-spec-ptr.c new file mode 100644 index 0000000000000..15380006a9558 --- /dev/null +++ b/clang/test/CodeGen/pp-spec-ptr.c @@ -0,0 +1,75 @@ +// RUN: %clang -c %s -o %S/a.o +// RUN: %clang %S/a.o -o %S/a.out +// RUN: %S/a.out | FileCheck %s -check-prefix=CHECK-RT +// RUN: rm %S/a.out %S/a.o + + + +#include + + +typedef struct Circle { int r; } Circle; +struct Figure { int f; } < Circle*; >; +struct FigureTag { } < tag_c : Circle*; >; + +typedef struct Rect { int w, h; } Rect; +Figure + ; +FigureTag + ; + +void Print1(){ + printf("Print1 default version\n"); +} + +void Print1() { + printf("Print1 tagged version\n"); +} + +void Print1() { + printf("Print1 r_tag version\n"); +} + +void SimpleFun(struct FigureTag.tag_c* f) { + printf("SimpleFun: %d %d\n", + f->__pp_specialization_type, + f->@->r); +} + + +void SimpleFunR(struct FigureTag.r_tag* f) { + printf("SimpleFunR: %d %d %d\n", + f->__pp_specialization_type, + f->@->w, + f->@->h); +} + +int main() { + struct Circle c; + c.r = 0; + + struct FigureTag.tag_c tfc; + tfc.@ = &c; + tfc.@->r = 7; + + // CHECK-RT: Field value: 7 == 7 + printf("Field value: %d == %d\n", + tfc.@->r, c.r); + + // CHECK-RT: Print1 tagged version + Print1<&tfc>(); + + // CHECK-RT: SimpleFun: 1 7 + SimpleFun(&tfc); + + Rect r; + r.w = 1; + r.h = 2; + struct FigureTag.r_tag tfr; + tfr.@ = &r; + tfr.@->w = 3; + + // CHECK-RT: Print1 r_tag version + Print1<&tfr>(); + + // CHECK-RT: SimpleFunR: 2 3 2 + SimpleFunR(&tfr); +} diff --git a/clang/test/CodeGen/pp-tagged-create_spec.c b/clang/test/CodeGen/pp-tagged-create_spec.c new file mode 100644 index 0000000000000..55661cdc16b7a --- /dev/null +++ b/clang/test/CodeGen/pp-tagged-create_spec.c @@ -0,0 +1,17 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +struct Circle {}; +typedef struct Figure {} < c : Circle > Figure; + +struct Decorator {} < Figure; >; + +Figure + ; + +int main() { + + struct Figure.decor.Figure* f = create_spec(Figure.decor.Figure); + // CHECK-RT: Tags: 2 1 + printf("Tags: %d %d\n", + f->__pp_specialization_type, + f->@.__pp_specialization_type); +} diff --git a/clang/test/CodeGen/pp-tagged-generalization.c b/clang/test/CodeGen/pp-tagged-generalization.c new file mode 100644 index 0000000000000..5abf7fa5c243f --- /dev/null +++ b/clang/test/CodeGen/pp-tagged-generalization.c @@ -0,0 +1,124 @@ +// RUN: %clang -S -emit-llvm %s 2>&1 -o - | FileCheck %s -check-prefix=CHECK-IR +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +#include + +struct WeekDay {} < Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday, + Sunday + : void >; + +struct Circle { int c; }; +struct Rect { int h, w; }; +struct Trian { int a, b, c; }; + +struct Figure { int f; } < t0 : Circle; + t1 : Rect; + t2, t3 : Trian >; + +struct SameTypeTest {} < Circle1, + Circle2, + Circle3 + : Circle>; + +//------- +void PrintFigure() { + printf("PrintFigure [Default]\n"); +} + +void PrintFigure() { + printf("PrintFigure* f> [Specialized]\n"); +} + +void PrintFigure() { + printf("PrintFigure* f> [Specialized]\n"); +} + +void PrintFigure() { + printf("PrintFigure* f> [Specialized]\n"); +} + +//-------- +void PrintSameType() { + printf("PrintSameType [Default]\n"); +} + +void PrintSameType() { + printf("PrintSameType* f> [Specialized]\n"); +} + +void PrintSameType() { + printf("PrintSameType* f> [Specialized]\n"); +} + + +//-------- +void PrintWeekday() { + printf("PrintFigure [Default]\n"); +} + +void PrintWeekday() { + printf("PrintFigure* d> [Specialized]\n"); +} + +void PrintWeekday() { + printf("PrintFigure* d> [Specialized]\n"); +} + +void foo() +{ +// CHECK-IR: %pp_head = getelementptr inbounds %struct.__pp_struct_Figure__t0, ptr %ttt, i32 0, i32 0 +// CHECK-IR: %pp_spec_type = getelementptr inbounds %struct.Figure, ptr %pp_head, i32 0, i32 1 +// CHECK-IR: %global_spec_tag = load i32, ptr @__pp_tag___pp_struct_Figure__t0, align 4 +// CHECK-IR: store i32 %global_spec_tag, ptr %pp_spec_type, align 4 + struct Figure.t0 ttt; +} + +int main() { + struct Figure.t0 t0_obj; + struct Figure.t1 t1_obj; + struct Figure.t2 t2_obj; + struct Figure.t3 t3_obj; + +// CHECK-RT: PrintFigure* f> [Specialized] + PrintFigure<&t0_obj>(); + +// CHECK-RT: PrintFigure* f> [Specialized] + PrintFigure<&t1_obj>(); + +// CHECK-RT: PrintFigure [Default] + PrintFigure<&t2_obj>(); + +// CHECK-RT: PrintFigure* f> [Specialized] + PrintFigure<&t3_obj>(); + + struct WeekDay.Monday monday; + struct WeekDay.Tuesday tuesday; + struct WeekDay.Friday friday; + +// CHECK-RT: PrintFigure* d> [Specialized] + PrintWeekday<&monday>(); + +// CHECK-RT: PrintFigure* d> [Specialized] + PrintWeekday<&tuesday>(); + +// CHECK-RT: PrintFigure [Default] + PrintWeekday<&friday>(); + + + struct SameTypeTest.Circle1 c1; + struct SameTypeTest.Circle2 c2; + struct SameTypeTest.Circle3 c3; + +// CHECK-RT: PrintSameType* f> [Specialized] + PrintSameType<&c1>(); +// CHECK-RT: PrintSameType [Default] + PrintSameType<&c2>(); +// CHECK-RT: PrintSameType* f> [Specialized] + PrintSameType<&c3>(); + return 0; +} diff --git a/clang/test/CodeGen/pp-tread-rect-ppp.c b/clang/test/CodeGen/pp-tread-rect-ppp.c new file mode 100644 index 0000000000000..bb86c70248036 --- /dev/null +++ b/clang/test/CodeGen/pp-tread-rect-ppp.c @@ -0,0 +1,127 @@ +// clang -pthread thread-rect-ppp.c +// RUN: %clang -pthread %s -o %S/a.out +// RUN: %S/a.out | FileCheck %s -check-prefix=CHECK-RT +// RUN: rm %S/a.out + +#include +#include +#include +#include + +//============================================================================== +// В начале предсталена обертка над функциями библиотеки pthread +// аналогичная объектно-ориентированной обертке +//============================================================================== + +// Обобщенная структура, используемая для обертки данных, +// передаваемых в поточную функцию, и для возврата результата +// Конкретные данные формируются в специализации для каждого +// отдельного потока +typedef struct ThreadData {pthread_t threadId;}<> ThreadData; + +// Обобщенная функция, задающая формат для передачи аргументов +// и подменяемая на соответствующий обработчик специализации. +// Часто он может бытьтолько один +void RunThread () {};// = 0; + +// POSIX функция, вызвывающая обработчик обобщения +// подменяемый обработчиком специализации +void* ThreadFunc(void* d) { + struct Thread* pt = (struct Thread*) d; + // RunThread<(struct Thread*) d>(); + RunThread(); + return NULL; +} + +// Функция создания и запуска потока +int StartThread(ThreadData* td) { + return pthread_create(&td->threadId, NULL, ThreadFunc, td); +} + +// Функция ожидания завершения потока +int WaitThread(ThreadData* td) { + return pthread_join(td->threadId, NULL); +} + +//============================================================================== +// Далее в других единицах компиляции +// могут быть описани различные специализации, +// определяющие потоки. +// В примере только прямоугольник. +//============================================================================== + +// Прямоугольник +typedef struct Rectangle{int x, y;} Rectangle; + +// Основа специализации. Прямоугольник, передаваемый потоку +// и формируемое значение результата (периметр) +typedef struct RectPreimeter {Rectangle r; double p;} RectPreimeter; + +// Вывод результата вычислений периметра конкретно прямоугольника +void PrintRectPerimeter(RectPreimeter* rp, const char* str) { + printf("Perimeter of %s = %f\n", str, rp->p); +} + +// Специализация для потока +struct ThreadData + ; + +// Обработчик специализации, запускаемый в потоке +// вычисляет периметр прямоугольника. +void RunThread() { + struct RectPreimeter* tmp = &rp->@; + tmp->p = (double)((tmp->r.x + tmp->r.y)*2); + // rp->@ = (double)((rp->@r.x+rp->@r.y)*2); +} + + +//============================================================================== +// Главная функция, осуществляющая необходимые вычисления +//============================================================================== + +int main () { + // Переменные, передаваемая запускаемому потоку + // Если инициализация напрямую еще не работает. + // Ее можно заменить на присваивания. + // Представлен вариант инициализации не всех полей. Может его и не будет. + // struct ThreadData thread1 = {0}<{3,5,0.0}>; + struct ThreadData.RectPreimeter thread1; + thread1.threadId = 0; + thread1.@r.x = 3; + thread1.@r.y = 5; + thread1.@p = 0.0; + + // struct ThreadData thread2 = {0}<{7,4,0.0}>; + struct ThreadData.RectPreimeter thread2; + thread2.threadId = 0; + thread2.@r.x = 7; + thread2.@r.y = 4; + thread2.@p = 0.0; + + // struct ThreadData thread3 = {0}<{6,8,0.0}>; + struct ThreadData.RectPreimeter thread3; + thread3.threadId = 0; + thread3.@r.x = 6; + thread3.@r.y = 8; + thread3.@p = 0.0; + + // Далее запуск трех потоков + StartThread(&thread1); + StartThread(&thread2); + StartThread(&thread3); + + // Ожидание завершения потоков + WaitThread(&thread1); + WaitThread(&thread2); + WaitThread(&thread3); + + // Печать периметров + PrintRectPerimeter(&(thread1.@), "Thread1"); + PrintRectPerimeter(&(thread2.@), "Thread2"); + PrintRectPerimeter(&(thread3.@), "Thread3"); + +// CHECK-RT: Perimeter of Thread1 = 16.000000 +// CHECK-RT: Perimeter of Thread2 = 22.000000 +// CHECK-RT: Perimeter of Thread3 = 28.000000 + + return 0; +} diff --git a/clang/test/CodeGen/pp-triple-create_spec.c b/clang/test/CodeGen/pp-triple-create_spec.c new file mode 100644 index 0000000000000..a7f896aa3129b --- /dev/null +++ b/clang/test/CodeGen/pp-triple-create_spec.c @@ -0,0 +1,65 @@ +// RUN: %clang %s -o %S/a.out && %S/a.out | FileCheck %s -check-prefix=CHECK-RT && rm %S/a.out + +#include +#include + +typedef struct SimpleRectangle { + double x, y; // ширина, высота +} SimpleRectangle; + +typedef struct SimpleTriangle { + double a, b, c; // стороны треугольника +} SimpleTriangle; + +typedef struct SimpleFigure {}<> SimpleFigure; +SimpleFigure + ; +SimpleFigure + ; + +typedef struct Point { + double x, y; // точка +} Point; + +typedef struct CoordRectangle { + Point top_left, down_right; // координаты верхнего и нижнего углов +} CoordRectangle; + +typedef struct CoordTriangle { + Point a, b, c; // вершины треугольника +} CoordTriangle; + +typedef struct CoordFigure {}<> CoordFigure; +CoordFigure + ; +CoordFigure + ; + +typedef struct Figure { }<> Figure; +Figure + ; +Figure + ; + +int main() +{ + struct Figure* pf = create_spec(Figure.simple.trian); + // CHECK-RT: Figure tag = 1 + printf("Figure tag = %d\n", pf->__pp_specialization_type); + + struct Figure.simple.trian* pfst = pf; + // CHECK-RT-NEXT: Figure tag = 1 + printf("Figure tag = %d\n", + pfst->__pp_specialization_type); + + struct SimpleFigure* ps_pfst = &(pfst->@); + // CHECK-RT-NEXT: Simple tag = 2 + printf("Simple tag = %d\n", + ps_pfst->__pp_specialization_type); + + struct Figure.simple* pfs = pf; + // CHECK-RT-NEXT: Figure tag = 1 + printf("Figure tag = %d\n", + pfs->__pp_specialization_type); + + struct SimpleFigure* ps_pfs = &(pfs->@); + // CHECK-RT-NEXT: Simple tag = 2 + printf("Simple tag = %d\n", + ps_pfs->__pp_specialization_type); + + return 0; +}