@@ -13,13 +13,14 @@ use crate::ir::{
1313 ProtoForBound , ProtoForRange , ProtoForStatement , ProtoStatement , ProtoSystemFunctionCall ,
1414 VarOffset , native_bytes, veryl_aot_sysfn_print,
1515} ;
16+ use crate :: { HashMap , HashSet } ;
1617use std:: cell:: RefCell ;
17- use std:: collections:: { HashMap , HashSet } ;
1818use std:: ffi:: c_void;
1919use std:: fs;
2020use std:: io:: ErrorKind ;
2121use std:: path:: { Path , PathBuf } ;
2222use std:: process:: { Command , Stdio } ;
23+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
2324use std:: sync:: mpsc:: Sender ;
2425use std:: sync:: { Arc , Mutex , OnceLock } ;
2526use std:: thread;
@@ -270,22 +271,43 @@ fn reset_wide_tmp() {
270271}
271272
272273// ---------------------------------------------------------------------------
273- // Chunk-local comb intermediate localization (VERYL_AOT_C_LOCALIZE, default on,
274- // `=0` to opt out). A comb scalar written and read only within its emit chunk
275- // is kept in a C local instead of round-tripping `comb_values` (gcc can't drop
276- // the store — escaping restrict param — but the emitter's global read-set can).
274+ // Chunk-local comb intermediate localization (on by default;
275+ // `VERYL_AOT_C_LOCALIZE=0` or `force_disable_localize` opts out). A comb
276+ // scalar written and read only within its emit chunk is kept in a C local
277+ // instead of round-tripping `comb_values` (gcc can't drop the store —
278+ // escaping restrict param — but the emitter's global read-set can).
277279// Soundness: localize only a signal (a) written by one top-level unconditional
278280// full-width scalar (≤64-bit) Assign, (b) read only in that chunk, (c) not
279281// blocklisted (event-read / array-range / partial-write / port). Blocklist
280282// built in `module.rs`.
283+
284+ /// Set by [`force_disable_localize`]; latches on and is never cleared, so
285+ /// localization can only ever be turned off, never back on.
286+ static LOCALIZE_FORCED_OFF : AtomicBool = AtomicBool :: new ( false ) ;
287+
288+ /// Whether chunk-local localization runs: on unless `VERYL_AOT_C_LOCALIZE=0`
289+ /// or a caller turned it off for the process.
290+ pub fn localize_enabled ( ) -> bool {
291+ if LOCALIZE_FORCED_OFF . load ( Ordering :: Relaxed ) {
292+ return false ;
293+ }
294+ std:: env:: var ( "VERYL_AOT_C_LOCALIZE" ) . as_deref ( ) != Ok ( "0" )
295+ }
296+
297+ /// Latch the process-wide off switch; `super::force_disable_localize` is the
298+ /// public entry point and carries the rationale.
299+ pub fn force_disable_localize ( ) {
300+ LOCALIZE_FORCED_OFF . store ( true , Ordering :: Relaxed ) ;
301+ }
302+
281303thread_local ! {
282304 /// Comb offsets the caller marked unsafe to localize (read outside the
283305 /// comb function / dynamically / partial-written / port-visible).
284306 static LOCALIZE_BLOCKLIST : RefCell <HashSet <isize >> =
285- RefCell :: new( HashSet :: new ( ) ) ;
307+ RefCell :: new( HashSet :: default ( ) ) ;
286308 /// Comb offsets localized in the chunk currently being emitted.
287309 static CURRENT_LOCAL : RefCell <HashSet <isize >> =
288- RefCell :: new( HashSet :: new ( ) ) ;
310+ RefCell :: new( HashSet :: default ( ) ) ;
289311 /// Runtime-indexed comb array ranges (base, num_elements, stride) — a
290312 /// candidate offset inside any of these is excluded (a constant-indexed
291313 /// element could be read dynamically by an event / another statement).
@@ -687,7 +709,7 @@ fn compute_localize_sets(
687709 a. walk_stmt ( s, i, true ) ;
688710 }
689711 }
690- let mut sets: Vec < HashSet < isize > > = vec ! [ HashSet :: new ( ) ; chunks. len( ) ] ;
712+ let mut sets: Vec < HashSet < isize > > = vec ! [ HashSet :: default ( ) ; chunks. len( ) ] ;
691713 for ( off, wc) in & a. write_chunk {
692714 let Some ( i) = wc else { continue } ;
693715 if a. bad . contains ( off)
@@ -3389,7 +3411,7 @@ pub fn emit_function(stmts: &[ProtoStatement]) -> Option<String> {
33893411 } ) ;
33903412 sets
33913413 } else {
3392- vec ! [ HashSet :: new ( ) ; chunks. len( ) ]
3414+ vec ! [ HashSet :: default ( ) ; chunks. len( ) ]
33933415 } ;
33943416 clear_current_local ( ) ;
33953417 let mut chunk_bodies: Vec < String > = Vec :: with_capacity ( chunks. len ( ) ) ;
0 commit comments