Skip to content

Commit 8ae8a90

Browse files
authored
[CIR] floating-point, pointer, and function types (#120484)
Upstream ClangIR support for `void` type, floating-point types, pointer types, and function types. Floating-point support is missing the IBM double-double format, because that hasn't been implemented in the incubator project yet. Pointer types do not yet support address spaces. Function type support includes only the return type and the parameter types. The many other properties and attributes of function types will be upstreamed later.
1 parent 8b37c1c commit 8ae8a90

19 files changed

+854
-0
lines changed

clang/include/clang/CIR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ include_directories(${MLIR_INCLUDE_DIR})
44
include_directories(${MLIR_TABLEGEN_OUTPUT_DIR})
55

66
add_subdirectory(Dialect)
7+
add_subdirectory(Interfaces)

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
1818
public:
1919
CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
2020
: mlir::OpBuilder(&mlirContext) {}
21+
22+
cir::PointerType getPointerTo(mlir::Type ty) {
23+
return cir::PointerType::get(getContext(), ty);
24+
}
25+
26+
cir::PointerType getVoidPtrTy() {
27+
return getPointerTo(cir::VoidType::get(getContext()));
28+
}
2129
};
2230

2331
} // namespace cir

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
#include "mlir/IR/BuiltinAttributes.h"
1717
#include "mlir/IR/Types.h"
1818
#include "mlir/Interfaces/DataLayoutInterfaces.h"
19+
#include "clang/CIR/Interfaces/CIRFPTypeInterface.h"
20+
21+
namespace cir {
22+
23+
bool isAnyFloatingPointType(mlir::Type t);
24+
25+
} // namespace cir
1926

2027
//===----------------------------------------------------------------------===//
2128
// CIR Dialect Tablegen'd Types

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

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define MLIR_CIR_DIALECT_CIR_TYPES
1515

1616
include "clang/CIR/Dialect/IR/CIRDialect.td"
17+
include "clang/CIR/Interfaces/CIRFPTypeInterface.td"
1718
include "mlir/Interfaces/DataLayoutInterfaces.td"
1819
include "mlir/IR/AttrTypeBase.td"
1920

@@ -129,4 +130,224 @@ def PrimitiveInt
129130
: AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64],
130131
"primitive int", "::cir::IntType">;
131132

133+
//===----------------------------------------------------------------------===//
134+
// FloatType
135+
//===----------------------------------------------------------------------===//
136+
137+
class CIR_FloatType<string name, string mnemonic>
138+
: CIR_Type<name, mnemonic,
139+
[
140+
DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
141+
DeclareTypeInterfaceMethods<CIRFPTypeInterface>,
142+
]> {}
143+
144+
def CIR_Single : CIR_FloatType<"Single", "float"> {
145+
let summary = "CIR single-precision 32-bit float type";
146+
let description = [{
147+
A 32-bit floating-point type whose format is IEEE-754 `binary32`. It
148+
represents the types `float`, `_Float32`, and `std::float32_t` in C and C++.
149+
}];
150+
}
151+
152+
def CIR_Double : CIR_FloatType<"Double", "double"> {
153+
let summary = "CIR double-precision 64-bit float type";
154+
let description = [{
155+
A 64-bit floating-point type whose format is IEEE-754 `binary64`. It
156+
represents the types `double', '_Float64`, `std::float64_t`, and `_Float32x`
157+
in C and C++. This is the underlying type for `long double` on some
158+
platforms, including Windows.
159+
}];
160+
}
161+
162+
def CIR_FP16 : CIR_FloatType<"FP16", "f16"> {
163+
let summary = "CIR half-precision 16-bit float type";
164+
let description = [{
165+
A 16-bit floating-point type whose format is IEEE-754 `binary16`. It
166+
represents the types '_Float16` and `std::float16_t` in C and C++.
167+
}];
168+
}
169+
170+
def CIR_BFloat16 : CIR_FloatType<"BF16", "bf16"> {
171+
let summary = "CIR bfloat16 16-bit float type";
172+
let description = [{
173+
A 16-bit floating-point type in the bfloat16 format, which is the same as
174+
IEEE `binary32` except that the lower 16 bits of the mantissa are missing.
175+
It represents the type `std::bfloat16_t` in C++, also spelled `__bf16` in
176+
some implementations.
177+
}];
178+
}
179+
180+
def CIR_FP80 : CIR_FloatType<"FP80", "f80"> {
181+
let summary = "CIR x87 80-bit float type";
182+
let description = [{
183+
An 80-bit floating-point type in the x87 extended precision format. The
184+
size and alignment of the type are both 128 bits, even though only 80 of
185+
those bits are used. This is the underlying type for `long double` on Linux
186+
x86 platforms, and it is available as an extension in some implementations.
187+
}];
188+
}
189+
190+
def CIR_FP128 : CIR_FloatType<"FP128", "f128"> {
191+
let summary = "CIR quad-precision 128-bit float type";
192+
let description = [{
193+
A 128-bit floating-point type whose format is IEEE-754 `binary128`. It
194+
represents the types `_Float128` and `std::float128_t` in C and C++, and the
195+
extension `__float128` in some implementations. This is the underlying type
196+
for `long double` on some platforms including Linux Arm.
197+
}];
198+
}
199+
200+
def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> {
201+
let summary = "CIR float type for `long double`";
202+
let description = [{
203+
A floating-point type that represents the `long double` type in C and C++.
204+
205+
The underlying floating-point format of a `long double` value depends on the
206+
target platform and the implementation. The `underlying` parameter specifies
207+
the CIR floating-point type that corresponds to this format. Underlying
208+
types of IEEE 64-bit, IEEE 128-bit, x87 80-bit, and IBM's double-double
209+
format are all in use.
210+
}];
211+
212+
let parameters = (ins "mlir::Type":$underlying);
213+
214+
let assemblyFormat = [{
215+
`<` $underlying `>`
216+
}];
217+
218+
let genVerifyDecl = 1;
219+
}
220+
221+
// Constraints
222+
223+
def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128, CIR_LongDouble,
224+
CIR_FP16, CIR_BFloat16]>;
225+
def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>;
226+
227+
//===----------------------------------------------------------------------===//
228+
// PointerType
229+
//===----------------------------------------------------------------------===//
230+
231+
def CIR_PointerType : CIR_Type<"Pointer", "ptr",
232+
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
233+
234+
let summary = "CIR pointer type";
235+
let description = [{
236+
The `cir.ptr` type represents C and C++ pointer types and C++ reference
237+
types, other than pointers-to-members. The `pointee` type is the type
238+
pointed to.
239+
240+
TODO(CIR): The address space attribute is not yet implemented.
241+
}];
242+
243+
let parameters = (ins "mlir::Type":$pointee);
244+
245+
let builders = [
246+
TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee), [{
247+
return $_get(pointee.getContext(), pointee);
248+
}]>,
249+
TypeBuilder<(ins "mlir::Type":$pointee), [{
250+
return $_get($_ctxt, pointee);
251+
}]>
252+
];
253+
254+
let assemblyFormat = [{
255+
`<` $pointee `>`
256+
}];
257+
258+
let genVerifyDecl = 1;
259+
260+
let skipDefaultBuilders = 1;
261+
262+
let extraClassDeclaration = [{
263+
bool isVoidPtr() const {
264+
return mlir::isa<cir::VoidType>(getPointee());
265+
}
266+
}];
267+
}
268+
269+
//===----------------------------------------------------------------------===//
270+
// FuncType
271+
//===----------------------------------------------------------------------===//
272+
273+
def CIR_FuncType : CIR_Type<"Func", "func"> {
274+
let summary = "CIR function type";
275+
let description = [{
276+
The `!cir.func` is a function type. It consists of a single return type, a
277+
list of parameter types and can optionally be variadic.
278+
279+
Example:
280+
281+
```mlir
282+
!cir.func<!bool ()>
283+
!cir.func<!s32i (!s8i, !s8i)>
284+
!cir.func<!s32i (!s32i, ...)>
285+
```
286+
}];
287+
288+
let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs,
289+
"mlir::Type":$returnType, "bool":$varArg);
290+
let assemblyFormat = [{
291+
`<` $returnType ` ` `(` custom<FuncTypeArgs>($inputs, $varArg) `>`
292+
}];
293+
294+
let builders = [
295+
TypeBuilderWithInferredContext<(ins
296+
"llvm::ArrayRef<mlir::Type>":$inputs, "mlir::Type":$returnType,
297+
CArg<"bool", "false">:$isVarArg), [{
298+
return $_get(returnType.getContext(), inputs, returnType, isVarArg);
299+
}]>
300+
];
301+
302+
let extraClassDeclaration = [{
303+
/// Returns whether the function is variadic.
304+
bool isVarArg() const { return getVarArg(); }
305+
306+
/// Returns the `i`th input operand type. Asserts if out of bounds.
307+
mlir::Type getInput(unsigned i) const { return getInputs()[i]; }
308+
309+
/// Returns the number of arguments to the function.
310+
unsigned getNumInputs() const { return getInputs().size(); }
311+
312+
/// Returns the result type of the function as an ArrayRef, enabling better
313+
/// integration with generic MLIR utilities.
314+
llvm::ArrayRef<mlir::Type> getReturnTypes() const;
315+
316+
/// Returns whether the function is returns void.
317+
bool isVoid() const;
318+
319+
/// Returns a clone of this function type with the given argument
320+
/// and result types.
321+
FuncType clone(mlir::TypeRange inputs, mlir::TypeRange results) const;
322+
}];
323+
}
324+
325+
//===----------------------------------------------------------------------===//
326+
// Void type
327+
//===----------------------------------------------------------------------===//
328+
329+
def CIR_VoidType : CIR_Type<"Void", "void"> {
330+
let summary = "CIR void type";
331+
let description = [{
332+
The `!cir.void` type represents the C and C++ `void` type.
333+
}];
334+
let extraClassDeclaration = [{
335+
std::string getAlias() const { return "void"; };
336+
}];
337+
}
338+
339+
// Constraints
340+
341+
// Pointer to void
342+
def VoidPtr : Type<
343+
And<[
344+
CPred<"::mlir::isa<::cir::PointerType>($_self)">,
345+
CPred<"::mlir::isa<::cir::VoidType>("
346+
"::mlir::cast<::cir::PointerType>($_self).getPointee())">,
347+
]>, "void*">,
348+
BuildableType<
349+
"cir::PointerType::get($_builder.getContext(),"
350+
"cir::VoidType::get($_builder.getContext()))"> {
351+
}
352+
132353
#endif // MLIR_CIR_DIALECT_CIR_TYPES
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===---------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===---------------------------------------------------------------------===//
8+
//
9+
// Defines the interface to generically handle CIR floating-point types.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H
14+
#define LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H
15+
16+
#include "mlir/IR/Types.h"
17+
#include "llvm/ADT/APFloat.h"
18+
19+
/// Include the tablegen'd interface declarations.
20+
#include "clang/CIR/Interfaces/CIRFPTypeInterface.h.inc"
21+
22+
#endif // LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Defines the interface to generically handle CIR floating-point types.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD
14+
#define LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD
15+
16+
include "mlir/IR/OpBase.td"
17+
18+
def CIRFPTypeInterface : TypeInterface<"CIRFPTypeInterface"> {
19+
let description = [{
20+
Contains helper functions to query properties about a floating-point type.
21+
}];
22+
let cppNamespace = "::cir";
23+
24+
let methods = [
25+
InterfaceMethod<[{
26+
Returns the bit width of this floating-point type.
27+
}],
28+
/*retTy=*/"unsigned",
29+
/*methodName=*/"getWidth",
30+
/*args=*/(ins),
31+
/*methodBody=*/"",
32+
/*defaultImplementation=*/[{
33+
return llvm::APFloat::semanticsSizeInBits($_type.getFloatSemantics());
34+
}]
35+
>,
36+
InterfaceMethod<[{
37+
Return the mantissa width.
38+
}],
39+
/*retTy=*/"unsigned",
40+
/*methodName=*/"getFPMantissaWidth",
41+
/*args=*/(ins),
42+
/*methodBody=*/"",
43+
/*defaultImplementation=*/[{
44+
return llvm::APFloat::semanticsPrecision($_type.getFloatSemantics());
45+
}]
46+
>,
47+
InterfaceMethod<[{
48+
Return the float semantics of this floating-point type.
49+
}],
50+
/*retTy=*/"const llvm::fltSemantics &",
51+
/*methodName=*/"getFloatSemantics"
52+
>,
53+
];
54+
}
55+
56+
#endif // LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# This replicates part of the add_mlir_interface cmake function from MLIR that
2+
# cannot be used here. This happens because it expects to be run inside MLIR
3+
# directory which is not the case for CIR (and also FIR, both have similar
4+
# workarounds).
5+
6+
function(add_clang_mlir_type_interface interface)
7+
set(LLVM_TARGET_DEFINITIONS ${interface}.td)
8+
mlir_tablegen(${interface}.h.inc -gen-type-interface-decls)
9+
mlir_tablegen(${interface}.cpp.inc -gen-type-interface-defs)
10+
add_public_tablegen_target(MLIR${interface}IncGen)
11+
add_dependencies(mlir-generic-headers MLIR${interface}IncGen)
12+
endfunction()
13+
14+
add_clang_mlir_type_interface(CIRFPTypeInterface)

clang/lib/CIR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
44
add_subdirectory(Dialect)
55
add_subdirectory(CodeGen)
66
add_subdirectory(FrontendAction)
7+
add_subdirectory(Interfaces)

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
2121
public:
2222
CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
2323
: CIRBaseBuilderTy(mlirContext), typeCache(tc) {}
24+
25+
cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
26+
if (&format == &llvm::APFloat::IEEEdouble())
27+
return cir::LongDoubleType::get(getContext(), typeCache.DoubleTy);
28+
if (&format == &llvm::APFloat::x87DoubleExtended())
29+
return cir::LongDoubleType::get(getContext(), typeCache.FP80Ty);
30+
if (&format == &llvm::APFloat::IEEEquad())
31+
return cir::LongDoubleType::get(getContext(), typeCache.FP128Ty);
32+
if (&format == &llvm::APFloat::PPCDoubleDouble())
33+
llvm_unreachable("NYI: PPC double-double format for long double");
34+
llvm_unreachable("Unsupported format for long double");
35+
}
2436
};
2537

2638
} // namespace clang::CIRGen

0 commit comments

Comments
 (0)