Author: Konstantinos Parasyris Date: 2026-09-21T12:59:20-07:00 New Revision: 37e2c3bc9610b7952405ddd7c3557c93e933e554
URL: https://github.com/llvm/llvm-project/commit/37e2c3bc9610b7952405ddd7c3557c93e933e554 DIFF: https://github.com/llvm/llvm-project/commit/37e2c3bc9610b7952405ddd7c3557c93e933e554.diff LOG: [CIR] Serialize lowering-relevant LangOptions as #cir.lowering_lang_options (#224757) Post-CIRGen lowering (LoweringPrepare, CallConvLowering) reads a handful of LangOptions flags that have no triple/module representation. A reloaded `.cir` module has no live `clang::LangOptions`, so those flags must be serialized for the file to be self-describing and lower the same way it was compiled. Add a module-level aggregate attribute `#cir.lowering_lang_options` holding the LangOpts facts lowering consumes: "exceptions, threadsafe_statics, cuda, cuda_is_device, hip, gpu_rdc, openmp, openmp_is_target_device, and clang_abi_compat". Target-derived facts (size_t width, CXXABI, comdat, char/pointer/atomic width, SDK version, fp formats) are **NOT** stored: they are rebuilt from `cir.triple` Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]> Added: clang/test/CIR/CodeGen/lowering-lang-options.cpp clang/test/CIR/IR/lowering-lang-options.cir Modified: clang/include/clang/CIR/Dialect/IR/CIRAttrs.td clang/include/clang/CIR/Dialect/IR/CIRDialect.td clang/lib/CIR/CodeGen/CIRGenModule.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index c5f19592d4592..717ef254b1965 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -2247,6 +2247,59 @@ def CIR_StaticLocalInfoAttr let canHaveIllegalCXXABIType = 0; } +//===----------------------------------------------------------------------===// +// LoweringLangOptionsAttr +//===----------------------------------------------------------------------===// + +def CIR_LoweringLangOptionsAttr + : CIR_Attr<"LoweringLangOptions", "lowering_lang_options"> { + let summary = "LangOptions facts that post-CIRGen lowering consumes"; + let description = [{ + Serializes the subset of `clang::LangOptions` that post-CIRGen lowering + reads, as plain data, so a reloaded `.cir` module lowers the same way it + was compiled without a live `clang::LangOptions`. Only LangOpts flags with + no triple/module representation live here; target-derived facts (size_t + width, CXXABI, fp formats, etc.) are rebuilt from `cir.triple` instead. + + Each bool field mirrors the like-named `LangOptions` member: `exceptions`, + `threadsafe_statics`, `cuda`, `cuda_is_device`, `hip`, `gpu_rdc`, + `openmp` (`LangOpts.OpenMP != 0`; only its on/off state matters), and + `openmp_is_target_device`. `clang_abi_compat` is an `i32` mirroring + `LangOptions::ClangABI`; it is an `i32` rather than a CIR enum because + `ClangABI` gains an enumerator every Clang release (see + `clang/Basic/ABIVersions.def`), and the ordinal round-trips fine within a + single toolchain. + + Example: + ``` + module attributes {cir.lowering_lang_options = #cir.lowering_lang_options< + exceptions = false, threadsafe_statics = true, cuda = false, + cuda_is_device = false, hip = false, gpu_rdc = false, openmp = false, + openmp_is_target_device = false, clang_abi_compat = 17>} { } + ``` + }]; + + let parameters = (ins + "bool":$exceptions, + "bool":$threadsafe_statics, + "bool":$cuda, + "bool":$cuda_is_device, + "bool":$hip, + "bool":$gpu_rdc, + "bool":$openmp, + "bool":$openmp_is_target_device, + "int32_t":$clang_abi_compat + ); + + let assemblyFormat = [{ + `<` struct($exceptions, $threadsafe_statics, $cuda, $cuda_is_device, $hip, + $gpu_rdc, $openmp, $openmp_is_target_device, + $clang_abi_compat) `>` + }]; + + let canHaveIllegalCXXABIType = 0; +} + //===----------------------------------------------------------------------===// // AnnotationAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index f07cd7c0dbeb3..423bffb06543a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -96,6 +96,10 @@ def CIR_Dialect : Dialect { // Mangled symbol name of the C++20 named-module initializer function, // precomputed by CIRGen so later passes don't need a live ASTContext. static llvm::StringRef getCXXModuleInitFnNameAttrName() { return "cir.cxx_module_init_fn_name"; } + // 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 getLoweringLangOptionsAttrName() { return "cir.lowering_lang_options"; } static llvm::StringRef getMustTailAttrName() { return "musttail"; } static llvm::StringRef getCatchCopyThunkAttrName() { return "cir.eh.catch_copy_thunk"; } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 1fc4dc134028b..2f032fe39e66e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -3973,6 +3973,24 @@ void CIRGenModule::release() { } } + // Serialize the lowering-relevant LangOptions onto the ModuleOp, + // unconditionally, so a reloaded .cir module is self-describing. See + // #cir.lowering_lang_options. + theModule->setAttr( + cir::CIRDialect::getLoweringLangOptionsAttrName(), + cir::LoweringLangOptionsAttr::get( + &getMLIRContext(), + /*exceptions=*/langOpts.Exceptions, + /*threadsafe_statics=*/langOpts.ThreadsafeStatics, + /*cuda=*/langOpts.CUDA, + /*cuda_is_device=*/langOpts.CUDAIsDevice, + /*hip=*/langOpts.HIP, + /*gpu_rdc=*/langOpts.GPURelocatableDeviceCode, + /*openmp=*/langOpts.OpenMP != 0, + /*openmp_is_target_device=*/langOpts.OpenMPIsTargetDevice, + /*clang_abi_compat=*/ + static_cast<int32_t>(langOpts.getClangABICompat()))); + // Classic codegen calls `checkAliases` here to validate any alias // definitions emitted during codegen. assert(!cir::MissingFeatures::checkAliases()); diff --git a/clang/test/CIR/CodeGen/lowering-lang-options.cpp b/clang/test/CIR/CodeGen/lowering-lang-options.cpp new file mode 100644 index 0000000000000..196577428208a --- /dev/null +++ b/clang/test/CIR/CodeGen/lowering-lang-options.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir \ +// RUN: -emit-cir %s -o - | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir \ +// RUN: -fexceptions -fcxx-exceptions -emit-cir %s -o - \ +// RUN: | FileCheck %s --check-prefix=EXC + +// CIRGen serializes the LangOptions facts that post-CIRGen lowering consumes +// onto the ModuleOp as a #cir.lowering_lang_options attribute, unconditionally, so +// a reloaded .cir module lowers the same way it was compiled without a live +// clang::LangOptions. + +int x; + +// Plain C++: exceptions off, thread-safe statics on, no CUDA/HIP/OpenMP. The +// clang_abi_compat ordinal mirrors LangOptions::ClangABI and is left as a +// regex since its default (Latest) shifts with each Clang release. +// PLAIN: cir.lowering_lang_options = #cir.lowering_lang_options< +// PLAIN-SAME: exceptions = false +// PLAIN-SAME: threadsafe_statics = true +// PLAIN-SAME: cuda = false +// PLAIN-SAME: cuda_is_device = false +// PLAIN-SAME: hip = false +// PLAIN-SAME: gpu_rdc = false +// PLAIN-SAME: openmp = false +// PLAIN-SAME: openmp_is_target_device = false +// PLAIN-SAME: clang_abi_compat = {{[0-9]+}}> + +// -fexceptions -fcxx-exceptions flips exceptions. (OpenMP is exercised in the +// #cir.lowering_lang_options round-trip test, since -fopenmp on a global here hits +// an unrelated CIRGen NYI for OpenMP globals.) +// EXC: cir.lowering_lang_options = #cir.lowering_lang_options< +// EXC-SAME: exceptions = true +// EXC-SAME: threadsafe_statics = true +// EXC-SAME: openmp = false +// EXC-SAME: openmp_is_target_device = false +// EXC-SAME: clang_abi_compat = {{[0-9]+}}> diff --git a/clang/test/CIR/IR/lowering-lang-options.cir b/clang/test/CIR/IR/lowering-lang-options.cir new file mode 100644 index 0000000000000..2ef90bd94ed4e --- /dev/null +++ b/clang/test/CIR/IR/lowering-lang-options.cir @@ -0,0 +1,16 @@ +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +// #cir.lowering_lang_options holds plain data, so it parses and prints without a +// live clang::LangOptions. Check that every field round-trips, including a +// non-default i32 clang_abi_compat and non-default booleans. + +module attributes {cir.lowering_lang_options = #cir.lowering_lang_options< + exceptions = true, threadsafe_statics = false, cuda = true, + cuda_is_device = true, hip = true, gpu_rdc = true, openmp = true, + openmp_is_target_device = true, clang_abi_compat = 9>} { +} + +// CHECK: cir.lowering_lang_options = #cir.lowering_lang_options< +// CHECK-SAME: exceptions = true, threadsafe_statics = false, cuda = true, +// CHECK-SAME: cuda_is_device = true, hip = true, gpu_rdc = true, openmp = true, +// CHECK-SAME: openmp_is_target_device = true, clang_abi_compat = 9> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
