aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenAtomic.cpp26
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenDecl.cpp10
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExpr.cpp182
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp165
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp5
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.cpp6
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h25
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp7
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenStmt.cpp4
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenValue.h11
-rw-r--r--clang/lib/CIR/Dialect/IR/CIRDialect.cpp10
-rw-r--r--clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp31
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp42
13 files changed, 476 insertions, 48 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index a9983f8..67ca60c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -407,6 +407,23 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
opName = cir::AtomicXchgOp::getOperationName();
break;
+ case AtomicExpr::AO__atomic_test_and_set: {
+ auto op = cir::AtomicTestAndSetOp::create(
+ builder, loc, ptr.getPointer(), order,
+ builder.getI64IntegerAttr(ptr.getAlignment().getQuantity()),
+ expr->isVolatile());
+ builder.createStore(loc, op, dest);
+ return;
+ }
+
+ case AtomicExpr::AO__atomic_clear: {
+ cir::AtomicClearOp::create(
+ builder, loc, ptr.getPointer(), order,
+ builder.getI64IntegerAttr(ptr.getAlignment().getQuantity()),
+ expr->isVolatile());
+ return;
+ }
+
case AtomicExpr::AO__opencl_atomic_init:
case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
@@ -502,10 +519,6 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
case AtomicExpr::AO__c11_atomic_fetch_nand:
case AtomicExpr::AO__atomic_fetch_nand:
case AtomicExpr::AO__scoped_atomic_fetch_nand:
-
- case AtomicExpr::AO__atomic_test_and_set:
-
- case AtomicExpr::AO__atomic_clear:
cgf.cgm.errorNYI(expr->getSourceRange(), "emitAtomicOp: expr op NYI");
return;
}
@@ -581,6 +594,8 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_test_and_set:
+ case AtomicExpr::AO__atomic_clear:
break;
case AtomicExpr::AO__atomic_load:
@@ -640,6 +655,9 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
dest = atomics.castToAtomicIntPointer(dest);
} else if (e->isCmpXChg()) {
dest = createMemTemp(resultTy, getLoc(e->getSourceRange()), "cmpxchg.bool");
+ } else if (e->getOp() == AtomicExpr::AO__atomic_test_and_set) {
+ dest = createMemTemp(resultTy, getLoc(e->getSourceRange()),
+ "test_and_set.bool");
} else if (!resultTy->isVoidType()) {
dest = atomics.createTempAlloca();
if (shouldCastToIntPtrTy)
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();
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index b4c3704..ed606b7 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1978,13 +1978,19 @@ void cir::TernaryOp::build(
result.addOperands(cond);
OpBuilder::InsertionGuard guard(builder);
Region *trueRegion = result.addRegion();
- Block *block = builder.createBlock(trueRegion);
+ builder.createBlock(trueRegion);
trueBuilder(builder, result.location);
Region *falseRegion = result.addRegion();
builder.createBlock(falseRegion);
falseBuilder(builder, result.location);
- auto yield = dyn_cast<YieldOp>(block->getTerminator());
+ // Get result type from whichever branch has a yield (the other may have
+ // unreachable from a throw expression)
+ auto yield =
+ dyn_cast_or_null<cir::YieldOp>(trueRegion->back().getTerminator());
+ if (!yield)
+ yield = dyn_cast_or_null<cir::YieldOp>(falseRegion->back().getTerminator());
+
assert((yield && yield.getNumOperands() <= 1) &&
"expected zero or one result type");
if (yield.getNumOperands() == 1)
diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
index 26e5c05..8589a2e 100644
--- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
@@ -505,10 +505,19 @@ public:
Block *trueBlock = &trueRegion.front();
mlir::Operation *trueTerminator = trueRegion.back().getTerminator();
rewriter.setInsertionPointToEnd(&trueRegion.back());
- auto trueYieldOp = dyn_cast<cir::YieldOp>(trueTerminator);
- rewriter.replaceOpWithNewOp<cir::BrOp>(trueYieldOp, trueYieldOp.getArgs(),
- continueBlock);
+ // Handle both yield and unreachable terminators (throw expressions)
+ if (auto trueYieldOp = dyn_cast<cir::YieldOp>(trueTerminator)) {
+ rewriter.replaceOpWithNewOp<cir::BrOp>(trueYieldOp, trueYieldOp.getArgs(),
+ continueBlock);
+ } else if (isa<cir::UnreachableOp>(trueTerminator)) {
+ // Terminator is unreachable (e.g., from throw), just keep it
+ } else {
+ trueTerminator->emitError("unexpected terminator in ternary true region, "
+ "expected yield or unreachable, got: ")
+ << trueTerminator->getName();
+ return mlir::failure();
+ }
rewriter.inlineRegionBefore(trueRegion, continueBlock);
Block *falseBlock = continueBlock;
@@ -517,9 +526,19 @@ public:
falseBlock = &falseRegion.front();
mlir::Operation *falseTerminator = falseRegion.back().getTerminator();
rewriter.setInsertionPointToEnd(&falseRegion.back());
- auto falseYieldOp = dyn_cast<cir::YieldOp>(falseTerminator);
- rewriter.replaceOpWithNewOp<cir::BrOp>(falseYieldOp, falseYieldOp.getArgs(),
- continueBlock);
+
+ // Handle both yield and unreachable terminators (throw expressions)
+ if (auto falseYieldOp = dyn_cast<cir::YieldOp>(falseTerminator)) {
+ rewriter.replaceOpWithNewOp<cir::BrOp>(
+ falseYieldOp, falseYieldOp.getArgs(), continueBlock);
+ } else if (isa<cir::UnreachableOp>(falseTerminator)) {
+ // Terminator is unreachable (e.g., from throw), just keep it
+ } else {
+ falseTerminator->emitError("unexpected terminator in ternary false "
+ "region, expected yield or unreachable, got: ")
+ << falseTerminator->getName();
+ return mlir::failure();
+ }
rewriter.inlineRegionBefore(falseRegion, continueBlock);
rewriter.setInsertionPointToEnd(condBlock);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0243bf1..3fc94eb 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -182,7 +182,7 @@ mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
rewriter, op.getLoc(), rewriter.getI32Type(), op.getLength(layout));
assert(!cir::MissingFeatures::aggValueSlotVolatile());
rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>(
- op, adaptor.getDst(), adaptor.getSrc(), length, /*isVolatile=*/false);
+ op, adaptor.getDst(), adaptor.getSrc(), length, op.getIsVolatile());
return mlir::success();
}
@@ -730,6 +730,46 @@ mlir::LogicalResult CIRToLLVMAtomicXchgOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMAtomicTestAndSetOpLowering::matchAndRewrite(
+ cir::AtomicTestAndSetOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ assert(!cir::MissingFeatures::atomicSyncScopeID());
+
+ mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(op.getMemOrder());
+
+ auto one = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
+ rewriter.getI8Type(), 1);
+ auto rmw = mlir::LLVM::AtomicRMWOp::create(
+ rewriter, op.getLoc(), mlir::LLVM::AtomicBinOp::xchg, adaptor.getPtr(),
+ one, llvmOrder, /*syncscope=*/llvm::StringRef(),
+ adaptor.getAlignment().value_or(0), op.getIsVolatile());
+
+ auto zero = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
+ rewriter.getI8Type(), 0);
+ auto cmp = mlir::LLVM::ICmpOp::create(
+ rewriter, op.getLoc(), mlir::LLVM::ICmpPredicate::ne, rmw, zero);
+
+ rewriter.replaceOp(op, cmp);
+ return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMAtomicClearOpLowering::matchAndRewrite(
+ cir::AtomicClearOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ assert(!cir::MissingFeatures::atomicSyncScopeID());
+
+ mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(op.getMemOrder());
+ auto zero = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
+ rewriter.getI8Type(), 0);
+ auto store = mlir::LLVM::StoreOp::create(
+ rewriter, op.getLoc(), zero, adaptor.getPtr(),
+ adaptor.getAlignment().value_or(0), op.getIsVolatile(),
+ /*isNonTemporal=*/false, /*isInvariantGroup=*/false, llvmOrder);
+
+ rewriter.replaceOp(op, store);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMBitClrsbOpLowering::matchAndRewrite(
cir::BitClrsbOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {