Skip to content

Commit 304ef65

Browse files
authored
[CIR] Upstream DivOp for ComplexType (llvm#153796)
This change adds support for the division operation between two complex types Issue: llvm#141365
1 parent c44c325 commit 304ef65

File tree

5 files changed

+816
-26
lines changed

5 files changed

+816
-26
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,7 +3185,7 @@ def CIR_ComplexSubOp : CIR_Op<"complex.sub", [
31853185
}
31863186

31873187
//===----------------------------------------------------------------------===//
3188-
// ComplexMulOp
3188+
// ComplexMulOp & ComplexDivOp
31893189
//===----------------------------------------------------------------------===//
31903190

31913191
def CIR_ComplexRangeKind : CIR_I32EnumAttr<
@@ -3204,12 +3204,13 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
32043204
The `cir.complex.mul` operation takes two complex numbers and returns
32053205
their product.
32063206

3207-
Range is used to select the implementation used when the operation
3208-
is lowered to the LLVM dialect. For multiplication, 'improved',
3209-
'promoted', and 'basic' are all handled equivalently, producing the
3210-
algebraic formula with no special handling for NaN value. If 'full' is
3211-
used, a runtime-library function is called if one of the intermediate
3212-
calculations produced a NaN value.
3207+
For complex types with floating-point components, the `range` attribute
3208+
specifies the algorithm to be used when the operation is lowered to
3209+
the LLVM dialect. For multiplication, 'improved', 'promoted', and 'basic'
3210+
are all handled equivalently, producing the algebraic formula with no
3211+
special handling for NaN value. If 'full' is used, a runtime-library
3212+
function is called if one of the intermediate calculations produced
3213+
a NaN value.
32133214

32143215
Example:
32153216

@@ -3232,6 +3233,48 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
32323233
}];
32333234
}
32343235

3236+
def CIR_ComplexDivOp : CIR_Op<"complex.div", [
3237+
Pure, SameOperandsAndResultType
3238+
]> {
3239+
let summary = "Complex division";
3240+
let description = [{
3241+
The `cir.complex.div` operation takes two complex numbers and returns
3242+
their quotient.
3243+
3244+
For complex types with floating-point components, the `range` attribute
3245+
specifies the algorithm to be used when the operation is lowered to
3246+
the LLVM dialect. For division, 'improved' produces Smith's algorithms for
3247+
Complex division with no additional handling for NaN values. If 'promoted'
3248+
is used, the values are promoted to a higher precision type, if possible,
3249+
and the calculation is performed using the algebraic formula, with
3250+
no additional handling for NaN values. We fall back on Smith's algorithm
3251+
when the target doesn't support a higher precision type. If 'full' is used,
3252+
a runtime-library function is called if one of the intermediate
3253+
calculations produced a NaN value. and for 'basic' algebraic formula with
3254+
no additional handling for the NaN value will be used. For integers types
3255+
`range` attribute will be ignored.
3256+
3257+
Example:
3258+
3259+
```mlir
3260+
%2 = cir.complex.div %0, %1 range(basic) : !cir.complex<!cir.float>
3261+
%2 = cir.complex.div %0, %1 range(full) : !cir.complex<!cir.float>
3262+
```
3263+
}];
3264+
3265+
let arguments = (ins
3266+
CIR_ComplexType:$lhs,
3267+
CIR_ComplexType:$rhs,
3268+
CIR_ComplexRangeKind:$range
3269+
);
3270+
3271+
let results = (outs CIR_ComplexType:$result);
3272+
3273+
let assemblyFormat = [{
3274+
$lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
3275+
}];
3276+
}
3277+
32353278
//===----------------------------------------------------------------------===//
32363279
// Bit Manipulation Operations
32373280
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,11 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
136136
mlir::Value emitBinAdd(const BinOpInfo &op);
137137
mlir::Value emitBinSub(const BinOpInfo &op);
138138
mlir::Value emitBinMul(const BinOpInfo &op);
139+
mlir::Value emitBinDiv(const BinOpInfo &op);
139140

140141
QualType getPromotionType(QualType ty, bool isDivOpCode = false) {
141142
if (auto *complexTy = ty->getAs<ComplexType>()) {
142143
QualType elementTy = complexTy->getElementType();
143-
if (isDivOpCode && elementTy->isFloatingType() &&
144-
cgf.getLangOpts().getComplexRange() ==
145-
LangOptions::ComplexRangeKind::CX_Promoted) {
146-
cgf.cgm.errorNYI("HigherPrecisionTypeForComplexArithmetic");
147-
return QualType();
148-
}
149-
150144
if (elementTy.UseExcessPrecision(cgf.getContext()))
151145
return cgf.getContext().getComplexType(cgf.getContext().FloatTy);
152146
}
@@ -162,13 +156,14 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
162156
e->getType(), e->getOpcode() == BinaryOperatorKind::BO_Div); \
163157
mlir::Value result = emitBin##OP(emitBinOps(e, promotionTy)); \
164158
if (!promotionTy.isNull()) \
165-
cgf.cgm.errorNYI("Binop emitUnPromotedValue"); \
159+
result = cgf.emitUnPromotedValue(result, e->getType()); \
166160
return result; \
167161
}
168162

169163
HANDLEBINOP(Add)
170164
HANDLEBINOP(Sub)
171165
HANDLEBINOP(Mul)
166+
HANDLEBINOP(Div)
172167
#undef HANDLEBINOP
173168

174169
// Compound assignments.
@@ -866,6 +861,22 @@ mlir::Value ComplexExprEmitter::emitBinMul(const BinOpInfo &op) {
866861
return builder.createComplexCreate(op.loc, newReal, newImag);
867862
}
868863

864+
mlir::Value ComplexExprEmitter::emitBinDiv(const BinOpInfo &op) {
865+
assert(!cir::MissingFeatures::fastMathFlags());
866+
assert(!cir::MissingFeatures::cgFPOptionsRAII());
867+
868+
if (mlir::isa<cir::ComplexType>(op.lhs.getType()) &&
869+
mlir::isa<cir::ComplexType>(op.rhs.getType())) {
870+
cir::ComplexRangeKind rangeKind =
871+
getComplexRangeAttr(op.fpFeatures.getComplexRange());
872+
return cir::ComplexDivOp::create(builder, op.loc, op.lhs, op.rhs,
873+
rangeKind);
874+
}
875+
876+
cgf.cgm.errorNYI("ComplexExprEmitter::emitBinDiv between Complex & Scalar");
877+
return {};
878+
}
879+
869880
LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) {
870881
assert(e->getOpcode() == BO_Assign && "Expected assign op");
871882

@@ -962,6 +973,14 @@ mlir::Value CIRGenFunction::emitPromotedValue(mlir::Value result,
962973
convertType(promotionType));
963974
}
964975

976+
mlir::Value CIRGenFunction::emitUnPromotedValue(mlir::Value result,
977+
QualType unPromotionType) {
978+
assert(!mlir::cast<cir::ComplexType>(result.getType()).isIntegerComplex() &&
979+
"integral complex will never be promoted");
980+
return builder.createCast(cir::CastKind::float_complex, result,
981+
convertType(unPromotionType));
982+
}
983+
965984
LValue CIRGenFunction::emitScalarCompoundAssignWithComplex(
966985
const CompoundAssignOperator *e, mlir::Value &result) {
967986
CompoundFunc op = getComplexOp(e->getOpcode());

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,8 @@ class CIRGenFunction : public CIRGenTypeCache {
13791379

13801380
LValue emitUnaryOpLValue(const clang::UnaryOperator *e);
13811381

1382+
mlir::Value emitUnPromotedValue(mlir::Value result, QualType unPromotionType);
1383+
13821384
/// Emit a reached-unreachable diagnostic if \p loc is valid and runtime
13831385
/// checking is enabled. Otherwise, just emit an unreachable instruction.
13841386
/// \p createNewBlock indicates whether to create a new block for the IR

0 commit comments

Comments
 (0)