Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
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");
Expand Down Expand Up @@ -670,7 +671,7 @@ void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
return;
}

cgf.cgm.errorNYI("emitStoreThroughBitfieldLValue");
cgf.emitStoreThroughBitfieldLValue(RValue::get(null), lv);
return;
}

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2041,8 +2041,9 @@ mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {
assert(!cir::MissingFeatures::tryEmitAsConstant());
Expr::EvalResult result;
if (e->EvaluateAsInt(result, cgf.getContext(), Expr::SE_AllowSideEffects)) {
cgf.cgm.errorNYI(e->getSourceRange(), "Constant interger member expr");
// Fall through to emit this as a non-constant access.
llvm::APSInt value = result.Val.getInt();
cgf.emitIgnoredExpr(e->getBase());
return builder.getConstInt(cgf.getLoc(e->getExprLoc()), value);
}
return emitLoadOfLValue(e);
}
Expand Down
64 changes: 64 additions & 0 deletions clang/test/CIR/CodeGen/struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,67 @@ void bin_comma() {
// OGCG: define{{.*}} void @_Z9bin_commav()
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false)

void compound_literal_expr() { CompleteS a = (CompleteS){}; }

// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init]
// CIR: %[[A_ELEM_0_PTR:.*]] = cir.get_member %[[A_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i>
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store{{.*}} %[[CONST_0]], %[[A_ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[A_ELEM_1_PTR:.*]] = cir.get_member %[[A_ADDR]][1] {name = "b"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s8i>
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s8i
// CIR: cir.store{{.*}} %[[CONST_0]], %[[A_ELEM_1_PTR]] : !s8i, !cir.ptr<!s8i>

// TODO(cir): zero-initialize the padding

// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
// LLVM: %[[A_ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 0
// LLVM: store i32 0, ptr %[[A_ELEM_0_PTR]], align 4
// LLVM: %[[A_ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 1
// LLVM: store i8 0, ptr %[[A_ELEM_1_PTR]], align 4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike OGCG, this doesn't zero-initialize the padding. Is that OK? Does the fact that we're setting each member prevent the optimizer from turning this into a memset?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a TODO for now, and later we can revisit it


// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false)

struct StructWithConstMember {
int a : 1;
};

void struct_with_const_member_expr() {
int a = (StructWithConstMember){}.a;
}

// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CIR: %[[RESULT:.*]] = cir.scope {
// CIR: %[[REF_ADDR:.*]] = cir.alloca !rec_StructWithConstMember, !cir.ptr<!rec_StructWithConstMember>, ["ref.tmp0"]
// CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[REF_ADDR]][0] {name = "a"} : !cir.ptr<!rec_StructWithConstMember> -> !cir.ptr<!u8i>
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[SET_BF:.*]] = cir.set_bitfield{{.*}} (#bfi_a, %[[ELEM_0_PTR]] : !cir.ptr<!u8i>, %[[CONST_0]] : !s32i) -> !s32i
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.yield %[[CONST_0]] : !s32i
// CIR: } : !s32i
// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i>

// TODO(cir): zero-initialize the padding

// LLVM: %[[REF_ADDR:.*]] = alloca %struct.StructWithConstMember, i64 1, align 4
// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[BF_LABEL:.*]]
// LLVM: [[BF_LABEL]]:
// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.StructWithConstMember, ptr %[[REF_ADDR]], i32 0, i32 0
// LLVM: %[[TMP_REF:.*]] = load i8, ptr %[[ELEM_0_PTR]], align 4
// LLVM: %[[BF_CLEAR:.*]] = and i8 %[[TMP_REF]], -2
// LLVM: %[[BF_SET:.*]] = or i8 %[[BF_CLEAR]], 0
// LLVM: store i8 %[[BF_SET]], ptr %[[ELEM_0_PTR]], align 4
// LLVM: br label %[[RESULT_LABEL:.*]]
// LLVM: [[RESULT_LABEL]]:
// LLVM: %[[RESULT:.*]] = phi i32 [ 0, %[[BF_LABEL]] ]
// LLVM: store i32 %[[RESULT]], ptr %[[A_ADDR]], align 4

// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[REF_ADDR:.*]] = alloca %struct.StructWithConstMember, align 4
// OGCG: %[[TMP_REF:.*]] = load i8, ptr %[[REF_ADDR]], align 4
// OGCG: %[[BF_CLEAR:.*]] = and i8 %[[TMP_REF]], -2
// OGCG: %[[BF_SET:.*]] = or i8 %[[BF_CLEAR]], 0
// OGCG: store i8 %[[BF_SET]], ptr %[[REF_ADDR]], align 4
// OGCG: store i32 0, ptr %[[A_ADDR]], align 4
Loading