Skip to content

Commit 19a9d55

Browse files
committed
[CIR] Upstream Unary Plus & Minus op for ComplexType
1 parent e67f323 commit 19a9d55

File tree

3 files changed

+160
-4
lines changed

3 files changed

+160
-4
lines changed

clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
8282
}
8383

8484
mlir::Value VisitUnaryDeref(const Expr *e);
85+
86+
mlir::Value VisitUnaryPlus(const UnaryOperator *e,
87+
QualType promotionType = QualType());
88+
89+
mlir::Value VisitPlus(const UnaryOperator *e, QualType promotionType);
90+
91+
mlir::Value VisitUnaryMinus(const UnaryOperator *e,
92+
QualType promotionType = QualType());
93+
94+
mlir::Value VisitMinus(const UnaryOperator *e, QualType promotionType);
95+
8596
mlir::Value VisitUnaryNot(const UnaryOperator *e);
8697

8798
struct BinOpInfo {
@@ -174,6 +185,58 @@ mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
174185
return {};
175186
}
176187

188+
mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *e,
189+
QualType promotionType) {
190+
QualType promotionTy = promotionType.isNull()
191+
? getPromotionType(e->getSubExpr()->getType())
192+
: promotionType;
193+
mlir::Value result = VisitPlus(e, promotionTy);
194+
if (!promotionTy.isNull()) {
195+
cgf.cgm.errorNYI("ComplexExprEmitter::VisitUnaryPlus emitUnPromotedValue");
196+
return {};
197+
}
198+
199+
return result;
200+
}
201+
202+
mlir::Value ComplexExprEmitter::VisitPlus(const UnaryOperator *e,
203+
QualType promotionType) {
204+
mlir::Value op;
205+
if (!promotionType.isNull())
206+
op = cgf.emitPromotedComplexExpr(e->getSubExpr(), promotionType);
207+
else
208+
op = Visit(e->getSubExpr());
209+
210+
return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()),
211+
cir::UnaryOpKind::Plus, op);
212+
}
213+
214+
mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e,
215+
QualType promotionType) {
216+
QualType promotionTy = promotionType.isNull()
217+
? getPromotionType(e->getSubExpr()->getType())
218+
: promotionType;
219+
mlir::Value result = VisitMinus(e, promotionTy);
220+
if (!promotionTy.isNull()) {
221+
cgf.cgm.errorNYI("ComplexExprEmitter::VisitUnaryMinus emitUnPromotedValue");
222+
return {};
223+
}
224+
225+
return result;
226+
}
227+
228+
mlir::Value ComplexExprEmitter::VisitMinus(const UnaryOperator *e,
229+
QualType promotionType) {
230+
mlir::Value op;
231+
if (!promotionType.isNull())
232+
op = cgf.emitPromotedComplexExpr(e->getSubExpr(), promotionType);
233+
else
234+
op = Visit(e->getSubExpr());
235+
236+
return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()),
237+
cir::UnaryOpKind::Minus, op);
238+
}
239+
177240
mlir::Value ComplexExprEmitter::emitConstant(
178241
const CIRGenFunction::ConstantEmission &constant, Expr *e) {
179242
assert(constant && "not a constant");
@@ -389,9 +452,15 @@ mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,
389452
default:
390453
break;
391454
}
392-
} else if (isa<UnaryOperator>(e)) {
393-
cgf.cgm.errorNYI("emitPromoted UnaryOperator");
394-
return {};
455+
} else if (const auto *unaryOp = dyn_cast<UnaryOperator>(e)) {
456+
switch (unaryOp->getOpcode()) {
457+
case UO_Minus:
458+
return VisitMinus(unaryOp, promotionTy);
459+
case UO_Plus:
460+
return VisitPlus(unaryOp, promotionTy);
461+
default:
462+
break;
463+
}
395464
}
396465

397466
mlir::Value result = Visit(const_cast<Expr *>(e));

clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
5656

5757
case cir::UnaryOpKind::Plus:
5858
case cir::UnaryOpKind::Minus:
59-
llvm_unreachable("Complex unary Plus/Minus NYI");
59+
resultReal = builder.createUnaryOp(loc, opKind, operandReal);
60+
resultImag = builder.createUnaryOp(loc, opKind, operandImag);
6061
break;
6162

6263
case cir::UnaryOpKind::Not:

clang/test/CIR/CodeGen/complex-unary.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,89 @@ void foo6() {
284284
// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
285285
// OGCG: store float %[[A_REAL_DEC]], ptr %[[RESULT_REAL_PTR]], align 4
286286
// OGCG: store float %[[A_IMAG]], ptr %[[RESULT_IMAG_PTR]], align 4
287+
288+
void foo7() {
289+
float _Complex a;
290+
float _Complex b = +a;
291+
}
292+
293+
// CIR-BEFORE: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
294+
// CIR-BEFORE: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
295+
// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
296+
// CIR-BEFORE: %[[COMPLEX_PLUS:.*]] = cir.unary(plus, %[[TMP]]) : !cir.complex<!cir.float>, !cir.complex<!cir.float>
297+
// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_PLUS]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
298+
299+
// CIR-AFTER: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
300+
// CIR-AFTER: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
301+
// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
302+
// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!cir.float> -> !cir.float
303+
// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!cir.float> -> !cir.float
304+
// CIR-AFTER: %[[REAL_PLUS:.*]] = cir.unary(plus, %[[REAL]]) : !cir.float, !cir.float
305+
// CIR-AFTER: %[[IMAG_PLUS:.*]] = cir.unary(plus, %[[IMAG]]) : !cir.float, !cir.float
306+
// CIR-AFTER: %[[NEW_COMPLEX:.*]] = cir.complex.create %[[REAL_PLUS]], %[[IMAG_PLUS]] : !cir.float -> !cir.complex<!cir.float>
307+
// CIR-AFTER: cir.store{{.*}} %[[NEW_COMPLEX]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
308+
309+
// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
310+
// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
311+
// LLVM: %[[TMP:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
312+
// LLVM: %[[REAL:.*]] = extractvalue { float, float } %[[TMP]], 0
313+
// LLVM: %[[IMAG:.*]] = extractvalue { float, float } %[[TMP]], 1
314+
// LLVM: %[[RESULT_TMP:.*]] = insertvalue { float, float } {{.*}}, float %[[REAL]], 0
315+
// LLVM: %[[RESULT_VAL:.*]] = insertvalue { float, float } %[[RESULT_TMP]], float %[[IMAG]], 1
316+
// LLVM: store { float, float } %[[RESULT_VAL]], ptr %[[B_ADDR]], align 4
317+
318+
// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
319+
// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
320+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
321+
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
322+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
323+
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
324+
// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
325+
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
326+
// OGCG: store float %[[A_REAL]], ptr %[[B_REAL_PTR]], align 4
327+
// OGCG: store float %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 4
328+
329+
void foo8() {
330+
float _Complex a;
331+
float _Complex b = -a;
332+
}
333+
334+
// CIR-BEFORE: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
335+
// CIR-BEFORE: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
336+
// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
337+
// CIR-BEFORE: %[[COMPLEX_MINUS:.*]] = cir.unary(minus, %[[TMP]]) : !cir.complex<!cir.float>, !cir.complex<!cir.float>
338+
// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_MINUS]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
339+
340+
// CIR-AFTER: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
341+
// CIR-AFTER: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
342+
// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
343+
// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!cir.float> -> !cir.float
344+
// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!cir.float> -> !cir.float
345+
// CIR-AFTER: %[[REAL_MINUS:.*]] = cir.unary(minus, %[[REAL]]) : !cir.float, !cir.float
346+
// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !cir.float, !cir.float
347+
// CIR-AFTER: %[[NEW_COMPLEX:.*]] = cir.complex.create %[[REAL_MINUS]], %[[IMAG_MINUS]] : !cir.float -> !cir.complex<!cir.float>
348+
// CIR-AFTER: cir.store{{.*}} %[[NEW_COMPLEX]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
349+
350+
// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
351+
// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
352+
// LLVM: %[[TMP:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
353+
// LLVM: %[[REAL:.*]] = extractvalue { float, float } %[[TMP]], 0
354+
// LLVM: %[[IMAG:.*]] = extractvalue { float, float } %[[TMP]], 1
355+
// LLVM: %[[REAL_MINUS:.*]] = fneg float %[[REAL]]
356+
// LLVM: %[[IMAG_MINUS:.*]] = fneg float %[[IMAG]]
357+
// LLVM: %[[RESULT_TMP:.*]] = insertvalue { float, float } {{.*}}, float %[[REAL_MINUS]], 0
358+
// LLVM: %[[RESULT_VAL:.*]] = insertvalue { float, float } %[[RESULT_TMP]], float %[[IMAG_MINUS]], 1
359+
// LLVM: store { float, float } %[[RESULT_VAL]], ptr %[[B_ADDR]], align 4
360+
361+
// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
362+
// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
363+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
364+
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
365+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
366+
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
367+
// OGCG: %[[A_REAL_MINUS:.*]] = fneg float %[[A_REAL]]
368+
// OGCG: %[[A_IMAG_MINUS:.*]] = fneg float %[[A_IMAG]]
369+
// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
370+
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
371+
// OGCG: store float %[[A_REAL_MINUS]], ptr %[[B_REAL_PTR]], align 4
372+
// OGCG: store float %[[A_IMAG_MINUS]], ptr %[[B_IMAG_PTR]], align 4

0 commit comments

Comments
 (0)