Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 2 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,10 +997,9 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) {
}

case cir::TEK_Complex: {
assert(!cir::MissingFeatures::complexType());
cgm.errorNYI(e->getSourceRange(), "complex l-values");
return {};
return emitComplexAssignmentLValue(e);
}

case cir::TEK_Aggregate:
cgm.errorNYI(e->getSourceRange(), "aggregate lvalues");
return {};
Expand Down
100 changes: 95 additions & 5 deletions clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
// Utilities
//===--------------------------------------------------------------------===//

LValue emitBinAssignLValue(const BinaryOperator *e, mlir::Value &val);

mlir::Value emitCast(CastKind ck, Expr *op, QualType destTy);

mlir::Value emitConstant(const CIRGenFunction::ConstantEmission &constant,
Expr *e);

/// Given an expression with complex type that represents a value l-value,
/// this method emits the address of the l-value, then loads and returns the
/// result.
Expand All @@ -27,18 +34,18 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
}

mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc);

/// Store the specified real/imag parts into the
/// specified value pointer.
void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv,
bool isInit);

mlir::Value VisitBinAssign(const BinaryOperator *e);
mlir::Value VisitCallExpr(const CallExpr *e);
mlir::Value VisitInitListExpr(InitListExpr *e);

mlir::Value VisitDeclRefExpr(DeclRefExpr *e);
mlir::Value VisitImplicitCastExpr(ImplicitCastExpr *e);
mlir::Value VisitInitListExpr(const InitListExpr *e);
mlir::Value VisitImaginaryLiteral(const ImaginaryLiteral *il);
};

} // namespace

static const ComplexType *getComplexType(QualType type) {
Expand All @@ -48,6 +55,48 @@ static const ComplexType *getComplexType(QualType type) {
return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
}

LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e,
mlir::Value &value) {
assert(cgf.getContext().hasSameUnqualifiedType(e->getLHS()->getType(),
e->getRHS()->getType()) &&
"Invalid assignment");

// Emit the RHS. __block variables need the RHS evaluated first.
value = Visit(e->getRHS());

// Compute the address to store into.
LValue lhs = cgf.emitLValue(e->getLHS());

// Store the result value into the LHS lvalue.
emitStoreOfComplex(cgf.getLoc(e->getExprLoc()), value, lhs, /*isInit*/ false);
return lhs;
}

mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
QualType destTy) {
switch (ck) {
case CK_LValueToRValue: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Braces aren't needed here.

return Visit(op);
}
default:
cgf.cgm.errorNYI("ComplexType Cast");
break;
}

return {};
}

mlir::Value ComplexExprEmitter::emitConstant(
const CIRGenFunction::ConstantEmission &constant, Expr *e) {
assert(constant && "not a constant");
if (constant.isReference())
return emitLoadOfLValue(constant.getReferenceLValue(cgf, e),
e->getExprLoc());

mlir::TypedAttr valueAttr = constant.getValue();
return builder.getConstant(cgf.getLoc(e->getSourceRange()), valueAttr);
}

mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
SourceLocation loc) {
assert(lv.isSimple() && "non-simple complex l-value?");
Expand All @@ -70,14 +119,44 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
builder.createStore(loc, val, destAddr);
}

mlir::Value ComplexExprEmitter::VisitBinAssign(const BinaryOperator *e) {
mlir::Value value;
LValue lv = emitBinAssignLValue(e, value);

// The result of an assignment in C is the assigned r-value.
if (!cgf.getLangOpts().CPlusPlus)
return value;

// If the lvalue is non-volatile, return the computed value of the
// assignment.
if (!lv.isVolatile())
return value;

return emitLoadOfLValue(lv, e->getExprLoc());
}

mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) {
if (e->getCallReturnType(cgf.getContext())->isReferenceType())
return emitLoadOfLValue(e);

return cgf.emitCallExpr(e).getValue();
}

mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *e) {
mlir::Value ComplexExprEmitter::VisitDeclRefExpr(DeclRefExpr *e) {
if (CIRGenFunction::ConstantEmission constant = cgf.tryEmitAsConstant(e))
return emitConstant(constant, e);
return emitLoadOfLValue(e);
}

mlir::Value ComplexExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *e) {
// Unlike for scalars, we don't have to worry about function->ptr demotion
// here.
if (e->changesVolatileQualification())
return emitLoadOfLValue(e);
return emitCast(e->getCastKind(), e->getSubExpr(), e->getType());
}

mlir::Value ComplexExprEmitter::VisitInitListExpr(const InitListExpr *e) {
mlir::Location loc = cgf.getLoc(e->getExprLoc());
if (e->getNumInits() == 2) {
mlir::Value real = cgf.emitScalarExpr(e->getInit(0));
Expand Down Expand Up @@ -127,6 +206,17 @@ ComplexExprEmitter::VisitImaginaryLiteral(const ImaginaryLiteral *il) {
return builder.create<cir::ConstantOp>(loc, complexAttr);
}

LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) {
assert(e->getOpcode() == BO_Assign && "Expected assign op");

mlir::Value value; // ignored
LValue lvalue = ComplexExprEmitter(*this).emitBinAssignLValue(e, value);
if (getLangOpts().OpenMP)
cgm.errorNYI("emitComplexAssignmentLValue OpenMP");

return lvalue;
}

mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) {
assert(e && getComplexType(e->getType()) &&
"Invalid complex expression to emit");
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,8 @@ class CIRGenFunction : public CIRGenTypeCache {
/// returning the result.
mlir::Value emitComplexExpr(const Expr *e);

LValue emitComplexAssignmentLValue(const BinaryOperator *e);

void emitCompoundStmt(const clang::CompoundStmt &s);

void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s);
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/CIR/CodeGen/CIRGenValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,7 @@ class LValue {
bool isSimple() const { return lvType == Simple; }
bool isVectorElt() const { return lvType == VectorElt; }
bool isBitField() const { return lvType == BitField; }

// TODO: Add support for volatile
bool isVolatile() const { return false; }
bool isVolatile() const { return quals.hasVolatile(); }

unsigned getVRQualifiers() const {
return quals.getCVRQualifiers() & ~clang::Qualifiers::Const;
Expand Down
26 changes: 26 additions & 0 deletions clang/test/CIR/CodeGen/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,29 @@ void foo14() {
// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
// OGCG: store i32 0, ptr %[[C_REAL_PTR]], align 4
// OGCG: store i32 2, ptr %[[C_IMAG_PTR]], align 4

void foo15() {
int _Complex a;
int _Complex b = a;
}

// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
// CIR: %[[COMPLEX_B:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
// CIR: cir.store{{.*}} %[[TMP_A]], %[[COMPLEX_B]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>

// LLVM: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, i64 1, align 4
// LLVM: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, i64 1, align 4
// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[COMPLEX_A]], align 4
// LLVM: store { i32, i32 } %[[TMP_A]], ptr %[[COMPLEX_B]], align 4

// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4
// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 0
// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1
// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 0
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1
// OGCG: store i32 %[[A_REAL]], ptr %[[B_REAL_PTR]], align 4
// OGCG: store i32 %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 4
Loading