Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 49 additions & 7 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2966,7 +2966,7 @@ def CIR_ComplexSubOp : CIR_Op<"complex.sub", [
}

//===----------------------------------------------------------------------===//
// ComplexMulOp
// ComplexMulOp & ComplexDivOp
//===----------------------------------------------------------------------===//

def CIR_ComplexRangeKind : CIR_I32EnumAttr<
Expand All @@ -2985,12 +2985,13 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
The `cir.complex.mul` operation takes two complex numbers and returns
their product.

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

Example:

Expand All @@ -3013,6 +3014,47 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
}];
}

def CIR_ComplexDivOp : CIR_Op<"complex.div", [
Pure, SameOperandsAndResultType
]> {
let summary = "Complex division";
let description = [{
The `cir.complex.div` operation takes two complex numbers and returns
their quotient.

For complex types with floating-point components, the `range` attribute
specifies the algorithm to be used when the operation is lowered to
the LLVM dialect. For division, 'improved' produces Smith's algorithms for
Complex division with no additional handling for NaN values. If 'promoted'
is used, the values are promoted to a higher precision type, if possible,
and the calculation is performed using the algebraic formula, with
no additional handling for NaN values. We fall back on Smith's algorithm
when the target does not support a higher precision type.
If 'full' is used, a runtime-library function is called if one of the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting is a bit off here.

intermediate calculations produced a NaN value. and for 'basic' algebraic
formula with no special handling for the NaN value will be used.

Example:

```mlir
%2 = cir.complex.div %0, %1 range(basic) : !cir.complex<!cir.float>
%2 = cir.complex.div %0, %1 range(full) : !cir.complex<!cir.float>
```
}];

let arguments = (ins
CIR_ComplexType:$lhs,
CIR_ComplexType:$rhs,
CIR_ComplexRangeKind:$range
);

let results = (outs CIR_ComplexType:$result);

let assemblyFormat = [{
$lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
}];
}

//===----------------------------------------------------------------------===//
// Bit Manipulation Operations
//===----------------------------------------------------------------------===//
Expand Down
35 changes: 27 additions & 8 deletions clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,11 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
mlir::Value emitBinAdd(const BinOpInfo &op);
mlir::Value emitBinSub(const BinOpInfo &op);
mlir::Value emitBinMul(const BinOpInfo &op);
mlir::Value emitBinDiv(const BinOpInfo &op);

QualType getPromotionType(QualType ty, bool isDivOpCode = false) {
if (auto *complexTy = ty->getAs<ComplexType>()) {
QualType elementTy = complexTy->getElementType();
if (isDivOpCode && elementTy->isFloatingType() &&
cgf.getLangOpts().getComplexRange() ==
LangOptions::ComplexRangeKind::CX_Promoted) {
cgf.cgm.errorNYI("HigherPrecisionTypeForComplexArithmetic");
return QualType();
}

if (elementTy.UseExcessPrecision(cgf.getContext()))
return cgf.getContext().getComplexType(cgf.getContext().FloatTy);
}
Expand All @@ -154,13 +148,14 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
e->getType(), e->getOpcode() == BinaryOperatorKind::BO_Div); \
mlir::Value result = emitBin##OP(emitBinOps(e, promotionTy)); \
if (!promotionTy.isNull()) \
cgf.cgm.errorNYI("Binop emitUnPromotedValue"); \
result = cgf.emitUnPromotedValue(result, e->getType()); \
return result; \
}

HANDLEBINOP(Add)
HANDLEBINOP(Sub)
HANDLEBINOP(Mul)
HANDLEBINOP(Div)
#undef HANDLEBINOP

// Compound assignments.
Expand Down Expand Up @@ -858,6 +853,22 @@ mlir::Value ComplexExprEmitter::emitBinMul(const BinOpInfo &op) {
return builder.createComplexCreate(op.loc, newReal, newImag);
}

mlir::Value ComplexExprEmitter::emitBinDiv(const BinOpInfo &op) {
assert(!cir::MissingFeatures::fastMathFlags());
assert(!cir::MissingFeatures::cgFPOptionsRAII());

if (mlir::isa<cir::ComplexType>(op.lhs.getType()) &&
mlir::isa<cir::ComplexType>(op.rhs.getType())) {
cir::ComplexRangeKind rangeKind =
getComplexRangeAttr(op.fpFeatures.getComplexRange());
return cir::ComplexDivOp::create(builder, op.loc, op.lhs, op.rhs,
rangeKind);
}

cgf.cgm.errorNYI("ComplexExprEmitter::emitBinDiv between Complex & Scalar");
return {};
}

LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) {
assert(e->getOpcode() == BO_Assign && "Expected assign op");

Expand Down Expand Up @@ -954,6 +965,14 @@ mlir::Value CIRGenFunction::emitPromotedValue(mlir::Value result,
convertType(promotionType));
}

mlir::Value CIRGenFunction::emitUnPromotedValue(mlir::Value result,
QualType unPromotionType) {
assert(!mlir::cast<cir::ComplexType>(result.getType()).isIntegerComplex() &&
"integral complex will never be promoted");
return builder.createCast(cir::CastKind::float_complex, result,
convertType(unPromotionType));
}

LValue CIRGenFunction::emitScalarCompoundAssignWithComplex(
const CompoundAssignOperator *e, mlir::Value &result) {
CompoundFunc op = getComplexOp(e->getOpcode());
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,8 @@ class CIRGenFunction : public CIRGenTypeCache {

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

mlir::Value emitUnPromotedValue(mlir::Value result, QualType unPromotionType);

/// Emit a reached-unreachable diagnostic if \p loc is valid and runtime
/// checking is enabled. Otherwise, just emit an unreachable instruction.
/// \p createNewBlock indicates whether to create a new block for the IR
Expand Down
Loading