Skip to content

Commit 4ae5d01

Browse files
committed
[CIR] DivOp & CompoundAssignmentDiv between ComplexType and ScalarType
1 parent c7d1425 commit 4ae5d01

File tree

3 files changed

+678
-5
lines changed

3 files changed

+678
-5
lines changed

clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
178178
mlir::Value VisitBinMulAssign(const CompoundAssignOperator *e) {
179179
return emitCompoundAssign(e, &ComplexExprEmitter::emitBinMul);
180180
}
181+
182+
mlir::Value VisitBinDivAssign(const CompoundAssignOperator *e) {
183+
return emitCompoundAssign(e, &ComplexExprEmitter::emitBinDiv);
184+
}
181185
};
182186
} // namespace
183187

@@ -865,6 +869,10 @@ mlir::Value ComplexExprEmitter::emitBinDiv(const BinOpInfo &op) {
865869
assert(!cir::MissingFeatures::fastMathFlags());
866870
assert(!cir::MissingFeatures::cgFPOptionsRAII());
867871

872+
// Handle division between Complex LHS and RHS with element type
873+
// floating-point, and also handling if the element type is integer and either
874+
// LHS or RHS is scalar because it will be implicitly casted to ComplexType
875+
// from the frontend
868876
if (mlir::isa<cir::ComplexType>(op.lhs.getType()) &&
869877
mlir::isa<cir::ComplexType>(op.rhs.getType())) {
870878
cir::ComplexRangeKind rangeKind =
@@ -873,8 +881,20 @@ mlir::Value ComplexExprEmitter::emitBinDiv(const BinOpInfo &op) {
873881
rangeKind);
874882
}
875883

876-
cgf.cgm.errorNYI("ComplexExprEmitter::emitBinDiv between Complex & Scalar");
877-
return {};
884+
if (mlir::isa<cir::ComplexType>(op.lhs.getType())) {
885+
mlir::Value real = builder.createComplexReal(op.loc, op.lhs);
886+
mlir::Value imag = builder.createComplexImag(op.loc, op.lhs);
887+
mlir::Value newReal = builder.createFDiv(op.loc, real, op.rhs);
888+
mlir::Value newImag = builder.createFDiv(op.loc, imag, op.rhs);
889+
return builder.createComplexCreate(op.loc, newReal, newImag);
890+
}
891+
892+
assert(mlir::isa<cir::ComplexType>(op.rhs.getType()));
893+
cir::ConstantOp nullValue = builder.getNullValue(op.lhs.getType(), op.loc);
894+
mlir::Value lhs = builder.createComplexCreate(op.loc, op.lhs, nullValue);
895+
cir::ComplexRangeKind rangeKind =
896+
getComplexRangeAttr(op.fpFeatures.getComplexRange());
897+
return cir::ComplexDivOp::create(builder, op.loc, lhs, op.rhs, rangeKind);
878898
}
879899

880900
LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) {
@@ -903,7 +923,7 @@ static CompoundFunc getComplexOp(BinaryOperatorKind op) {
903923
case BO_MulAssign:
904924
return &ComplexExprEmitter::emitBinMul;
905925
case BO_DivAssign:
906-
llvm_unreachable("getComplexOp: BO_DivAssign");
926+
return &ComplexExprEmitter::emitBinDiv;
907927
case BO_SubAssign:
908928
return &ComplexExprEmitter::emitBinSub;
909929
case BO_AddAssign:

clang/test/CIR/CodeGen/complex-compound-assignment.cpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,3 +572,170 @@ void foo9() {
572572
// C_OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
573573
// C_OGCG: %[[ADD_REAL:.*]] = fadd float %[[TMP_B]], %[[A_REAL]]
574574
// C_OGCG: store float %[[ADD_REAL]], ptr %[[B_ADDR]], align 4
575+
576+
void foo10() {
577+
float _Complex a;
578+
float _Complex b;
579+
a /= b;
580+
}
581+
582+
// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
583+
// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
584+
// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
585+
// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
586+
// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
587+
// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
588+
// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
589+
// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
590+
// CIR: %[[RESULT:.*]] = cir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]], %[[B_REAL]], %[[B_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float>
591+
// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
592+
593+
// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
594+
// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
595+
// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
596+
// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
597+
// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
598+
// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
599+
// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
600+
// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
601+
// LLVM: %[[RESULT:.*]] = call { float, float } @__divsc3(float %[[A_REAL]], float %[[A_IMAG]], float %[[B_REAL]], float %[[B_IMAG]])
602+
// LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4
603+
604+
// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
605+
// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
606+
// OGCG: %[[RESULT_ADDR:.*]] = alloca { float, float }, align 4
607+
// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
608+
// OGCG: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
609+
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
610+
// OGCG: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
611+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
612+
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
613+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
614+
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
615+
// OGCG: %[[RESULT:.*]] = call noundef <2 x float> @__divsc3(float noundef %[[A_REAL]], float noundef %[[A_IMAG]], float noundef %[[B_REAL]], float noundef %[[B_IMAG]])
616+
// OGCG: store <2 x float> %[[RESULT]], ptr %[[RESULT_ADDR]], align 4
617+
// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT_ADDR]], i32 0, i32 0
618+
// OGCG: %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
619+
// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT_ADDR]], i32 0, i32 1
620+
// OGCG: %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], align 4
621+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
622+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
623+
// OGCG: store float %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
624+
// OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4
625+
626+
void foo11() {
627+
float _Complex a;
628+
float b;
629+
a /= b;
630+
}
631+
632+
// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
633+
// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b"]
634+
// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.float>, !cir.float
635+
// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
636+
// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
637+
// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
638+
// CIR: %[[RESULT_REAL:.*]] = cir.binop(div, %[[A_REAL]], %[[TMP_B]]) : !cir.float
639+
// CIR: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[A_IMAG]], %[[TMP_B]]) : !cir.float
640+
// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
641+
// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
642+
643+
// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
644+
// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4
645+
// LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
646+
// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
647+
// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
648+
// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
649+
// LLVM: %[[RESULT_REAL:.*]] = fdiv float %[[A_REAL]], %[[TMP_B]]
650+
// LLVM: %[[RESULT_IMAG:.*]] = fdiv float %[[A_IMAG]], %[[TMP_B]]
651+
// LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
652+
// LLVM: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[RESULT_IMAG]], 1
653+
// LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4
654+
655+
// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
656+
// OGCG: %[[B_ADDR:.*]] = alloca float, align 4
657+
// OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
658+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
659+
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
660+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
661+
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
662+
// OGCG: %[[RESULT_REAL:.*]] = fdiv float %[[A_REAL]], %[[TMP_B]]
663+
// OGCG: %[[RESULT_IMAG:.*]] = fdiv float %[[A_IMAG]], %[[TMP_B]]
664+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
665+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
666+
// OGCG: store float %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
667+
// OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4
668+
669+
void foo12() {
670+
int _Complex a;
671+
int b;
672+
a /= b;
673+
}
674+
675+
// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
676+
// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b"]
677+
// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
678+
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
679+
// CIR: %[[B_COMPLEX:.*]] = cir.complex.create %[[TMP_B]], %[[CONST_0]] : !s32i -> !cir.complex<!s32i>
680+
// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
681+
// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!s32i> -> !s32i
682+
// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!s32i> -> !s32i
683+
// CIR: %[[B_REAL:.*]] = cir.complex.real %[[B_COMPLEX]] : !cir.complex<!s32i> -> !s32i
684+
// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[B_COMPLEX]] : !cir.complex<!s32i> -> !s32i
685+
// CIR: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !s32i
686+
// CIR: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !s32i
687+
// CIR: %[[MUL_BR_BR:.*]] = cir.binop(mul, %[[B_REAL]], %[[B_REAL]]) : !s32i
688+
// CIR: %[[MUL_BI_BI:.*]] = cir.binop(mul, %[[B_IMAG]], %[[B_IMAG]]) : !s32i
689+
// CIR: %[[ADD_ARBR_AIBI:.*]] = cir.binop(add, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !s32i
690+
// CIR: %[[ADD_BRBR_BIBI:.*]] = cir.binop(add, %[[MUL_BR_BR]], %[[MUL_BI_BI]]) : !s32i
691+
// CIR: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]) : !s32i
692+
// CIR: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !s32i
693+
// CIR: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !s32i
694+
// CIR: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !s32i
695+
// CIR: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]) : !s32i
696+
// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !s32i -> !cir.complex<!s32i>
697+
// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
698+
699+
// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
700+
// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
701+
// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
702+
// LLVM: %[[TMP_B_COMPLEX:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[TMP_B]], 0
703+
// LLVM: %[[B_COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_B_COMPLEX]], i32 0, 1
704+
// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4
705+
// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0
706+
// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1
707+
// LLVM: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[TMP_B]]
708+
// LLVM: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], 0
709+
// LLVM: %[[MUL_BR_BR:.*]] = mul i32 %[[TMP_B]], %[[TMP_B]]
710+
// LLVM: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]]
711+
// LLVM: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], 0
712+
// LLVM: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
713+
// LLVM: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[TMP_B]]
714+
// LLVM: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], 0
715+
// LLVM: %[[SUB_AIBR_ARBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_AR_BI]]
716+
// LLVM: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
717+
// LLVM: %[[TMP_RESULT:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[RESULT_REAL]], 0
718+
// LLVM: %[[RESULT:.*]] = insertvalue { i32, i32 } %[[TMP_RESULT]], i32 %[[RESULT_IMAG]], 1
719+
// LLVM: store { i32, i32 } %[[RESULT]], ptr %[[A_ADDR]], align 4
720+
721+
// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4
722+
// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4
723+
// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
724+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
725+
// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
726+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
727+
// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
728+
// OGCG: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[TMP_B]]
729+
// OGCG: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], 0
730+
// OGCG: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]]
731+
// OGCG: %[[MUL_BR_BR:.*]] = mul i32 %[[TMP_B]], %[[TMP_B]]
732+
// OGCG: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], 0
733+
// OGCG: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[TMP_B]]
734+
// OGCG: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], 0
735+
// OGCG: %[[SUB_AIBR_ARBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_AR_BI]]
736+
// OGCG: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
737+
// OGCG: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
738+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
739+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
740+
// OGCG: store i32 %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
741+
// OGCG: store i32 %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4

0 commit comments

Comments
 (0)