diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index a3cf0885b8ae2..4c99f166c2989 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1536,7 +1536,7 @@ class TargetInfo : public TransferrableTargetInfo, /// which requires support for cpu_supports and cpu_is functionality. bool supportsMultiVersioning() const { return getTriple().isX86() || getTriple().isAArch64() || - getTriple().isRISCV(); + getTriple().isRISCV() || getTriple().isOSBinFormatXCOFF(); } /// Identify whether this target supports IFuncs. diff --git a/clang/include/clang/Sema/SemaPPC.h b/clang/include/clang/Sema/SemaPPC.h index f8edecc4fcb7b..0cf6ba7ff29dd 100644 --- a/clang/include/clang/Sema/SemaPPC.h +++ b/clang/include/clang/Sema/SemaPPC.h @@ -53,6 +53,10 @@ class SemaPPC : public SemaBase { // vector double vec_xxpermdi(vector double, vector double, int); // vector short vec_xxsldwi(vector short, vector short, int); bool BuiltinVSX(CallExpr *TheCall); + + bool checkTargetClonesAttr(SmallVectorImpl &Params, + SmallVectorImpl &Locs, + SmallVectorImpl> &NewParams); }; } // namespace clang diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 97c59b2ceec2f..ecc85d5c42f88 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14962,6 +14962,11 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (VersionStr.starts_with("arch=")) TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); + else if (Target->getTriple().isOSAIX() && + VersionStr.starts_with( + "cpu=")) // TODO make a function that extracts CPU from a + // feature string + TargetCPU = VersionStr.drop_front(sizeof("cpu=") - 1); else if (VersionStr != "default") Features.push_back((StringRef{"+"} + VersionStr).str()); Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index d4fd7a7f16d53..4e94fa3c8b1d0 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -147,3 +147,7 @@ add_clang_library(clangAST # These generated headers are included transitively. target_parser_gen ) +set_source_files_properties( + ASTContext.cpp + PROPERTIES COMPILE_FLAGS "-g -O0") + diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index adfc6ee326b5a..18ab54b80f0e1 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -141,3 +141,7 @@ target_link_libraries(clangBasic PRIVATE ${LLVM_ATOMIC_LIB} ) + +set_source_files_properties( + TargetInfo.cpp Targets/X86.cpp Targets.cpp Targets/PPC.cpp + PROPERTIES COMPILE_FLAGS "-g -O0") diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index a6e1ad10568bb..a6eb61fdc9907 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -671,6 +671,43 @@ void PPCTargetInfo::setFeatureEnabled(llvm::StringMap &Features, } } +ParsedTargetAttr PPCTargetInfo::parseTargetAttr(StringRef Features) const { + ParsedTargetAttr Ret; + if (Features == "default") + return Ret; + SmallVector AttrFeatures; + Features.split(AttrFeatures, ","); + + // Grab the various features and prepend a "+" to turn on the feature to + // the backend and add them to our existing set of features. + for (auto &Feature : AttrFeatures) { + // Go ahead and trim whitespace rather than either erroring or + // accepting it weirdly. + Feature = Feature.trim(); + + // While we're here iterating check for a different target cpu. + if (Feature.starts_with("cpu=")) { + if (!Ret.CPU.empty()) + Ret.Duplicate = "cpu="; + else + Ret.CPU = Feature.split("=").second.trim(); + } else if (Feature.starts_with("tune=")) { + if (!Ret.Tune.empty()) + Ret.Duplicate = "tune="; + else + Ret.Tune = Feature.split("=").second.trim(); + } else if (Feature.starts_with("no-")) + Ret.Features.push_back("-" + Feature.split("-").second.str()); + else + Ret.Features.push_back("+" + Feature.str()); + } + return Ret; +} + +llvm::APInt PPCTargetInfo::getFMVPriority(ArrayRef Features) const { + return llvm::APInt(32, Features.empty() ? 0 : 1); +} + // Make sure that registers are added in the correct array index which should be // the DWARF number for PPC registers. const char *const PPCTargetInfo::GCCRegNames[] = { diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 9f3a4cd2da716..b137cde179e21 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -200,6 +200,10 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { bool supportsTargetAttributeTune() const override { return true; } + ParsedTargetAttr parseTargetAttr(StringRef Str) const override; + + llvm::APInt getFMVPriority(ArrayRef Features) const override; + ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index ad9ef91c781a8..5bce446b35f8a 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -172,3 +172,76 @@ add_clang_library(clangCodeGen clangLex clangSerialization ) + +set_source_files_properties( + ABIInfo.cpp + ABIInfoImpl.cpp + BackendUtil.cpp + CGAtomic.cpp + CGBlocks.cpp + CGBuiltin.cpp + CGCUDANV.cpp + CGCUDARuntime.cpp + CGCXX.cpp + CGCXXABI.cpp + CGCall.cpp + CGClass.cpp + CGCleanup.cpp + CGCoroutine.cpp + CGDebugInfo.cpp + CGDecl.cpp + CGDeclCXX.cpp + CGException.cpp + CGExpr.cpp + CGExprAgg.cpp + CGExprCXX.cpp + CGExprComplex.cpp + CGExprConstant.cpp + CGExprScalar.cpp + CGGPUBuiltin.cpp + CGHLSLRuntime.cpp + CGHLSLBuiltins.cpp + CGLoopInfo.cpp + CGNonTrivialStruct.cpp + CGObjC.cpp + CGObjCGNU.cpp + CGObjCMac.cpp + CGObjCRuntime.cpp + CGOpenCLRuntime.cpp + CGOpenMPRuntime.cpp + CGOpenMPRuntimeGPU.cpp + CGPointerAuth.cpp + CGRecordLayoutBuilder.cpp + CGStmt.cpp + CGStmtOpenMP.cpp + CGVTT.cpp + CGVTables.cpp + CodeGenABITypes.cpp + CodeGenAction.cpp + CodeGenFunction.cpp + CodeGenModule.cpp + CodeGenPGO.cpp + CodeGenSYCL.cpp + CodeGenTBAA.cpp + CodeGenTypes.cpp + ConstantInitBuilder.cpp + CoverageMappingGen.cpp + ItaniumCXXABI.cpp + HLSLBufferLayoutBuilder.cpp + LinkInModulesPass.cpp + MacroPPCallbacks.cpp + MicrosoftCXXABI.cpp + ModuleBuilder.cpp + ObjectFilePCHContainerWriter.cpp + PatternInit.cpp + SanitizerMetadata.cpp + TargetBuiltins/ARM.cpp + TargetBuiltins/PPC.cpp + TargetBuiltins/RISCV.cpp + TargetBuiltins/X86.cpp + TargetInfo.cpp + Targets/AArch64.cpp + Targets/ARM.cpp + Targets/PPC.cpp + Targets/X86.cpp + PROPERTIES COMPILE_FLAGS "-g -O0") diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index b2fe9171372d8..ba919c056a43a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -44,6 +44,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsPowerPC.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Support/CRC.h" #include "llvm/Support/xxhash.h" @@ -2994,10 +2995,80 @@ void CodeGenFunction::EmitMultiVersionResolver( case llvm::Triple::riscv64: EmitRISCVMultiVersionResolver(Resolver, Options); return; - + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + if (getContext().getTargetInfo().getTriple().isOSAIX()) { + EmitPPCAIXMultiVersionResolver(Resolver, Options); + return; + } + [[fallthrough]]; default: - assert(false && "Only implemented for x86, AArch64 and RISC-V targets"); + assert(false && + "Only implemented for x86, AArch64, RISC-V, and PowerPC targets"); + } +} + +/* + * Desc_t *foo_desc = ppc_get_function_descriptor(&foo); + * if (foo_desc->addr == ppc_get_function_entry(&foo)) { + * FuncPtr fp = resolver(); + * __c11_atomic_store((_Atomic FuncPtr *)&foo_desc->addr, fp, 0); + * } + * return ((int (*)(int)) foo_desc)(a); + */ +void CodeGenFunction::EmitPPCAIXMultiVersionResolver( + llvm::Function *Resolver, ArrayRef Options) { + + llvm::PointerType *PtrTy = Builder.getPtrTy(); + // entry: + llvm::BasicBlock *CurBlock = createBasicBlock("entry", Resolver); + + SmallVector, 3> PhiArgs; + for (const FMVResolverOption &RO : Options) { + Builder.SetInsertPoint(CurBlock); + // The 'default' or 'generic' case. + if (!RO.Architecture && RO.Features.empty()) { + // if.default: + // %fmv.default = call ptr @getEntryPoint(ptr noundef @foo_default) + // br label %resolver_exit + assert(&RO == Options.end() - 1 && + "Default or Generic case must be last"); + Builder.CreateRet(RO.Function); + break; + } + // if.else_n: + // %is_version_n = __builtin_cpu_supports(version_n) + // br i1 %is_version_n, label %if.version_n, label %if.default + // + // if.version_n: + // %fmv.version.n = call ptr @getEntryPoint(ptr noundef @foo_version_n) + // br label %resolver_exit + assert(RO.Features.size() == 1 && + "for now one feature requirement per version"); + llvm::Value *Condition; + if (RO.Features[0].starts_with("cpu=")) { + Condition = + EmitPPCBuiltinCpu(Builtin::BI__builtin_cpu_is, Builder.getInt1Ty(), + RO.Features[0].split("=").second.trim()); + } else { + Condition = EmitPPCBuiltinCpu(Builtin::BI__builtin_cpu_supports, + Builder.getInt1Ty(), RO.Features[0]); + } + llvm::BasicBlock *ThenBlock = createBasicBlock("if.version", Resolver); + CurBlock = createBasicBlock("if.else", Resolver); + Builder.CreateCondBr(Condition, ThenBlock, CurBlock); + + Builder.SetInsertPoint(ThenBlock); + Builder.CreateRet(RO.Function); } + + // If no generic/default, emit an unreachable. + // Builder.SetInsertPoint(CurBlock); + // llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap); + // TrapCall->setDoesNotReturn(); + // TrapCall->setDoesNotThrow(); + // Builder.CreateUnreachable(); + // Builder.ClearInsertionPoint(); } void CodeGenFunction::EmitRISCVMultiVersionResolver( diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 727487b46054f..d75a46fe85f1c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4852,6 +4852,8 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *BuildVector(ArrayRef Ops); llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitPPCBuiltinCpu(unsigned BuiltinID, llvm::Type *ReturnType, + StringRef CPUStr); llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, @@ -5519,6 +5521,9 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitRISCVMultiVersionResolver(llvm::Function *Resolver, ArrayRef Options); + void EmitPPCAIXMultiVersionResolver(llvm::Function *Resolver, + ArrayRef Options); + private: QualType getVarArgType(const Expr *Arg); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index d05092a250040..e77c3568c19af 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -78,6 +78,9 @@ using namespace clang; using namespace CodeGen; +void pdecl(const Decl* D) { D->dump(); } +void pgdecl(const GlobalDecl &GD) { GD.getDecl()->dump(); } + static llvm::cl::opt LimitedCoverage( "limited-coverage-experimental", llvm::cl::Hidden, llvm::cl::desc("Emit limited coverage mapping information (experimental)")); @@ -2005,6 +2008,20 @@ static bool isUniqueInternalLinkageDecl(GlobalDecl GD, (CGM.getFunctionLinkage(GD) == llvm::GlobalValue::InternalLinkage); } +// On certain platforms, a declared (but not defined) FMV shall be treated +// like a regular non-FMV function. +static bool IgnoreFMVOnADeclaration(const llvm::Triple &Triple, + const FunctionDecl *FD) { + if (!FD->isMultiVersion()) + return false; + + if (Triple.isOSAIX()) { + assert(FD->isTargetClonesMultiVersion()); + return !FD->isDefined(); + } + return false; +} + static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, const NamedDecl *ND, bool OmitMultiVersionMangling = false) { @@ -2054,8 +2071,9 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, Out << CGM.getModuleNameHash(); } - if (const auto *FD = dyn_cast(ND)) - if (FD->isMultiVersion() && !OmitMultiVersionMangling) { + if (const auto *FD = dyn_cast(ND)) { + if (FD->isMultiVersion() && !OmitMultiVersionMangling && + !IgnoreFMVOnADeclaration(CGM.getTriple(), FD)) { switch (FD->getMultiVersionKind()) { case MultiVersionKind::CPUDispatch: case MultiVersionKind::CPUSpecific: @@ -2092,6 +2110,7 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, llvm_unreachable("None multiversion type isn't valid here"); } } + } // Make unique name for device side static file-scope variable for HIP. if (CGM.getContext().shouldExternalize(ND) && @@ -2910,9 +2929,11 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD, // While we populated the feature map above, we still need to // get and parse the target attribute so we can get the cpu for // the function. - if (TD) { - ParsedTargetAttr ParsedAttr = - Target.parseTargetAttr(TD->getFeaturesStr()); + StringRef FeatureStr = + TD ? TD->getFeaturesStr() + : (TC ? TC->getFeatureStr(GD.getMultiVersionIndex()) : StringRef()); + if (!FeatureStr.empty()) { + ParsedTargetAttr ParsedAttr = Target.parseTargetAttr(FeatureStr); if (!ParsedAttr.CPU.empty() && getTarget().isValidCPUName(ParsedAttr.CPU)) { TargetCPU = ParsedAttr.CPU; @@ -4511,7 +4532,7 @@ getFMVPriority(const TargetInfo &TI, static llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, GlobalDecl GD) { const FunctionDecl *FD = cast(GD.getDecl()); - if (FD->getFormalLinkage() == Linkage::Internal) + if (FD->getFormalLinkage() == Linkage::Internal || CGM.getTriple().isOSAIX()) return llvm::GlobalValue::InternalLinkage; return llvm::GlobalValue::WeakODRLinkage; } @@ -4545,7 +4566,7 @@ void CodeGenModule::emitMultiVersionFunctions() { // For AArch64, a resolver is only emitted if a function marked with // target_version("default")) or target_clones("default") is defined // in this TU. For other architectures it is always emitted. - bool ShouldEmitResolver = !getTarget().getTriple().isAArch64(); + bool ShouldEmitResolver = !getTriple().isAArch64(); SmallVector Options; getContext().forEachMultiversionedFunctionVersion( @@ -4593,7 +4614,8 @@ void CodeGenModule::emitMultiVersionFunctions() { if (auto *IFunc = dyn_cast(ResolverConstant)) { ResolverConstant = IFunc->getResolver(); if (FD->isTargetClonesMultiVersion() && - !getTarget().getTriple().isAArch64()) { + !getTarget().getTriple().isAArch64() && + !getTarget().getTriple().isOSAIX()) { std::string MangledName = getMangledNameImpl( *this, GD, FD, /*OmitMultiVersionMangling=*/true); if (!GetGlobalValue(MangledName + ".ifunc")) { @@ -4841,9 +4863,12 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { llvm::Constant *Resolver = GetOrCreateLLVMFunction( MangledName + ".resolver", ResolverType, GlobalDecl{}, /*ForVTable=*/false); - llvm::GlobalIFunc *GIF = - llvm::GlobalIFunc::create(DeclTy, AS, getMultiversionLinkage(*this, GD), - "", Resolver, &getModule()); + + auto Linkage = getTriple().isOSAIX() ? getFunctionLinkage(GD) + : getMultiversionLinkage(*this, GD); + + llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(DeclTy, AS, Linkage, "", + Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); if (ResolverGV) @@ -4862,7 +4887,11 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { void CodeGenModule::setMultiVersionResolverAttributes(llvm::Function *Resolver, GlobalDecl GD) { const NamedDecl *D = dyn_cast_or_null(GD.getDecl()); - Resolver->setLinkage(getMultiversionLinkage(*this, GD)); + + auto ResolverLinkage = getTriple().isOSAIX() + ? llvm::GlobalValue::InternalLinkage + : getMultiversionLinkage(*this, GD); + Resolver->setLinkage(ResolverLinkage); // Function body has to be emitted before calling setGlobalVisibility // for Resolver to be considered as definition. @@ -4936,6 +4965,10 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( AddDeferredMultiVersionResolverToEmit(GD); NameWithoutMultiVersionMangling = getMangledNameImpl( *this, GD, FD, /*OmitMultiVersionMangling=*/true); + } else if (IgnoreFMVOnADeclaration(getTriple(), FD)) { + // TODO this might not be necessary after fix in getMangledNameImpl + NameWithoutMultiVersionMangling = getMangledNameImpl( + *this, GD, FD, /*OmitMultiVersionMangling=*/true); } else return GetOrCreateMultiVersionResolver(GD); } @@ -6392,6 +6425,9 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, auto *Fn = cast(GV); setFunctionLinkage(GD, Fn); + if (getTriple().isOSAIX() && D->isTargetClonesMultiVersion()) + Fn->setLinkage(llvm::GlobalValue::InternalLinkage); + // FIXME: this is redundant with part of setFunctionDefinitionAttributes setGVProperties(Fn, GD); diff --git a/clang/lib/CodeGen/TargetBuiltins/PPC.cpp b/clang/lib/CodeGen/TargetBuiltins/PPC.cpp index ba65cf1ce9b90..276632d706d9d 100644 --- a/clang/lib/CodeGen/TargetBuiltins/PPC.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/PPC.cpp @@ -70,31 +70,19 @@ static llvm::Value *emitPPCLoadReserveIntrinsic(CodeGenFunction &CGF, return CI; } -Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, - const CallExpr *E) { - // Do not emit the builtin arguments in the arguments of a function call, - // because the evaluation order of function arguments is not specified in C++. - // This is important when testing to ensure the arguments are emitted in the - // same order every time. Eg: - // Instead of: - // return Builder.CreateFDiv(EmitScalarExpr(E->getArg(0)), - // EmitScalarExpr(E->getArg(1)), "swdiv"); - // Use: - // Value *Op0 = EmitScalarExpr(E->getArg(0)); - // Value *Op1 = EmitScalarExpr(E->getArg(1)); - // return Builder.CreateFDiv(Op0, Op1, "swdiv") - - Intrinsic::ID ID = Intrinsic::not_intrinsic; +Value *CodeGenFunction::EmitPPCBuiltinCpu(unsigned BuiltinID, + llvm::Type *ReturnType, + StringRef CPUStr) { #include "llvm/TargetParser/PPCTargetParser.def" auto GenAIXPPCBuiltinCpuExpr = [&](unsigned SupportMethod, unsigned FieldIdx, unsigned Mask, CmpInst::Predicate CompOp, unsigned OpValue) -> Value * { if (SupportMethod == BUILTIN_PPC_FALSE) - return llvm::ConstantInt::getFalse(ConvertType(E->getType())); + return llvm::ConstantInt::getFalse(ReturnType); if (SupportMethod == BUILTIN_PPC_TRUE) - return llvm::ConstantInt::getTrue(ConvertType(E->getType())); + return llvm::ConstantInt::getTrue(ReturnType); assert(SupportMethod <= SYS_CALL && "Invalid value for SupportMethod."); @@ -137,12 +125,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, ConstantInt::get(IsValueType64Bit ? Int64Ty : Int32Ty, OpValue)); }; - switch (BuiltinID) { - default: return nullptr; - - case Builtin::BI__builtin_cpu_is: { - const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); - StringRef CPUStr = cast(CPUExpr)->getString(); + if (BuiltinID == Builtin::BI__builtin_cpu_is) { llvm::Triple Triple = getTarget().getTriple(); typedef std::tuple CPUInfo; @@ -170,18 +153,15 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, "Invalid CPU name. Missed by SemaChecking?"); if (LinuxSupportMethod == BUILTIN_PPC_FALSE) - return llvm::ConstantInt::getFalse(ConvertType(E->getType())); + return llvm::ConstantInt::getFalse(ReturnType); Value *Op0 = llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID); llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld); Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_is"); return Builder.CreateICmpEQ(TheCall, llvm::ConstantInt::get(Int32Ty, LinuxIDValue)); - } - case Builtin::BI__builtin_cpu_supports: { + } else if (BuiltinID == Builtin::BI__builtin_cpu_supports) { llvm::Triple Triple = getTarget().getTriple(); - const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); - StringRef CPUStr = cast(CPUExpr)->getString(); if (Triple.isOSAIX()) { typedef std::tuple @@ -217,8 +197,36 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, #undef PPC_FAWORD_HWCAP #undef PPC_FAWORD_HWCAP2 #undef PPC_FAWORD_CPUID - } + } else + assert(0 && "unexpected builtin"); +} + +Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + // Do not emit the builtin arguments in the arguments of a function call, + // because the evaluation order of function arguments is not specified in C++. + // This is important when testing to ensure the arguments are emitted in the + // same order every time. Eg: + // Instead of: + // return Builder.CreateFDiv(EmitScalarExpr(E->getArg(0)), + // EmitScalarExpr(E->getArg(1)), "swdiv"); + // Use: + // Value *Op0 = EmitScalarExpr(E->getArg(0)); + // Value *Op1 = EmitScalarExpr(E->getArg(1)); + // return Builder.CreateFDiv(Op0, Op1, "swdiv") + + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + default: + return nullptr; + case Builtin::BI__builtin_cpu_is: + case Builtin::BI__builtin_cpu_supports: { + const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); + StringRef CPUStr = cast(CPUExpr)->getString(); + return EmitPPCBuiltinCpu(BuiltinID, ConvertType(E->getType()), CPUStr); + } // __builtin_ppc_get_timebase is GCC 4.8+'s PowerPC-specific name for what we // call __builtin_readcyclecounter. case PPC::BI__builtin_ppc_get_timebase: diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index 380e8c06c46f0..434e6c7a034ce 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -128,8 +128,54 @@ class AIXABIInfo : public ABIInfo { RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const override; + + using ABIInfo::appendAttributeMangling; + void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, + raw_ostream &Out) const override; + void appendAttributeMangling(StringRef AttrStr, + raw_ostream &Out) const override; }; +void AIXABIInfo::appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, + raw_ostream &Out) const { + appendAttributeMangling(Attr->getFeatureStr(Index), Out); +} + +void AIXABIInfo::appendAttributeMangling(StringRef AttrStr, + raw_ostream &Out) const { + if (AttrStr == "default") { + Out << ".default"; + return; + } + + Out << '.'; + const TargetInfo &TI = CGT.getTarget(); + ParsedTargetAttr Info = TI.parseTargetAttr(AttrStr); + + llvm::sort(Info.Features, [&TI](StringRef LHS, StringRef RHS) { + // Multiversioning doesn't allow "no-${feature}", so we can + // only have "+" prefixes here. + assert(LHS.starts_with("+") && RHS.starts_with("+") && + "Features should always have a prefix."); + return TI.getFMVPriority({LHS.substr(1)}) + .ugt(TI.getFMVPriority({RHS.substr(1)})); + }); + + bool IsFirst = true; + if (!Info.CPU.empty()) { + IsFirst = false; + Out << "cpu_" << Info.CPU; + } + + assert(Info.Features.empty() && "unhandled case"); + for (StringRef Feat : Info.Features) { + if (!IsFirst) + Out << '_'; + IsFirst = false; + Out << Feat.substr(1); + } +} + class AIXTargetCodeGenInfo : public TargetCodeGenInfo { const bool Is64Bit; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 51e0ee10b080b..ee7bbd4058681 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -116,3 +116,5 @@ add_clang_library(clangSema clangLex clangSupport ) + +set_source_files_properties(SemaPPC.cpp PROPERTIES COMPILE_FLAGS "-g -O0") diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b876911384f6f..9c9ed69a55dd5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -54,6 +54,7 @@ #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaOpenMP.h" +#include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" #include "clang/Sema/SemaSYCL.h" #include "clang/Sema/SemaSwift.h" @@ -3443,6 +3444,9 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } else if (S.Context.getTargetInfo().getTriple().isX86()) { if (S.X86().checkTargetClonesAttr(Params, Locations, NewParams)) return; + } else if (S.Context.getTargetInfo().getTriple().isOSAIX()) { + if (S.PPC().checkTargetClonesAttr(Params, Locations, NewParams)) + return; } Params.clear(); for (auto &SmallStr : NewParams) diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index bfa458d207b46..f3291e3f3d9de 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -442,4 +442,60 @@ bool SemaPPC::BuiltinVSX(CallExpr *TheCall) { return false; } +bool SemaPPC::checkTargetClonesAttr( + SmallVectorImpl &Params, SmallVectorImpl &Locs, + SmallVectorImpl> &NewParams) { + using namespace DiagAttrParams; + + assert(Params.size() == Locs.size() && + "Mismatch between number of string parameters and locations"); + + bool HasDefault = false; + bool HasComma = false; + for (unsigned I = 0, E = Params.size(); I < E; ++I) { + const StringRef Param = Params[I].trim(); + const SourceLocation &Loc = Locs[I]; + + if (Param.empty() || Param.ends_with(',')) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + + if (Param.contains(',')) + HasComma = true; + + StringRef LHS; + StringRef RHS = Param; + do { + std::tie(LHS, RHS) = RHS.split(','); + LHS = LHS.trim(); + const SourceLocation &CurLoc = + Loc.getLocWithOffset(LHS.data() - Param.data()); + + if (LHS.starts_with("cpu=")) { + if (!getASTContext().getTargetInfo().isValidCPUName( + LHS.drop_front(sizeof("cpu=") - 1))) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << CPU << LHS.drop_front(sizeof("cpu=") - 1) + << TargetClones; + } else if (LHS == "default") + HasDefault = true; + else if (!getASTContext().getTargetInfo().isValidFeatureName(LHS) || + getASTContext().getTargetInfo().getFMVPriority(LHS) == 0) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << LHS << TargetClones; + + if (llvm::is_contained(NewParams, LHS)) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + // Note: Add even if there are duplicates, since it changes name mangling. + NewParams.push_back(LHS); + } while (!RHS.empty()); + } + if (HasComma && Params.size() > 1) + Diag(Locs[0], diag::warn_target_clone_mixed_values); + + if (!HasDefault) + return Diag(Locs[0], diag::err_target_clone_must_have_default); + + return false; +} } // namespace clang diff --git a/clang/test/Sema/attr-target.c b/clang/test/Sema/attr-target.c index 65ece3c27d299..ddf6654632187 100644 --- a/clang/test/Sema/attr-target.c +++ b/clang/test/Sema/attr-target.c @@ -75,15 +75,13 @@ int __attribute__((target("tune=pwr8"))) baz(void) { return 4; } //expected-warning@+1 {{unsupported 'fpmath=' in the 'target' attribute string; 'target' attribute ignored}} int __attribute__((target("fpmath=387"))) walrus(void) { return 4; } //expected-warning@+1 {{unknown CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}} -int __attribute__((target("float128,arch=hiss"))) meow(void) { return 4; } +int __attribute__((target("float128,cpu=hiss"))) meow(void) { return 4; } // no warning, same as saying 'nothing'. -int __attribute__((target("arch="))) turtle(void) { return 4; } +int __attribute__((target("cpu="))) turtle(void) { return 4; } //expected-warning@+1 {{unknown CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}} -int __attribute__((target("arch=hiss,arch=woof"))) pine_tree(void) { return 4; } -//expected-warning@+1 {{duplicate 'arch=' in the 'target' attribute string; 'target' attribute ignored}} -int __attribute__((target("arch=pwr9,arch=pwr10"))) oak_tree(void) { return 4; } -//expected-warning@+1 {{unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored}} -int __attribute__((target("branch-protection=none"))) birch_tree(void) { return 5; } +int __attribute__((target("cpu=hiss,cpu=woof"))) pine_tree(void) { return 4; } +//expected-warning@+1 {{duplicate 'cpu=' in the 'target' attribute string; 'target' attribute ignored}} +int __attribute__((target("cpu=pwr9,cpu=pwr10"))) oak_tree(void) { return 4; } //expected-warning@+1 {{unknown tune CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}} int __attribute__((target("tune=hiss,tune=woof"))) apple_tree(void) { return 4; } diff --git a/compiler-rt/lib/builtins/ppc/init_ifuncs.c b/compiler-rt/lib/builtins/ppc/init_ifuncs.c index b3b8f7fab5b5b..e95a5496d4c57 100644 --- a/compiler-rt/lib/builtins/ppc/init_ifuncs.c +++ b/compiler-rt/lib/builtins/ppc/init_ifuncs.c @@ -1,28 +1,38 @@ -typedef void* Ptr; -typedef struct { Ptr addr, toc, env; } Descr; -typedef struct { Descr* desc; Ptr (*resolver)(); } IFUNC_PAIR; +typedef void *Ptr; +typedef struct { + Ptr addr, toc, env; +} Descr; +typedef struct { + Descr *desc; + Ptr (*resolver)(); +} IFUNCPair; -// A zero-length entry in section "ifunc_sec" to satisfy the __start_ifunc_sec -// and __stop_ifunc_sec references in this file, when no user code has any. -__attribute__((section("ifunc_sec"))) static int dummy_ifunc_sec[0]; +#define CONC2(A, B) A##B +#define CONC(A, B) CONC2(A, B) -extern IFUNC_PAIR __start_ifunc_sec, __stop_ifunc_sec; +#define IFUNC_SEC __ifunc_sec +#define IFUNC_SEC_STR "__ifunc_sec" +#define START_SEC CONC(__start_, IFUNC_SEC) +#define STOP_SEC CONC(__stop_, IFUNC_SEC) -__attribute__((constructor)) -void __init_ifuncs() { +// A zero-length entry in section "__ifunc_sec" to satisfy the START_SEC and +// STOP_SEC references in this file, when no user code has any ifuncs. +__attribute__((section(IFUNC_SEC_STR))) static int dummy_ifunc_sec[0]; + +extern IFUNCPair START_SEC, STOP_SEC; + +__attribute__((constructor)) void __init_ifuncs() { void *volatile ref = &dummy_ifunc_sec; // hack to keep dummy_ifunc_sec alive - // hack to prevent compiler from assuming __start_ifunc_sec and - // __stop_ifunc_sec occupy different addresses. - IFUNC_PAIR *volatile volatile_end = &__stop_ifunc_sec; - for (IFUNC_PAIR *pair = &__start_ifunc_sec, *end = volatile_end; pair != end; - pair++) { + // hack to prevent compiler from assuming START_SEC and STOP_SEC + // occupy different addresses. + IFUNCPair *volatile volatile_end = &STOP_SEC; + for (IFUNCPair *pair = &START_SEC, *end = volatile_end; pair != end; pair++) { // Call the resolver and copy the entire descriptor because: // - the resolved function might be in another DSO, so copy the TOC address // - we might be linking with objects from a language that uses the // enviroment pointer, so copy it too. - Descr *result = (Descr*)pair->resolver(); + Descr *result = (Descr *)pair->resolver(); *(pair->desc) = *result; } } - diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp index fce6b2ac5cf8d..a460da2135d1e 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" #include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -49,6 +50,11 @@ namespace { constexpr unsigned DefaultSectionAlign = 4; constexpr int16_t MaxSectionIndex = INT16_MAX; +static cl::opt DisableRelocSort( + "disable-reloc-sort", cl::init(true), + cl::desc("disable sorting relocation entries before writing to disk."), + cl::Hidden); + // Packs the csect's alignment and type into a byte. uint8_t getEncodedType(const MCSectionXCOFF *); @@ -1123,16 +1129,21 @@ void XCOFFWriter::writeRelocation(XCOFFRelocation Reloc, } void XCOFFWriter::writeRelocations() { - for (const auto *Section : Sections) { + for (auto *Section : Sections) { if (Section->Index == SectionEntry::UninitializedIndex) // Nothing to write for this Section. continue; - for (const auto *Group : Section->Groups) { + for (auto *Group : Section->Groups) { if (Group->empty()) continue; - for (const auto &Csect : *Group) { + for (auto &Csect : *Group) { + if (!DisableRelocSort) + std::sort(Csect.Relocations.begin(), Csect.Relocations.end(), + [](const XCOFFRelocation &a, const XCOFFRelocation &b) { + return a.FixupOffsetInCsect < b.FixupOffsetInCsect; + }); for (const auto Reloc : Csect.Relocations) writeRelocation(Reloc, Csect); } diff --git a/llvm/lib/Target/PowerPC/CMakeLists.txt b/llvm/lib/Target/PowerPC/CMakeLists.txt index 6c2037c6a89de..da42c642d1164 100644 --- a/llvm/lib/Target/PowerPC/CMakeLists.txt +++ b/llvm/lib/Target/PowerPC/CMakeLists.txt @@ -87,3 +87,6 @@ add_subdirectory(AsmParser) add_subdirectory(Disassembler) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) +set_source_files_properties( + PPCAsmPrinter.cpp + PROPERTIES COMPILE_FLAGS "-g -O0 -DLLVM_ENABLE_DUMP") diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index c0c8f6c65cc2d..ff2c5bed4f947 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -87,6 +87,9 @@ using namespace PatternMatch; #define DEBUG_TYPE "asmprinter" +void xpm(const Module *M) { M->dump(); } +void xpi(const Instruction *I) { I->dump(); } +void xpv(const Value *V) { V->dump(); } STATISTIC(NumTOCEntries, "Number of Total TOC Entries Emitted."); STATISTIC(NumTOCConstPool, "Number of Constant Pool TOC Entries."); STATISTIC(NumTOCGlobalInternal, @@ -3570,10 +3573,9 @@ void PPCAIXAsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { // generate the code for .foo now: if (TOCRestoreNeededForCallToImplementation(GI)) { reportFatalUsageError( - "unimplemented: TOC register save/restore needed for function " + - Twine(GI.getName()) + - ", because couldn't prove all candidates are static or hidden/protected" - " visibility definitions"); + "unimplemented: TOC register save/restore needed for ifunc \"" + + Twine(GI.getName()) + "\", because couldn't prove all candidates are " + "static or hidden/protected visibility definitions"); return; } diff --git a/llvm/test/CodeGen/PowerPC/aix-ifunc.ll b/llvm/test/CodeGen/PowerPC/aix-ifunc.ll new file mode 100644 index 0000000000000..21699f771b91d --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-ifunc.ll @@ -0,0 +1,69 @@ +; RUN: llc -mtriple=powerpc64-ibm-aix-xcoff %s -o - | FileCheck %s --check-prefixes=COMMON,NO-FUNCSECT -DALIGN=3 -DPTR_SIZE=8 -DLOAD=ld -DOFF=16 +; RUN: llc -mtriple=powerpc-ibm-aix-xcoff %s -o - | FileCheck %s --check-prefixes=COMMON,NO-FUNCSECT -DALIGN=2 -DPTR_SIZE=4 -DLOAD=lwz -DOFF=8 + +; RUN: llc -mtriple=powerpc64-ibm-aix-xcoff --function-sections %s -o - | FileCheck %s --check-prefixes=COMMON,FUNCSECT -DALIGN=3 -DPTR_SIZE=8 -DLOAD=ld -DOFF=16 +; RUN: llc -mtriple=powerpc-ibm-aix-xcoff --function-sections %s -o - | FileCheck %s --check-prefixes=COMMON,FUNCSECT -DALIGN=2 -DPTR_SIZE=4 -DLOAD=lwz -DOFF=8 + +;;;; section __ifunc_sec holding the [foo:foo_resolver] pairs +; COMMON: .csect __ifunc_sec[RW],2 +; COMMON-NEXT: .align [[ALIGN]] +; COMMON-NEXT: L..__update_foo: +; COMMON-NEXT: .vbyte [[PTR_SIZE]], foo[DS] +; COMMON-NEXT: .vbyte [[PTR_SIZE]], foo.resolver[DS] + +;;;; forward declare the __init_ifuncs constructor +; COMMON-NEXT: .extern .__init_ifuncs[PR] + +;;;; declare foo[DS] and .foo[PR] +; FUNCSECT-NEXT: .csect .foo[PR],5 +; FUNCSECT-NEXT: .globl foo[DS] +; FUNCSECT-NEXT: .globl .foo[PR] +; FUNCSECT-NEXT: .lglobl L..__update_foo +; FUNCSECT-NEXT: .align 2 + +; NO-FUNCSECT-NEXT: .csect ..text..[PR],5 +; NO-FUNCSECT-NEXT: .globl foo[DS] +; NO-FUNCSECT-NEXT: .globl .foo +; NO-FUNCSECT-NEXT: .lglobl L..__update_foo +; NO-FUNCSECT-NEXT: .align 2 + +;;;; define foo's descriptor +; COMMON-NEXT: .csect foo[DS],[[ALIGN]] +; FUNCSECT-NEXT: .vbyte [[PTR_SIZE]], .foo[PR] +; NO-FUNCSECT-NEXT: .vbyte [[PTR_SIZE]], .foo +; COMMON-NEXT: .vbyte [[PTR_SIZE]], TOC[TC0] +; COMMON-NEXT: .vbyte [[PTR_SIZE]], 0 + +;;;; emit foo's body +; FUNCSECT-NEXT: .csect .foo[PR],5 +; NO-FUNCSECT-NEXT: .csect ..text..[PR],5 +; NO-FUNCSECT-NEXT: .foo: +; COMMON-NEXT: .ref L..__update_foo +; COMMON-NEXT: .ref .__init_ifuncs[PR] +; COMMON-NEXT: [[LOAD]] 12, [[FOO_TOC:.*]](2) +; COMMON-NEXT: [[LOAD]] 11, [[OFF]](12) +; COMMON-NEXT: [[LOAD]] 12, 0(12) +; COMMON-NEXT: mtctr 12 +; COMMON-NEXT: bctr + +;;;; foo's TOC entry +; COMMON: [[FOO_TOC]]: +; COMMON-NEXT: .tc foo[TC],foo[DS] + + +@foo = ifunc i32 (...), ptr @foo.resolver + +define hidden i32 @my_foo() { +entry: + ret i32 4 +} + +define internal ptr @foo.resolver() { +entry: + ret ptr @my_foo +} + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2}