Skip to content
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
41 changes: 41 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrConstraints.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

//===----------------------------------------------------------------------===//
//
// 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">;

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_AnyFPAttr : CIR_AttrConstraint<"::cir::FPAttr", "floating-point attribute">;
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
Loading