diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen')
24 files changed, 791 insertions, 296 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm-project/clang/lib/CodeGen/BackendUtil.cpp index a6142d99f3b6..ec203f6f28bc 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/BackendUtil.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/BackendUtil.cpp @@ -1001,8 +1001,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline( } if (CodeGenOpts.FatLTO) { - assert(CodeGenOpts.UnifiedLTO && "FatLTO requires UnifiedLTO"); - MPM.addPass(PB.buildFatLTODefaultPipeline(Level)); + MPM.addPass(PB.buildFatLTODefaultPipeline( + Level, PrepareForThinLTO, + PrepareForThinLTO || shouldEmitRegularLTOSummary())); } else if (PrepareForThinLTO) { MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(Level)); } else if (PrepareForLTO) { @@ -1073,8 +1074,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit", uint32_t(CodeGenOpts.EnableSplitLTOUnit)); - // FatLTO always means UnifiedLTO - if (!TheModule->getModuleFlag("UnifiedLTO")) + if (CodeGenOpts.UnifiedLTO && !TheModule->getModuleFlag("UnifiedLTO")) TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1)); } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp index 998fcc3af581..7ef764b8e1ac 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp @@ -1019,7 +1019,7 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, FAMSize = Builder.CreateIntCast(FAMSize, ResType, IsSigned); Value *Res = FAMSize; - if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (isa<DeclRefExpr>(Base)) { // The whole struct is specificed in the __bdos. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); @@ -10056,7 +10056,7 @@ CodeGenFunction::getSVEOverloadTypes(const SVETypeFlags &TypeFlags, llvm::Type *DefaultType = getSVEType(TypeFlags); - if (TypeFlags.isOverloadWhile()) + if (TypeFlags.isOverloadWhileOrMultiVecCvt()) return {DefaultType, Ops[1]->getType()}; if (TypeFlags.isOverloadWhileRW()) @@ -13287,7 +13287,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, const auto *DR = cast<DeclRefExpr>(CE->getSubExpr()); const auto *Enumerator = cast<EnumConstantDecl>(DR->getDecl()); - auto &InitVal = Enumerator->getInitVal(); + auto InitVal = Enumerator->getInitVal(); std::string InitValStr; if (InitVal.isNegative() || InitVal > uint64_t(INT64_MAX)) InitValStr = std::to_string(InitVal.getSExtValue()); @@ -18178,6 +18178,45 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, llvm::Function *F = CGM.getIntrinsic(IID, {ArgTy}); return Builder.CreateCall(F, {Addr, Val, ZeroI32, ZeroI32, ZeroI1}); } + case AMDGPU::BI__builtin_amdgcn_global_load_tr_i32: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v2i32: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4f16: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4i16: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8f16: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8i16: { + + llvm::Type *ArgTy; + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_global_load_tr_i32: + ArgTy = llvm::Type::getInt32Ty(getLLVMContext()); + break; + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v2i32: + ArgTy = llvm::FixedVectorType::get( + llvm::Type::getInt32Ty(getLLVMContext()), 2); + break; + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4f16: + ArgTy = llvm::FixedVectorType::get( + llvm::Type::getHalfTy(getLLVMContext()), 4); + break; + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4i16: + ArgTy = llvm::FixedVectorType::get( + llvm::Type::getInt16Ty(getLLVMContext()), 4); + break; + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8f16: + ArgTy = llvm::FixedVectorType::get( + llvm::Type::getHalfTy(getLLVMContext()), 8); + break; + case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8i16: + ArgTy = llvm::FixedVectorType::get( + llvm::Type::getInt16Ty(getLLVMContext()), 8); + break; + } + + llvm::Value *Addr = EmitScalarExpr(E->getArg(0)); + llvm::Function *F = + CGM.getIntrinsic(Intrinsic::amdgcn_global_load_tr, {ArgTy}); + return Builder.CreateCall(F, {Addr}); + } case AMDGPU::BI__builtin_amdgcn_read_exec: return EmitAMDGCNBallotForExec(*this, E, Int64Ty, Int64Ty, false); case AMDGPU::BI__builtin_amdgcn_read_exec_lo: diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGCUDANV.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGCUDANV.cpp index 353370f1d761..5b43272bfa62 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGCUDANV.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGCUDANV.cpp @@ -893,7 +893,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { llvm::raw_svector_ostream OS(ModuleID); OS << ModuleIDPrefix << llvm::format("%" PRIx64, FatbinWrapper->getGUID()); llvm::Constant *ModuleIDConstant = makeConstantArray( - std::string(ModuleID.str()), "", ModuleIDSectionName, 32, /*AddNull=*/true); + std::string(ModuleID), "", ModuleIDSectionName, 32, /*AddNull=*/true); // Create an alias for the FatbinWrapper that nvcc will look for. llvm::GlobalAlias::create(llvm::GlobalValue::ExternalLinkage, diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGCXX.cpp index 110e21f7cb6d..e95a735f92f7 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGCXX.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGCXX.cpp @@ -40,6 +40,11 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { if (getCodeGenOpts().OptimizationLevel == 0) return true; + // Disable this optimization for ARM64EC. FIXME: This probably should work, + // but getting the symbol table correct is complicated. + if (getTarget().getTriple().isWindowsArm64EC()) + return true; + // If sanitizing memory to check for use-after-dtor, do not emit as // an alias, unless this class owns no members. if (getCodeGenOpts().SanitizeMemoryUseAfterDtor && diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp index 13677cf150ae..28c211aa631e 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp @@ -1767,14 +1767,31 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx, FPT->isNothrow()) FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); - if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask) + unsigned SMEBits = FPT->getAArch64SMEAttributes(); + if (SMEBits & FunctionType::SME_PStateSMEnabledMask) FuncAttrs.addAttribute("aarch64_pstate_sm_enabled"); - if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask) + if (SMEBits & FunctionType::SME_PStateSMCompatibleMask) FuncAttrs.addAttribute("aarch64_pstate_sm_compatible"); - if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask) + + // ZA + if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out || + FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut) + FuncAttrs.addAttribute("aarch64_pstate_za_shared"); + if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves || + FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In) { FuncAttrs.addAttribute("aarch64_pstate_za_shared"); - if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask) FuncAttrs.addAttribute("aarch64_pstate_za_preserved"); + } + + // ZT0 + if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Preserves) + FuncAttrs.addAttribute("aarch64_preserves_zt0"); + if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_In) + FuncAttrs.addAttribute("aarch64_in_zt0"); + if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Out) + FuncAttrs.addAttribute("aarch64_out_zt0"); + if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_InOut) + FuncAttrs.addAttribute("aarch64_inout_zt0"); } static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs, @@ -2446,9 +2463,6 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>()) FuncAttrs.addAttribute("aarch64_pstate_sm_body"); - - if (TargetDecl->hasAttr<ArmNewZAAttr>()) - FuncAttrs.addAttribute("aarch64_pstate_za_new"); } // Attach "no-builtins" attributes to: diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGCleanup.h b/contrib/llvm-project/clang/lib/CodeGen/CGCleanup.h index 079a3e25d6dc..fcfbf41b0eaf 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGCleanup.h +++ b/contrib/llvm-project/clang/lib/CodeGen/CGCleanup.h @@ -613,6 +613,7 @@ struct EHPersonality { static const EHPersonality MSVC_CxxFrameHandler3; static const EHPersonality GNU_Wasm_CPlusPlus; static const EHPersonality XL_CPlusPlus; + static const EHPersonality ZOS_CPlusPlus; /// Does this personality use landingpads or the family of pad instructions /// designed to form funclets? diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp index 236d53bee4e8..0f3f684d61dc 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1926,7 +1926,7 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( int ThisAdjustment = 0; if (VTableContextBase::hasVtableSlot(Method)) { - if (Method->isPure()) + if (Method->isPureVirtual()) SPFlags |= llvm::DISubprogram::SPFlagPureVirtual; else SPFlags |= llvm::DISubprogram::SPFlagVirtual; @@ -2201,6 +2201,14 @@ CGDebugInfo::CollectTemplateParams(std::optional<TemplateArgs> OArgs, TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, defaultParameter, V)); } break; + case TemplateArgument::StructuralValue: { + QualType T = TA.getStructuralValueType(); + llvm::DIType *TTy = getOrCreateType(T, Unit); + llvm::Constant *V = ConstantEmitter(CGM).emitAbstract( + SourceLocation(), TA.getAsStructuralValue(), T); + TemplateParams.push_back(DBuilder.createTemplateValueParameter( + TheCU, Name, TTy, defaultParameter, V)); + } break; case TemplateArgument::Template: { std::string QualName; llvm::raw_string_ostream OS(QualName); @@ -5401,6 +5409,8 @@ std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const { // feasible some day. return TA.getAsIntegral().getBitWidth() <= 64 && IsReconstitutableType(TA.getIntegralType()); + case TemplateArgument::StructuralValue: + return false; case TemplateArgument::Type: return IsReconstitutableType(TA.getAsType()); default: diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGDecl.cpp index a5da0aa2965a..bbe14ef4c172 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGDecl.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGDecl.cpp @@ -1759,20 +1759,34 @@ void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D, Address Loc) { auto trivialAutoVarInit = getContext().getLangOpts().getTrivialAutoVarInit(); + auto trivialAutoVarInitMaxSize = + getContext().getLangOpts().TrivialAutoVarInitMaxSize; CharUnits Size = getContext().getTypeSizeInChars(type); bool isVolatile = type.isVolatileQualified(); if (!Size.isZero()) { + // We skip auto-init variables by their alloc size. Take this as an example: + // "struct Foo {int x; char buff[1024];}" Assume the max-size flag is 1023. + // All Foo type variables will be skipped. Ideally, we only skip the buff + // array and still auto-init X in this example. + // TODO: Improve the size filtering to by member size. + auto allocSize = CGM.getDataLayout().getTypeAllocSize(Loc.getElementType()); switch (trivialAutoVarInit) { case LangOptions::TrivialAutoVarInitKind::Uninitialized: llvm_unreachable("Uninitialized handled by caller"); case LangOptions::TrivialAutoVarInitKind::Zero: if (CGM.stopAutoInit()) return; + if (trivialAutoVarInitMaxSize > 0 && + allocSize > trivialAutoVarInitMaxSize) + return; emitStoresForZeroInit(CGM, D, Loc, isVolatile, Builder); break; case LangOptions::TrivialAutoVarInitKind::Pattern: if (CGM.stopAutoInit()) return; + if (trivialAutoVarInitMaxSize > 0 && + allocSize > trivialAutoVarInitMaxSize) + return; emitStoresForPatternInit(CGM, D, Loc, isVolatile, Builder); break; } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp index 56a246eb65e0..5a9d06da12de 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp @@ -127,6 +127,8 @@ const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr }; const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1", nullptr}; +const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2", + nullptr}; static const EHPersonality &getCPersonality(const TargetInfo &Target, const LangOptions &L) { @@ -187,6 +189,8 @@ static const EHPersonality &getCXXPersonality(const TargetInfo &Target, return EHPersonality::GNU_CPlusPlus_SEH; if (L.hasWasmExceptions()) return EHPersonality::GNU_Wasm_CPlusPlus; + if (T.isOSzOS()) + return EHPersonality::ZOS_CPlusPlus; return EHPersonality::GNU_CPlusPlus; } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp index d12e85b48d0b..c5f6b6d3a99f 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp @@ -1516,6 +1516,14 @@ LValue CodeGenFunction::EmitLValue(const Expr *E, return LV; } +static QualType getConstantExprReferredType(const FullExpr *E, + const ASTContext &Ctx) { + const Expr *SE = E->getSubExpr()->IgnoreImplicit(); + if (isa<OpaqueValueExpr>(SE)) + return SE->getType(); + return cast<CallExpr>(SE)->getCallReturnType(Ctx)->getPointeeType(); +} + LValue CodeGenFunction::EmitLValueHelper(const Expr *E, KnownNonNull_t IsKnownNonNull) { ApplyDebugLocation DL(*this, E); @@ -1554,9 +1562,7 @@ LValue CodeGenFunction::EmitLValueHelper(const Expr *E, case Expr::ConstantExprClass: { const ConstantExpr *CE = cast<ConstantExpr>(E); if (llvm::Value *Result = ConstantEmitter(*this).tryEmitConstantExpr(CE)) { - QualType RetType = cast<CallExpr>(CE->getSubExpr()->IgnoreImplicit()) - ->getCallReturnType(getContext()) - ->getPointeeType(); + QualType RetType = getConstantExprReferredType(CE, getContext()); return MakeNaturalAlignAddrLValue(Result, RetType); } return EmitLValue(cast<ConstantExpr>(E)->getSubExpr(), IsKnownNonNull); diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp index 98ae56e2df88..d136bfc37278 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGExprCXX.cpp @@ -1038,11 +1038,25 @@ void CodeGenFunction::EmitNewArrayInitializer( return true; }; + const InitListExpr *ILE = dyn_cast<InitListExpr>(Init); + const CXXParenListInitExpr *CPLIE = nullptr; + const StringLiteral *SL = nullptr; + const ObjCEncodeExpr *OCEE = nullptr; + const Expr *IgnoreParen = nullptr; + if (!ILE) { + IgnoreParen = Init->IgnoreParenImpCasts(); + CPLIE = dyn_cast<CXXParenListInitExpr>(IgnoreParen); + SL = dyn_cast<StringLiteral>(IgnoreParen); + OCEE = dyn_cast<ObjCEncodeExpr>(IgnoreParen); + } + // If the initializer is an initializer list, first do the explicit elements. - if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + if (ILE || CPLIE || SL || OCEE) { // Initializing from a (braced) string literal is a special case; the init // list element does not initialize a (single) array element. - if (ILE->isStringLiteralInit()) { + if ((ILE && ILE->isStringLiteralInit()) || SL || OCEE) { + if (!ILE) + Init = IgnoreParen; // Initialize the initial portion of length equal to that of the string // literal. The allocation must be for at least this much; we emitted a // check for that earlier. @@ -1054,12 +1068,13 @@ void CodeGenFunction::EmitNewArrayInitializer( AggValueSlot::DoesNotOverlap, AggValueSlot::IsNotZeroed, AggValueSlot::IsSanitizerChecked); - EmitAggExpr(ILE->getInit(0), Slot); + EmitAggExpr(ILE ? ILE->getInit(0) : Init, Slot); // Move past these elements. InitListElements = - cast<ConstantArrayType>(ILE->getType()->getAsArrayTypeUnsafe()) - ->getSize().getZExtValue(); + cast<ConstantArrayType>(Init->getType()->getAsArrayTypeUnsafe()) + ->getSize() + .getZExtValue(); CurPtr = Builder.CreateConstInBoundsGEP( CurPtr, InitListElements, "string.init.end"); @@ -1073,7 +1088,9 @@ void CodeGenFunction::EmitNewArrayInitializer( return; } - InitListElements = ILE->getNumInits(); + ArrayRef<const Expr *> InitExprs = + ILE ? ILE->inits() : CPLIE->getInitExprs(); + InitListElements = InitExprs.size(); // If this is a multi-dimensional array new, we will initialize multiple // elements with each init list element. @@ -1101,7 +1118,8 @@ void CodeGenFunction::EmitNewArrayInitializer( } CharUnits StartAlign = CurPtr.getAlignment(); - for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { + unsigned i = 0; + for (const Expr *IE : InitExprs) { // Tell the cleanup that it needs to destroy up to this // element. TODO: some of these stores can be trivially // observed to be unnecessary. @@ -1111,18 +1129,17 @@ void CodeGenFunction::EmitNewArrayInitializer( // FIXME: If the last initializer is an incomplete initializer list for // an array, and we have an array filler, we can fold together the two // initialization loops. - StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), - ILE->getInit(i)->getType(), CurPtr, + StoreAnyExprIntoOneUnit(*this, IE, IE->getType(), CurPtr, AggValueSlot::DoesNotOverlap); CurPtr = Address(Builder.CreateInBoundsGEP( CurPtr.getElementType(), CurPtr.getPointer(), Builder.getSize(1), "array.exp.next"), CurPtr.getElementType(), - StartAlign.alignmentAtOffset((i + 1) * ElementSize)); + StartAlign.alignmentAtOffset((++i) * ElementSize)); } // The remaining elements are filled with the array filler expression. - Init = ILE->getArrayFiller(); + Init = ILE ? ILE->getArrayFiller() : CPLIE->getArrayFiller(); // Extract the initializer for the individual array elements by pulling // out the array filler from all the nested initializer lists. This avoids @@ -1561,16 +1578,23 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // 1. Build a call to the allocation function. FunctionDecl *allocator = E->getOperatorNew(); - // If there is a brace-initializer, cannot allocate fewer elements than inits. + // If there is a brace-initializer or C++20 parenthesized initializer, cannot + // allocate fewer elements than inits. unsigned minElements = 0; if (E->isArray() && E->hasInitializer()) { - const InitListExpr *ILE = dyn_cast<InitListExpr>(E->getInitializer()); - if (ILE && ILE->isStringLiteralInit()) + const Expr *Init = E->getInitializer(); + const InitListExpr *ILE = dyn_cast<InitListExpr>(Init); + const CXXParenListInitExpr *CPLIE = dyn_cast<CXXParenListInitExpr>(Init); + const Expr *IgnoreParen = Init->IgnoreParenImpCasts(); + if ((ILE && ILE->isStringLiteralInit()) || + isa<StringLiteral>(IgnoreParen) || isa<ObjCEncodeExpr>(IgnoreParen)) { minElements = - cast<ConstantArrayType>(ILE->getType()->getAsArrayTypeUnsafe()) - ->getSize().getZExtValue(); - else if (ILE) - minElements = ILE->getNumInits(); + cast<ConstantArrayType>(Init->getType()->getAsArrayTypeUnsafe()) + ->getSize() + .getZExtValue(); + } else if (ILE || CPLIE) { + minElements = ILE ? ILE->getNumInits() : CPLIE->getInitExprs().size(); + } } llvm::Value *numElements = nullptr; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGExprComplex.cpp index e532794b71bd..839fe16cd772 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGExprComplex.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGExprComplex.cpp @@ -892,6 +892,9 @@ ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr, llvm::Value *LHSi, llvm::Value *RHSr, llvm::Value *RHSi) { + // FIXME: This could eventually be replaced by an LLVM intrinsic to + // avoid this long IR sequence. + // (a + ib) / (c + id) = (e + if) llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c| llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d| @@ -936,7 +939,7 @@ ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr, llvm::Value *RC = Builder.CreateFMul(CdD, RHSr); // rc llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // tmp=d+rc - llvm::Value *T7 = Builder.CreateFMul(LHSr, RC); // ar + llvm::Value *T7 = Builder.CreateFMul(LHSr, CdD); // ar llvm::Value *T8 = Builder.CreateFAdd(T7, LHSi); // ar+b llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (ar+b)/tmp @@ -978,7 +981,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi); else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited) return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi); - else if (!CGF.getLangOpts().FastMath) { + else if (!CGF.getLangOpts().FastMath || + // '-ffast-math' is used in the command line but followed by an + // '-fno-cx-limited-range'. + Op.FPFeatures.getComplexRange() == LangOptions::CX_Full) { LHSi = OrigLHSi; // If we have a complex operand on the RHS and FastMath is not allowed, we // delegate to a libcall to handle all of the complexities and minimize diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGExprScalar.cpp index 9ec185153d12..181b15e9c7d0 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGExprScalar.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGExprScalar.cpp @@ -4960,6 +4960,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { CGF.getProfileCount(lhsExpr)); CGF.EmitBlock(LHSBlock); + + // If the top of the logical operator nest, update the MCDC bitmap for the + // ConditionalOperator prior to visiting its LHS and RHS blocks, since they + // may also contain a boolean expression. + if (CGF.MCDCLogOpStack.empty()) + CGF.maybeUpdateMCDCTestVectorBitmap(condExpr); + CGF.incrementProfileCounter(E); eval.begin(CGF); Value *LHS = Visit(lhsExpr); @@ -4969,6 +4976,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { Builder.CreateBr(ContBlock); CGF.EmitBlock(RHSBlock); + + // If the top of the logical operator nest, update the MCDC bitmap for the + // ConditionalOperator prior to visiting its LHS and RHS blocks, since they + // may also contain a boolean expression. + if (CGF.MCDCLogOpStack.empty()) + CGF.maybeUpdateMCDCTestVectorBitmap(condExpr); + eval.begin(CGF); Value *RHS = Visit(rhsExpr); eval.end(CGF); @@ -4987,10 +5001,6 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { PN->addIncoming(LHS, LHSBlock); PN->addIncoming(RHS, RHSBlock); - // If the top of the logical operator nest, update the MCDC bitmap. - if (CGF.MCDCLogOpStack.empty()) - CGF.maybeUpdateMCDCTestVectorBitmap(condExpr); - return PN; } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGObjC.cpp index acc85165a470..03fc0ec7ff54 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGObjC.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGObjC.cpp @@ -3941,6 +3941,8 @@ static unsigned getBaseMachOPlatformID(const llvm::Triple &TT) { return llvm::MachO::PLATFORM_TVOS; case llvm::Triple::WatchOS: return llvm::MachO::PLATFORM_WATCHOS; + case llvm::Triple::XROS: + return llvm::MachO::PLATFORM_XROS; case llvm::Triple::DriverKit: return llvm::MachO::PLATFORM_DRIVERKIT; default: @@ -4024,6 +4026,9 @@ static bool isFoundationNeededForDarwinAvailabilityCheck( case llvm::Triple::MacOSX: FoundationDroppedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/15); break; + case llvm::Triple::XROS: + // XROS doesn't need Foundation. + return false; case llvm::Triple::DriverKit: // DriverKit doesn't need Foundation. return false; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp index cd1a0b6a130f..a36b0cdddaf0 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp @@ -18,6 +18,8 @@ #include "CGObjCRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CodeGenTypes.h" +#include "SanitizerMetadata.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" @@ -597,6 +599,10 @@ public: llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) override; + + // Map to unify direct method definitions. + llvm::DenseMap<const ObjCMethodDecl *, llvm::Function *> + DirectMethodDefinitions; void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) override; @@ -917,6 +923,14 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { ClassAliasSection, ConstantStringSection }; + /// The subset of `objc_class_flags` used at compile time. + enum ClassFlags { + /// This is a metaclass + ClassFlagMeta = (1 << 0), + /// This class has been initialised by the runtime (+initialize has been + /// sent if necessary). + ClassFlagInitialized = (1 << 8), + }; static const char *const SectionsBaseNames[8]; static const char *const PECOFFSectionsBaseNames[8]; template<SectionKind K> @@ -932,6 +946,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { /// structure describing the receiver and the class, and a selector as /// arguments. Returns the IMP for the corresponding method. LazyRuntimeFunction MsgLookupSuperFn; + /// Function to ensure that +initialize is sent to a class. + LazyRuntimeFunction SentInitializeFn; /// A flag indicating if we've emitted at least one protocol. /// If we haven't, then we need to emit an empty protocol, to ensure that the /// __start__objc_protocols and __stop__objc_protocols sections exist. @@ -1431,12 +1447,24 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { const std::string &TypeEncoding) override { return GetConstantSelector(Sel, TypeEncoding); } + std::string GetSymbolNameForTypeEncoding(const std::string &TypeEncoding) { + std::string MangledTypes = std::string(TypeEncoding); + // @ is used as a special character in ELF symbol names (used for symbol + // versioning), so mangle the name to not include it. Replace it with a + // character that is not a valid type encoding character (and, being + // non-printable, never will be!) + if (CGM.getTriple().isOSBinFormatELF()) + std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1'); + // = in dll exported names causes lld to fail when linking on Windows. + if (CGM.getTriple().isOSWindows()) + std::replace(MangledTypes.begin(), MangledTypes.end(), '=', '\2'); + return MangledTypes; + } llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) { if (TypeEncoding.empty()) return NULLPtr; - std::string MangledTypes = std::string(TypeEncoding); - std::replace(MangledTypes.begin(), MangledTypes.end(), - '@', '\1'); + std::string MangledTypes = + GetSymbolNameForTypeEncoding(std::string(TypeEncoding)); std::string TypesVarName = ".objc_sel_types_" + MangledTypes; auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName); if (!TypesGlobal) { @@ -1453,13 +1481,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { } llvm::Constant *GetConstantSelector(Selector Sel, const std::string &TypeEncoding) override { - // @ is used as a special character in symbol names (used for symbol - // versioning), so mangle the name to not include it. Replace it with a - // character that is not a valid type encoding character (and, being - // non-printable, never will be!) - std::string MangledTypes = TypeEncoding; - std::replace(MangledTypes.begin(), MangledTypes.end(), - '@', '\1'); + std::string MangledTypes = GetSymbolNameForTypeEncoding(TypeEncoding); auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" + MangledTypes).str(); if (auto *GV = TheModule.getNamedGlobal(SelVarName)) @@ -1671,9 +1693,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { const ObjCIvarDecl *Ivar) override { std::string TypeEncoding; CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding); - // Prevent the @ from being interpreted as a symbol version. - std::replace(TypeEncoding.begin(), TypeEncoding.end(), - '@', '\1'); + TypeEncoding = GetSymbolNameForTypeEncoding(TypeEncoding); const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() + '.' + Ivar->getNameAsString() + '.' + TypeEncoding; return Name; @@ -1715,7 +1735,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { metaclassFields.addInt(LongTy, 0); // unsigned long info; // objc_class_flag_meta - metaclassFields.addInt(LongTy, 1); + metaclassFields.addInt(LongTy, ClassFlags::ClassFlagMeta); // long instance_size; // Setting this to zero is consistent with the older ABI, but it might be // more sensible to set this to sizeof(struct objc_class) @@ -1989,6 +2009,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { CGObjCGNUstep2(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 10, 4, 2) { MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, PtrToObjCSuperTy, SelectorTy); + SentInitializeFn.init(&CGM, "objc_send_initialize", + llvm::Type::getVoidTy(VMContext), IdTy); // struct objc_property // { // const char *name; @@ -2002,6 +2024,106 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { { PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty }); } + void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) override { + auto &Builder = CGF.Builder; + bool ReceiverCanBeNull = true; + auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl()); + auto selfValue = Builder.CreateLoad(selfAddr); + + // Generate: + // + // /* unless the receiver is never NULL */ + // if (self == nil) { + // return (ReturnType){ }; + // } + // + // /* for class methods only to force class lazy initialization */ + // if (!__objc_{class}_initialized) + // { + // objc_send_initialize(class); + // __objc_{class}_initialized = 1; + // } + // + // _cmd = @selector(...) + // ... + + if (OMD->isClassMethod()) { + const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD); + + // Nullable `Class` expressions cannot be messaged with a direct method + // so the only reason why the receive can be null would be because + // of weak linking. + ReceiverCanBeNull = isWeakLinkedClass(OID); + } + + llvm::MDBuilder MDHelper(CGM.getLLVMContext()); + if (ReceiverCanBeNull) { + llvm::BasicBlock *SelfIsNilBlock = + CGF.createBasicBlock("objc_direct_method.self_is_nil"); + llvm::BasicBlock *ContBlock = + CGF.createBasicBlock("objc_direct_method.cont"); + + // if (self == nil) { + auto selfTy = cast<llvm::PointerType>(selfValue->getType()); + auto Zero = llvm::ConstantPointerNull::get(selfTy); + + Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero), + SelfIsNilBlock, ContBlock, + MDHelper.createBranchWeights(1, 1 << 20)); + + CGF.EmitBlock(SelfIsNilBlock); + + // return (ReturnType){ }; + auto retTy = OMD->getReturnType(); + Builder.SetInsertPoint(SelfIsNilBlock); + if (!retTy->isVoidType()) { + CGF.EmitNullInitialization(CGF.ReturnValue, retTy); + } + CGF.EmitBranchThroughCleanup(CGF.ReturnBlock); + // } + + // rest of the body + CGF.EmitBlock(ContBlock); + Builder.SetInsertPoint(ContBlock); + } + + if (OMD->isClassMethod()) { + // Prefix of the class type. + auto *classStart = + llvm::StructType::get(PtrTy, PtrTy, PtrTy, LongTy, LongTy); + auto &astContext = CGM.getContext(); + auto flags = Builder.CreateLoad( + Address{Builder.CreateStructGEP(classStart, selfValue, 4), LongTy, + CharUnits::fromQuantity( + astContext.getTypeAlign(astContext.UnsignedLongTy))}); + auto isInitialized = + Builder.CreateAnd(flags, ClassFlags::ClassFlagInitialized); + llvm::BasicBlock *notInitializedBlock = + CGF.createBasicBlock("objc_direct_method.class_uninitialized"); + llvm::BasicBlock *initializedBlock = + CGF.createBasicBlock("objc_direct_method.class_initialized"); + Builder.CreateCondBr(Builder.CreateICmpEQ(isInitialized, Zeros[0]), + notInitializedBlock, initializedBlock, + MDHelper.createBranchWeights(1, 1 << 20)); + CGF.EmitBlock(notInitializedBlock); + Builder.SetInsertPoint(notInitializedBlock); + CGF.EmitRuntimeCall(SentInitializeFn, selfValue); + Builder.CreateBr(initializedBlock); + CGF.EmitBlock(initializedBlock); + Builder.SetInsertPoint(initializedBlock); + } + + // only synthesize _cmd if it's referenced + if (OMD->getCmdDecl()->isUsed()) { + // `_cmd` is not a parameter to direct methods, so storage must be + // explicitly declared for it. + CGF.EmitVarDecl(*OMD->getCmdDecl()); + Builder.CreateStore(GetSelector(CGF, OMD), + CGF.GetAddrOfLocalVar(OMD->getCmdDecl())); + } + } }; const char *const CGObjCGNUstep2::SectionsBaseNames[8] = @@ -2645,13 +2767,18 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, } } + bool isDirect = Method && Method->isDirectMethod(); + IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; - if (Method) - cmd = GetSelector(CGF, Method); - else - cmd = GetSelector(CGF, Sel); - cmd = EnforceType(Builder, cmd, SelectorTy); + if (!isDirect) { + if (Method) + cmd = GetSelector(CGF, Method); + else + cmd = GetSelector(CGF, Sel); + cmd = EnforceType(Builder, cmd, SelectorTy); + } + Receiver = EnforceType(Builder, Receiver, IdTy); llvm::Metadata *impMD[] = { @@ -2663,7 +2790,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, CallArgList ActualArgs; ActualArgs.add(RValue::get(Receiver), ASTIdTy); - ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); + if (!isDirect) + ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); @@ -2682,7 +2810,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, // Rather than doing a whole target-specific analysis, we assume it // only works for void, integer, and pointer types, and in all // other cases we do an explicit nil check is emitted code. In - // addition to ensuring we produe a zero value for other types, this + // addition to ensuring we produce a zero value for other types, this // sidesteps the few outright CC incompatibilities we know about that // could otherwise lead to crashes, like when a method is expected to // return on the x87 floating point stack or adjust the stack pointer @@ -2716,8 +2844,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, // FIXME: we probably need a size limit here, but we've // never imposed one before } else { - // Otherwise, use an explicit check just to be sure. - requiresExplicitZeroResult = true; + // Otherwise, use an explicit check just to be sure, unless we're + // calling a direct method, where the implementation does this for us. + requiresExplicitZeroResult = !isDirect; } } @@ -2761,10 +2890,14 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, // Get the IMP to call llvm::Value *imp; - // If we have non-legacy dispatch specified, we try using the objc_msgSend() - // functions. These are not supported on all platforms (or all runtimes on a - // given platform), so we - switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { + // If this is a direct method, just emit it here. + if (isDirect) + imp = GenerateMethod(Method, Method->getClassInterface()); + else + // If we have non-legacy dispatch specified, we try using the + // objc_msgSend() functions. These are not supported on all platforms + // (or all runtimes on a given platform), so we + switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { case CodeGenOptions::Legacy: imp = LookupIMP(CGF, Receiver, cmd, node, MSI); break; @@ -2787,7 +2920,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend") .getCallee(); } - } + } // Reset the receiver in case the lookup modified it ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy); @@ -2797,7 +2930,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, llvm::CallBase *call; CGCallee callee(CGCalleeInfo(), imp); RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call); - call->setMetadata(msgSendMDKind, node); + if (!isDirect) + call->setMetadata(msgSendMDKind, node); if (requiresNilReceiverCheck) { llvm::BasicBlock *nonNilPathBB = CGF.Builder.GetInsertBlock(); @@ -3920,14 +4054,50 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, CodeGenTypes &Types = CGM.getTypes(); llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD)); - std::string FunctionName = getSymbolNameForMethod(OMD); - - llvm::Function *Method - = llvm::Function::Create(MethodTy, - llvm::GlobalValue::InternalLinkage, - FunctionName, - &TheModule); - return Method; + + bool isDirect = OMD->isDirectMethod(); + std::string FunctionName = + getSymbolNameForMethod(OMD, /*include category*/ !isDirect); + + if (!isDirect) + return llvm::Function::Create(MethodTy, + llvm::GlobalVariable::InternalLinkage, + FunctionName, &TheModule); + + auto *COMD = OMD->getCanonicalDecl(); + auto I = DirectMethodDefinitions.find(COMD); + llvm::Function *OldFn = nullptr, *Fn = nullptr; + + if (I == DirectMethodDefinitions.end()) { + auto *F = + llvm::Function::Create(MethodTy, llvm::GlobalVariable::ExternalLinkage, + FunctionName, &TheModule); + DirectMethodDefinitions.insert(std::make_pair(COMD, F)); + return F; + } + + // Objective-C allows for the declaration and implementation types + // to differ slightly. + // + // If we're being asked for the Function associated for a method + // implementation, a previous value might have been cached + // based on the type of the canonical declaration. + // + // If these do not match, then we'll replace this function with + // a new one that has the proper type below. + if (!OMD->getBody() || COMD->getReturnType() == OMD->getReturnType()) + return I->second; + + OldFn = I->second; + Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage, "", + &CGM.getModule()); + Fn->takeName(OldFn); + OldFn->replaceAllUsesWith(Fn); + OldFn->eraseFromParent(); + + // Replace the cached function in the map. + I->second = Fn; + return Fn; } void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF, diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp index ea6645a39e83..4855e7410a01 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1044,6 +1044,13 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM) ? CGM.getLangOpts().OMPHostIRFile : StringRef{}); OMPBuilder.setConfig(Config); + + // The user forces the compiler to behave as if omp requires + // unified_shared_memory was given. + if (CGM.getLangOpts().OpenMPForceUSM) { + HasRequiresUnifiedSharedMemory = true; + OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true); + } } void CGOpenMPRuntime::clear() { diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp index b89017de0bcf..beff0ad9da27 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp @@ -2399,9 +2399,9 @@ EmitAsmStores(CodeGenFunction &CGF, const AsmStmt &S, Tmp = Builder.CreatePtrToInt( Tmp, llvm::IntegerType::get(CTX, (unsigned)TmpSize)); Tmp = Builder.CreateTrunc(Tmp, TruncTy); - } else if (TruncTy->isIntegerTy()) { + } else if (Tmp->getType()->isIntegerTy() && TruncTy->isIntegerTy()) { Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy); - } else if (TruncTy->isVectorTy()) { + } else if (Tmp->getType()->isVectorTy() || TruncTy->isVectorTy()) { Tmp = Builder.CreateBitCast(Tmp, TruncTy); } } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp index 27a2cab4f753..8dee3f74b44b 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGVTables.cpp @@ -793,7 +793,7 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, llvm::Constant *fnPtr; // Pure virtual member functions. - if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { + if (cast<CXXMethodDecl>(GD.getDecl())->isPureVirtual()) { if (!PureVirtualFn) PureVirtualFn = getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName()); diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp index ad6fc71c1e50..1280bcd36de9 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp @@ -229,7 +229,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { ABIFLen = 32; else if (ABIStr.ends_with("d")) ABIFLen = 64; - return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen); + bool EABI = ABIStr.ends_with("e"); + return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen, EABI); } case llvm::Triple::systemz: { @@ -721,43 +722,70 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags, } } +static std::optional<llvm::GlobalValue::VisibilityTypes> +getLLVMVisibility(clang::LangOptions::VisibilityFromDLLStorageClassKinds K) { + // Map to LLVM visibility. + switch (K) { + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Keep: + return std::nullopt; + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Default: + return llvm::GlobalValue::DefaultVisibility; + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Hidden: + return llvm::GlobalValue::HiddenVisibility; + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Protected: + return llvm::GlobalValue::ProtectedVisibility; + } + llvm_unreachable("unknown option value!"); +} + +void setLLVMVisibility(llvm::GlobalValue &GV, + std::optional<llvm::GlobalValue::VisibilityTypes> V) { + if (!V) + return; + + // Reset DSO locality before setting the visibility. This removes + // any effects that visibility options and annotations may have + // had on the DSO locality. Setting the visibility will implicitly set + // appropriate globals to DSO Local; however, this will be pessimistic + // w.r.t. to the normal compiler IRGen. + GV.setDSOLocal(false); + GV.setVisibility(*V); +} + static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO, llvm::Module &M) { if (!LO.VisibilityFromDLLStorageClass) return; - llvm::GlobalValue::VisibilityTypes DLLExportVisibility = - CodeGenModule::GetLLVMVisibility(LO.getDLLExportVisibility()); - llvm::GlobalValue::VisibilityTypes NoDLLStorageClassVisibility = - CodeGenModule::GetLLVMVisibility(LO.getNoDLLStorageClassVisibility()); - llvm::GlobalValue::VisibilityTypes ExternDeclDLLImportVisibility = - CodeGenModule::GetLLVMVisibility(LO.getExternDeclDLLImportVisibility()); - llvm::GlobalValue::VisibilityTypes ExternDeclNoDLLStorageClassVisibility = - CodeGenModule::GetLLVMVisibility( - LO.getExternDeclNoDLLStorageClassVisibility()); + std::optional<llvm::GlobalValue::VisibilityTypes> DLLExportVisibility = + getLLVMVisibility(LO.getDLLExportVisibility()); + + std::optional<llvm::GlobalValue::VisibilityTypes> + NoDLLStorageClassVisibility = + getLLVMVisibility(LO.getNoDLLStorageClassVisibility()); + + std::optional<llvm::GlobalValue::VisibilityTypes> + ExternDeclDLLImportVisibility = + getLLVMVisibility(LO.getExternDeclDLLImportVisibility()); + + std::optional<llvm::GlobalValue::VisibilityTypes> + ExternDeclNoDLLStorageClassVisibility = + getLLVMVisibility(LO.getExternDeclNoDLLStorageClassVisibility()); for (llvm::GlobalValue &GV : M.global_values()) { if (GV.hasAppendingLinkage() || GV.hasLocalLinkage()) continue; - // Reset DSO locality before setting the visibility. This removes - // any effects that visibility options and annotations may have - // had on the DSO locality. Setting the visibility will implicitly set - // appropriate globals to DSO Local; however, this will be pessimistic - // w.r.t. to the normal compiler IRGen. - GV.setDSOLocal(false); - - if (GV.isDeclarationForLinker()) { - GV.setVisibility(GV.getDLLStorageClass() == - llvm::GlobalValue::DLLImportStorageClass - ? ExternDeclDLLImportVisibility - : ExternDeclNoDLLStorageClassVisibility); - } else { - GV.setVisibility(GV.getDLLStorageClass() == - llvm::GlobalValue::DLLExportStorageClass - ? DLLExportVisibility - : NoDLLStorageClassVisibility); - } + if (GV.isDeclarationForLinker()) + setLLVMVisibility(GV, GV.getDLLStorageClass() == + llvm::GlobalValue::DLLImportStorageClass + ? ExternDeclDLLImportVisibility + : ExternDeclNoDLLStorageClassVisibility); + else + setLLVMVisibility(GV, GV.getDLLStorageClass() == + llvm::GlobalValue::DLLExportStorageClass + ? DLLExportVisibility + : NoDLLStorageClassVisibility); GV.setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); } @@ -1201,7 +1229,7 @@ void CodeGenModule::Release() { llvm::CodeModel::Model codeModel = static_cast<llvm::CodeModel::Model>(CM); getModule().setCodeModel(codeModel); - if (CM == llvm::CodeModel::Medium && + if ((CM == llvm::CodeModel::Medium || CM == llvm::CodeModel::Large) && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) { getModule().setLargeDataThreshold(getCodeGenOpts().LargeDataThreshold); @@ -1688,8 +1716,10 @@ static void AppendCPUSpecificCPUDispatchMangling(const CodeGenModule &CGM, static void AppendTargetVersionMangling(const CodeGenModule &CGM, const TargetVersionAttr *Attr, raw_ostream &Out) { - if (Attr->isDefaultVersion()) + if (Attr->isDefaultVersion()) { + Out << ".default"; return; + } Out << "._"; const TargetInfo &TI = CGM.getTarget(); llvm::SmallVector<StringRef, 8> Feats; @@ -1752,8 +1782,10 @@ static void AppendTargetClonesMangling(const CodeGenModule &CGM, const TargetInfo &TI = CGM.getTarget(); if (TI.getTriple().isAArch64()) { StringRef FeatureStr = Attr->getFeatureStr(VersionIndex); - if (FeatureStr == "default") + if (FeatureStr == "default") { + Out << ".default"; return; + } Out << "._"; SmallVector<StringRef, 8> Features; FeatureStr.split(Features, "+"); @@ -2380,8 +2412,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, if (D->hasAttr<ArmLocallyStreamingAttr>()) B.addAttribute("aarch64_pstate_sm_body"); - if (D->hasAttr<ArmNewZAAttr>()) - B.addAttribute("aarch64_pstate_za_new"); + if (auto *Attr = D->getAttr<ArmNewAttr>()) { + if (Attr->isNewZA()) + B.addAttribute("aarch64_pstate_za_new"); + if (Attr->isNewZT0()) + B.addAttribute("aarch64_new_zt0"); + } // Track whether we need to add the optnone LLVM attribute, // starting with the default for this optimization level. @@ -3999,6 +4035,8 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD, EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); // Ensure that the resolver function is also emitted. GetOrCreateMultiVersionResolver(GD); + } else if (FD->hasAttr<TargetVersionAttr>()) { + GetOrCreateMultiVersionResolver(GD); } else EmitGlobalFunctionDefinition(GD, GV); } @@ -4180,14 +4218,7 @@ void CodeGenModule::emitMultiVersionFunctions() { llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD); if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) { ResolverConstant = IFunc->getResolver(); - // In Aarch64, default versions of multiversioned functions are mangled to - // their 'normal' assembly name. This deviates from other targets which - // append a '.default' string. As a result we need to continue appending - // .ifunc in Aarch64. - // FIXME: Should Aarch64 mangling for 'default' multiversion function and - // in turn ifunc function match that of other targets? - if (FD->isTargetClonesMultiVersion() && - !getTarget().getTriple().isAArch64()) { + if (FD->isTargetClonesMultiVersion()) { const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI); std::string MangledName = getMangledNameImpl( @@ -4368,14 +4399,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { // a separate resolver). std::string ResolverName = MangledName; if (getTarget().supportsIFunc()) { - // In Aarch64, default versions of multiversioned functions are mangled to - // their 'normal' assembly name. This deviates from other targets which - // append a '.default' string. As a result we need to continue appending - // .ifunc in Aarch64. - // FIXME: Should Aarch64 mangling for 'default' multiversion function and - // in turn ifunc function match that of other targets? - if (!FD->isTargetClonesMultiVersion() || - getTarget().getTriple().isAArch64()) + if (!FD->isTargetClonesMultiVersion()) ResolverName += ".ifunc"; } else if (FD->isTargetMultiVersion()) { ResolverName += ".resolver"; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenPGO.cpp b/contrib/llvm-project/clang/lib/CodeGen/CodeGenPGO.cpp index d68844d476eb..5d7c38477457 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenPGO.cpp @@ -28,6 +28,8 @@ static llvm::cl::opt<bool> llvm::cl::desc("Enable value profiling"), llvm::cl::Hidden, llvm::cl::init(false)); +extern llvm::cl::opt<bool> SystemHeadersCoverage; + using namespace clang; using namespace CodeGen; @@ -1022,7 +1024,7 @@ bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) { // Don't map the functions in system headers. const auto &SM = CGM.getContext().getSourceManager(); auto Loc = D->getBody()->getBeginLoc(); - return SM.isInSystemHeader(Loc); + return !SystemHeadersCoverage && SM.isInSystemHeader(Loc); } void CodeGenPGO::emitCounterRegionMapping(const Decl *D) { diff --git a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp index b245abd16c3f..5eca00f22bb8 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -37,7 +37,7 @@ static llvm::cl::opt<bool> EmptyLineCommentCoverage( "disable it on test)"), llvm::cl::init(true), llvm::cl::Hidden); -static llvm::cl::opt<bool> SystemHeadersCoverage( +llvm::cl::opt<bool> SystemHeadersCoverage( "system-headers-coverage", llvm::cl::desc("Enable collecting coverage from system headers"), llvm::cl::init(false), llvm::cl::Hidden); @@ -119,12 +119,16 @@ class SourceMappingRegion { /// as the line execution count if there are no other regions on the line. bool GapRegion; + /// Whetever this region is skipped ('if constexpr' or 'if consteval' untaken + /// branch, or anything skipped but not empty line / comments) + bool SkippedRegion; + public: SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart, std::optional<SourceLocation> LocEnd, bool GapRegion = false) - : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) { - } + : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion), + SkippedRegion(false) {} SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount, MCDCParameters MCDCParams, @@ -132,13 +136,14 @@ public: std::optional<SourceLocation> LocEnd, bool GapRegion = false) : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams), - LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {} + LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion), + SkippedRegion(false) {} SourceMappingRegion(MCDCParameters MCDCParams, std::optional<SourceLocation> LocStart, std::optional<SourceLocation> LocEnd) : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd), - GapRegion(false) {} + GapRegion(false), SkippedRegion(false) {} const Counter &getCounter() const { return Count; } @@ -174,6 +179,10 @@ public: void setGap(bool Gap) { GapRegion = Gap; } + bool isSkipped() const { return SkippedRegion; } + + void setSkipped(bool Skipped) { SkippedRegion = Skipped; } + bool isBranch() const { return FalseCount.has_value(); } bool isMCDCDecision() const { return MCDCParams.NumConditions != 0; } @@ -468,6 +477,10 @@ public: MappingRegions.push_back(CounterMappingRegion::makeGapRegion( Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd)); + } else if (Region.isSkipped()) { + MappingRegions.push_back(CounterMappingRegion::makeSkipped( + *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, + SR.ColumnEnd)); } else if (Region.isBranch()) { MappingRegions.push_back(CounterMappingRegion::makeBranchRegion( Region.getCounter(), Region.getFalseCounter(), @@ -573,6 +586,11 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { /// creation. struct MCDCCoverageBuilder { + struct DecisionIDPair { + MCDCConditionID TrueID = 0; + MCDCConditionID FalseID = 0; + }; + /// The AST walk recursively visits nested logical-AND or logical-OR binary /// operator nodes and then visits their LHS and RHS children nodes. As this /// happens, the algorithm will assign IDs to each operator's LHS and RHS side @@ -616,14 +634,14 @@ struct MCDCCoverageBuilder { /// /// A node ID of '0' always means MC/DC isn't being tracked. /// - /// As the AST walk proceeds recursively, the algorithm will also use stacks + /// As the AST walk proceeds recursively, the algorithm will also use a stack /// to track the IDs of logical-AND and logical-OR operations on the RHS so /// that it can be determined which nodes are executed next, depending on how /// a LHS or RHS of a logical-AND or logical-OR is evaluated. This /// information relies on the assigned IDs and are embedded within the /// coverage region IDs of each branch region associated with a leaf-level /// condition. This information helps the visualization tool reconstruct all - /// possible test vectors for the purposes of MC/DC analysis. if a "next" node + /// possible test vectors for the purposes of MC/DC analysis. If a "next" node /// ID is '0', it means it's the end of the test vector. The following rules /// are used: /// @@ -663,54 +681,40 @@ struct MCDCCoverageBuilder { private: CodeGenModule &CGM; - llvm::SmallVector<MCDCConditionID> AndRHS; - llvm::SmallVector<MCDCConditionID> OrRHS; - llvm::SmallVector<const BinaryOperator *> NestLevel; + llvm::SmallVector<DecisionIDPair> DecisionStack; llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDs; llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap; MCDCConditionID NextID = 1; bool NotMapped = false; + /// Represent a sentinel value of [0,0] for the bottom of DecisionStack. + static constexpr DecisionIDPair DecisionStackSentinel{0, 0}; + /// Is this a logical-AND operation? bool isLAnd(const BinaryOperator *E) const { return E->getOpcode() == BO_LAnd; } - /// Push an ID onto the corresponding RHS stack. - void pushRHS(const BinaryOperator *E) { - llvm::SmallVector<MCDCConditionID> &rhs = isLAnd(E) ? AndRHS : OrRHS; - rhs.push_back(CondIDs[CodeGenFunction::stripCond(E->getRHS())]); - } - - /// Pop an ID from the corresponding RHS stack. - void popRHS(const BinaryOperator *E) { - llvm::SmallVector<MCDCConditionID> &rhs = isLAnd(E) ? AndRHS : OrRHS; - if (!rhs.empty()) - rhs.pop_back(); - } - - /// If the expected ID is on top, pop it off the corresponding RHS stack. - void popRHSifTop(const BinaryOperator *E) { - if (!OrRHS.empty() && CondIDs[E] == OrRHS.back()) - OrRHS.pop_back(); - else if (!AndRHS.empty() && CondIDs[E] == AndRHS.back()) - AndRHS.pop_back(); - } - public: MCDCCoverageBuilder(CodeGenModule &CGM, llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDMap, llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap) - : CGM(CGM), CondIDs(CondIDMap), MCDCBitmapMap(MCDCBitmapMap) {} + : CGM(CGM), DecisionStack(1, DecisionStackSentinel), CondIDs(CondIDMap), + MCDCBitmapMap(MCDCBitmapMap) {} - /// Return the ID of the RHS of the next, upper nest-level logical-OR. - MCDCConditionID getNextLOrCondID() const { - return OrRHS.empty() ? 0 : OrRHS.back(); - } + /// Return whether the build of the control flow map is at the top-level + /// (root) of a logical operator nest in a boolean expression prior to the + /// assignment of condition IDs. + bool isIdle() const { return (NextID == 1 && !NotMapped); } - /// Return the ID of the RHS of the next, upper nest-level logical-AND. - MCDCConditionID getNextLAndCondID() const { - return AndRHS.empty() ? 0 : AndRHS.back(); + /// Return whether any IDs have been assigned in the build of the control + /// flow map, indicating that the map is being generated for this boolean + /// expression. + bool isBuilding() const { return (NextID > 1); } + + /// Set the given condition's ID. + void setCondID(const Expr *Cond, MCDCConditionID ID) { + CondIDs[CodeGenFunction::stripCond(Cond)] = ID; } /// Return the ID of a given condition. @@ -722,6 +726,9 @@ public: return I->second; } + /// Return the LHS Decision ([0,0] if not set). + const DecisionIDPair &back() const { return DecisionStack.back(); } + /// Push the binary operator statement to track the nest level and assign IDs /// to the operator's LHS and RHS. The RHS may be a larger subtree that is /// broken up on successive levels. @@ -730,68 +737,67 @@ public: return; // If binary expression is disqualified, don't do mapping. - if (NestLevel.empty() && MCDCBitmapMap.find(CodeGenFunction::stripCond( - E)) == MCDCBitmapMap.end()) + if (!isBuilding() && !MCDCBitmapMap.contains(CodeGenFunction::stripCond(E))) NotMapped = true; - // Push Stmt on 'NestLevel' stack to keep track of nest location. - NestLevel.push_back(E); - // Don't go any further if we don't need to map condition IDs. if (NotMapped) return; + const DecisionIDPair &ParentDecision = DecisionStack.back(); + // If the operator itself has an assigned ID, this means it represents a - // larger subtree. In this case, pop its ID out of the RHS stack and - // assign that ID to its LHS node. Its RHS will receive a new ID. - if (CondIDs.find(CodeGenFunction::stripCond(E)) != CondIDs.end()) { - // If Stmt has an ID, assign its ID to LHS - CondIDs[CodeGenFunction::stripCond(E->getLHS())] = CondIDs[E]; - - // Since the operator's LHS assumes the operator's same ID, pop the - // operator from the RHS stack so that if LHS short-circuits, it won't be - // incorrectly re-used as the node executed next. - popRHSifTop(E); - } else { - // Otherwise, assign ID+1 to LHS. - CondIDs[CodeGenFunction::stripCond(E->getLHS())] = NextID++; - } + // larger subtree. In this case, assign that ID to its LHS node. Its RHS + // will receive a new ID below. Otherwise, assign ID+1 to LHS. + if (CondIDs.contains(CodeGenFunction::stripCond(E))) + setCondID(E->getLHS(), getCondID(E)); + else + setCondID(E->getLHS(), NextID++); - // Assign ID+1 to RHS. - CondIDs[CodeGenFunction::stripCond(E->getRHS())] = NextID++; + // Assign a ID+1 for the RHS. + MCDCConditionID RHSid = NextID++; + setCondID(E->getRHS(), RHSid); - // Push ID of Stmt's RHS so that LHS nodes know about it - pushRHS(E); + // Push the LHS decision IDs onto the DecisionStack. + if (isLAnd(E)) + DecisionStack.push_back({RHSid, ParentDecision.FalseID}); + else + DecisionStack.push_back({ParentDecision.TrueID, RHSid}); + } + + /// Pop and return the LHS Decision ([0,0] if not set). + DecisionIDPair pop() { + if (!CGM.getCodeGenOpts().MCDCCoverage || NotMapped) + return DecisionStack.front(); + + assert(DecisionStack.size() > 1); + DecisionIDPair D = DecisionStack.back(); + DecisionStack.pop_back(); + return D; } - /// Pop the binary operator from the next level. If the walk is at the top of - /// the next, assign the total number of conditions. - unsigned popAndReturnCondCount(const BinaryOperator *E) { + /// Return the total number of conditions and reset the state. The number of + /// conditions is zero if the expression isn't mapped. + unsigned getTotalConditionsAndReset(const BinaryOperator *E) { if (!CGM.getCodeGenOpts().MCDCCoverage) return 0; - unsigned TotalConds = 0; - - // Pop Stmt from 'NestLevel' stack. - assert(NestLevel.back() == E); - NestLevel.pop_back(); + assert(!isIdle()); + assert(DecisionStack.size() == 1); // Reset state if not doing mapping. - if (NestLevel.empty() && NotMapped) { + if (NotMapped) { NotMapped = false; + assert(NextID == 1); return 0; } - // Pop RHS ID. - popRHS(E); + // Set number of conditions and reset. + unsigned TotalConds = NextID - 1; - // If at the parent (NestLevel=0), set conds and reset. - if (NestLevel.empty()) { - TotalConds = NextID - 1; + // Reset ID back to beginning. + NextID = 1; - // Reset ID back to beginning. - NextID = 1; - } return TotalConds; } }; @@ -1018,13 +1024,15 @@ struct CounterCoverageMappingBuilder return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())); } + using MCDCDecisionIDPair = MCDCCoverageBuilder::DecisionIDPair; + /// Create a Branch Region around an instrumentable condition for coverage /// and add it to the function's SourceRegions. A branch region tracks a /// "True" counter and a "False" counter for boolean expressions that /// result in the generation of a branch. - void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt, - MCDCConditionID ID = 0, MCDCConditionID TrueID = 0, - MCDCConditionID FalseID = 0) { + void + createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt, + const MCDCDecisionIDPair &IDPair = MCDCDecisionIDPair()) { // Check for NULL conditions. if (!C) return; @@ -1034,6 +1042,10 @@ struct CounterCoverageMappingBuilder // function's SourceRegions) because it doesn't apply to any other source // code other than the Condition. if (CodeGenFunction::isInstrumentedCondition(C)) { + MCDCConditionID ID = MCDCBuilder.getCondID(C); + MCDCConditionID TrueID = IDPair.TrueID; + MCDCConditionID FalseID = IDPair.FalseID; + // If a condition can fold to true or false, the corresponding branch // will be removed. Create a region with both counters hard-coded to // zero. This allows us to visualize them in a special way. @@ -1252,6 +1264,69 @@ struct CounterCoverageMappingBuilder popRegions(Index); } + /// Find a valid range starting with \p StartingLoc and ending before \p + /// BeforeLoc. + std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc, + SourceLocation BeforeLoc) { + // If StartingLoc is in function-like macro, use its start location. + if (StartingLoc.isMacroID()) { + FileID FID = SM.getFileID(StartingLoc); + const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion(); + if (EI->isFunctionMacroExpansion()) + StartingLoc = EI->getExpansionLocStart(); + } + + size_t StartDepth = locationDepth(StartingLoc); + size_t EndDepth = locationDepth(BeforeLoc); + while (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) { + bool UnnestStart = StartDepth >= EndDepth; + bool UnnestEnd = EndDepth >= StartDepth; + if (UnnestEnd) { + assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), + BeforeLoc)); + + BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc); + assert(BeforeLoc.isValid()); + EndDepth--; + } + if (UnnestStart) { + assert(SM.isWrittenInSameFile(StartingLoc, + getStartOfFileOrMacro(StartingLoc))); + + StartingLoc = getIncludeOrExpansionLoc(StartingLoc); + assert(StartingLoc.isValid()); + StartDepth--; + } + } + // If the start and end locations of the gap are both within the same macro + // file, the range may not be in source order. + if (StartingLoc.isMacroID() || BeforeLoc.isMacroID()) + return std::nullopt; + if (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc) || + !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder()) + return std::nullopt; + return {{StartingLoc, BeforeLoc}}; + } + + void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) { + const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc); + + if (!Skipped) + return; + + const auto NewStartLoc = Skipped->getBegin(); + const auto EndLoc = Skipped->getEnd(); + + if (NewStartLoc == EndLoc) + return; + assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder()); + handleFileExit(NewStartLoc); + size_t Index = pushRegion({}, NewStartLoc, EndLoc); + getRegion().setSkipped(true); + handleFileExit(EndLoc); + popRegions(Index); + } + /// Keep counts of breaks and continues inside loops. struct BreakContinue { Counter BreakCount; @@ -1701,43 +1776,119 @@ struct CounterCoverageMappingBuilder Visit(S->getSubStmt()); } + void coverIfConsteval(const IfStmt *S) { + assert(S->isConsteval()); + + const auto *Then = S->getThen(); + const auto *Else = S->getElse(); + + // It's better for llvm-cov to create a new region with same counter + // so line-coverage can be properly calculated for lines containing + // a skipped region (without it the line is marked uncovered) + const Counter ParentCount = getRegion().getCounter(); + + extendRegion(S); + + if (S->isNegatedConsteval()) { + // ignore 'if consteval' + markSkipped(S->getIfLoc(), getStart(Then)); + propagateCounts(ParentCount, Then); + + if (Else) { + // ignore 'else <else>' + markSkipped(getEnd(Then), getEnd(Else)); + } + } else { + assert(S->isNonNegatedConsteval()); + // ignore 'if consteval <then> [else]' + markSkipped(S->getIfLoc(), Else ? getStart(Else) : getEnd(Then)); + + if (Else) + propagateCounts(ParentCount, Else); + } + } + + void coverIfConstexpr(const IfStmt *S) { + assert(S->isConstexpr()); + + // evaluate constant condition... + const auto *E = cast<ConstantExpr>(S->getCond()); + const bool isTrue = E->getResultAsAPSInt().getExtValue(); + + extendRegion(S); + + // I'm using 'propagateCounts' later as new region is better and allows me + // to properly calculate line coverage in llvm-cov utility + const Counter ParentCount = getRegion().getCounter(); + + // ignore 'if constexpr (' + SourceLocation startOfSkipped = S->getIfLoc(); + + if (const auto *Init = S->getInit()) { + const auto start = getStart(Init); + const auto end = getEnd(Init); + + // this check is to make sure typedef here which doesn't have valid source + // location won't crash it + if (start.isValid() && end.isValid()) { + markSkipped(startOfSkipped, start); + propagateCounts(ParentCount, Init); + startOfSkipped = getEnd(Init); + } + } + + const auto *Then = S->getThen(); + const auto *Else = S->getElse(); + + if (isTrue) { + // ignore '<condition>)' + markSkipped(startOfSkipped, getStart(Then)); + propagateCounts(ParentCount, Then); + + if (Else) + // ignore 'else <else>' + markSkipped(getEnd(Then), getEnd(Else)); + } else { + // ignore '<condition>) <then> [else]' + markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then)); + + if (Else) + propagateCounts(ParentCount, Else); + } + } + void VisitIfStmt(const IfStmt *S) { + // "if constexpr" and "if consteval" are not normal conditional statements, + // their discarded statement should be skipped + if (S->isConsteval()) + return coverIfConsteval(S); + else if (S->isConstexpr()) + return coverIfConstexpr(S); + extendRegion(S); if (S->getInit()) Visit(S->getInit()); // Extend into the condition before we propagate through it below - this is // needed to handle macros that generate the "if" but not the condition. - if (!S->isConsteval()) - extendRegion(S->getCond()); + extendRegion(S->getCond()); Counter ParentCount = getRegion().getCounter(); + Counter ThenCount = getRegionCounter(S); - // If this is "if !consteval" the then-branch will never be taken, we don't - // need to change counter - Counter ThenCount = - S->isNegatedConsteval() ? ParentCount : getRegionCounter(S); - - if (!S->isConsteval()) { - // Emitting a counter for the condition makes it easier to interpret the - // counter for the body when looking at the coverage. - propagateCounts(ParentCount, S->getCond()); + // Emitting a counter for the condition makes it easier to interpret the + // counter for the body when looking at the coverage. + propagateCounts(ParentCount, S->getCond()); - // The 'then' count applies to the area immediately after the condition. - std::optional<SourceRange> Gap = - findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen())); - if (Gap) - fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount); - } + // The 'then' count applies to the area immediately after the condition. + std::optional<SourceRange> Gap = + findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen())); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount); extendRegion(S->getThen()); Counter OutCount = propagateCounts(ThenCount, S->getThen()); - - // If this is "if consteval" the else-branch will never be taken, we don't - // need to change counter - Counter ElseCount = S->isNonNegatedConsteval() - ? ParentCount - : subtractCounters(ParentCount, ThenCount); + Counter ElseCount = subtractCounters(ParentCount, ThenCount); if (const Stmt *Else = S->getElse()) { bool ThenHasTerminateStmt = HasTerminateStmt; @@ -1760,11 +1911,9 @@ struct CounterCoverageMappingBuilder GapRegionCounter = OutCount; } - if (!S->isConsteval()) { - // Create Branch Region around condition. - createBranchRegion(S->getCond(), ThenCount, - subtractCounters(ParentCount, ThenCount)); - } + // Create Branch Region around condition. + createBranchRegion(S->getCond(), ThenCount, + subtractCounters(ParentCount, ThenCount)); } void VisitCXXTryStmt(const CXXTryStmt *S) { @@ -1822,20 +1971,28 @@ struct CounterCoverageMappingBuilder } void VisitBinLAnd(const BinaryOperator *E) { - // Keep track of Binary Operator and assign MCDC condition IDs + bool IsRootNode = MCDCBuilder.isIdle(); + + // Keep track of Binary Operator and assign MCDC condition IDs. MCDCBuilder.pushAndAssignIDs(E); extendRegion(E->getLHS()); propagateCounts(getRegion().getCounter(), E->getLHS()); handleFileExit(getEnd(E->getLHS())); + // Track LHS True/False Decision. + const auto DecisionLHS = MCDCBuilder.pop(); + // Counter tracks the right hand side of a logical and operator. extendRegion(E->getRHS()); propagateCounts(getRegionCounter(E), E->getRHS()); - // Process Binary Operator and create MCDC Decision Region if top-level + // Track RHS True/False Decision. + const auto DecisionRHS = MCDCBuilder.back(); + + // Create MCDC Decision Region if at top-level (root). unsigned NumConds = 0; - if ((NumConds = MCDCBuilder.popAndReturnCondCount(E))) + if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E))) createDecisionRegion(E, getRegionBitmap(E), NumConds); // Extract the RHS's Execution Counter. @@ -1847,30 +2004,13 @@ struct CounterCoverageMappingBuilder // Extract the Parent Region Counter. Counter ParentCnt = getRegion().getCounter(); - // Extract the MCDC condition IDs (returns 0 if not needed). - MCDCConditionID NextOrID = MCDCBuilder.getNextLOrCondID(); - MCDCConditionID NextAndID = MCDCBuilder.getNextLAndCondID(); - MCDCConditionID LHSid = MCDCBuilder.getCondID(E->getLHS()); - MCDCConditionID RHSid = MCDCBuilder.getCondID(E->getRHS()); - // Create Branch Region around LHS condition. - // MC/DC: For "LHS && RHS" - // - If LHS is TRUE, execution goes to the RHS. - // - If LHS is FALSE, execution goes to the LHS of the next logical-OR. - // If that does not exist, execution exits (ID == 0). createBranchRegion(E->getLHS(), RHSExecCnt, - subtractCounters(ParentCnt, RHSExecCnt), LHSid, RHSid, - NextOrID); + subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS); // Create Branch Region around RHS condition. - // MC/DC: For "LHS && RHS" - // - If RHS is TRUE, execution goes to LHS of the next logical-AND. - // If that does not exist, execution exits (ID == 0). - // - If RHS is FALSE, execution goes to the LHS of the next logical-OR. - // If that does not exist, execution exits (ID == 0). createBranchRegion(E->getRHS(), RHSTrueCnt, - subtractCounters(RHSExecCnt, RHSTrueCnt), RHSid, - NextAndID, NextOrID); + subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS); } // Determine whether the right side of OR operation need to be visited. @@ -1884,20 +2024,28 @@ struct CounterCoverageMappingBuilder } void VisitBinLOr(const BinaryOperator *E) { - // Keep track of Binary Operator and assign MCDC condition IDs + bool IsRootNode = MCDCBuilder.isIdle(); + + // Keep track of Binary Operator and assign MCDC condition IDs. MCDCBuilder.pushAndAssignIDs(E); extendRegion(E->getLHS()); Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS()); handleFileExit(getEnd(E->getLHS())); + // Track LHS True/False Decision. + const auto DecisionLHS = MCDCBuilder.pop(); + // Counter tracks the right hand side of a logical or operator. extendRegion(E->getRHS()); propagateCounts(getRegionCounter(E), E->getRHS()); - // Process Binary Operator and create MCDC Decision Region if top-level + // Track RHS True/False Decision. + const auto DecisionRHS = MCDCBuilder.back(); + + // Create MCDC Decision Region if at top-level (root). unsigned NumConds = 0; - if ((NumConds = MCDCBuilder.popAndReturnCondCount(E))) + if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E))) createDecisionRegion(E, getRegionBitmap(E), NumConds); // Extract the RHS's Execution Counter. @@ -1913,28 +2061,13 @@ struct CounterCoverageMappingBuilder // Extract the Parent Region Counter. Counter ParentCnt = getRegion().getCounter(); - // Extract the MCDC condition IDs (returns 0 if not needed). - MCDCConditionID NextOrID = MCDCBuilder.getNextLOrCondID(); - MCDCConditionID NextAndID = MCDCBuilder.getNextLAndCondID(); - MCDCConditionID LHSid = MCDCBuilder.getCondID(E->getLHS()); - MCDCConditionID RHSid = MCDCBuilder.getCondID(E->getRHS()); - // Create Branch Region around LHS condition. - // MC/DC: For "LHS || RHS" - // - If LHS is TRUE, execution goes to the LHS of the next logical-AND. - // If that does not exist, execution exits (ID == 0). - // - If LHS is FALSE, execution goes to the RHS. createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt), - RHSExecCnt, LHSid, NextAndID, RHSid); + RHSExecCnt, DecisionLHS); // Create Branch Region around RHS condition. - // MC/DC: For "LHS || RHS" - // - If RHS is TRUE, execution goes to LHS of the next logical-AND. - // If that does not exist, execution exits (ID == 0). - // - If RHS is FALSE, execution goes to the LHS of the next logical-OR. - // If that does not exist, execution exits (ID == 0). createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt), - RHSFalseCnt, RHSid, NextAndID, NextOrID); + RHSFalseCnt, DecisionRHS); } void VisitLambdaExpr(const LambdaExpr *LE) { diff --git a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h index 0c0781a2d5ab..7682f197041c 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h +++ b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h @@ -496,7 +496,8 @@ createPPC64_SVR4_TargetCodeGenInfo(CodeGenModule &CGM, PPC64_SVR4_ABIKind Kind, bool SoftFloatABI); std::unique_ptr<TargetCodeGenInfo> -createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen); +createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, unsigned FLen, + bool EABI); std::unique_ptr<TargetCodeGenInfo> createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM); diff --git a/contrib/llvm-project/clang/lib/CodeGen/Targets/RISCV.cpp b/contrib/llvm-project/clang/lib/CodeGen/Targets/RISCV.cpp index 1e1d249b37ac..0851d1993d0c 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/Targets/RISCV.cpp @@ -25,8 +25,9 @@ private: // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target // with soft float ABI has FLen==0). unsigned FLen; - static const int NumArgGPRs = 8; - static const int NumArgFPRs = 8; + const int NumArgGPRs; + const int NumArgFPRs; + const bool EABI; bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off, @@ -34,8 +35,10 @@ private: CharUnits &Field2Off) const; public: - RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen) - : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {} + RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen, + bool EABI) + : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen), NumArgGPRs(EABI ? 6 : 8), + NumArgFPRs(FLen != 0 ? 8 : 0), EABI(EABI) {} // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo is virtual, so we overload it. @@ -86,7 +89,7 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { } int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; - int ArgFPRsLeft = FLen ? NumArgFPRs : 0; + int ArgFPRsLeft = NumArgFPRs; int NumFixedArgs = FI.getNumRequiredArgs(); int ArgNum = 0; @@ -396,9 +399,12 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, // Determine the number of GPRs needed to pass the current argument // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" // register pairs, so may consume 3 registers. + // TODO: To be compatible with GCC's behaviors, we don't align registers + // currently if we are using ILP32E calling convention. This behavior may be + // changed when RV32E/ILP32E is ratified. int NeededArgGPRs = 1; if (!IsFixed && NeededAlign == 2 * XLen) - NeededArgGPRs = 2 + (ArgGPRsLeft % 2); + NeededArgGPRs = 2 + (EABI && XLen == 32 ? 0 : (ArgGPRsLeft % 2)); else if (Size > XLen && Size <= 2 * XLen) NeededArgGPRs = 2; @@ -480,6 +486,13 @@ Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, auto TInfo = getContext().getTypeInfoInChars(Ty); + // TODO: To be compatible with GCC's behaviors, we force arguments with + // 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`, + // `unsigned long long` and `double` to have 4-byte alignment. This + // behavior may be changed when RV32E/ILP32E is ratified. + if (EABI && XLen == 32) + TInfo.Align = std::min(TInfo.Align, CharUnits::fromQuantity(4)); + // Arguments bigger than 2*Xlen bytes are passed indirectly. bool IsIndirect = TInfo.Width > 2 * SlotSize; @@ -499,8 +512,9 @@ namespace { class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { public: RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, - unsigned FLen) - : TargetCodeGenInfo(std::make_unique<RISCVABIInfo>(CGT, XLen, FLen)) {} + unsigned FLen, bool EABI) + : TargetCodeGenInfo( + std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { @@ -526,6 +540,7 @@ public: std::unique_ptr<TargetCodeGenInfo> CodeGen::createRISCVTargetCodeGenInfo(CodeGenModule &CGM, unsigned XLen, - unsigned FLen) { - return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen); + unsigned FLen, bool EABI) { + return std::make_unique<RISCVTargetCodeGenInfo>(CGM.getTypes(), XLen, FLen, + EABI); } diff --git a/contrib/llvm-project/clang/lib/CodeGen/Targets/X86.cpp b/contrib/llvm-project/clang/lib/CodeGen/Targets/X86.cpp index d053f41ab168..2291c991fb11 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/Targets/X86.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/Targets/X86.cpp @@ -40,6 +40,11 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, return llvm::Type::getX86_MMXTy(CGF.getLLVMContext()); } + if (Constraint == "k") { + llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGF.getLLVMContext()); + return llvm::FixedVectorType::get(Int1Ty, Ty->getScalarSizeInBits()); + } + // No operation needed return Ty; } |