diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 86e0653b2f8c..1315f732bb68 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -476,6 +476,17 @@ struct MissingFeatures { static bool mustProgress() { return false; } static bool skipTempCopy() { return false; } + + static bool addressSpaceInGlobalVar() { return false; } + + static bool useARMGuardVarABI() { return false; } + + // PtrAuth added a RawAddress type subclassing from Address. + static bool rawAddress() { return false; } + + // LLVM has values that can be named (e.g. %x) and MLIR doens't, add this when + // we have a solution + static bool namedValues() { return false; } }; } // namespace cir diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 20a596e1fe9c..233ffeee71c2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -19,8 +19,13 @@ #include "TargetInfo.h" #include "clang/AST/Attr.h" +#include "clang/AST/Attrs.inc" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/GlobalDecl.h" +#include "clang/Basic/Specifiers.h" +#include "clang/CIR/ABIArgInfo.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/FnInfoOpts.h" @@ -943,6 +948,12 @@ static CanQual GetFormalType(const CXXMethodDecl *MD) { .getAs(); } +void CIRGenFunction::emitFunctionProlog(const CIRGenFunctionInfo &functionInfo, + cir::FuncOp fn, + const FunctionArgList &args) { + return; +} + /// TODO(cir): this should be shared with LLVM codegen static void addExtParameterInfosForCall( llvm::SmallVectorImpl ¶mInfos, @@ -1319,6 +1330,7 @@ CIRGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *md) { return arrangeCIRFunctionInfo(astContext.VoidTy, cir::FnInfoOpts::None, ArgTys, FTP->getExtInfo(), {}, RequiredArgs(1)); } + /// Figure out the rules for calling a function with the given formal type using /// the given arguments. The arguments are necessary because the function might /// be unprototyped, in which case it's target-dependent in crazy ways. @@ -1483,3 +1495,35 @@ void CIRGenModule::getDefaultFunctionAttributes( // TODO(cir): addMergableDefaultFunctionAttributes(codeGenOpts, funcAttrs); } } + +void CIRGenFunction::createCoercedStore(mlir::Value src, Address dst, + llvm::TypeSize dstSize, + bool dstIsVolatile) { + if (!dstSize) + return; + + mlir::Type srcTy = src.getType(); + llvm::TypeSize srcSize = CGM.getDataLayout().getTypeAllocSize(srcTy); + + // GEP into structs to try to make typesm match. + // FIXME: This isn't really that useful with opaque types, but it impacts a + // lot of regressiont ests. + if (srcTy != dst.getElementType()) { + llvm_unreachable("NYI"); + } + + if (srcSize.isScalable() || srcSize <= dstSize) { + if (isa(srcTy) && + isa(dst.getElementType()) && + srcSize == CGM.getDataLayout().getTypeAllocSize(dst.getElementType())) { + llvm_unreachable("NYI"); + } else { + getBuilder().createStore(src.getLoc(), src, dst.withElementType(getBuilder(), srcTy), + dstIsVolatile); + } + } else if (isa(srcTy)) { + llvm_unreachable("NYI"); + } else { + llvm_unreachable("NYI"); + } +} diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 6d3c035e3901..01e394ccca6b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -1289,3 +1289,84 @@ void CIRGenFunction::pushDestroyAndDeferDeactivation( pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray); DeferredDeactivationCleanupStack.push_back({EHStack.stable_begin(), flag}); } + +/// Emit an alloca (or GlobalValue depending on target) +/// for the specified parameter and set up LocalDeclMap. +void CIRGenFunction::emitParmDecl(const VarDecl &varDecl, ParamValue arg, + unsigned argNo) { + bool noDebugInfo = false; + // FIXME: Why isn't ImplicitParamDecl a ParmVarDecl? + assert((isa(varDecl) || isa(varDecl)) && + "Invalid argument to buildParmDecl"); + + // Set the name of the parameter's initial value to make IR easier to read. + // Don't modify the names of globals. + if (cir::MissingFeatures::namedValues()) + llvm_unreachable("NYI"); + + QualType ty = varDecl.getType(); + + // Use better CIR generation for certain implicit parameters. + if ([[maybe_unused]] auto const *ipd = + dyn_cast(&varDecl)) { + llvm_unreachable("NYI"); + } + + Address declPtr = Address::invalid(); + assert(!cir::MissingFeatures::rawAddress()); + Address allocaPtr = Address::invalid(); + bool doStore = false; + bool isScalar = hasScalarEvaluationKind(ty); + bool useIndirectDebugAddress = false; + + // If we already have a pointer to the argument, reuse the input pointer. + if (arg.isIndirect()) { + llvm_unreachable("NYI"); + } else { + // Check if the parameter address is controlled by OpenMP runtime. + Address openMPLocalAddr = + getLangOpts().OpenMP + ? CGM.getOpenMPRuntime().getAddressOfLocalVariable(*this, &varDecl) + : Address::invalid(); + if (getLangOpts().OpenMP && openMPLocalAddr.isValid()) { + llvm_unreachable("NYI"); + } else { + // Otherwise, create a temporary to hold the value. + declPtr = CreateMemTemp(ty, getContext().getDeclAlign(&varDecl), + getLoc(varDecl.getLocation()), + varDecl.getName() + ".addr", &allocaPtr); + } + doStore = true; + } + + mlir::Value argVal = (doStore ? arg.getDirectValue() : nullptr); + + LValue lv = makeAddrLValue(declPtr, ty); + if (isScalar) { + Qualifiers qs = ty.getQualifiers(); + if ([[maybe_unused]] Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) { + llvm_unreachable("NYI"); + } + } + + // Store the initial value into the alloca. + if (doStore) + emitStoreOfScalar(argVal, lv, /*isInit=*/true); + + setAddrOfLocalVar(&varDecl, declPtr); + + // Emit debug info for param declarations in non-thunk functions. + if (CIRGenDebugInfo *di = getDebugInfo()) { + llvm_unreachable("NYI"); + } + + if (varDecl.hasAttr()) + llvm_unreachable("NYI"); + + // We can only check return value nullability if all arguments to the function + // staisfy their nullability preconditions. This makes it necessary to emit + // null checks for args in the function body itself. + if (requiresReturnValueNullabilityCheck()) { + llvm_unreachable("NYI"); + } +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 808fe95af5b2..a98801e99ddd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1331,7 +1331,7 @@ void CIRGenFunction::StartFunction(GlobalDecl gd, QualType retTy, llvm_unreachable("NYI"); } - // TODO: emitFunctionProlog + emitFunctionProlog(*CurFnInfo, cast(CurFn), args); { // Set the insertion point in the builder to the beginning of the diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 2d62cbce0a87..22248a84ed7d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -426,6 +426,16 @@ class CIRGenFunction : public CIRGenTypeCache { } }; + /// Used by -fsanitize=nullability-return to determine whether the return + /// value can be checked. + mlir::Value retValNullabilityPrecondition = nullptr; + + /// Check if -fsanitize=nullability-return instrumentation is required for + /// this function. + bool requiresReturnValueNullabilityCheck() const { + return bool(retValNullabilityPrecondition); + } + /// A mapping from NRVO variables to the flags used to indicate /// when the NRVO has been applied to this variable. llvm::DenseMap NRVOFlags; @@ -553,6 +563,9 @@ class CIRGenFunction : public CIRGenTypeCache { /// should emit cleanups. bool CurFuncIsThunk = false; + /// In ARC, whether we should autorelease the return value. + bool autoreleaseResult = false; + /// Hold counters for incrementally naming temporaries unsigned CounterRefTmp = 0; unsigned CounterAggTmp = 0; @@ -708,6 +721,35 @@ class CIRGenFunction : public CIRGenTypeCache { return getAsNaturalAddressOf(Addr, PointeeType).getBasePointer(); } + mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, + llvm::ArrayRef args = {}); + + void emitInvariantStart(CharUnits Size); + + + /// emitFunctionProlog - Emit the target specific CIR code to load the + /// arguments for the given function. This is also responsible for naming the + /// MLIR function arguments. + void emitFunctionProlog(const CIRGenFunctionInfo &functionInfo, + cir::FuncOp fn, const FunctionArgList &args); + + /// Create a check for a function parameter that may potentially be + /// declared as non-null. + void emitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc, + AbstractCallee AC, unsigned ParmNum); + + void emitCallArg(CallArgList &args, const clang::Expr *E, + clang::QualType ArgType); + + LValue emitCallExprLValue(const CallExpr *E); + + /// Similarly to emitAnyExpr(), however, the result will always be accessible + /// even if no aggregate location is provided. + RValue emitAnyExprToTemp(const clang::Expr *E); + + CIRGenCallee emitCallee(const clang::Expr *E); + + void finishFunction(SourceLocation EndLoc); // Many of MSVC builtins are on x64, ARM and AArch64; to avoid repeating code, @@ -905,6 +947,46 @@ class CIRGenFunction : public CIRGenTypeCache { nextCleanupDestIndex++); } + class ParamValue { + union { + Address addr; + mlir::Value value; + }; + + bool isIndirectV; + + ParamValue(mlir::Value v) : value(v), isIndirectV(false) {} + ParamValue(Address a) : addr(a), isIndirectV(true) {} + + public: + static ParamValue forDirect(mlir::Value value) { return ParamValue(value); } + static ParamValue forIndirect(Address addr) { + assert(!addr.getAlignment().isZero()); + return ParamValue(addr); + } + + bool isIndirect() const { return isIndirectV; } + mlir::Value getAnyValue() const { + if (!isIndirect()) + return value; + assert(!addr.hasOffset() && "unexpected offset"); + return addr.getBasePointer(); + } + + mlir::Value getDirectValue() const { + assert(!isIndirect()); + return value; + } + + Address getIndirectAddress() const { + assert(isIndirect()); + return addr; + } + }; + + // emitParmDecl - Emit a ParmVarDecl or an ImplicitParmDecl. + void emitParmDecl(const VarDecl &varDecl, ParamValue arg, unsigned argNo); + /// Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. mlir::Value evaluateExprAsBool(const clang::Expr *E); @@ -1166,6 +1248,35 @@ class CIRGenFunction : public CIRGenTypeCache { return false; } + /// Emit an aggregate assignment. + void emitAggregateAssign(LValue Dest, LValue Src, QualType EltTy) { + bool IsVolatile = hasVolatileMember(EltTy); + emitAggregateCopy(Dest, Src, EltTy, AggValueSlot::MayOverlap, IsVolatile); + } + + LValue emitAggExprToLValue(const Expr *E); + + /// Create a store to \arg dstPtr from \arg src, truncating the stored value + /// to at most \arg dstSize bytes. + void createCoercedStore(mlir::Value src, Address dst, llvm::TypeSize dstSize, + bool dstIsVolatile); + + /// Emit an aggregate copy. + /// + /// \param isVolatile \c true iff either the source or the destination is + /// volatile. + /// \param MayOverlap Whether the tail padding of the destination might be + /// occupied by some other object. More efficient code can often be + /// generated if not. + void emitAggregateCopy(LValue Dest, LValue Src, QualType EltTy, + AggValueSlot::Overlap_t MayOverlap, + bool isVolatile = false); + + /// Emit a reached-unreachable diagnostic if \p Loc is valid and runtime + /// checking is enabled. Otherwise, just emit an unreachable instruction. + void emitUnreachable(SourceLocation Loc); + + /// /// Cleanups /// -------- @@ -1708,29 +1819,10 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitAArch64SMEBuiltinExpr(unsigned BuiltinID, const CallExpr *E); mlir::Value emitAArch64SVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E); - /// Emit an aggregate assignment. - void emitAggregateAssign(LValue Dest, LValue Src, QualType EltTy) { - bool IsVolatile = hasVolatileMember(EltTy); - emitAggregateCopy(Dest, Src, EltTy, AggValueSlot::MayOverlap, IsVolatile); - } - - /// Emit an aggregate copy. - /// - /// \param isVolatile \c true iff either the source or the destination is - /// volatile. - /// \param MayOverlap Whether the tail padding of the destination might be - /// occupied by some other object. More efficient code can often be - /// generated if not. - void emitAggregateCopy(LValue Dest, LValue Src, QualType EltTy, - AggValueSlot::Overlap_t MayOverlap, - bool isVolatile = false); - void emitAggregateStore(mlir::Value Val, Address Dest, bool DestIsVolatile); void emitAggExpr(const clang::Expr *E, AggValueSlot Slot); - LValue emitAggExprToLValue(const Expr *E); - mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, QualType ty, SourceLocation loc, SourceLocation assumptionLoc, @@ -1771,10 +1863,6 @@ class CIRGenFunction : public CIRGenTypeCache { void emitAnyExprToMem(const Expr *E, Address Location, Qualifiers Quals, bool IsInitializer); - /// Similarly to emitAnyExpr(), however, the result will always be accessible - /// even if no aggregate location is provided. - RValue emitAnyExprToTemp(const clang::Expr *E); - mlir::Value emitARMMVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue, llvm::Triple::ArchType Arch); @@ -1892,22 +1980,15 @@ class CIRGenFunction : public CIRGenTypeCache { const clang::CallExpr *E, ReturnValueSlot returnValue, mlir::Value Chain = nullptr); - void emitCallArg(CallArgList &args, const clang::Expr *E, - clang::QualType ArgType); - void emitCallArgs( CallArgList &Args, PrototypeWrapper Prototype, llvm::iterator_range ArgRange, AbstractCallee AC = AbstractCallee(), unsigned ParamsToSkip = 0, EvaluationOrder Order = EvaluationOrder::Default); - CIRGenCallee emitCallee(const clang::Expr *E); - RValue emitCallExpr(const clang::CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); - LValue emitCallExprLValue(const CallExpr *E); - template mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType, mlir::ArrayAttr value, @@ -2218,8 +2299,6 @@ class CIRGenFunction : public CIRGenTypeCache { bool InheritedFromVBase, const CXXInheritedCtorInitExpr *E); - void emitInvariantStart(CharUnits Size); - mlir::LogicalResult emitLabel(const clang::LabelDecl *D); mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &S); @@ -2304,11 +2383,6 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value NumElements, mlir::Value AllocSizeWithoutCookie); - /// Create a check for a function parameter that may potentially be - /// declared as non-null. - void emitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc, - AbstractCallee AC, unsigned ParmNum); - /// Given an assignment `*LHS = RHS`, emit a test that checks if \p RHS is /// nonnull, if 1\p LHS is marked _Nonnull. void emitNullabilityCheck(LValue LHS, mlir::Value RHS, @@ -2373,9 +2447,6 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitRotate(const CallExpr *E, bool IsRotateRight); - mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, - llvm::ArrayRef args = {}); - mlir::Value emitScalarConstant(const ConstantEmission &Constant, Expr *E); /// Emit a conversion from the specified type to the specified destination @@ -2476,10 +2547,6 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitUnPromotedValue(mlir::Value result, QualType PromotionType); - /// Emit a reached-unreachable diagnostic if \p Loc is valid and runtime - /// checking is enabled. Otherwise, just emit an unreachable instruction. - void emitUnreachable(SourceLocation Loc); - /// Emit local annotations for the local variable V, declared by D. void emitVarAnnotations(const VarDecl *decl, mlir::Value val);