Skip to content

Conversation

@lanza
Copy link
Member

@lanza lanza commented Nov 24, 2025

Stack from ghstack (oldest at bottom):

Add support for C++ static local variables with non-trivial destructors
and dynamic initialization. This implements the guarded initialization
pattern required by the C++ standard for one-time initialization.

Implementation Details

New CIR Operation: GuardedInitOp

  • Defined in CIROps.td as cir.guarded.init
  • Represents the guarded initialization pattern for static locals
  • Contains an init_region for initialization code
  • Attributes: thread_safe, perform_init
  • Parameters: guard variable (pointer), static variable (symbol)

CIRGen Changes:

  • CIRGenFunction: Added emitCXXGuardedInit() and emitCXXGlobalVarDeclInit()
  • CIRGenCXXABI: Added virtual emitGuardedInit() method for ABI abstraction
  • CIRGenItaniumCXXABI: Core implementation with guard variable creation
    • Follows Itanium C++ ABI specification
    • Guard variable mangling: _ZGVZ{function}E{variable}
    • Guard type: i64 (generic ABI) or i8 (internal linkage)
    • Zero-initialized with same linkage as guarded variable
  • CIRGenDecl: Integration at two call sites
    • Dynamic initialization (constant emission fails)
    • Constant init with non-trivial destructor

Lowering Implementation:

  • LoweringPrepare: Converts GuardedInitOp to control flow
  • Pattern: if (!guard) { init_code; guard = 1; }
  • Thread-safe guards marked as NYI (requires _cxa_guard* runtime calls)

Verifier:

  • Validates guard variable is pointer type
  • Ensures init_region has exactly one block
  • Confirms termination with cir.yield

Design Rationale

Follows ClangIR's deferred lowering principle:

  • CIRGen emits high-level GuardedInitOp with initialization semantics
  • LoweringPrepare handles platform-specific lowering
  • Enables future optimizations (e.g., guard elision)

Copies CodeGen structure from:

  • clang/lib/CodeGen/CGDecl.cpp:353-402 (AddInitializerToStaticVarDecl)
  • clang/lib/CodeGen/CGDeclCXX.cpp:176-232 (EmitCXXGlobalVarDeclInit)
  • clang/lib/CodeGen/ItaniumCXXABI.cpp:2691-2906 (EmitGuardedInit)

Testing

New Test:

  • clang/test/CIR/CodeGen/static-var-init.cpp
    • Tests CIR emission and LLVM lowering
    • Covers: destructor-only, dynamic init, constant init cases
    • Validates guard variable creation and initialization pattern

Crash Tests Fixed:

  • static-var-guarded-init.cpp - Static with non-trivial destructor
  • static-var-dyn-cast.cpp - Static with template constructor
  • Both updated with CHECK directives, XFAIL removed

Supported Cases

✅ Static variables with non-trivial destructors
✅ Static variables with dynamic initialization
✅ Static variables with constant init + non-trivial destructor
✅ Reference static variables
⏳ Thread-safe guards (NYI, marked for future work)

Itanium C++ ABI Compliance

Implements Section 3.3.2 "One-time construction API":

  • Guard variable semantics (first byte = initialization status)
  • Proper mangling for guard variables
  • Destructor registration via existing __cxa_atexit mechanism

Code Style

All code follows ClangIR standards:

  • CIRGen: camelBack for members/parameters/variables
  • Formatted with clang-format
  • Includes comprehensive comments explaining design

Future Work

Thread-safe guards (Phase 2):

  • Implement __cxa_guard_acquire/release/abort calls
  • Add atomic operations for guard variable access
  • Handle exception cleanup during initialization

Potential optimizations:

  • Guard elision when initialization proven safe
  • Constant folding for always-initialized cases
  • TLS optimization for thread-local statics

[ghstack-poisoned]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants