llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) <details> <summary>Changes</summary> Implement support for Aggregate Atomic to non-atomic cast with padding --- Full diff: https://github.com/llvm/llvm-project/pull/219680.diff 2 Files Affected: - (modified) clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp (+37-4) - (modified) clang/test/CIR/CodeGen/agg-atomic-cast.c (+54-1) ``````````diff diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 922c4cb65e66e..2b3cf598f35a3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -236,6 +236,17 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { void VisitLambdaExpr(LambdaExpr *e); void VisitExprWithCleanups(ExprWithCleanups *e); + /// Attempt to look through various unimportant expressions to find a + /// cast of the given kind. + static Expr *findPeephole(Expr *op, CastKind kind, const ASTContext &ctx) { + op = op->IgnoreParenNoopCasts(ctx); + if (auto *castE = dyn_cast<CastExpr>(op)) { + if (castE->getCastKind() == kind) + return castE->getSubExpr(); + } + return nullptr; + } + // Stubs -- These should be moved up when they are implemented. void VisitCastExpr(CastExpr *e) { switch (e->getCastKind()) { @@ -282,10 +293,32 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { if (dest.isIgnored() || !cgf.cgm.isPaddedAtomicType(atomicType)) return Visit(e->getSubExpr()); - cgf.cgm.errorNYI( - e->getSourceRange(), - "AggExprEmitter: AtomicCast not ignored and has padded atomic type"); - return; + // These two cases are reverses of each other; try to peephole them. + CastKind peepholeTarget = + (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic); + if (Expr *op = + findPeephole(e->getSubExpr(), peepholeTarget, cgf.getContext())) { + cgf.cgm.errorNYI(op->getSourceRange(), + "AggExprEmitter: VisitCastExpr peephole"); + } + + // If we're converting an r-value of non-atomic type to an r-value + // of atomic type, just emit directly into the relevant sub-object. + if (isToAtomic) { + cgf.cgm.errorNYI(e->getSourceRange(), + "AggExprEmitter: VisitCastExpr r-value of non-atomic " + "type to an r-value of atomic type"); + return; + } + + mlir::Location loc = cgf.getLoc(e->getExprLoc()); + AggValueSlot atomicSlot = cgf.createAggTemp(atomicType, loc); + cgf.emitAggExpr(e->getSubExpr(), atomicSlot); + + Address valueAddr = cgf.getBuilder().createGetMember( + loc, atomicSlot.getAddress(), "value_addr", 0); + RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile()); + return emitFinalDestCopy(valueType, rvalue); } case CK_LValueToRValue: // If we're loading from a volatile type, force the destination diff --git a/clang/test/CIR/CodeGen/agg-atomic-cast.c b/clang/test/CIR/CodeGen/agg-atomic-cast.c index 1ba901d8d96ca..a6c7452ce94d3 100644 --- a/clang/test/CIR/CodeGen/agg-atomic-cast.c +++ b/clang/test/CIR/CodeGen/agg-atomic-cast.c @@ -18,7 +18,7 @@ void non_atomic_to_atomic_cast() { // CIR: %[[SA_ADDR:.*]] = cir.alloca "as" {{.*}} init : !cir.ptr<!rec_S> // CIR: cir.copy %[[S_ADDR]] align(4) to %[[SA_ADDR]] align(4) : !cir.ptr<!rec_S> -// LLVM: %[[S_ADDR:.*]] = alloca %struct.S, align 4 +// LLVM: %[[S_ADDR:.*]] = alloca %struct.S, align 4 // LLVM: %[[SA_ADDR:.*]] = alloca %struct.S, align 4 // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[SA_ADDR]], ptr align 4 %[[S_ADDR]], i64 4, i1 false) @@ -48,3 +48,56 @@ void atomic_to_non_atomic_cast() { // OGCG: %[[S_ADDR:.*]] = alloca %struct.S, align 4 // OGCG: %[[ATOMIC_LOAD:.*]] = load atomic i32, ptr %[[AS_ADDR]] seq_cst, align 4 // OGCG: store i32 %[[ATOMIC_LOAD]], ptr %[[S_ADDR]], align 4 + +struct T { + char a, b, c; +}; // size 3 => padded atomic representation + + +struct T load_atomic_struct() { + _Atomic(struct T) a; + return a; +} + +// CIR: %[[RET_ADDR:.*]] = cir.alloca "coerce" {{.*}} : !cir.ptr<!rec_T> +// CIR: %[[RET_VAL_ADDR:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!rec_T> +// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!rec_anon_struct> +// CIR: %[[NON_ATOMIC_TMP_ADDR:.*]] = cir.alloca "tmp" {{.*}} : !cir.ptr<!rec_anon_struct> +// CIR: %[[A_U32:.*]] = cir.cast bitcast %[[A_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i> +// CIR: %[[TMP_ATOMIC_A:.*]] = cir.load {{.*}} atomic(seq_cst) %[[A_U32]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[NON_ATOMIC_TMP:.*]] = cir.cast bitcast %[[NON_ATOMIC_TMP_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i> +// CIR: cir.store {{.*}} %[[TMP_ATOMIC_A]], %[[NON_ATOMIC_TMP]] : !u32i, !cir.ptr<!u32i> +// CIR: %[[VALUE_ADDR:.*]] = cir.get_member %[[NON_ATOMIC_TMP_ADDR]][0] {name = "value_addr"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!rec_T> +// CIR: cir.copy %[[VALUE_ADDR]] {{.*}} to %[[RET_VAL_ADDR]] {{.*}} : !cir.ptr<!rec_T> +// CIR: %[[TMP_RET_VAL:.*]] = cir.load %[[RET_VAL_ADDR]] : !cir.ptr<!rec_T>, !rec_T +// CIR: cir.store %[[TMP_RET_VAL]], %[[RET_ADDR]] : !rec_T, !cir.ptr<!rec_T> +// CIR: %[[RET_ADDR_U64:.*]] = cir.cast bitcast %[[RET_ADDR]] : !cir.ptr<!rec_T> -> !cir.ptr<!cir.int<u, 24>> +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR_U64]] : !cir.ptr<!cir.int<u, 24>>, !cir.int<u, 24> +// CIR: cir.return %[[TMP_RET]] : !cir.int<u, 24> + +// The difference between LLVM and OGCG in type from struct.T to i24 is due to missing ABI lowering. + +// LLVM: %[[RET_ADDR:.*]] = alloca %struct.T, align 4 +// LLVM: %[[RET_VAL_ADDR:.*]] = alloca %struct.T, align 1 +// LLVM: %[[A_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4 +// LLVM: %[[NON_ATOMIC_TMP:.*]] = alloca { %struct.T, [1 x i8] }, align 4 +// LLVM: %[[TMP_A:.*]] = load atomic i32, ptr %[[A_ADDR]] seq_cst, align 4 +// LLVM: store i32 %[[TMP_A]], ptr %[[NON_ATOMIC_TMP]], align 4 +// LLVM: %[[NON_ATOMIC_PTR:.*]] = getelementptr inbounds nuw { %struct.T, [1 x i8] }, ptr %[[NON_ATOMIC_TMP]], i32 0, i32 0 +// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[RET_VAL_ADDR]], ptr align 4 %[[NON_ATOMIC_PTR]], i64 3, i1 false) +// LLVM: %[[TMP_RET_VAL:.*]] = load %struct.T, ptr %[[RET_VAL_ADDR]], align 1 +// LLVM: store %struct.T %[[TMP_RET_VAL]], ptr %[[RET_ADDR]], align 1 +// LLVM: %[[TMP_RET:.*]] = load i24, ptr %[[RET_ADDR]], align 4 +// LLVM: ret i24 %[[TMP_RET]] + +// OGCG: %[[RET_VAL_ADDR:.*]] = alloca %struct.T, align 1 +// OGCG: %[[A_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4 +// OGCG: %[[NON_ATOMIC_TMP:.*]] = alloca { %struct.T, [1 x i8] }, align 4 +// OGCG: %[[RET_ADDR:.*]] = alloca i24, align 4 +// OGCG: %[[TMP_A:.*]] = load atomic i32, ptr %[[A_ADDR]] seq_cst, align 4 +// OGCG: store i32 %[[TMP_A]], ptr %[[NON_ATOMIC_TMP]], align 4 +// OGCG: %[[NON_ATOMIC_PTR:.*]] = getelementptr inbounds nuw { %struct.T, [1 x i8] }, ptr %atomic-to-nonatomic.temp, i32 0, i32 0 +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[RET_VAL_ADDR]], ptr align 4 %[[NON_ATOMIC_PTR]], i64 3, i1 false) +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET_ADDR]], ptr align 1 %[[RET_VAL_ADDR]], i64 3, i1 false) +// OGCG: %[[TMP_RET:.*]] = load i24, ptr %[[RET_ADDR]], align 4 +// OGCG: ret i24 %[[TMP_RET]] `````````` </details> https://github.com/llvm/llvm-project/pull/219680 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
