Skip to content

Commit 5454491

Browse files
committed
[CIR][CIRGen] Add complex type and its CIRGen support
This patch adds !cir.complex type to model the _Complex type in C. It also contains support for its CIRGen. In detail, this patch adds the following CIR types, ops, and attributes: - The `!cir.complex` type is added to model the _Complex type in C. This type is parameterized with the type of the components of the complex number, which must be either an integer type or a floating-point type. - The `#cir.complex` attribute is added to represent a literal value of _Complex type. - The `cir.complex.create` op is added, which creates a complex value from its real and imaginary parts. - The `cir.complex.real` and `cir.complex.imag` ops are added to extract the real and imaginary part of a value of `!cir.complex` type. CIRGen support for the new complex type is also added.
1 parent 3bad644 commit 5454491

21 files changed

+1746
-61
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

+33
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,39 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
4141
public:
4242
CIRBaseBuilderTy(mlir::MLIRContext &C) : mlir::OpBuilder(&C) {}
4343

44+
mlir::cir::BoolType getBoolTy() {
45+
return ::mlir::cir::BoolType::get(getContext());
46+
}
47+
48+
mlir::cir::BoolAttr getCIRBoolAttr(bool state) {
49+
return mlir::cir::BoolAttr::get(getContext(), getBoolTy(), state);
50+
}
51+
52+
mlir::TypedAttr getZeroAttr(mlir::Type t) {
53+
return mlir::cir::ZeroAttr::get(getContext(), t);
54+
}
55+
56+
mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
57+
if (ty.isa<mlir::cir::IntType>())
58+
return mlir::cir::IntAttr::get(ty, 0);
59+
if (auto fltType = ty.dyn_cast<mlir::cir::SingleType>())
60+
return mlir::cir::FPAttr::getZero(fltType);
61+
if (auto fltType = ty.dyn_cast<mlir::cir::DoubleType>())
62+
return mlir::cir::FPAttr::getZero(fltType);
63+
if (auto complexTy = ty.dyn_cast<mlir::cir::ComplexType>())
64+
return mlir::cir::ComplexAttr::getZero(complexTy);
65+
if (auto arrTy = ty.dyn_cast<mlir::cir::ArrayType>())
66+
return getZeroAttr(arrTy);
67+
if (auto ptrTy = ty.dyn_cast<mlir::cir::PointerType>())
68+
return getConstPtrAttr(ptrTy, 0);
69+
if (auto structTy = ty.dyn_cast<mlir::cir::StructType>())
70+
return getZeroAttr(structTy);
71+
if (ty.isa<mlir::cir::BoolType>()) {
72+
return getCIRBoolAttr(false);
73+
}
74+
llvm_unreachable("Zero initializer for given type is NYI");
75+
}
76+
4477
mlir::Value getConstAPSInt(mlir::Location loc, const llvm::APSInt &val) {
4578
auto ty = mlir::cir::IntType::get(getContext(), val.getBitWidth(),
4679
val.isSigned());

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

+35
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,41 @@ def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> {
242242
}];
243243
}
244244

245+
//===----------------------------------------------------------------------===//
246+
// ComplexAttr
247+
//===----------------------------------------------------------------------===//
248+
249+
def ComplexAttr : CIR_Attr<"Complex", "complex", [TypedAttrInterface]> {
250+
let summary = "An attribute containing a complex number value";
251+
let description = [{
252+
A `#cir.complex` attribute is a literal attribute that represents a complex
253+
number value of the specified complex type.
254+
255+
The `real` parameter gives the real part of the complex number, and the
256+
`imag` parameter gives the imaginary part of the complex number.
257+
}];
258+
259+
let parameters = (ins AttributeSelfTypeParameter<"">:$type, "TypedAttr":$real,
260+
"TypedAttr":$imag);
261+
262+
let builders = [
263+
AttrBuilderWithInferredContext<(ins "Type":$type, "TypedAttr":$real,
264+
"TypedAttr":$imag), [{
265+
return $_get(type.getContext(), type, real, imag);
266+
}]>,
267+
];
268+
269+
let extraClassDeclaration = [{
270+
static ComplexAttr getZero(Type type);
271+
}];
272+
273+
let genVerifyDecl = 1;
274+
275+
let assemblyFormat = [{
276+
`<` $real `,` $imag `>`
277+
}];
278+
}
279+
245280
//===----------------------------------------------------------------------===//
246281
// ConstPointerAttr
247282
//===----------------------------------------------------------------------===//

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

+101-1
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,18 @@ def CK_FloatToBoolean : I32EnumAttrCase<"float_to_bool", 10>;
6969
def CK_BooleanToIntegral : I32EnumAttrCase<"bool_to_int", 11>;
7070
def CK_IntegralToFloat : I32EnumAttrCase<"int_to_float", 12>;
7171
def CK_BooleanToFloat : I32EnumAttrCase<"bool_to_float", 13>;
72+
def CK_IntegralToComplex : I32EnumAttrCase<"int_to_complex", 14>;
73+
def CK_FloatToComplex : I32EnumAttrCase<"float_to_complex", 15>;
74+
def CK_ComplexCast : I32EnumAttrCase<"complex", 16>;
7275

7376
def CastKind : I32EnumAttr<
7477
"CastKind",
7578
"cast kind",
7679
[CK_IntegralToBoolean, CK_ArrayToPointerDecay, CK_IntegralCast,
7780
CK_BitCast, CK_FloatingCast, CK_PtrToBoolean, CK_FloatToIntegral,
7881
CK_IntegralToPointer, CK_PointerToIntegral, CK_FloatToBoolean,
79-
CK_BooleanToIntegral, CK_IntegralToFloat, CK_BooleanToFloat]> {
82+
CK_BooleanToIntegral, CK_IntegralToFloat, CK_BooleanToFloat,
83+
CK_IntegralToComplex, CK_FloatToComplex, CK_ComplexCast]> {
8084
let cppNamespace = "::mlir::cir";
8185
}
8286

@@ -98,6 +102,8 @@ def CastOp : CIR_Op<"cast", [Pure]> {
98102
- `ptr_to_bool`
99103
- `bool_to_int`
100104
- `bool_to_float`
105+
- `int_to_complex`
106+
- `float_to_complex`
101107

102108
This is effectively a subset of the rules from
103109
`llvm-project/clang/include/clang/AST/OperationKinds.def`; but note that some
@@ -920,6 +926,7 @@ def UnaryOpKind_Dec : I32EnumAttrCase<"Dec", 2, "dec">;
920926
def UnaryOpKind_Plus : I32EnumAttrCase<"Plus", 3, "plus">;
921927
def UnaryOpKind_Minus : I32EnumAttrCase<"Minus", 4, "minus">;
922928
def UnaryOpKind_Not : I32EnumAttrCase<"Not", 5, "not">;
929+
def UnaryOpKind_Conjugate : I32EnumAttrCase<"Conjugate", 6, "conjugate">;
923930

924931
def UnaryOpKind : I32EnumAttr<
925932
"UnaryOpKind",
@@ -929,6 +936,7 @@ def UnaryOpKind : I32EnumAttr<
929936
UnaryOpKind_Plus,
930937
UnaryOpKind_Minus,
931938
UnaryOpKind_Not,
939+
UnaryOpKind_Conjugate,
932940
]> {
933941
let cppNamespace = "::mlir::cir";
934942
}
@@ -1154,6 +1162,98 @@ def BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> {
11541162
];
11551163
}
11561164

1165+
//===----------------------------------------------------------------------===//
1166+
// ComplexCreateOp
1167+
//===----------------------------------------------------------------------===//
1168+
1169+
def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> {
1170+
let summary = "Create a new complex value from its real and imaginary parts";
1171+
let description = [{
1172+
The `cir.complex.create` operation takes two operands of the same type and
1173+
returns a value of `!cir.complex` type. The real and imaginary part of the
1174+
returned complex value is specified by the operands.
1175+
1176+
The element type of the returned complex value is the same as the type of
1177+
the operand. The type of the two operands must be either an integer type or
1178+
a floating-point type.
1179+
1180+
Example:
1181+
1182+
```mlir
1183+
!u32i = !cir.int<u, 32>
1184+
!complex = !cir.complex<!u32i>
1185+
1186+
%0 = cir.const(#cir.int<1> : !u32i) : !u32i
1187+
%1 = cir.const(#cir.int<2> : !u32i) : !u32i
1188+
%2 = cir.complex.create(%0 : !u32i, %1) : !complex
1189+
```
1190+
}];
1191+
1192+
let results = (outs CIR_ComplexType:$result);
1193+
let arguments = (ins CIR_AnyType:$real, CIR_AnyType:$imag);
1194+
1195+
let assemblyFormat = [{
1196+
`(` $real `:` qualified(type($real)) `,` $imag `)`
1197+
`:` type($result) attr-dict
1198+
}];
1199+
1200+
let hasVerifier = 1;
1201+
}
1202+
1203+
//===----------------------------------------------------------------------===//
1204+
// ComplexRealOp and ComplexImagOp
1205+
//===----------------------------------------------------------------------===//
1206+
1207+
def ComplexRealOp : CIR_Op<"complex.real", [Pure]> {
1208+
let summary = "Extract the real part of a complex value";
1209+
let description = [{
1210+
`cir.complex.real` operation takes an operand of complex type and returns
1211+
the real part of it.
1212+
1213+
Example:
1214+
1215+
```mlir
1216+
!complex = !cir.complex<!cir.float>
1217+
%0 = cir.const(#cir.complex<#cir.fp<1.0>, #cir.fp<2.0>> : !complex) : !complex
1218+
%1 = cir.complex.real(%0 : !complex) : !cir.float
1219+
```
1220+
}];
1221+
1222+
let results = (outs CIR_AnyType:$result);
1223+
let arguments = (ins CIR_ComplexType:$operand);
1224+
1225+
let assemblyFormat = [{
1226+
`(` $operand `:` qualified(type($operand)) `)` `:` type($result) attr-dict
1227+
}];
1228+
1229+
let hasVerifier = 1;
1230+
}
1231+
1232+
def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> {
1233+
let summary = "Extract the imaginary part of a complex value";
1234+
let description = [{
1235+
`cir.complex.imag` operation takes an operand of complex type and returns
1236+
the imaginary part of it.
1237+
1238+
Example:
1239+
1240+
```mlir
1241+
!complex = !cir.complex<!cir.float>
1242+
%0 = cir.const(#cir.complex<#cir.fp<1.0>, #cir.fp<2.0>> : !complex) : !complex
1243+
%1 = cir.complex.imag(%0 : !complex) : !cir.float
1244+
```
1245+
}];
1246+
1247+
let results = (outs CIR_AnyType:$result);
1248+
let arguments = (ins CIR_ComplexType:$operand);
1249+
1250+
let assemblyFormat = [{
1251+
`(` $operand `:` qualified(type($operand)) `)` `:` type($result) attr-dict
1252+
}];
1253+
1254+
let hasVerifier = 1;
1255+
}
1256+
11571257
//===----------------------------------------------------------------------===//
11581258
// BitsOp
11591259
//===----------------------------------------------------------------------===//

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

+27-1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,32 @@ def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> {
182182
def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_LongDouble]>;
183183
def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>;
184184

185+
//===----------------------------------------------------------------------===//
186+
// ComplexType
187+
//===----------------------------------------------------------------------===//
188+
189+
def CIR_ComplexType : CIR_Type<"Complex", "complex",
190+
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
191+
192+
let summary = "CIR complex type";
193+
let description = [{
194+
CIR type that represents a C/C++ complex number. `cir.complex` models the
195+
C type `_Complex`.
196+
197+
The parameter `elementTy` gives the type of the real and imaginary part of
198+
the complex number. `elementTy` must be either a CIR integer type or a CIR
199+
floating-point type.
200+
}];
201+
202+
let parameters = (ins "mlir::Type":$elementTy);
203+
204+
let assemblyFormat = [{
205+
`<` $elementTy `>`
206+
}];
207+
208+
let genVerifyDecl = 1;
209+
}
210+
185211
//===----------------------------------------------------------------------===//
186212
// PointerType
187213
//===----------------------------------------------------------------------===//
@@ -475,7 +501,7 @@ def CIR_StructType : Type<CPred<"$_self.isa<::mlir::cir::StructType>()">,
475501
def CIR_AnyType : AnyTypeOf<[
476502
CIR_IntType, CIR_PointerType, CIR_DataMemberType, CIR_BoolType, CIR_ArrayType,
477503
CIR_VectorType, CIR_FuncType, CIR_VoidType, CIR_StructType, CIR_ExceptionInfo,
478-
CIR_AnyFloat,
504+
CIR_AnyFloat, CIR_ComplexType
479505
]>;
480506

481507
#endif // MLIR_CIR_DIALECT_CIR_TYPES

clang/lib/CIR/CodeGen/CIRGenBuilder.h

+33-27
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,6 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
136136
return mlir::cir::GlobalViewAttr::get(type, symbol, indices);
137137
}
138138

139-
mlir::TypedAttr getZeroAttr(mlir::Type t) {
140-
return mlir::cir::ZeroAttr::get(getContext(), t);
141-
}
142-
143-
mlir::cir::BoolAttr getCIRBoolAttr(bool state) {
144-
return mlir::cir::BoolAttr::get(getContext(), getBoolTy(), state);
145-
}
146-
147139
mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) {
148140
assert(t.isa<mlir::cir::PointerType>() && "expected cir.ptr");
149141
return mlir::cir::ConstPtrAttr::get(getContext(), t, 0);
@@ -243,25 +235,6 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
243235
return mlir::cir::DataMemberAttr::get(getContext(), ty, std::nullopt);
244236
}
245237

246-
mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
247-
if (ty.isa<mlir::cir::IntType>())
248-
return mlir::cir::IntAttr::get(ty, 0);
249-
if (auto fltType = ty.dyn_cast<mlir::cir::SingleType>())
250-
return mlir::cir::FPAttr::getZero(fltType);
251-
if (auto fltType = ty.dyn_cast<mlir::cir::DoubleType>())
252-
return mlir::cir::FPAttr::getZero(fltType);
253-
if (auto arrTy = ty.dyn_cast<mlir::cir::ArrayType>())
254-
return getZeroAttr(arrTy);
255-
if (auto ptrTy = ty.dyn_cast<mlir::cir::PointerType>())
256-
return getConstPtrAttr(ptrTy, 0);
257-
if (auto structTy = ty.dyn_cast<mlir::cir::StructType>())
258-
return getZeroAttr(structTy);
259-
if (ty.isa<mlir::cir::BoolType>()) {
260-
return getCIRBoolAttr(false);
261-
}
262-
llvm_unreachable("Zero initializer for given type is NYI");
263-
}
264-
265238
// TODO(cir): Once we have CIR float types, replace this by something like a
266239
// NullableValueInterface to allow for type-independent queries.
267240
bool isNullValue(mlir::Attribute attr) const {
@@ -744,6 +717,12 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
744717
addr.getPointer());
745718
}
746719

720+
mlir::Value createVolatileLoad(mlir::Location loc, Address addr) {
721+
return create<mlir::cir::LoadOp>(loc, addr.getElementType(),
722+
addr.getPointer(), /*isDeref=*/false,
723+
/*is_volatile=*/true);
724+
}
725+
747726
mlir::Value createAlignedLoad(mlir::Location loc, mlir::Type ty,
748727
mlir::Value ptr,
749728
[[maybe_unused]] llvm::MaybeAlign align,
@@ -884,6 +863,33 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
884863
return create<mlir::cir::GetRuntimeMemberOp>(loc, resultTy, objectPtr,
885864
memberPtr);
886865
}
866+
867+
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
868+
mlir::Value imag) {
869+
assert(real.getType() == imag.getType() &&
870+
"operands to cir.complex.create must have the same type");
871+
872+
auto complexTy = mlir::cir::ComplexType::get(getContext(), real.getType());
873+
return create<mlir::cir::ComplexCreateOp>(loc, complexTy, real, imag);
874+
}
875+
876+
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
877+
auto operandComplexTy = operand.getType().cast<mlir::cir::ComplexType>();
878+
auto resultTy = operandComplexTy.getElementTy();
879+
return create<mlir::cir::ComplexRealOp>(loc, resultTy, operand);
880+
}
881+
882+
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
883+
auto operandComplexTy = operand.getType().cast<mlir::cir::ComplexType>();
884+
auto resultTy = operandComplexTy.getElementTy();
885+
return create<mlir::cir::ComplexImagOp>(loc, resultTy, operand);
886+
}
887+
888+
mlir::Value createComplexIsZero(mlir::Location loc, mlir::Value operand) {
889+
auto zero = getNullValue(operand.getType(), loc);
890+
return create<mlir::cir::CmpOp>(loc, getBoolTy(), mlir::cir::CmpOpKind::eq,
891+
operand, zero);
892+
}
887893
};
888894

889895
} // namespace cir

clang/lib/CIR/CodeGen/CIRGenCXX.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ static void buildDeclInit(CIRGenFunction &CGF, const VarDecl *D,
201201
CGF.buildScalarInit(Init, CGF.getLoc(D->getLocation()), lv, false);
202202
return;
203203
case TEK_Complex:
204-
llvm_unreachable("complext evaluation NYI");
204+
CGF.buildComplexInit(Init, CGF.getLoc(D->getLocation()), lv);
205+
return;
205206
}
206207
}
207208

clang/lib/CIR/CodeGen/CIRGenClass.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ void CIRGenFunction::buildInitializerForField(FieldDecl *Field, LValue LHS,
805805
}
806806
break;
807807
case TEK_Complex:
808-
llvm_unreachable("NYI");
808+
buildComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
809809
break;
810810
case TEK_Aggregate: {
811811
AggValueSlot Slot = AggValueSlot::forLValue(

0 commit comments

Comments
 (0)