-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[CIR] Upstream ComplexType builtin_complex #144225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CIR] Upstream ComplexType builtin_complex #144225
Conversation
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for builtin_complex Full diff: https://github.com/llvm/llvm-project/pull/144225.diff 4 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index c59ac78210f81..b1b2e9080af45 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -50,6 +50,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
}
mlir::Location loc = getLoc(e->getExprLoc());
- cgm.errorNYI(loc, "non constant foldable builtin calls");
+ switch (builtinID) {
+ case Builtin::BI__builtin_complex: {
+ mlir::Value real = emitScalarExpr(e->getArg(0));
+ mlir::Value imag = emitScalarExpr(e->getArg(1));
+ return RValue::getComplex(real, imag);
+ }
+ default:
+ cgm.errorNYI(loc, "non constant foldable builtin calls");
+ }
return getUndefRValue(e->getType());
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 2ffe75a388e98..0c7c5c382267c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -15,11 +15,25 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
explicit ComplexExprEmitter(CIRGenFunction &cgf)
: cgf(cgf), builder(cgf.getBuilder()) {}
+ //===--------------------------------------------------------------------===//
+ // Utilities
+ //===--------------------------------------------------------------------===//
+
+ /// 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.
+ mlir::Value emitLoadOfLValue(const Expr *e) {
+ return emitLoadOfLValue(cgf.emitLValue(e), e->getExprLoc());
+ }
+
+ 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 VisitCallExpr(const CallExpr *e);
mlir::Value VisitInitListExpr(InitListExpr *e);
};
@@ -32,6 +46,16 @@ static const ComplexType *getComplexType(QualType type) {
return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
}
+mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
+ SourceLocation loc) {
+ assert(lv.isSimple() && "non-simple complex l-value?");
+ if (lv.getType()->isAtomicType())
+ cgf.cgm.errorNYI("emitLoadOfLValue with Atomic LV");
+
+ const Address srcAddr = lv.getAddress();
+ return builder.createLoad(cgf.getLoc(loc), srcAddr);
+}
+
void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
LValue lv, bool isInit) {
if (lv.getType()->isAtomicType() ||
@@ -44,6 +68,15 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
builder.createStore(loc, val, destAddr);
}
+mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) {
+ if (e->getCallReturnType(cgf.getContext())->isReferenceType())
+ return emitLoadOfLValue(e);
+
+ mlir::Location loc = cgf.getLoc(e->getExprLoc());
+ auto complex = cgf.emitCallExpr(e).getComplexVal();
+ return builder.createComplexCreate(loc, complex.first, complex.second);
+}
+
mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *e) {
mlir::Location loc = cgf.getLoc(e->getExprLoc());
if (e->getNumInits() == 2) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index c1e08ba1e9b67..ca932382c5150 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -96,6 +96,7 @@ class RValue {
er.isVolatile = false;
return er;
}
+
static RValue getComplex(const std::pair<mlir::Value, mlir::Value> &c) {
return getComplex(c.first, c.second);
}
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index d193b9f32efbc..8319a7ddecb1d 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -176,3 +176,27 @@ void foo7() {
// OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4
// OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4
+void foo9(double r, double i) {
+ double _Complex c = __builtin_complex(r, i);
+}
+
+// CIR: %[[INIT:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["c", init]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.double>, !cir.double
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.double>, !cir.double
+// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[TMP_B]] : !cir.double -> !cir.complex<!cir.double>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>
+
+// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8
+// LLVM: %[[TMP_A:.*]] = load double, ptr {{.*}}, align 8
+// LLVM: %[[TMP_B:.*]] = load double, ptr {{.*}}, align 8
+// LLVM: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[TMP_A]], 0
+// LLVM: %[[TMP_2:.*]] = insertvalue { double, double } %[[TMP]], double %[[TMP_B]], 1
+// LLVM: store { double, double } %[[TMP_2]], ptr %[[COMPLEX]], align 8
+
+// OGCG: %[[COMPLEX]] = alloca { double, double }, align 8
+// OGCG: %[[TMP_A:.*]] = load double, ptr {{.*}}, align 8
+// OGCG: %[[TMP_B:.*]] = load double, ptr {{.*}}, align 8
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: store double %[[TMP_A]], ptr %[[C_REAL_PTR]], align 8
+// OGCG: store double %[[TMP_B]], ptr %[[C_IMAG_PTR]], align 8
|
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for builtin_complex Full diff: https://github.com/llvm/llvm-project/pull/144225.diff 4 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index c59ac78210f81..b1b2e9080af45 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -50,6 +50,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
}
mlir::Location loc = getLoc(e->getExprLoc());
- cgm.errorNYI(loc, "non constant foldable builtin calls");
+ switch (builtinID) {
+ case Builtin::BI__builtin_complex: {
+ mlir::Value real = emitScalarExpr(e->getArg(0));
+ mlir::Value imag = emitScalarExpr(e->getArg(1));
+ return RValue::getComplex(real, imag);
+ }
+ default:
+ cgm.errorNYI(loc, "non constant foldable builtin calls");
+ }
return getUndefRValue(e->getType());
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 2ffe75a388e98..0c7c5c382267c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -15,11 +15,25 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
explicit ComplexExprEmitter(CIRGenFunction &cgf)
: cgf(cgf), builder(cgf.getBuilder()) {}
+ //===--------------------------------------------------------------------===//
+ // Utilities
+ //===--------------------------------------------------------------------===//
+
+ /// 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.
+ mlir::Value emitLoadOfLValue(const Expr *e) {
+ return emitLoadOfLValue(cgf.emitLValue(e), e->getExprLoc());
+ }
+
+ 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 VisitCallExpr(const CallExpr *e);
mlir::Value VisitInitListExpr(InitListExpr *e);
};
@@ -32,6 +46,16 @@ static const ComplexType *getComplexType(QualType type) {
return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
}
+mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
+ SourceLocation loc) {
+ assert(lv.isSimple() && "non-simple complex l-value?");
+ if (lv.getType()->isAtomicType())
+ cgf.cgm.errorNYI("emitLoadOfLValue with Atomic LV");
+
+ const Address srcAddr = lv.getAddress();
+ return builder.createLoad(cgf.getLoc(loc), srcAddr);
+}
+
void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
LValue lv, bool isInit) {
if (lv.getType()->isAtomicType() ||
@@ -44,6 +68,15 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
builder.createStore(loc, val, destAddr);
}
+mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) {
+ if (e->getCallReturnType(cgf.getContext())->isReferenceType())
+ return emitLoadOfLValue(e);
+
+ mlir::Location loc = cgf.getLoc(e->getExprLoc());
+ auto complex = cgf.emitCallExpr(e).getComplexVal();
+ return builder.createComplexCreate(loc, complex.first, complex.second);
+}
+
mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *e) {
mlir::Location loc = cgf.getLoc(e->getExprLoc());
if (e->getNumInits() == 2) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index c1e08ba1e9b67..ca932382c5150 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -96,6 +96,7 @@ class RValue {
er.isVolatile = false;
return er;
}
+
static RValue getComplex(const std::pair<mlir::Value, mlir::Value> &c) {
return getComplex(c.first, c.second);
}
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index d193b9f32efbc..8319a7ddecb1d 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -176,3 +176,27 @@ void foo7() {
// OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4
// OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4
+void foo9(double r, double i) {
+ double _Complex c = __builtin_complex(r, i);
+}
+
+// CIR: %[[INIT:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["c", init]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.double>, !cir.double
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.double>, !cir.double
+// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[TMP_B]] : !cir.double -> !cir.complex<!cir.double>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>
+
+// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8
+// LLVM: %[[TMP_A:.*]] = load double, ptr {{.*}}, align 8
+// LLVM: %[[TMP_B:.*]] = load double, ptr {{.*}}, align 8
+// LLVM: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[TMP_A]], 0
+// LLVM: %[[TMP_2:.*]] = insertvalue { double, double } %[[TMP]], double %[[TMP_B]], 1
+// LLVM: store { double, double } %[[TMP_2]], ptr %[[COMPLEX]], align 8
+
+// OGCG: %[[COMPLEX]] = alloca { double, double }, align 8
+// OGCG: %[[TMP_A:.*]] = load double, ptr {{.*}}, align 8
+// OGCG: %[[TMP_B:.*]] = load double, ptr {{.*}}, align 8
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: store double %[[TMP_A]], ptr %[[C_REAL_PTR]], align 8
+// OGCG: store double %[[TMP_B]], ptr %[[C_IMAG_PTR]], align 8
|
|
||
mlir::Location loc = cgf.getLoc(e->getExprLoc()); | ||
auto complex = cgf.emitCallExpr(e).getComplexVal(); | ||
return builder.createComplexCreate(loc, complex.first, complex.second); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call to functions that return a complex value should yield a single mlir::Value
that represents the complex value. #142779 modifies RValue
and uses two mlir::Value
s to represent a complex rvalue, which could result in unnecessary complex unpacking and packing operations being emitted by CIRGen.
I suggest we follow the incubator's approach and update the definition of RValue
. Instead of using two mlir::Value
s to represent a complex rvalue, use just one mlir::Value
(just like how it represents a regular scalar value).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a PR for the suggested change to RValue
here: #144519
clang/test/CIR/CodeGen/complex.cpp
Outdated
@@ -176,3 +176,27 @@ void foo7() { | |||
// OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4 | |||
// OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4 | |||
|
|||
void foo9(double r, double i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void foo9(double r, double i) { | |
void foo9(double a, double b) { |
For consistency with what you've called these variables in the checks.
SourceLocation loc) { | ||
assert(lv.isSimple() && "non-simple complex l-value?"); | ||
if (lv.getType()->isAtomicType()) | ||
cgf.cgm.errorNYI("emitLoadOfLValue with Atomic LV"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cgf.cgm.errorNYI("emitLoadOfLValue with Atomic LV"); | |
cgf.cgm.errorNYI(loc, "emitLoadOfLValue with Atomic LV"); |
This is very useful in the diagnostic produced.
@@ -44,6 +68,15 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, | |||
builder.createStore(loc, val, destAddr); | |||
} | |||
|
|||
mlir::Value ComplexExprEmitter::VisitCallExpr(const CallExpr *e) { | |||
if (e->getCallReturnType(cgf.getContext())->isReferenceType()) | |||
return emitLoadOfLValue(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know what sort of source construct gets us here? A test case for this would be useful.
return RValue::getComplex(real, imag); | ||
} | ||
default: | ||
cgm.errorNYI(loc, "non constant foldable builtin calls"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see this, along with the code on line 52, remain with the getUndefRValue
on line 62. They're all part of the same logic to report and unhandled builtin.
clang/test/CIR/CodeGen/complex.cpp
Outdated
@@ -176,3 +176,27 @@ void foo7() { | |||
// OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4 | |||
// OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4 | |||
|
|||
void foo9(double r, double i) { | |||
double _Complex c = __builtin_complex(r, i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does __builtin_complex
also accept integers? If so, add a test case for that.
I believe both arguments (or either) can also be an expression. So a test cases like this would be useful:
double _Complex c2 = __builtin_complex(a + b, a * 2.0);
double _Complex c3 = __builtin_complex(a + 1.0, 3.0);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
builtin_complex
accepts only floating points -
Both arguments can be expressed, but I need to implement the rest of the visitors in
ComplexExprEmitter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For arguments with expressions, I can update the tests when implementing new visitors
08893cb
to
b420265
Compare
return emitLoadOfLValue(e); | ||
|
||
mlir::Location loc = cgf.getLoc(e->getExprLoc()); | ||
auto complex = cgf.emitCallExpr(e).getComplexVal(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use auto here.
case Builtin::BI__builtin_complex: { | ||
mlir::Value real = emitScalarExpr(e->getArg(0)); | ||
mlir::Value imag = emitScalarExpr(e->getArg(1)); | ||
return RValue::getComplex(real, imag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the suggestion by @Lancern below, we should be calling createComplexCreate here rather than returning separate values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, once #144519 is merged, I will update it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have anything else to add besides current reviews, LGTM once it's updated to incorporate the other landed change.
b420265
to
79c9b9f
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
0cb671c
to
17f2054
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/162/builds/24860 Here is the relevant piece of the build log for the reference
|
This change adds support for builtin_complex
#141365