-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[CIR] floating-point, pointer, and function types #120484
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
Conversation
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.
@llvm/pr-subscribers-clangir Author: David Olsen (dkolsen-pgi) ChangesUpstream ClangIR support for 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. Patch is 38.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/120484.diff 19 Files Affected:
diff --git a/clang/include/clang/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt
index f8d6f407a03d02..e20c896171c928 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 75ae74e926fbc6..0e414921324b7f 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 2bc7d77b2bc8a3..5d1eb17e146d03 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 ce0b6ba1d68c55..ef00b26c1fd98c 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<string name, string mnemonic>
+ : CIR_Type<name, mnemonic,
+ [
+ DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
+ DeclareTypeInterfaceMethods<CIRFPTypeInterface>,
+ ]> {}
+
+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<DataLayoutTypeInterface>]> {
+
+ 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<cir::VoidType>(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<!bool ()>
+ !cir.func<!s32i (!s8i, !s8i)>
+ !cir.func<!s32i (!s32i, ...)>
+ ```
+ }];
+
+ let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs,
+ "mlir::Type":$returnType, "bool":$varArg);
+ let assemblyFormat = [{
+ `<` $returnType ` ` `(` custom<FuncTypeArgs>($inputs, $varArg) `>`
+ }];
+
+ let builders = [
+ TypeBuilderWithInferredContext<(ins
+ "llvm::ArrayRef<mlir::Type>":$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<mlir::Type> 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 00000000000000..40b85ef6cfb626
--- /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 00000000000000..33ad0fc1aa53cb
--- /dev/null
+++ b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td
@@ -0,0 +1,52 @@
+//===- CIRFPTypeInterface.td - CIR FP Interface Definitions -----*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#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 00000000000000..1c90b6b5a23cb2
--- /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 11cca734808dfa..f3ef8525e15c26 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 92115778518d4a..01d56963883cc2 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 0db24c3b41d18d..416d532028d090 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 a357663c33e0f8..99c0123c64b28c 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 181af1898baff2..7e4e2f58cfce18 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 <cassert>
using namespace clang;
using namespace clang::CIRGen;
@@ -18,6 +21,87 @@ 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<MemberPointerType>() && "NYI");
+
+ // If this isn't a tagged type, we can convert it!
+ const TagType *tagType = type->getAs<TagType>();
+ if (!tagType)
+ return true;
+
+ // Incomplete types cannot be converted.
+ if (tagType->isIncompleteType())
+ return false;
+
+ // If this is an enum, then it is always safe to convert.
+ const RecordType *recordType = dyn_cast<RecordType>(tagType);
+ if (!recordType)
+ return true;
+
+ // Otherwise, we have to be careful. If it is a struct that we're in the
+ // process of expanding, then we can't convert the function type. That's ok
+ // though because we must be in a pointer context under the struct, so we can
+ // just convert it to a dummy type.
+ //
+ // We decide this by checking whether ConvertRecordDeclType returns us an
+ // opaque type for a struct that we know is defined.
+ // TODO(cir): struct types are not implemented yet, so skip the final check.
+ // return isSafeToConvert(recordType->getDecl(), *this);
+ return true;
+}
+
+/// 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::isFuncTypeConvertibl...
[truncated]
|
@llvm/pr-subscribers-clang Author: David Olsen (dkolsen-pgi) ChangesUpstream ClangIR support for 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. Patch is 38.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/120484.diff 19 Files Affected:
diff --git a/clang/include/clang/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt
index f8d6f407a03d02..e20c896171c928 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 75ae74e926fbc6..0e414921324b7f 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 2bc7d77b2bc8a3..5d1eb17e146d03 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 ce0b6ba1d68c55..ef00b26c1fd98c 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<string name, string mnemonic>
+ : CIR_Type<name, mnemonic,
+ [
+ DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
+ DeclareTypeInterfaceMethods<CIRFPTypeInterface>,
+ ]> {}
+
+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<DataLayoutTypeInterface>]> {
+
+ 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<cir::VoidType>(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<!bool ()>
+ !cir.func<!s32i (!s8i, !s8i)>
+ !cir.func<!s32i (!s32i, ...)>
+ ```
+ }];
+
+ let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs,
+ "mlir::Type":$returnType, "bool":$varArg);
+ let assemblyFormat = [{
+ `<` $returnType ` ` `(` custom<FuncTypeArgs>($inputs, $varArg) `>`
+ }];
+
+ let builders = [
+ TypeBuilderWithInferredContext<(ins
+ "llvm::ArrayRef<mlir::Type>":$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<mlir::Type> 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 00000000000000..40b85ef6cfb626
--- /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 00000000000000..33ad0fc1aa53cb
--- /dev/null
+++ b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td
@@ -0,0 +1,52 @@
+//===- CIRFPTypeInterface.td - CIR FP Interface Definitions -----*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#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 00000000000000..1c90b6b5a23cb2
--- /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 11cca734808dfa..f3ef8525e15c26 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 92115778518d4a..01d56963883cc2 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 0db24c3b41d18d..416d532028d090 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 a357663c33e0f8..99c0123c64b28c 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 181af1898baff2..7e4e2f58cfce18 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 <cassert>
using namespace clang;
using namespace clang::CIRGen;
@@ -18,6 +21,87 @@ 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<MemberPointerType>() && "NYI");
+
+ // If this isn't a tagged type, we can convert it!
+ const TagType *tagType = type->getAs<TagType>();
+ if (!tagType)
+ return true;
+
+ // Incomplete types cannot be converted.
+ if (tagType->isIncompleteType())
+ return false;
+
+ // If this is an enum, then it is always safe to convert.
+ const RecordType *recordType = dyn_cast<RecordType>(tagType);
+ if (!recordType)
+ return true;
+
+ // Otherwise, we have to be careful. If it is a struct that we're in the
+ // process of expanding, then we can't convert the function type. That's ok
+ // though because we must be in a pointer context under the struct, so we can
+ // just convert it to a dummy type.
+ //
+ // We decide this by checking whether ConvertRecordDeclType returns us an
+ // opaque type for a struct that we know is defined.
+ // TODO(cir): struct types are not implemented yet, so skip the final check.
+ // return isSafeToConvert(recordType->getDecl(), *this);
+ return true;
+}
+
+/// 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::isFuncTypeConvertibl...
[truncated]
|
// certain circumstances have been reached. | ||
assert(!type->getAs<MemberPointerType>() && "NYI"); | ||
|
||
// If this isn't a tagged type, we can convert it! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, tag
type, not tagged
type, as this just represents any of the struct, class, union, or enum types.
Second, is the rest of this true? Non-Tag types include atomics, Attributed types, bitint types, block pointers, complex, various dependent types, vector types, etc. Do we really just mean to do BuiltinType
here instead? Or do we really mean we can do the rest already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used to check if a type is problematic when it is used as part of a function type. According to the comment here, only incomplete class
/struct
/union
types are problematic when creating ClangIR function types.
The currently upstreamed ClangIR code can't handle atomic types or vector types or some of the other types you mentioned, in any context. But when ClangIR can handle them, they will just work as part of function types; the code here won't need to change.
This entire function could have been left out of this PR since it doesn't do anything useful yet. But because everything in the function except for the last line builds and runs, I decided to include it in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, I think just an assert in the '!TagType' check here would be valuable, just that asserts it is a BuiltinType
(or, the NYI diagnostic).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree about this one. If the source code uses a vector type as the type of a function parameter, ClangIR code gen will fail with a NYI error in CIRGenTypes::convertType
when trying to convert the Clang vector type into a CIR type. There isn't a good reason to add a general-purpose check here in a function that is looking for a very specific condition that has only to do with function types.
Maybe this function should be renamed to isConvertedTypeUsableInFunctionTypes
, to emphasize that it is not checking if a type is convertible, but checking whether or not a type is problematic if used as a return type or a parameter type within a function type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, the assert here makes a lot of sense, in that it shows off the assumption that we're intentionally not handling these types. The point is that we're NOT doing the work to figure out if those types are problematic if used in return /parameter in a function type (for good reason, since it'll fail earlier). SO we should assert for that, so that when CIRGenTypes::convertType
stops emitting the NYI, that this will be quickly noticed, rather than returning a value we wouldn't be sure of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is known that incomplete tag types are the only ones that are problematic in this context.
This seems inaccurate to me. CIR doesn't seem to be able to represent(see here: https://github.com/llvm/clangir/blob/main/clang/include/clang/CIR/Dialect/IR/CIRTypes.td) Atomic Types, BitInt types, Block types, and Matrix types upon quick look (that is perhaps an incomplete list).
The function was written across;
llvm/clangir@101e732
and
llvm/clangir@93f55f6
Neither of which mention those types specifically? It seems it USED to have an assert for not-tag-type, though it isn't clear that the authors considered the above types.
Can @lanza and @bcardosolopes chime in and let me know if I'm misinterpreting the commits there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's totally fine to be conservative about assumptions, we need asserts for both things that are NYI but also for things we assume as invariants, IMO the more the merrier cause it's easier to catch miscompilations.
Neither of which mention those types specifically? It seems it USED to have an assert for not-tag-type, though it isn't clear that the authors considered the above types.
I don't remember the full context anymore, but assertion on a assumed invariant in the incubator to be even more protective also sounds good to me (guess running the tests upon such change will give us the final answer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bcardosolopes What exactly do you suggest doing here in this function. Asserting on assumed invariants is great. But I don't see any invariants here that could be asserted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember the details on why it was necessary at the time to deviate - so I just made this be equivalent to traditional codegen and everything passes: llvm/clangir@04d7dcf
That said, I don't think we need to introduce any asserts here, can't get better than OG for the sake of completeness. Not supported types will crash given the other mechanisms David mentioned, but the recursive logic is sound with pre-existing work.
Unless Erich has any other concerns, this LGTM to land.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this includes llvm/clangir@04d7dcf in it, rather than the current implementation, I think I'm OK without any asserts. I'll Approve, but conditional on that patch being included in this one.
Fix the opening comment on some newly added files. Add asserts that the Clang types `float` and `double` are IEEE 32-bit and 64-bit.
@dkolsen-pgi Great PR! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with some minor nits
My bad here, we usually don't accept such changes and I missed that during review time. ClangIR policy to changes outside CIR is to upstream them to MLIR and after that's done we cherry-pick it to the incubator (so rebases are smooth). I'll have to revert your change, sorry for the churn! |
@bcardosolopes I can work on the phase 2 of the change I had in mind and remove also the |
Neat, if you can do that I won't need to revert and make it easier for everyone |
@keryell :
Upstreaming is happening in logical chunks, using the latest version of the feature. I am paying no attention to the order of commits in the incubator project. Unfortunately, your change landed after I started working on this change (or at least after I had last refreshed my incubator workspace). So I didn't see it, and didn't incorporate your change into this one. Once this PR is merged, could you please make your change again in the LLVM repository? Bruno floated this idea in #clangir on Discord, of asking people who change already upstreamed code to make the change in both the incubator and the LLVM repository. You may be the first guinea pig for this. We can see if this is a good process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approve, conditional on isFuncParamTypeConvertible change being pulled from the incubator.
Merge in change llvm/clangir@04d7dcf which simplifies function CIRGenTypes::isFuncParamTypeConvertible.
This reverts commit 8ae8a90.
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.