Skip to content

[CIR] Upstream global initialization for ComplexType #141369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 5, 2025
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::IntAttr::get(ty, 0);
if (cir::isAnyFloatingPointType(ty))
return cir::FPAttr::getZero(ty);
if (auto complexType = mlir::dyn_cast<cir::ComplexType>(ty))
return cir::ZeroAttr::get(complexType);
if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty))
return cir::ZeroAttr::get(arrTy);
if (auto vecTy = mlir::dyn_cast<cir::VectorType>(ty))
Expand Down
42 changes: 42 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the CIR dialect attributes constraints.
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD
#define CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD

include "mlir/IR/CommonAttrConstraints.td"

class CIR_IsAttrPred<code attr> : CPred<"::mlir::isa<" # attr # ">($_self)">;

class CIR_AttrConstraint<code attr, string summary = "">
: Attr<CIR_IsAttrPred<attr>, summary>;

//===----------------------------------------------------------------------===//
// IntAttr constraints
//===----------------------------------------------------------------------===//

def CIR_AnyIntAttr : CIR_AttrConstraint<"::cir::IntAttr", "integer attribute">;

//===----------------------------------------------------------------------===//
// FPAttr constraints
//===----------------------------------------------------------------------===//

def CIR_AnyFPAttr : CIR_AttrConstraint<"::cir::FPAttr",
"floating-point attribute">;

def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr],
"integer or floating point type"> {
string cppType = "::mlir::TypedAttr";
}
Comment on lines +37 to +40
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr],
"integer or floating point type"> {
string cppType = "::mlir::TypedAttr";
}
def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr],
"integer or floating point type", "::mlir::TypedAttr">;

Copy link
Member Author

Choose a reason for hiding this comment

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

I will check why, but def CIR_AnyIntOrFloatAttr : AnyAttrOf<[CIR_AnyIntAttr, CIR_AnyFPAttr], "integer or floating point type", "::mlir::TypedAttr">; still report MissingcppType field in Attribute/Type parameter: CIR_AnyIntOrFloatAttr

It should be the same before and after the suggestion because it the third param

class AnyAttrOf<list<Attr> allowedAttrs, string summary = "",
                string cppType = "::mlir::Attribute",
                string fromStorage = "$_self">

Copy link
Contributor

Choose a reason for hiding this comment

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

lgtm then, I can polish this when merged :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I updated the other suggestion, for this one, I will try to see why it's not working on the side

Copy link
Member Author

Choose a reason for hiding this comment

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

If there is no other comment, I can merge now 🤔 @xlauko ?


#endif // CLANG_CIR_DIALECT_IR_CIRATTRCONSTRAINTS_TD
45 changes: 45 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ include "mlir/IR/BuiltinAttributeInterfaces.td"
include "mlir/IR/EnumAttr.td"

include "clang/CIR/Dialect/IR/CIRDialect.td"
include "clang/CIR/Dialect/IR/CIRAttrConstraints.td"

//===----------------------------------------------------------------------===//
// CIR Attrs
Expand Down Expand Up @@ -276,6 +277,50 @@ def ConstPtrAttr : CIR_Attr<"ConstPtr", "ptr", [TypedAttrInterface]> {
}];
}

//===----------------------------------------------------------------------===//
// ConstComplexAttr
//===----------------------------------------------------------------------===//

def ConstComplexAttr : CIR_Attr<"ConstComplex", "const_complex",
[TypedAttrInterface]> {
let summary = "An attribute that contains a constant complex value";
let description = [{
The `#cir.const_complex` attribute contains a constant value of complex
number type. The `real` parameter gives the real part of the complex number
and the `imag` parameter gives the imaginary part of the complex number.

The `real` and `imag` parameters must both reference the same type and must
be either IntAttr or FPAttr.

```mlir
%ci = #cir.const_complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i>
: !cir.complex<!s32i>
%cf = #cir.const_complex<#cir.fp<1.000000e+00> : !cir.float,
#cir.fp<2.000000e+00> : !cir.float> : !cir.complex<!cir.float>
```
}];

let parameters = (ins
AttributeSelfTypeParameter<"", "cir::ComplexType">:$type,
CIR_AnyIntOrFloatAttr:$real,
CIR_AnyIntOrFloatAttr:$imag
);

let builders = [
AttrBuilderWithInferredContext<(ins "cir::ComplexType":$type,
"mlir::TypedAttr":$real,
"mlir::TypedAttr":$imag), [{
return $_get(type.getContext(), type, real, imag);
}]>,
];

let genVerifyDecl = 1;

let assemblyFormat = [{
`<` qualified($real) `,` qualified($imag) `>`
}];
}

//===----------------------------------------------------------------------===//
// VisibilityAttr
//===----------------------------------------------------------------------===//
Expand Down
50 changes: 50 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,56 @@ def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> {
}];
}

//===----------------------------------------------------------------------===//
// ComplexType
//===----------------------------------------------------------------------===//

def CIR_ComplexType : CIR_Type<"Complex", "complex",
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {

let summary = "CIR complex type";
let description = [{
CIR type that represents a C complex number. `cir.complex` models the C type
`T _Complex`.
Copy link
Contributor

Choose a reason for hiding this comment

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

A comment here mentioning how this relates to std::complex would be useful. Note that the representation of std::complex depends on the header file and I believe can even vary depending on which preprocessor symbols are defined (which maybe depends on the target). I don't want a comprehensive explanation of all possibilities here, just a general note explaining that this doesn't directly map to std::complex.

I'm not sure what guarantees the C++ standard makes about the implementation of std::complex, but it would be very nice if we could in some way indicate when std::complex is being used. It looks like std::complex is generally unsupported in the incubator, so there's some work to be done to figure that out, I think.


`cir.complex` type is not directly mapped to `std::complex`.

The type models complex values, per C99 6.2.5p11. It supports the C99
complex float types as well as the GCC integer complex extensions.

The parameter `elementType` gives the type of the real and imaginary part of
the complex number. `elementType` must be either a CIR integer type or a CIR
floating-point type.

```mlir
!cir.complex<!s32i>
!cir.complex<!cir.float>
```
}];

let parameters = (ins CIR_AnyIntOrFloatType:$elementType);

let builders = [
TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{
return $_get(elementType.getContext(), elementType);
}]>,
];

let assemblyFormat = [{
`<` $elementType `>`
}];

let extraClassDeclaration = [{
bool isFloatingPointComplex() const {
return isAnyFloatingPointType(getElementType());
}

bool isIntegerComplex() const {
return mlir::isa<cir::IntType>(getElementType());
}
}];
}

//===----------------------------------------------------------------------===//
// PointerType
//===----------------------------------------------------------------------===//
Expand Down
29 changes: 25 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,33 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value,
case APValue::Union:
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate struct or union");
return {};
case APValue::FixedPoint:
case APValue::ComplexInt:
case APValue::ComplexFloat:
case APValue::ComplexFloat: {
mlir::Type desiredType = cgm.convertType(destType);
cir::ComplexType complexType =
mlir::dyn_cast<cir::ComplexType>(desiredType);

mlir::Type complexElemTy = complexType.getElementType();
if (isa<cir::IntType>(complexElemTy)) {
llvm::APSInt real = value.getComplexIntReal();
llvm::APSInt imag = value.getComplexIntImag();
return builder.getAttr<cir::ConstComplexAttr>(
complexType, builder.getAttr<cir::IntAttr>(complexElemTy, real),
builder.getAttr<cir::IntAttr>(complexElemTy, imag));
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Should you assert isa<cir::FPType>(complexElemTy)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I think assert(isa<cir::CIRFPTypeInterface>(complexElemTy) && "...")

assert(isa<cir::CIRFPTypeInterface>(complexElemTy) &&
"expected floating-point type");
llvm::APFloat real = value.getComplexFloatReal();
llvm::APFloat imag = value.getComplexFloatImag();
return builder.getAttr<cir::ConstComplexAttr>(
complexType, builder.getAttr<cir::FPAttr>(complexElemTy, real),
builder.getAttr<cir::FPAttr>(complexElemTy, imag));
}
case APValue::FixedPoint:
case APValue::AddrLabelDiff:
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate fixed point, complex int, "
"complex float, addr label diff");
cgm.errorNYI(
"ConstExprEmitter::tryEmitPrivate fixed point, addr label diff");
return {};
}
llvm_unreachable("Unknown APValue kind");
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,13 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
break;
}

case Type::Complex: {
const auto *ct = cast<clang::ComplexType>(ty);
mlir::Type elementTy = convertType(ct->getElementType());
resultType = cir::ComplexType::get(elementTy);
break;
}

case Type::LValueReference:
case Type::RValueReference: {
const ReferenceType *refTy = cast<ReferenceType>(ty);
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return success();
}

//===----------------------------------------------------------------------===//
// ConstComplexAttr definitions
//===----------------------------------------------------------------------===//

LogicalResult
ConstComplexAttr::verify(function_ref<InFlightDiagnostic()> emitError,
cir::ComplexType type, mlir::TypedAttr real,
mlir::TypedAttr imag) {
mlir::Type elemType = type.getElementType();
if (real.getType() != elemType)
return emitError()
<< "type of the real part does not match the complex type";

if (imag.getType() != elemType)
return emitError()
<< "type of the imaginary part does not match the complex type";

return success();
}

//===----------------------------------------------------------------------===//
// CIR ConstArrayAttr
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,11 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
}

if (isa<cir::ZeroAttr>(attrType)) {
if (isa<cir::RecordType, cir::ArrayType, cir::VectorType>(opType))
if (isa<cir::RecordType, cir::ArrayType, cir::VectorType, cir::ComplexType>(
opType))
return success();
return op->emitOpError("zero expects struct or array type");
return op->emitOpError(
"zero expects struct, array, vector, or complex type");
}

if (mlir::isa<cir::BoolAttr>(attrType)) {
Expand All @@ -252,7 +254,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
return success();
}

if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr>(attrType))
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
cir::ConstComplexAttr>(attrType))
return success();

assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
Expand Down
24 changes: 23 additions & 1 deletion clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,31 @@ LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
}

//===----------------------------------------------------------------------===//
// FuncType Definitions
// ComplexType Definitions
//===----------------------------------------------------------------------===//

llvm::TypeSize
cir::ComplexType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
// C17 6.2.5p13:
// Each complex type has the same representation and alignment requirements
// as an array type containing exactly two elements of the corresponding
// real type.

return dataLayout.getTypeSizeInBits(getElementType()) * 2;
}

uint64_t
cir::ComplexType::getABIAlignment(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
// C17 6.2.5p13:
// Each complex type has the same representation and alignment requirements
// as an array type containing exactly two elements of the corresponding
// real type.

return dataLayout.getTypeABIAlignment(getElementType());
}

FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
assert(results.size() == 1 && "expected exactly one result type");
return get(llvm::to_vector(inputs), results[0], isVarArg());
Expand Down
Loading