Skip to content

Commit

Permalink
[CIR] Add support for long double type (#536)
Browse files Browse the repository at this point in the history
This PR adds support for the `long double` type in C/C++. It includes a
new CIR type `!cir.long_double` to represent the `long double` type.
CIRGen and LLVMIR lowering support for the new type is also added.

Since the underlying floating point format used by a `long double` value
is implementation-defined, the `!cir.long_double` type is parameterized
to include information about the underlying floating point format.
Specifically, a `long double` value may have one of the following
formats:

  1) IEEE-754 binary64 format (i.e. the same format used by `double`);
  2) x87 80-bit floating point format;
  3) IEEE-754 binary128 format;
  4) PowerPC double double format.

This PR invents 3 more CIR types to represent the above floating-point
formats, and `!cir.long_double` is parameterized by another CIR
floating-point type which represents its underlying format:

  - `!cir.long_double<!cir.double>` represents the 1st variant above;
  - `!cir.long_double<!cir.f80>` represents the 2nd variant above;
  - `!cir.long_double<!cir.f128>` represents the 3rd variant above;
- `!cir.long_double<!cir.ppc_doubledouble>` represents the 4th variant
above.

Co-authored-by: Bruno Cardoso Lopes <bcardosolopes@users.noreply.github.com>
  • Loading branch information
Lancern and bcardosolopes authored Apr 19, 2024
1 parent aa6e197 commit 4a2955e
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 183 deletions.
29 changes: 28 additions & 1 deletion clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,36 @@ def CIR_Double : CIR_FloatType<"Double", "double"> {
}];
}

def CIR_FP80 : CIR_FloatType<"FP80", "f80"> {
let summary = "CIR type that represents x87 80-bit floating-point format";
let description = [{
Floating-point type that represents the x87 80-bit floating-point format.
}];
}

def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> {
let summary = "CIR extended-precision float type";
let description = [{
Floating-point type that represents the `long double` type in C/C++.

The underlying floating-point format of a long double value depends on the
implementation. The `underlying` parameter specifies the CIR floating-point
type that corresponds to this format. For now, it can only be either
`!cir.double` or `!cir.fp80`.
}];

let parameters = (ins "mlir::Type":$underlying);

let assemblyFormat = [{
`<` $underlying `>`
}];

let genVerifyDecl = 1;
}

// Constraints

def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double]>;
def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_LongDouble]>;
def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>;

//===----------------------------------------------------------------------===//
Expand Down
27 changes: 8 additions & 19 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,29 +373,18 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
}
bool isInt(mlir::Type i) { return i.isa<mlir::cir::IntType>(); }

mlir::Type getLongDouble80BitsTy() const { llvm_unreachable("NYI"); }

/// Get the proper floating point type for the given semantics.
mlir::Type getFloatTyForFormat(const llvm::fltSemantics &format,
bool useNativeHalf) const {
if (&format == &llvm::APFloat::IEEEhalf()) {
llvm_unreachable("IEEEhalf float format is NYI");
}

if (&format == &llvm::APFloat::BFloat())
llvm_unreachable("BFloat float format is NYI");
if (&format == &llvm::APFloat::IEEEsingle())
return typeCache.FloatTy;
mlir::cir::LongDoubleType
getLongDoubleTy(const llvm::fltSemantics &format) const {
if (&format == &llvm::APFloat::IEEEdouble())
return typeCache.DoubleTy;
return mlir::cir::LongDoubleType::get(getContext(), typeCache.DoubleTy);
if (&format == &llvm::APFloat::x87DoubleExtended())
return mlir::cir::LongDoubleType::get(getContext(), typeCache.FP80Ty);
if (&format == &llvm::APFloat::IEEEquad())
llvm_unreachable("IEEEquad float format is NYI");
llvm_unreachable("NYI");
if (&format == &llvm::APFloat::PPCDoubleDouble())
llvm_unreachable("PPCDoubleDouble float format is NYI");
if (&format == &llvm::APFloat::x87DoubleExtended())
return getLongDouble80BitsTy();
llvm_unreachable("NYI");

llvm_unreachable("Unknown float format!");
llvm_unreachable("unsupported long double format");
}

mlir::Type getVirtualFnPtrType(bool isVarArg = false) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
// TODO: BFloatTy
FloatTy = ::mlir::cir::SingleType::get(builder.getContext());
DoubleTy = ::mlir::cir::DoubleType::get(builder.getContext());
FP80Ty = ::mlir::cir::FP80Type::get(builder.getContext());
// TODO(cir): perhaps we should abstract long double variations into a custom
// cir.long_double type. Said type would also hold the semantics for lowering.

Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypeCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct CIRGenTypeCache {
// cir.long_double type. Said type would also hold the semantics for lowering.
mlir::cir::SingleType FloatTy;
mlir::cir::DoubleType DoubleTy;
mlir::cir::FP80Type FP80Ty;

/// int
mlir::Type UIntTy;
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,8 +479,7 @@ mlir::Type CIRGenTypes::ConvertType(QualType T) {
ResultType = CGM.DoubleTy;
break;
case BuiltinType::LongDouble:
ResultType = Builder.getFloatTyForFormat(Context.getFloatTypeSemantics(T),
/*useNativeHalf=*/false);
ResultType = Builder.getLongDoubleTy(Context.getFloatTypeSemantics(T));
break;
case BuiltinType::Float128:
case BuiltinType::Ibm128:
Expand Down
61 changes: 61 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,67 @@ DoubleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
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 {
return llvm::TypeSize::getFixed(16);
}

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 &LongDoubleType::getFloatSemantics() const {
return getUnderlying()
.cast<mlir::cir::CIRFPTypeInterface>()
.getFloatSemantics();
}

llvm::TypeSize
LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
return getUnderlying()
.cast<mlir::DataLayoutTypeInterface>()
.getTypeSizeInBits(dataLayout, params);
}

uint64_t
LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
return getUnderlying().cast<mlir::DataLayoutTypeInterface>().getABIAlignment(
dataLayout, params);
}

uint64_t LongDoubleType::getPreferredAlignment(
const ::mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
return getUnderlying()
.cast<mlir::DataLayoutTypeInterface>()
.getPreferredAlignment(dataLayout, params);
}

LogicalResult
LongDoubleType::verify(function_ref<InFlightDiagnostic()> emitError,
mlir::Type underlying) {
if (!underlying.isa<DoubleType, FP80Type>()) {
emitError() << "invalid underlying type for long double";
return failure();
}

return success();
}

//===----------------------------------------------------------------------===//
// FuncType Definitions
//===----------------------------------------------------------------------===//
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2956,6 +2956,12 @@ void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
converter.addConversion([&](mlir::cir::DoubleType type) -> mlir::Type {
return mlir::FloatType::getF64(type.getContext());
});
converter.addConversion([&](mlir::cir::FP80Type type) -> mlir::Type {
return mlir::FloatType::getF80(type.getContext());
});
converter.addConversion([&](mlir::cir::LongDoubleType type) -> mlir::Type {
return converter.convertType(type.getUnderlying());
});
converter.addConversion([&](mlir::cir::FuncType type) -> mlir::Type {
auto result = converter.convertType(type.getReturnType());
llvm::SmallVector<mlir::Type> arguments;
Expand Down
Loading

0 comments on commit 4a2955e

Please sign in to comment.