diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 10 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 182 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 165 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 5 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.h | 25 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp | 7 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenValue.h | 11 |
9 files changed, 380 insertions, 35 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 4a19d91..5667273 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -740,6 +740,16 @@ struct CallStackRestore final : EHScopeStack::Cleanup { }; } // namespace +/// Push the standard destructor for the given type as +/// at least a normal cleanup. +void CIRGenFunction::pushDestroy(QualType::DestructionKind dtorKind, + Address addr, QualType type) { + assert(dtorKind && "cannot push destructor for trivial type"); + + CleanupKind cleanupKind = getCleanupKind(dtorKind); + pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind)); +} + void CIRGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer) { pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 4897c29..9732c9c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1626,14 +1626,15 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { /// Emit code to compute the specified expression which /// can have any type. The result is returned as an RValue struct. -RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) { +RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot, + bool ignoreResult) { switch (CIRGenFunction::getEvaluationKind(e->getType())) { case cir::TEK_Scalar: return RValue::get(emitScalarExpr(e)); case cir::TEK_Complex: return RValue::getComplex(emitComplexExpr(e)); case cir::TEK_Aggregate: { - if (aggSlot.isIgnored()) + if (!ignoreResult && aggSlot.isIgnored()) aggSlot = createAggTemp(e->getType(), getLoc(e->getSourceRange()), getCounterAggTmpAsString()); emitAggExpr(e, aggSlot); @@ -1869,8 +1870,7 @@ RValue CIRGenFunction::emitCallExpr(const clang::CallExpr *e, /// Emit code to compute the specified expression, ignoring the result. void CIRGenFunction::emitIgnoredExpr(const Expr *e) { if (e->isPRValue()) { - assert(!cir::MissingFeatures::aggValueSlot()); - emitAnyExpr(e); + emitAnyExpr(e, AggValueSlot::ignored(), /*ignoreResult=*/true); return; } @@ -2394,6 +2394,180 @@ LValue CIRGenFunction::emitPredefinedLValue(const PredefinedExpr *e) { return emitStringLiteralLValue(sl, gvName); } +LValue CIRGenFunction::emitOpaqueValueLValue(const OpaqueValueExpr *e) { + assert(OpaqueValueMappingData::shouldBindAsLValue(e)); + return getOrCreateOpaqueLValueMapping(e); +} + +namespace { +// Handle the case where the condition is a constant evaluatable simple integer, +// which means we don't have to separately handle the true/false blocks. +std::optional<LValue> handleConditionalOperatorLValueSimpleCase( + CIRGenFunction &cgf, const AbstractConditionalOperator *e) { + const Expr *condExpr = e->getCond(); + llvm::APSInt condExprVal; + if (!cgf.constantFoldsToSimpleInteger(condExpr, condExprVal)) + return std::nullopt; + + const Expr *live = e->getTrueExpr(), *dead = e->getFalseExpr(); + if (!condExprVal.getBoolValue()) + std::swap(live, dead); + + if (cgf.containsLabel(dead)) + return std::nullopt; + + // If the true case is live, we need to track its region. + assert(!cir::MissingFeatures::incrementProfileCounter()); + assert(!cir::MissingFeatures::pgoUse()); + // If a throw expression we emit it and return an undefined lvalue + // because it can't be used. + if (auto *throwExpr = dyn_cast<CXXThrowExpr>(live->IgnoreParens())) { + cgf.emitCXXThrowExpr(throwExpr); + // Return an undefined lvalue - the throw terminates execution + // so this value will never actually be used + mlir::Type elemTy = cgf.convertType(dead->getType()); + mlir::Value undefPtr = + cgf.getBuilder().getNullPtr(cgf.getBuilder().getPointerTo(elemTy), + cgf.getLoc(throwExpr->getSourceRange())); + return cgf.makeAddrLValue(Address(undefPtr, elemTy, CharUnits::One()), + dead->getType()); + } + return cgf.emitLValue(live); +} + +/// Emit the operand of a glvalue conditional operator. This is either a glvalue +/// or a (possibly-parenthesized) throw-expression. If this is a throw, no +/// LValue is returned and the current block has been terminated. +static std::optional<LValue> emitLValueOrThrowExpression(CIRGenFunction &cgf, + const Expr *operand) { + if (auto *throwExpr = dyn_cast<CXXThrowExpr>(operand->IgnoreParens())) { + cgf.emitCXXThrowExpr(throwExpr); + return std::nullopt; + } + + return cgf.emitLValue(operand); +} +} // namespace + +// Create and generate the 3 blocks for a conditional operator. +// Leaves the 'current block' in the continuation basic block. +template <typename FuncTy> +CIRGenFunction::ConditionalInfo +CIRGenFunction::emitConditionalBlocks(const AbstractConditionalOperator *e, + const FuncTy &branchGenFunc) { + ConditionalInfo info; + ConditionalEvaluation eval(*this); + mlir::Location loc = getLoc(e->getSourceRange()); + CIRGenBuilderTy &builder = getBuilder(); + + mlir::Value condV = emitOpOnBoolExpr(loc, e->getCond()); + SmallVector<mlir::OpBuilder::InsertPoint, 2> insertPoints{}; + mlir::Type yieldTy{}; + + auto emitBranch = [&](mlir::OpBuilder &b, mlir::Location loc, + const Expr *expr, std::optional<LValue> &resultLV) { + CIRGenFunction::LexicalScope lexScope{*this, loc, b.getInsertionBlock()}; + curLexScope->setAsTernary(); + + assert(!cir::MissingFeatures::incrementProfileCounter()); + eval.beginEvaluation(); + resultLV = branchGenFunc(*this, expr); + mlir::Value resultPtr = resultLV ? resultLV->getPointer() : mlir::Value(); + eval.endEvaluation(); + + if (resultPtr) { + yieldTy = resultPtr.getType(); + cir::YieldOp::create(b, loc, resultPtr); + } else { + // If LHS or RHS is a void expression we need + // to patch arms as to properly match yield types. + // If the current block's terminator is an UnreachableOp (from a throw), + // we don't need a yield + if (builder.getInsertionBlock()->mightHaveTerminator()) { + mlir::Operation *terminator = + builder.getInsertionBlock()->getTerminator(); + if (isa_and_nonnull<cir::UnreachableOp>(terminator)) + insertPoints.push_back(b.saveInsertionPoint()); + } + } + }; + + info.result = cir::TernaryOp::create( + builder, loc, condV, + /*trueBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + emitBranch(b, loc, e->getTrueExpr(), info.lhs); + }, + /*falseBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + emitBranch(b, loc, e->getFalseExpr(), info.rhs); + }) + .getResult(); + + // If both arms are void, so be it. + if (!yieldTy) + yieldTy = VoidTy; + + // Insert required yields. + for (mlir::OpBuilder::InsertPoint &toInsert : insertPoints) { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.restoreInsertionPoint(toInsert); + + // Block does not return: build empty yield. + if (!yieldTy) { + cir::YieldOp::create(builder, loc); + } else { // Block returns: set null yield value. + mlir::Value op0 = builder.getNullValue(yieldTy, loc); + cir::YieldOp::create(builder, loc, op0); + } + } + + return info; +} + +LValue CIRGenFunction::emitConditionalOperatorLValue( + const AbstractConditionalOperator *expr) { + if (!expr->isGLValue()) { + // ?: here should be an aggregate. + assert(hasAggregateEvaluationKind(expr->getType()) && + "Unexpected conditional operator!"); + return emitAggExprToLValue(expr); + } + + OpaqueValueMapping binding(*this, expr); + if (std::optional<LValue> res = + handleConditionalOperatorLValueSimpleCase(*this, expr)) + return *res; + + ConditionalInfo info = + emitConditionalBlocks(expr, [](CIRGenFunction &cgf, const Expr *e) { + return emitLValueOrThrowExpression(cgf, e); + }); + + if ((info.lhs && !info.lhs->isSimple()) || + (info.rhs && !info.rhs->isSimple())) { + cgm.errorNYI(expr->getSourceRange(), + "unsupported conditional operator with non-simple lvalue"); + return LValue(); + } + + if (info.lhs && info.rhs) { + Address lhsAddr = info.lhs->getAddress(); + Address rhsAddr = info.rhs->getAddress(); + Address result(info.result, lhsAddr.getElementType(), + std::min(lhsAddr.getAlignment(), rhsAddr.getAlignment())); + AlignmentSource alignSource = + std::max(info.lhs->getBaseInfo().getAlignmentSource(), + info.rhs->getBaseInfo().getAlignmentSource()); + assert(!cir::MissingFeatures::opTBAA()); + return makeAddrLValue(result, expr->getType(), LValueBaseInfo(alignSource)); + } + + assert((info.lhs || info.rhs) && + "both operands of glvalue conditional are throw-expressions?"); + return info.lhs ? *info.lhs : *info.rhs; +} + /// An LValue is a candidate for having its loads and stores be made atomic if /// we are operating under /volatile:ms *and* the LValue itself is volatile and /// performing such an operation can be performed without a libcall. diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 901b937..568cbdb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -24,6 +24,73 @@ using namespace clang; using namespace clang::CIRGen; namespace { +// FIXME(cir): This should be a common helper between CIRGen +// and traditional CodeGen +/// Is the value of the given expression possibly a reference to or +/// into a __block variable? +static bool isBlockVarRef(const Expr *e) { + // Make sure we look through parens. + e = e->IgnoreParens(); + + // Check for a direct reference to a __block variable. + if (const DeclRefExpr *dre = dyn_cast<DeclRefExpr>(e)) { + const VarDecl *var = dyn_cast<VarDecl>(dre->getDecl()); + return (var && var->hasAttr<BlocksAttr>()); + } + + // More complicated stuff. + + // Binary operators. + if (const BinaryOperator *op = dyn_cast<BinaryOperator>(e)) { + // For an assignment or pointer-to-member operation, just care + // about the LHS. + if (op->isAssignmentOp() || op->isPtrMemOp()) + return isBlockVarRef(op->getLHS()); + + // For a comma, just care about the RHS. + if (op->getOpcode() == BO_Comma) + return isBlockVarRef(op->getRHS()); + + // FIXME: pointer arithmetic? + return false; + + // Check both sides of a conditional operator. + } else if (const AbstractConditionalOperator *op = + dyn_cast<AbstractConditionalOperator>(e)) { + return isBlockVarRef(op->getTrueExpr()) || + isBlockVarRef(op->getFalseExpr()); + + // OVEs are required to support BinaryConditionalOperators. + } else if (const OpaqueValueExpr *op = dyn_cast<OpaqueValueExpr>(e)) { + if (const Expr *src = op->getSourceExpr()) + return isBlockVarRef(src); + + // Casts are necessary to get things like (*(int*)&var) = foo(). + // We don't really care about the kind of cast here, except + // we don't want to look through l2r casts, because it's okay + // to get the *value* in a __block variable. + } else if (const CastExpr *cast = dyn_cast<CastExpr>(e)) { + if (cast->getCastKind() == CK_LValueToRValue) + return false; + return isBlockVarRef(cast->getSubExpr()); + + // Handle unary operators. Again, just aggressively look through + // it, ignoring the operation. + } else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) { + return isBlockVarRef(uop->getSubExpr()); + + // Look into the base of a field access. + } else if (const MemberExpr *mem = dyn_cast<MemberExpr>(e)) { + return isBlockVarRef(mem->getBase()); + + // Look into the base of a subscript. + } else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(e)) { + return isBlockVarRef(sub->getBase()); + } + + return false; +} + class AggExprEmitter : public StmtVisitor<AggExprEmitter> { CIRGenFunction &cgf; @@ -41,9 +108,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { AggValueSlot ensureSlot(mlir::Location loc, QualType t) { if (!dest.isIgnored()) return dest; - - cgf.cgm.errorNYI(loc, "Slot for ignored address"); - return dest; + return cgf.createAggTemp(t, loc, "agg.tmp.ensured"); } void ensureDest(mlir::Location loc, QualType ty) { @@ -89,6 +154,47 @@ public: (void)cgf.emitCompoundStmt(*e->getSubStmt(), &retAlloca, dest); } + void VisitBinAssign(const BinaryOperator *e) { + // For an assignment to work, the value on the right has + // to be compatible with the value on the left. + assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(), + e->getRHS()->getType()) && + "Invalid assignment"); + + if (isBlockVarRef(e->getLHS()) && + e->getRHS()->HasSideEffects(cgf.getContext())) { + cgf.cgm.errorNYI(e->getSourceRange(), + "block var reference with side effects"); + return; + } + + LValue lhs = cgf.emitLValue(e->getLHS()); + + // If we have an atomic type, evaluate into the destination and then + // do an atomic copy. + assert(!cir::MissingFeatures::atomicTypes()); + + // Codegen the RHS so that it stores directly into the LHS. + assert(!cir::MissingFeatures::aggValueSlotGC()); + AggValueSlot lhsSlot = AggValueSlot::forLValue( + lhs, AggValueSlot::IsDestructed, AggValueSlot::IsAliased, + AggValueSlot::MayOverlap); + + // A non-volatile aggregate destination might have volatile member. + if (!lhsSlot.isVolatile() && cgf.hasVolatileMember(e->getLHS()->getType())) + lhsSlot.setVolatile(true); + + cgf.emitAggExpr(e->getRHS(), lhsSlot); + + // Copy into the destination if the assignment isn't ignored. + emitFinalDestCopy(e->getType(), lhs); + + if (!dest.isIgnored() && !dest.isExternallyDestructed() && + e->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + cgf.pushDestroy(QualType::DK_nontrivial_c_struct, dest.getAddress(), + e->getType()); + } + void VisitDeclRefExpr(DeclRefExpr *e) { emitAggLoadOfLValue(e); } void VisitInitListExpr(InitListExpr *e); @@ -170,19 +276,10 @@ public: void VisitConstantExpr(ConstantExpr *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr"); } - void VisitMemberExpr(MemberExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitMemberExpr"); - } - void VisitUnaryDeref(UnaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryDeref"); - } - void VisitStringLiteral(StringLiteral *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitStringLiteral"); - } - void VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitCompoundLiteralExpr"); - } + void VisitMemberExpr(MemberExpr *e) { emitAggLoadOfLValue(e); } + void VisitUnaryDeref(UnaryOperator *e) { emitAggLoadOfLValue(e); } + void VisitStringLiteral(StringLiteral *e) { emitAggLoadOfLValue(e); } + void VisitCompoundLiteralExpr(CompoundLiteralExpr *e); void VisitPredefinedExpr(const PredefinedExpr *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitPredefinedExpr"); @@ -195,9 +292,6 @@ public: cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitPointerToDataMemberBinaryOperator"); } - void VisitBinAssign(const BinaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinAssign"); - } void VisitBinComma(const BinaryOperator *e) { cgf.emitIgnoredExpr(e->getLHS()); Visit(e->getRHS()); @@ -325,6 +419,31 @@ void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) { emitFinalDestCopy(e->getType(), lv); } +void AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *e) { + if (dest.isPotentiallyAliased() && e->getType().isPODType(cgf.getContext())) { + // For a POD type, just emit a load of the lvalue + a copy, because our + // compound literal might alias the destination. + emitAggLoadOfLValue(e); + return; + } + + AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType()); + + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + bool destruct = + !cgf.getLangOpts().CPlusPlus && !slot.isExternallyDestructed(); + if (destruct) + slot.setExternallyDestructed(); + + cgf.emitAggExpr(e->getInitializer(), slot); + + if (destruct) + if ([[maybe_unused]] QualType::DestructionKind dtorKind = + e->getType().isDestructedType()) + cgf.cgm.errorNYI(e->getSourceRange(), "compound literal with destructor"); +} + void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType arrayQTy, Expr *e, ArrayRef<Expr *> args, Expr *arrayFiller) { @@ -487,7 +606,8 @@ void AggExprEmitter::emitCopy(QualType type, const AggValueSlot &dest, LValue destLV = cgf.makeAddrLValue(dest.getAddress(), type); LValue srcLV = cgf.makeAddrLValue(src.getAddress(), type); assert(!cir::MissingFeatures::aggValueSlotVolatile()); - cgf.emitAggregateCopy(destLV, srcLV, type, dest.mayOverlap()); + cgf.emitAggregateCopy(destLV, srcLV, type, dest.mayOverlap(), + dest.isVolatile() || src.isVolatile()); } void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) { @@ -788,7 +908,8 @@ void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) { } void CIRGenFunction::emitAggregateCopy(LValue dest, LValue src, QualType ty, - AggValueSlot::Overlap_t mayOverlap) { + AggValueSlot::Overlap_t mayOverlap, + bool isVolatile) { // TODO(cir): this function needs improvements, commented code for now since // this will be touched again soon. assert(!ty->isAnyComplexType() && "Unexpected copy of complex"); @@ -844,7 +965,7 @@ void CIRGenFunction::emitAggregateCopy(LValue dest, LValue src, QualType ty, cgm.errorNYI("emitAggregateCopy: GC"); [[maybe_unused]] cir::CopyOp copyOp = - builder.createCopy(destPtr.getPointer(), srcPtr.getPointer()); + builder.createCopy(destPtr.getPointer(), srcPtr.getPointer(), isVolatile); assert(!cir::MissingFeatures::opTBAA()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index fcde487..d8f4943 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -196,9 +196,8 @@ public: return Visit(e->getSubExpr()); } mlir::Value VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) { - cgf.cgm.errorNYI(dae->getExprLoc(), - "ComplexExprEmitter VisitCXXDefaultArgExpr"); - return {}; + CIRGenFunction::CXXDefaultArgExprScope scope(cgf, dae); + return Visit(dae->getExpr()); } mlir::Value VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) { CIRGenFunction::CXXDefaultInitExprScope scope(cgf, die); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index ba36cbe..25a46df 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -822,6 +822,10 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { std::string("l-value not implemented for '") + e->getStmtClassName() + "'"); return LValue(); + case Expr::ConditionalOperatorClass: + return emitConditionalOperatorLValue(cast<ConditionalOperator>(e)); + case Expr::BinaryConditionalOperatorClass: + return emitConditionalOperatorLValue(cast<BinaryConditionalOperator>(e)); case Expr::ArraySubscriptExprClass: return emitArraySubscriptExpr(cast<ArraySubscriptExpr>(e)); case Expr::UnaryOperatorClass: @@ -866,6 +870,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { return emitCastLValue(cast<CastExpr>(e)); case Expr::MaterializeTemporaryExprClass: return emitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(e)); + case Expr::OpaqueValueExprClass: + return emitOpaqueValueLValue(cast<OpaqueValueExpr>(e)); case Expr::ChooseExprClass: return emitLValue(cast<ChooseExpr>(e)->getChosenSubExpr()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 3c36f5c..5a71126 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -733,6 +733,11 @@ public: SourceLocExprScopeGuard sourceLocScope; }; + struct CXXDefaultArgExprScope : SourceLocExprScopeGuard { + CXXDefaultArgExprScope(CIRGenFunction &cfg, const CXXDefaultArgExpr *e) + : SourceLocExprScopeGuard(e, cfg.curSourceLocExprScope) {} + }; + LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t); LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty); @@ -853,6 +858,13 @@ public: FunctionArgList args, clang::SourceLocation loc, clang::SourceLocation startLoc); + /// returns true if aggregate type has a volatile member. + bool hasVolatileMember(QualType t) { + if (const auto *rd = t->getAsRecordDecl()) + return rd->hasVolatileMember(); + return false; + } + /// The cleanup depth enclosing all the cleanups associated with the /// parameters. EHScopeStack::stable_iterator prologueCleanupDepth; @@ -1077,6 +1089,9 @@ public: static Destroyer destroyCXXObject; + void pushDestroy(QualType::DestructionKind dtorKind, Address addr, + QualType type); + void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer); @@ -1131,14 +1146,16 @@ public: /// 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); + AggValueSlot::Overlap_t mayOverlap, + bool isVolatile = false); /// Emit code to compute the specified expression which can have any type. The /// result is returned as an RValue struct. If this is an aggregate /// expression, the aggloc/agglocvolatile arguments indicate where the result /// should be returned. RValue emitAnyExpr(const clang::Expr *e, - AggValueSlot aggSlot = AggValueSlot::ignored()); + AggValueSlot aggSlot = AggValueSlot::ignored(), + bool ignoreResult = false); /// Emits the code necessary to evaluate an arbitrary expression into the /// given memory location. @@ -1518,6 +1535,10 @@ public: LValue emitMemberExpr(const MemberExpr *e); + LValue emitOpaqueValueLValue(const OpaqueValueExpr *e); + + LValue emitConditionalOperatorLValue(const AbstractConditionalOperator *expr); + /// Given an expression with a pointer type, emit the value and compute our /// best estimate of the alignment of the pointee. /// diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp index f638d39..be063033 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp @@ -590,15 +590,18 @@ void OpenACCRecipeBuilderBase::createReductionRecipeCombiner( } else { // else we have to handle each individual field after after a // get-element. + const CIRGenRecordLayout &layout = + cgf.cgm.getTypes().getCIRGenRecordLayout(rd); for (const auto &[field, combiner] : llvm::zip_equal(rd->fields(), combinerRecipes)) { mlir::Type fieldType = cgf.convertType(field->getType()); auto fieldPtr = cir::PointerType::get(fieldType); + unsigned fieldIndex = layout.getCIRFieldNo(field); mlir::Value lhsField = builder.createGetMember( - loc, fieldPtr, lhsArg, field->getName(), field->getFieldIndex()); + loc, fieldPtr, lhsArg, field->getName(), fieldIndex); mlir::Value rhsField = builder.createGetMember( - loc, fieldPtr, rhsArg, field->getName(), field->getFieldIndex()); + loc, fieldPtr, rhsArg, field->getName(), fieldIndex); emitSingleCombiner(lhsField, rhsField, combiner); } diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 5ba64dd..ad8c4d0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -475,8 +475,8 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) { } break; case cir::TEK_Complex: - getCIRGenModule().errorNYI(s.getSourceRange(), - "complex function return type"); + emitComplexExprIntoLValue(rv, makeAddrLValue(returnValue, rv->getType()), + /*isInit=*/true); break; case cir::TEK_Aggregate: assert(!cir::MissingFeatures::aggValueSlotGC()); diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index c05142e..ab245a77 100644 --- a/clang/lib/CIR/CodeGen/CIRGenValue.h +++ b/clang/lib/CIR/CodeGen/CIRGenValue.h @@ -380,6 +380,15 @@ public: clang::Qualifiers getQualifiers() const { return quals; } + bool isVolatile() const { return quals.hasVolatile(); } + + void setVolatile(bool flag) { + if (flag) + quals.addVolatile(); + else + quals.removeVolatile(); + } + Address getAddress() const { return addr; } bool isIgnored() const { return !addr.isValid(); } @@ -390,6 +399,8 @@ public: IsZeroed_t isZeroed() const { return IsZeroed_t(zeroedFlag); } + IsAliased_t isPotentiallyAliased() const { return IsAliased_t(aliasedFlag); } + RValue asRValue() const { if (isIgnored()) return RValue::getIgnored(); |