diff --git a/clang/include/clang/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt index f8d6f407a03d0..e20c896171c92 100644 --- a/clang/include/clang/CIR/CMakeLists.txt +++ b/clang/include/clang/CIR/CMakeLists.txt @@ -4,3 +4,4 @@ include_directories(${MLIR_INCLUDE_DIR}) include_directories(${MLIR_TABLEGEN_OUTPUT_DIR}) add_subdirectory(Dialect) +add_subdirectory(Interfaces) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 75ae74e926fbc..0e414921324b7 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -18,6 +18,14 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { public: CIRBaseBuilderTy(mlir::MLIRContext &mlirContext) : mlir::OpBuilder(&mlirContext) {} + + cir::PointerType getPointerTo(mlir::Type ty) { + return cir::PointerType::get(getContext(), ty); + } + + cir::PointerType getVoidPtrTy() { + return getPointerTo(cir::VoidType::get(getContext())); + } }; } // namespace cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index 2bc7d77b2bc8a..5d1eb17e146d0 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -16,6 +16,13 @@ #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Types.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h" + +namespace cir { + +bool isAnyFloatingPointType(mlir::Type t); + +} // namespace cir //===----------------------------------------------------------------------===// // CIR Dialect Tablegen'd Types diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index ce0b6ba1d68c5..ef00b26c1fd98 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -14,6 +14,7 @@ #define MLIR_CIR_DIALECT_CIR_TYPES include "clang/CIR/Dialect/IR/CIRDialect.td" +include "clang/CIR/Interfaces/CIRFPTypeInterface.td" include "mlir/Interfaces/DataLayoutInterfaces.td" include "mlir/IR/AttrTypeBase.td" @@ -129,4 +130,224 @@ def PrimitiveInt : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64], "primitive int", "::cir::IntType">; +//===----------------------------------------------------------------------===// +// FloatType +//===----------------------------------------------------------------------===// + +class CIR_FloatType + : CIR_Type, + DeclareTypeInterfaceMethods, + ]> {} + +def CIR_Single : CIR_FloatType<"Single", "float"> { + let summary = "CIR single-precision 32-bit float type"; + let description = [{ + A 32-bit floating-point type whose format is IEEE-754 `binary32`. It + represents the types `float`, `_Float32`, and `std::float32_t` in C and C++. + }]; +} + +def CIR_Double : CIR_FloatType<"Double", "double"> { + let summary = "CIR double-precision 64-bit float type"; + let description = [{ + A 64-bit floating-point type whose format is IEEE-754 `binary64`. It + represents the types `double', '_Float64`, `std::float64_t`, and `_Float32x` + in C and C++. This is the underlying type for `long double` on some + platforms, including Windows. + }]; +} + +def CIR_FP16 : CIR_FloatType<"FP16", "f16"> { + let summary = "CIR half-precision 16-bit float type"; + let description = [{ + A 16-bit floating-point type whose format is IEEE-754 `binary16`. It + represents the types '_Float16` and `std::float16_t` in C and C++. + }]; +} + +def CIR_BFloat16 : CIR_FloatType<"BF16", "bf16"> { + let summary = "CIR bfloat16 16-bit float type"; + let description = [{ + A 16-bit floating-point type in the bfloat16 format, which is the same as + IEEE `binary32` except that the lower 16 bits of the mantissa are missing. + It represents the type `std::bfloat16_t` in C++, also spelled `__bf16` in + some implementations. + }]; +} + +def CIR_FP80 : CIR_FloatType<"FP80", "f80"> { + let summary = "CIR x87 80-bit float type"; + let description = [{ + An 80-bit floating-point type in the x87 extended precision format. The + size and alignment of the type are both 128 bits, even though only 80 of + those bits are used. This is the underlying type for `long double` on Linux + x86 platforms, and it is available as an extension in some implementations. + }]; +} + +def CIR_FP128 : CIR_FloatType<"FP128", "f128"> { + let summary = "CIR quad-precision 128-bit float type"; + let description = [{ + A 128-bit floating-point type whose format is IEEE-754 `binary128`. It + represents the types `_Float128` and `std::float128_t` in C and C++, and the + extension `__float128` in some implementations. This is the underlying type + for `long double` on some platforms including Linux Arm. + }]; +} + +def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> { + let summary = "CIR float type for `long double`"; + let description = [{ + A floating-point type that represents the `long double` type in C and C++. + + The underlying floating-point format of a `long double` value depends on the + target platform and the implementation. The `underlying` parameter specifies + the CIR floating-point type that corresponds to this format. Underlying + types of IEEE 64-bit, IEEE 128-bit, x87 80-bit, and IBM's double-double + format are all in use. + }]; + + let parameters = (ins "mlir::Type":$underlying); + + let assemblyFormat = [{ + `<` $underlying `>` + }]; + + let genVerifyDecl = 1; +} + +// Constraints + +def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128, CIR_LongDouble, + CIR_FP16, CIR_BFloat16]>; +def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>; + +//===----------------------------------------------------------------------===// +// PointerType +//===----------------------------------------------------------------------===// + +def CIR_PointerType : CIR_Type<"Pointer", "ptr", + [DeclareTypeInterfaceMethods]> { + + let summary = "CIR pointer type"; + let description = [{ + The `cir.ptr` type represents C and C++ pointer types and C++ reference + types, other than pointers-to-members. The `pointee` type is the type + pointed to. + + TODO(CIR): The address space attribute is not yet implemented. + }]; + + let parameters = (ins "mlir::Type":$pointee); + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee), [{ + return $_get(pointee.getContext(), pointee); + }]>, + TypeBuilder<(ins "mlir::Type":$pointee), [{ + return $_get($_ctxt, pointee); + }]> + ]; + + let assemblyFormat = [{ + `<` $pointee `>` + }]; + + let genVerifyDecl = 1; + + let skipDefaultBuilders = 1; + + let extraClassDeclaration = [{ + bool isVoidPtr() const { + return mlir::isa(getPointee()); + } + }]; +} + +//===----------------------------------------------------------------------===// +// FuncType +//===----------------------------------------------------------------------===// + +def CIR_FuncType : CIR_Type<"Func", "func"> { + let summary = "CIR function type"; + let description = [{ + The `!cir.func` is a function type. It consists of a single return type, a + list of parameter types and can optionally be variadic. + + Example: + + ```mlir + !cir.func + !cir.func + !cir.func + ``` + }]; + + let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs, + "mlir::Type":$returnType, "bool":$varArg); + let assemblyFormat = [{ + `<` $returnType ` ` `(` custom($inputs, $varArg) `>` + }]; + + let builders = [ + TypeBuilderWithInferredContext<(ins + "llvm::ArrayRef":$inputs, "mlir::Type":$returnType, + CArg<"bool", "false">:$isVarArg), [{ + return $_get(returnType.getContext(), inputs, returnType, isVarArg); + }]> + ]; + + let extraClassDeclaration = [{ + /// Returns whether the function is variadic. + bool isVarArg() const { return getVarArg(); } + + /// Returns the `i`th input operand type. Asserts if out of bounds. + mlir::Type getInput(unsigned i) const { return getInputs()[i]; } + + /// Returns the number of arguments to the function. + unsigned getNumInputs() const { return getInputs().size(); } + + /// Returns the result type of the function as an ArrayRef, enabling better + /// integration with generic MLIR utilities. + llvm::ArrayRef getReturnTypes() const; + + /// Returns whether the function is returns void. + bool isVoid() const; + + /// Returns a clone of this function type with the given argument + /// and result types. + FuncType clone(mlir::TypeRange inputs, mlir::TypeRange results) const; + }]; +} + +//===----------------------------------------------------------------------===// +// Void type +//===----------------------------------------------------------------------===// + +def CIR_VoidType : CIR_Type<"Void", "void"> { + let summary = "CIR void type"; + let description = [{ + The `!cir.void` type represents the C and C++ `void` type. + }]; + let extraClassDeclaration = [{ + std::string getAlias() const { return "void"; }; + }]; +} + +// Constraints + +// Pointer to void +def VoidPtr : Type< + And<[ + CPred<"::mlir::isa<::cir::PointerType>($_self)">, + CPred<"::mlir::isa<::cir::VoidType>(" + "::mlir::cast<::cir::PointerType>($_self).getPointee())">, + ]>, "void*">, + BuildableType< + "cir::PointerType::get($_builder.getContext()," + "cir::VoidType::get($_builder.getContext()))"> { +} + #endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.h b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.h new file mode 100644 index 0000000000000..40b85ef6cfb62 --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.h @@ -0,0 +1,22 @@ +//===---------------------------------------------------------------------===// +// +// 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 +// +//===---------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR floating-point types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H +#define LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H + +#include "mlir/IR/Types.h" +#include "llvm/ADT/APFloat.h" + +/// Include the tablegen'd interface declarations. +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h.inc" + +#endif // LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H diff --git a/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td new file mode 100644 index 0000000000000..973851b61444f --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR floating-point types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD +#define LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD + +include "mlir/IR/OpBase.td" + +def CIRFPTypeInterface : TypeInterface<"CIRFPTypeInterface"> { + let description = [{ + Contains helper functions to query properties about a floating-point type. + }]; + let cppNamespace = "::cir"; + + let methods = [ + InterfaceMethod<[{ + Returns the bit width of this floating-point type. + }], + /*retTy=*/"unsigned", + /*methodName=*/"getWidth", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return llvm::APFloat::semanticsSizeInBits($_type.getFloatSemantics()); + }] + >, + InterfaceMethod<[{ + Return the mantissa width. + }], + /*retTy=*/"unsigned", + /*methodName=*/"getFPMantissaWidth", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return llvm::APFloat::semanticsPrecision($_type.getFloatSemantics()); + }] + >, + InterfaceMethod<[{ + Return the float semantics of this floating-point type. + }], + /*retTy=*/"const llvm::fltSemantics &", + /*methodName=*/"getFloatSemantics" + >, + ]; +} + +#endif // LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD diff --git a/clang/include/clang/CIR/Interfaces/CMakeLists.txt b/clang/include/clang/CIR/Interfaces/CMakeLists.txt new file mode 100644 index 0000000000000..1c90b6b5a23cb --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CMakeLists.txt @@ -0,0 +1,14 @@ +# This replicates part of the add_mlir_interface cmake function from MLIR that +# cannot be used here. This happens because it expects to be run inside MLIR +# directory which is not the case for CIR (and also FIR, both have similar +# workarounds). + +function(add_clang_mlir_type_interface interface) + set(LLVM_TARGET_DEFINITIONS ${interface}.td) + mlir_tablegen(${interface}.h.inc -gen-type-interface-decls) + mlir_tablegen(${interface}.cpp.inc -gen-type-interface-defs) + add_public_tablegen_target(MLIR${interface}IncGen) + add_dependencies(mlir-generic-headers MLIR${interface}IncGen) +endfunction() + +add_clang_mlir_type_interface(CIRFPTypeInterface) diff --git a/clang/lib/CIR/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt index 11cca734808df..f3ef8525e15c2 100644 --- a/clang/lib/CIR/CMakeLists.txt +++ b/clang/lib/CIR/CMakeLists.txt @@ -4,3 +4,4 @@ include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include) add_subdirectory(Dialect) add_subdirectory(CodeGen) add_subdirectory(FrontendAction) +add_subdirectory(Interfaces) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 92115778518d4..01d56963883cc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -21,6 +21,18 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { public: CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc) : CIRBaseBuilderTy(mlirContext), typeCache(tc) {} + + cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const { + if (&format == &llvm::APFloat::IEEEdouble()) + return cir::LongDoubleType::get(getContext(), typeCache.DoubleTy); + if (&format == &llvm::APFloat::x87DoubleExtended()) + return cir::LongDoubleType::get(getContext(), typeCache.FP80Ty); + if (&format == &llvm::APFloat::IEEEquad()) + return cir::LongDoubleType::get(getContext(), typeCache.FP128Ty); + if (&format == &llvm::APFloat::PPCDoubleDouble()) + llvm_unreachable("NYI: PPC double-double format for long double"); + llvm_unreachable("Unsupported format for long double"); + } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 0db24c3b41d18..416d532028d09 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -35,6 +35,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, diags(diags), target(astContext.getTargetInfo()), genTypes(*this) { // Initialize cached types + VoidTy = cir::VoidType::get(&getMLIRContext()); SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true); SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true); SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true); @@ -45,6 +46,12 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false); UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false); UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false); + FP16Ty = cir::FP16Type::get(&getMLIRContext()); + BFloat16Ty = cir::BF16Type::get(&getMLIRContext()); + FloatTy = cir::SingleType::get(&getMLIRContext()); + DoubleTy = cir::DoubleType::get(&getMLIRContext()); + FP80Ty = cir::FP80Type::get(&getMLIRContext()); + FP128Ty = cir::FP128Type::get(&getMLIRContext()); } mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index a357663c33e0f..99c0123c64b28 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h @@ -23,6 +23,9 @@ namespace clang::CIRGen { struct CIRGenTypeCache { CIRGenTypeCache() = default; + // ClangIR void type + cir::VoidType VoidTy; + // ClangIR signed integral types of common sizes cir::IntType SInt8Ty; cir::IntType SInt16Ty; @@ -36,6 +39,14 @@ struct CIRGenTypeCache { cir::IntType UInt32Ty; cir::IntType UInt64Ty; cir::IntType UInt128Ty; + + // ClangIR floating-point types with fixed formats + cir::FP16Type FP16Ty; + cir::BF16Type BFloat16Ty; + cir::SingleType FloatTy; + cir::DoubleType DoubleTy; + cir::FP80Type FP80Ty; + cir::FP128Type FP128Ty; }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 181af1898baff..8519854556b1c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -4,6 +4,9 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" + +#include using namespace clang; using namespace clang::CIRGen; @@ -18,6 +21,70 @@ mlir::MLIRContext &CIRGenTypes::getMLIRContext() const { return *builder.getContext(); } +/// Return true if the specified type in a function parameter or result position +/// can be converted to a CIR type at this point. This boils down to being +/// whether it is complete, as well as whether we've temporarily deferred +/// expanding the type because we're in a recursive context. +bool CIRGenTypes::isFuncParamTypeConvertible(clang::QualType type) { + // Some ABIs cannot have their member pointers represented in LLVM IR unless + // certain circumstances have been reached. + assert(!type->getAs() && "NYI"); + + // If this isn't a tag type, we can convert it. + const TagType *tagType = type->getAs(); + if (!tagType) + return true; + + // Function types involving incomplete class types are problematic in MLIR. + return !tagType->isIncompleteType(); +} + +/// Code to verify a given function type is complete, i.e. the return type and +/// all of the parameter types are complete. Also check to see if we are in a +/// RS_StructPointer context, and if so whether any struct types have been +/// pended. If so, we don't want to ask the ABI lowering code to handle a type +/// that cannot be converted to a CIR type. +bool CIRGenTypes::isFuncTypeConvertible(const FunctionType *ft) { + if (!isFuncParamTypeConvertible(ft->getReturnType())) + return false; + + if (const auto *fpt = dyn_cast(ft)) + for (unsigned i = 0, e = fpt->getNumParams(); i != e; i++) + if (!isFuncParamTypeConvertible(fpt->getParamType(i))) + return false; + + return true; +} + +mlir::Type CIRGenTypes::ConvertFunctionTypeInternal(QualType qft) { + assert(qft.isCanonical()); + const FunctionType *ft = cast(qft.getTypePtr()); + // First, check whether we can build the full fucntion type. If the function + // type depends on an incomplete type (e.g. a struct or enum), we cannot lower + // the function type. + if (!isFuncTypeConvertible(ft)) { + cgm.errorNYI(SourceLocation(), "function type involving an incomplete type", + qft); + return cir::FuncType::get(SmallVector{}, cgm.VoidTy); + } + + // TODO(CIR): This is a stub of what the final code will be. See the + // implementation of this function and the implementation of class + // CIRGenFunction in the ClangIR incubator project. + + if (const auto *fpt = dyn_cast(ft)) { + SmallVector mlirParamTypes; + for (unsigned i = 0; i < fpt->getNumParams(); ++i) { + mlirParamTypes.push_back(convertType(fpt->getParamType(i))); + } + return cir::FuncType::get( + mlirParamTypes, convertType(fpt->getReturnType().getUnqualifiedType()), + fpt->isVariadic()); + } + cgm.errorNYI(SourceLocation(), "non-prototype function type", qft); + return cir::FuncType::get(SmallVector{}, cgm.VoidTy); +} + mlir::Type CIRGenTypes::convertType(QualType type) { type = astContext.getCanonicalType(type); const Type *ty = type.getTypePtr(); @@ -34,6 +101,12 @@ mlir::Type CIRGenTypes::convertType(QualType type) { switch (ty->getTypeClass()) { case Type::Builtin: { switch (cast(ty)->getKind()) { + + // void + case BuiltinType::Void: + resultType = cgm.VoidTy; + break; + // Signed integral types. case BuiltinType::Char_S: case BuiltinType::Int: @@ -63,6 +136,47 @@ mlir::Type CIRGenTypes::convertType(QualType type) { cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), /*isSigned=*/false); break; + + // Floating-point types + case BuiltinType::Float16: + resultType = cgm.FP16Ty; + break; + case BuiltinType::Half: + if (astContext.getLangOpts().NativeHalfType || + !astContext.getTargetInfo().useFP16ConversionIntrinsics()) { + resultType = cgm.FP16Ty; + } else { + cgm.errorNYI(SourceLocation(), "processing of built-in type", type); + resultType = cgm.SInt32Ty; + } + break; + case BuiltinType::BFloat16: + resultType = cgm.BFloat16Ty; + break; + case BuiltinType::Float: + assert(&astContext.getFloatTypeSemantics(type) == + &llvm::APFloat::IEEEsingle() && + "ClangIR NYI: 'float' in a format other than IEEE 32-bit"); + resultType = cgm.FloatTy; + break; + case BuiltinType::Double: + assert(&astContext.getFloatTypeSemantics(type) == + &llvm::APFloat::IEEEdouble() && + "ClangIR NYI: 'double' in a format other than IEEE 64-bit"); + resultType = cgm.DoubleTy; + break; + case BuiltinType::LongDouble: + resultType = + builder.getLongDoubleTy(astContext.getFloatTypeSemantics(type)); + break; + case BuiltinType::Float128: + resultType = cgm.FP128Ty; + break; + case BuiltinType::Ibm128: + cgm.errorNYI(SourceLocation(), "processing of built-in type", type); + resultType = cgm.SInt32Ty; + break; + default: cgm.errorNYI(SourceLocation(), "processing of built-in type", type); resultType = cgm.SInt32Ty; @@ -70,6 +184,23 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } break; } + + case Type::Pointer: { + const PointerType *ptrTy = cast(ty); + QualType elemTy = ptrTy->getPointeeType(); + assert(!elemTy->isConstantMatrixType() && "not implemented"); + + mlir::Type pointeeType = convertType(elemTy); + + resultType = builder.getPointerTo(pointeeType); + break; + } + + case Type::FunctionNoProto: + case Type::FunctionProto: + resultType = ConvertFunctionTypeInternal(type); + break; + case Type::BitInt: { const auto *bitIntTy = cast(type); if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) { @@ -81,6 +212,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } break; } + default: cgm.errorNYI(SourceLocation(), "processing of type", type); resultType = cgm.SInt32Ty; diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 563d7759831fa..71427e1200027 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -19,6 +19,7 @@ namespace clang { class ASTContext; +class FunctionType; class QualType; class Type; } // namespace clang @@ -39,10 +40,18 @@ class CIRGenTypes { clang::ASTContext &astContext; CIRGenBuilderTy &builder; + /// Heper for ConvertType. + mlir::Type ConvertFunctionTypeInternal(clang::QualType ft); + public: CIRGenTypes(CIRGenModule &cgm); ~CIRGenTypes(); + /// Utility to check whether a function type can be converted to a CIR type + /// (i.e. doesn't depend on an incomplete tag type). + bool isFuncTypeConvertible(const clang::FunctionType *ft); + bool isFuncParamTypeConvertible(clang::QualType type); + /// This map of clang::Type to mlir::Type (which includes CIR type) is a /// cache of types that have already been processed. using TypeCacheTy = llvm::DenseMap; diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 9ada31c11de95..782b814d75daa 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -21,4 +21,5 @@ add_clang_library(clangCIR clangLex ${dialect_libs} MLIRCIR + MLIRCIRInterfaces ) diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index de38337057d3d..48be11ba4e243 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -16,6 +16,16 @@ #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "llvm/ADT/TypeSwitch.h" +//===----------------------------------------------------------------------===// +// CIR Custom Parser/Printer Signatures +//===----------------------------------------------------------------------===// + +static mlir::ParseResult +parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector ¶ms, + bool &isVarArg); +static void printFuncTypeArgs(mlir::AsmPrinter &p, + mlir::ArrayRef params, bool isVarArg); + //===----------------------------------------------------------------------===// // Get autogenerated stuff //===----------------------------------------------------------------------===// @@ -133,6 +143,276 @@ IntType::verify(llvm::function_ref emitError, return mlir::success(); } +//===----------------------------------------------------------------------===// +// Floating-point type definitions +//===----------------------------------------------------------------------===// + +const llvm::fltSemantics &SingleType::getFloatSemantics() const { + return llvm::APFloat::IEEEsingle(); +} + +llvm::TypeSize +SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t +SingleType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +SingleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &DoubleType::getFloatSemantics() const { + return llvm::APFloat::IEEEdouble(); +} + +llvm::TypeSize +DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t +DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +DoubleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &FP16Type::getFloatSemantics() const { + return llvm::APFloat::IEEEhalf(); +} + +llvm::TypeSize +FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +FP16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &BF16Type::getFloatSemantics() const { + return llvm::APFloat::BFloat(); +} + +llvm::TypeSize +BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +BF16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &FP80Type::getFloatSemantics() const { + return llvm::APFloat::x87DoubleExtended(); +} + +llvm::TypeSize +FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + // Though only 80 bits are used for the value, the type is 128 bits in size. + return llvm::TypeSize::getFixed(128); +} + +uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return 16; +} + +uint64_t +FP80Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return 16; +} + +const llvm::fltSemantics &FP128Type::getFloatSemantics() const { + return llvm::APFloat::IEEEquad(); +} + +llvm::TypeSize +FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return 16; +} + +uint64_t +FP128Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return 16; +} + +const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const { + return mlir::cast(getUnderlying()) + .getFloatSemantics(); +} + +llvm::TypeSize +LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return mlir::cast(getUnderlying()) + .getTypeSizeInBits(dataLayout, params); +} + +uint64_t +LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return mlir::cast(getUnderlying()) + .getABIAlignment(dataLayout, params); +} + +uint64_t LongDoubleType::getPreferredAlignment( + const ::mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return mlir::cast(getUnderlying()) + .getPreferredAlignment(dataLayout, params); +} + +LogicalResult +LongDoubleType::verify(function_ref emitError, + mlir::Type underlying) { + if (!mlir::isa(underlying)) { + emitError() << "invalid underlying type for long double"; + return failure(); + } + + return success(); +} + +//===----------------------------------------------------------------------===// +// Floating-point type helpers +//===----------------------------------------------------------------------===// + +bool cir::isAnyFloatingPointType(mlir::Type t) { + return isa(t); +} + +//===----------------------------------------------------------------------===// +// FuncType Definitions +//===----------------------------------------------------------------------===// + +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()); +} + +mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p, + llvm::SmallVector ¶ms, + bool &isVarArg) { + isVarArg = false; + // `(` `)` + if (succeeded(p.parseOptionalRParen())) + return mlir::success(); + + // `(` `...` `)` + if (succeeded(p.parseOptionalEllipsis())) { + isVarArg = true; + return p.parseRParen(); + } + + // type (`,` type)* (`,` `...`)? + mlir::Type type; + if (p.parseType(type)) + return mlir::failure(); + params.push_back(type); + while (succeeded(p.parseOptionalComma())) { + if (succeeded(p.parseOptionalEllipsis())) { + isVarArg = true; + return p.parseRParen(); + } + if (p.parseType(type)) + return mlir::failure(); + params.push_back(type); + } + + return p.parseRParen(); +} + +void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef params, + bool isVarArg) { + llvm::interleaveComma(params, p, + [&p](mlir::Type type) { p.printType(type); }); + if (isVarArg) { + if (!params.empty()) + p << ", "; + p << "..."; + } + p << ')'; +} + +llvm::ArrayRef FuncType::getReturnTypes() const { + return static_cast(getImpl())->returnType; +} + +bool FuncType::isVoid() const { return mlir::isa(getReturnType()); } + +//===----------------------------------------------------------------------===// +// PointerType Definitions +//===----------------------------------------------------------------------===// + +llvm::TypeSize +PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: improve this in face of address spaces + return llvm::TypeSize::getFixed(64); +} + +uint64_t +PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: improve this in face of address spaces + return 8; +} + +uint64_t PointerType::getPreferredAlignment( + const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: improve this in face of address spaces + return 8; +} + +mlir::LogicalResult +PointerType::verify(llvm::function_ref emitError, + mlir::Type pointee) { + // TODO(CIR): Verification of the address space goes here. + return mlir::success(); +} + //===----------------------------------------------------------------------===// // CIR Dialect //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt index 7ddc4ce501907..df60f69df6fc0 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -11,5 +11,6 @@ add_clang_library(MLIRCIR MLIRDLTIDialect MLIRDataLayoutInterfaces MLIRFuncDialect + MLIRCIRInterfaces clangAST ) diff --git a/clang/lib/CIR/Interfaces/CIRFPTypeInterface.cpp b/clang/lib/CIR/Interfaces/CIRFPTypeInterface.cpp new file mode 100644 index 0000000000000..41817e90b5232 --- /dev/null +++ b/clang/lib/CIR/Interfaces/CIRFPTypeInterface.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR floating-point types. +// +//===----------------------------------------------------------------------===// + +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h" + +using namespace cir; + +/// Include the generated interfaces. +#include "clang/CIR/Interfaces/CIRFPTypeInterface.cpp.inc" diff --git a/clang/lib/CIR/Interfaces/CMakeLists.txt b/clang/lib/CIR/Interfaces/CMakeLists.txt new file mode 100644 index 0000000000000..fcd8b6963d06c --- /dev/null +++ b/clang/lib/CIR/Interfaces/CMakeLists.txt @@ -0,0 +1,14 @@ +add_clang_library(MLIRCIRInterfaces + CIRFPTypeInterface.cpp + + ADDITIONAL_HEADER_DIRS + ${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces + + DEPENDS + MLIRCIRFPTypeInterfaceIncGen + + LINK_LIBS + ${dialect_libs} + MLIRIR + MLIRSupport + ) diff --git a/clang/test/CIR/global-var-simple.cpp b/clang/test/CIR/global-var-simple.cpp index 5230ff53f87d7..bbd452655a01b 100644 --- a/clang/test/CIR/global-var-simple.cpp +++ b/clang/test/CIR/global-var-simple.cpp @@ -57,3 +57,42 @@ _BitInt(20) sb20; unsigned _BitInt(48) ub48; // CHECK: cir.global @ub48 : !cir.int + +_Float16 f16; +// CHECK: cir.global @f16 : !cir.f16 + +__bf16 bf16; +// CHECK: cir.global @bf16 : !cir.bf16 + +float f; +// CHECK: cir.global @f : !cir.float + +double d; +// CHECK: cir.global @d : !cir.double + +long double ld; +// CHECK: cir.global @ld : !cir.long_double + +__float128 f128; +// CHECK: cir.global @f128 : !cir.f128 + +void *vp; +// CHECK: cir.global @vp : !cir.ptr + +int *ip; +// CHECK: cir.global @ip : !cir.ptr> + +double *dp; +// CHECK: cir.global @dp : !cir.ptr + +char **cpp; +// CHECK: cir.global @cpp : !cir.ptr>> + +void (*fp)(); +// CHECK: cir.global @fp : !cir.ptr> + +int (*fpii)(int); +// CHECK: cir.global @fpii : !cir.ptr (!cir.int)>> + +void (*fpvar)(int, ...); +// CHECK: cir.global @fpvar : !cir.ptr, ...)>>