Skip to content

Commit 953be42

Browse files
authored
[CIR] Upstream Unary Plus & Minus op for ComplexType (#150281)
This change adds support for Unary Plus & Minus op for ComplexType #141365
1 parent 1bf89e9 commit 953be42

File tree

3 files changed

+142
-4
lines changed

3 files changed

+142
-4
lines changed

clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
9191
}
9292

9393
mlir::Value VisitUnaryDeref(const Expr *e);
94+
95+
mlir::Value VisitUnaryPlus(const UnaryOperator *e);
96+
97+
mlir::Value VisitPlusMinus(const UnaryOperator *e, cir::UnaryOpKind kind,
98+
QualType promotionType);
99+
100+
mlir::Value VisitUnaryMinus(const UnaryOperator *e);
101+
94102
mlir::Value VisitUnaryNot(const UnaryOperator *e);
95103

96104
struct BinOpInfo {
@@ -282,6 +290,41 @@ mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
282290
llvm_unreachable("unknown cast resulting in complex value");
283291
}
284292

293+
mlir::Value ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *e) {
294+
QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
295+
mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Plus, promotionTy);
296+
if (!promotionTy.isNull()) {
297+
cgf.cgm.errorNYI("ComplexExprEmitter::VisitUnaryPlus emitUnPromotedValue");
298+
return {};
299+
}
300+
return result;
301+
}
302+
303+
mlir::Value ComplexExprEmitter::VisitPlusMinus(const UnaryOperator *e,
304+
cir::UnaryOpKind kind,
305+
QualType promotionType) {
306+
assert(kind == cir::UnaryOpKind::Plus ||
307+
kind == cir::UnaryOpKind::Minus &&
308+
"Invalid UnaryOp kind for ComplexType Plus or Minus");
309+
310+
mlir::Value op;
311+
if (!promotionType.isNull())
312+
op = cgf.emitPromotedComplexExpr(e->getSubExpr(), promotionType);
313+
else
314+
op = Visit(e->getSubExpr());
315+
return builder.createUnaryOp(cgf.getLoc(e->getExprLoc()), kind, op);
316+
}
317+
318+
mlir::Value ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *e) {
319+
QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
320+
mlir::Value result = VisitPlusMinus(e, cir::UnaryOpKind::Minus, promotionTy);
321+
if (!promotionTy.isNull()) {
322+
cgf.cgm.errorNYI("ComplexExprEmitter::VisitUnaryMinus emitUnPromotedValue");
323+
return {};
324+
}
325+
return result;
326+
}
327+
285328
mlir::Value ComplexExprEmitter::emitConstant(
286329
const CIRGenFunction::ConstantEmission &constant, Expr *e) {
287330
assert(constant && "not a constant");
@@ -538,9 +581,17 @@ mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,
538581
default:
539582
break;
540583
}
541-
} else if (isa<UnaryOperator>(e)) {
542-
cgf.cgm.errorNYI("emitPromoted UnaryOperator");
543-
return {};
584+
} else if (const auto *unaryOp = dyn_cast<UnaryOperator>(e)) {
585+
switch (unaryOp->getOpcode()) {
586+
case UO_Minus:
587+
case UO_Plus: {
588+
auto kind = unaryOp->getOpcode() == UO_Plus ? cir::UnaryOpKind::Plus
589+
: cir::UnaryOpKind::Minus;
590+
return VisitPlusMinus(unaryOp, kind, promotionTy);
591+
}
592+
default:
593+
break;
594+
}
544595
}
545596

546597
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
@@ -155,7 +155,8 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
155155

156156
case cir::UnaryOpKind::Plus:
157157
case cir::UnaryOpKind::Minus:
158-
llvm_unreachable("Complex unary Plus/Minus NYI");
158+
resultReal = builder.createUnaryOp(loc, opKind, operandReal);
159+
resultImag = builder.createUnaryOp(loc, opKind, operandImag);
159160
break;
160161

161162
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)