llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Mariya Podchishchaeva (Fznamznon) <details> <summary>Changes</summary> The attribute allows to preserve information about `-mlong-double-*` and other long double length controlling options used to create serialized CIR and maps directly to long-double-size metadata. Clang won't emit the attribute if no `long_double` type is present in the module. Assisted-by: claude --- Full diff: https://github.com/llvm/llvm-project/pull/234275.diff 11 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+29) - (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (+1) - (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+19) - (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+1) - (modified) clang/lib/CIR/CodeGen/CIRGenTypes.h (+4) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+61) - (modified) clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp (+27) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+13) - (added) clang/test/CIR/CodeGen/long-double-format-attr.c (+40) - (added) clang/test/CIR/IR/invalid-long-double-format.cir (+42) - (added) clang/test/CIR/Lowering/long-double-format-attr.cir (+7) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index b3cc021989fde..9ab592437a5e3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -2672,6 +2672,35 @@ def CIR_LoweringLangOptionsAttr let canHaveIllegalCXXABIType = 0; } +//===----------------------------------------------------------------------===// +// LongDoubleFormatAttr +//===----------------------------------------------------------------------===// + +def CIR_LongDoubleFormat : CIR_I32Enum<"LongDoubleFormat", + "long double format", [ + I32EnumCase<"IEEEsingle", 0, "float">, + I32EnumCase<"IEEEdouble", 1, "double">, + I32EnumCase<"X87DoubleExtended", 2, "x86_fp80">, + I32EnumCase<"IEEEquad", 3, "fp128">, + I32EnumCase<"PPCDoubleDouble", 4, "ppc_fp128"> +]>; + +def CIR_LongDoubleFormatAttr + : CIR_EnumAttr<CIR_LongDoubleFormat, "long_double_format"> { + let summary = "Module long double format"; + let description = [{ + Records the floating-point format used for `long double` in the module. + The values of the attribute mirror possible values of `long-double-type` + LLVM IR metadata. + + Example: + ``` + module attributes { + cir.long_double_format = #cir.long_double_format<x86_fp80>} {} + ``` + }]; +} + //===----------------------------------------------------------------------===// // AnnotationAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index 53e4730e95d97..ad4f8182904fd 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -120,6 +120,7 @@ def CIR_Dialect : Dialect { // LangOptions facts that post-CIRGen lowering consumes, serialized by // CIRGen so a reloaded .cir module is self-describing without a live // clang::LangOptions. See #cir.lowering_lang_options. + static llvm::StringRef getLongDoubleFormatAttrName() { return "cir.long_double_format"; } static llvm::StringRef getLoweringLangOptionsAttrName() { return "cir.lowering_lang_options"; } // Platform SDK version from -target-sdk-version, as printed by // llvm::VersionTuple (e.g. "12.3"). Absent when none was given. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 6142ee62f3be1..74609be3dffeb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -4027,6 +4027,25 @@ void CIRGenModule::release() { cir::CIRDialect::getModuleFramePointerAttrName(), cir::FramePointerKindAttr::get(&getMLIRContext(), *kind)); + if (getTypes().isLongDoubleReferenced()) { + const llvm::fltSemantics *flt = &getTarget().getLongDoubleFormat(); + std::optional<cir::LongDoubleFormat> format; + if (flt == &llvm::APFloat::IEEEquad()) + format = cir::LongDoubleFormat::IEEEquad; + else if (flt == &llvm::APFloat::IEEEdouble()) + format = cir::LongDoubleFormat::IEEEdouble; + else if (flt == &llvm::APFloat::PPCDoubleDouble()) + format = cir::LongDoubleFormat::PPCDoubleDouble; + else if (flt == &llvm::APFloat::x87DoubleExtended()) + format = cir::LongDoubleFormat::X87DoubleExtended; + else if (flt == &llvm::APFloat::IEEEsingle()) + format = cir::LongDoubleFormat::IEEEsingle; + if (format) + theModule->setAttr( + cir::CIRDialect::getLongDoubleFormatAttrName(), + cir::LongDoubleFormatAttr::get(&getMLIRContext(), *format)); + } + if (!recordLayoutEntries.empty()) theModule->setAttr( cir::CIRDialect::getRecordLayoutsAttrName(), diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index e1da57c9a38db..8eaecbad8b1f1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -486,6 +486,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) { resultType = cgm.doubleTy; break; case BuiltinType::LongDouble: + longDoubleReferenced = true; resultType = builder.getLongDoubleTy(astContext.getFloatTypeSemantics(type)); break; diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 852e1f4ab6699..d243817d9ca77 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -74,6 +74,9 @@ class CIRGenTypes { llvm::SmallVector<const clang::RecordDecl *, 8> deferredRecords; + /// True if any instance of long double types are used. + bool longDoubleReferenced = false; + /// Cache of record type keys known to be safe to convert (i.e., /// isSafeToConvert returned true). Cleared whenever recordsBeingLaidOut /// changes, since the safety result depends on which records are currently @@ -92,6 +95,7 @@ class 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 isLongDoubleReferenced() const { return longDoubleReferenced; } bool isFuncTypeConvertible(const clang::FunctionType *ft); bool isFuncParamTypeConvertible(clang::QualType type); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index b5ee092283075..88a6a50b76502 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -281,6 +281,43 @@ bool cir::CIRDialect::isPureCIRType(mlir::Type ty) const { return result; } +/// Returns true if \p triple can use \p format for long double: either it is +/// the target default, or the target lets the user select it (-mlong-double-64, +/// -mlong-double-80, -mlong-double-128, -mabi=ieeelongdouble). +static bool isLongDoubleFormatSupported(const llvm::Triple &triple, + cir::LongDoubleFormat format) { + auto toFormat = [](llvm::LongDoubleFormat f) { + switch (f) { + case llvm::LongDoubleFormat::IEEEsingle: + return cir::LongDoubleFormat::IEEEsingle; + case llvm::LongDoubleFormat::IEEEdouble: + return cir::LongDoubleFormat::IEEEdouble; + case llvm::LongDoubleFormat::X87DoubleExtended: + return cir::LongDoubleFormat::X87DoubleExtended; + case llvm::LongDoubleFormat::IEEEquad: + return cir::LongDoubleFormat::IEEEquad; + case llvm::LongDoubleFormat::PPCDoubleDouble: + return cir::LongDoubleFormat::PPCDoubleDouble; + } + llvm_unreachable("unknown long double format"); + }; + if (format == toFormat(triple.getDefaultLongDoubleFormat())) + return true; + + switch (format) { + case cir::LongDoubleFormat::IEEEdouble: + case cir::LongDoubleFormat::IEEEquad: + return triple.isX86() || triple.isPPC(); + case cir::LongDoubleFormat::X87DoubleExtended: + return triple.isX86(); + case cir::LongDoubleFormat::PPCDoubleDouble: + return triple.isPPC(); + case cir::LongDoubleFormat::IEEEsingle: + return false; + } + llvm_unreachable("unknown long double format"); +} + LogicalResult cir::CIRDialect::verifyOperationAttribute(mlir::Operation *op, mlir::NamedAttribute attr) { @@ -313,6 +350,30 @@ cir::CIRDialect::verifyOperationAttribute(mlir::Operation *op, return success(); } + if (attrName == getLongDoubleFormatAttrName()) { + if (!mlir::isa<mlir::ModuleOp>(op)) + return op->emitOpError() << "expects '" << getLongDoubleFormatAttrName() + << "' attribute to be attached to '" + << mlir::ModuleOp::getOperationName() << "'"; + auto format = mlir::dyn_cast<cir::LongDoubleFormatAttr>(attr.getValue()); + if (!format) + return op->emitOpError() + << "expects '" << getLongDoubleFormatAttrName() + << "' to be a #cir.long_double_format attribute"; + + auto triple = op->getAttrOfType<mlir::StringAttr>(getTripleAttrName()); + if (!triple) + return success(); + + llvm::Triple tripleVal(triple.getValue()); + if (!isLongDoubleFormatSupported(tripleVal, format.getValue())) + return op->emitOpError() + << "long double format '" + << cir::stringifyLongDoubleFormat(format.getValue()) + << "' is not supported on target '" << triple.getValue() << "'"; + return success(); + } + if (attrName == getOffloadContainerAttrName()) { if (!mlir::isa<mlir::UnitAttr>(attr.getValue())) return op->emitOpError() << "expects '" << getOffloadContainerAttrName() diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp index 2fda1c996ad5c..4e058513b1786 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp @@ -115,6 +115,28 @@ std::unique_ptr<LowerModule> createLowerModule(mlir::ModuleOp module) { langOpts.setClangABICompat(static_cast<clang::LangOptions::ClangABI>( loweringLangOpts.getClangAbiCompat())); } + if (auto ldFormat = mlir::dyn_cast_if_present<cir::LongDoubleFormatAttr>( + module->getAttr(cir::CIRDialect::getLongDoubleFormatAttrName()))) { + switch (ldFormat.getValue()) { + case cir::LongDoubleFormat::IEEEsingle: + // There is no frontend option to force 32 bit long double, so let it + // derive from the target. + break; + case cir::LongDoubleFormat::IEEEdouble: + langOpts.LongDoubleSize = 64; + break; + case cir::LongDoubleFormat::X87DoubleExtended: + langOpts.LongDoubleSize = 80; + break; + case cir::LongDoubleFormat::IEEEquad: + langOpts.LongDoubleSize = 128; + break; + case cir::LongDoubleFormat::PPCDoubleDouble: + // TargetInfo::adjust would turn 128 into IEEE quad, so leave it unset to + // keep the target's own ppc_fp128 format. + break; + } + } // Some langopts are still not lowered. assert(!cir::MissingFeatures::lowerModuleLangOpts()); @@ -133,6 +155,11 @@ std::unique_ptr<LowerModule> createLowerModule(mlir::ModuleOp module) { codeGenOpts.OptimizeSize = optInfo.getSize(); } + clang::DiagnosticOptions diagOpts; + clang::DiagnosticsEngine diags(clang::DiagnosticIDs::create(), diagOpts, + new clang::IgnoringDiagConsumer()); + targetInfo->adjust(diags, langOpts, /*Aux=*/nullptr); + return std::make_unique<LowerModule>(std::move(langOpts), std::move(codeGenOpts), module, std::move(targetInfo)); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 417d629be68b9..8c2dc1e40e0f0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4809,6 +4809,19 @@ void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) { builder.getArrayAttr({flag})); } + if (auto ldFormat = module->getAttrOfType<cir::LongDoubleFormatAttr>( + cir::CIRDialect::getLongDoubleFormatAttrName())) { + mlir::OpBuilder builder(module.getContext()); + builder.setInsertionPointToEnd(module.getBody()); + auto flag = mlir::LLVM::ModuleFlagAttr::get( + module.getContext(), mlir::LLVM::ModFlagBehavior::Error, + builder.getStringAttr("long-double-type"), + builder.getStringAttr(cir::stringifyLongDoubleFormat( + ldFormat.getValue()))); + mlir::LLVM::ModuleFlagsOp::create(builder, module.getLoc(), + builder.getArrayAttr({flag})); + } + lowerOpenCLModuleMetadataAttrs(module); } diff --git a/clang/test/CIR/CodeGen/long-double-format-attr.c b/clang/test/CIR/CodeGen/long-double-format-attr.c new file mode 100644 index 0000000000000..48d3324da0283 --- /dev/null +++ b/clang/test/CIR/CodeGen/long-double-format-attr.c @@ -0,0 +1,40 @@ +// This test mirrors CodeGen/long-double-module-flag.c +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fclangir -emit-cir -o - | FileCheck %s --check-prefix=X86FP80-CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -DNOLDBL %s -emit-cir -o - | FileCheck %s --check-prefix=NOLDBL-CIR + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fclangir -emit-llvm -o - | FileCheck %s --check-prefix=X86FP80 +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu %s -fclangir -emit-llvm -o - | FileCheck %s --check-prefix=FP128 + +// FIXME: enable when arm abi is supported +// RUN-disabled: %clang_cc1 -triple arm-none-eabi %s -fclangir -emit-llvm -o - | FileCheck %s --check-prefix=DOUBLE +// FIXME: enable when PPC double-double format for long double is done +// RUN-disabled: %clang_cc1 -triple powerpc64le-unknown-linux-gnu %s -fclangir -emit-llvm -o - | FileCheck %s --check-prefix=PPCFP128 + +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu %s -fclangir -emit-llvm -mabi=ieeelongdouble -o - | FileCheck %s --check-prefix=FP128 +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu %s -fclangir -emit-llvm -mlong-double-64 -o - | FileCheck %s --check-prefix=DOUBLE +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -DNOLDBL %s -emit-llvm -o - | FileCheck %s --check-prefix=NOLDBL + +// classic CG runs. +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=X86FP80 +// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=FP128 +// RUN: %clang_cc1 -triple arm-none-eabi %s -emit-llvm -o - | FileCheck %s --check-prefix=DOUBLE +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=PPCFP128 +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu %s -emit-llvm -mabi=ieeelongdouble -o - | FileCheck %s --check-prefix=FP128 +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu %s -emit-llvm -mlong-double-64 -o - | FileCheck %s --check-prefix=DOUBLE +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -DNOLDBL %s -emit-llvm -o - | FileCheck %s --check-prefix=NOLDBL + +#ifndef NOLDBL +long double foo(long double a, long double b) { + return a + b; +} +#endif + +int bar() { return 1; } + +// X86FP80-CIR: cir.long_double_format = #cir.long_double_format<x86_fp80> +// X86FP80: ![[#]] = !{i32 1, !"long-double-type", !"x86_fp80"} +// FP128: ![[#]] = !{i32 1, !"long-double-type", !"fp128"} +// DOUBLE: ![[#]] = !{i32 1, !"long-double-type", !"double"} +// PPCFP128: ![[#]] = !{i32 1, !"long-double-type", !"ppc_fp128"} +// NOLDBL-NOT: !"long-double-type" +// NOLDBL-CIR-NOT: cir.long_double_format diff --git a/clang/test/CIR/IR/invalid-long-double-format.cir b/clang/test/CIR/IR/invalid-long-double-format.cir new file mode 100644 index 0000000000000..ba7fafeae7ad4 --- /dev/null +++ b/clang/test/CIR/IR/invalid-long-double-format.cir @@ -0,0 +1,42 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +// expected-error@+1 {{long double format 'float' is not supported on target 'x86_64-unknown-linux-gnu'}} +module attributes {cir.triple = "x86_64-unknown-linux-gnu", + cir.long_double_format = #cir.long_double_format<float>} { +} + +// ----- + +// expected-error@+1 {{long double format 'ppc_fp128' is not supported on target 'x86_64-unknown-linux-gnu'}} +module attributes {cir.triple = "x86_64-unknown-linux-gnu", + cir.long_double_format = #cir.long_double_format<ppc_fp128>} { +} + +// ----- + +// expected-error@+1 {{long double format 'x86_fp80' is not supported on target 'aarch64-unknown-linux-gnu'}} +module attributes {cir.triple = "aarch64-unknown-linux-gnu", + cir.long_double_format = #cir.long_double_format<x86_fp80>} { +} + +// ----- + +module { + // expected-error@+1 {{expects 'cir.long_double_format' attribute to be attached to 'builtin.module'}} + cir.func @f() attributes {cir.long_double_format = #cir.long_double_format<double>} { + cir.return + } +} + +// ----- + +// Valid: PPC can use IEEE quad (-mabi=ieeelongdouble) and ppc_fp128. +module attributes {cir.triple = "powerpc64le-unknown-linux-gnu", + cir.long_double_format = #cir.long_double_format<fp128>} { +} + +// ----- + +module attributes {cir.triple = "powerpc64le-unknown-linux-gnu", + cir.long_double_format = #cir.long_double_format<ppc_fp128>} { +} diff --git a/clang/test/CIR/Lowering/long-double-format-attr.cir b/clang/test/CIR/Lowering/long-double-format-attr.cir new file mode 100644 index 0000000000000..eaf6e9e374539 --- /dev/null +++ b/clang/test/CIR/Lowering/long-double-format-attr.cir @@ -0,0 +1,7 @@ +// RUN: cir-translate %s --cir-to-llvmir -o - | FileCheck %s --check-prefix=LLVM + +module attributes {cir.triple = "x86_64-unknown-linux-gnu", + cir.long_double_format = #cir.long_double_format<double>} { +} + +// LLVM: !{i32 1, !"long-double-type", !"double"} `````````` </details> https://github.com/llvm/llvm-project/pull/234275 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
