@@ -2851,128 +2851,89 @@ class CodegenContext {
28512851 wire : Wire ,
28522852 visited = new Set < string > ( ) ,
28532853 ) : number {
2854- return this . canResolveWireCheaply ( wire , visited ) ? 0 : 1 ;
2854+ // Optimistic cost — cost of the first source only.
2855+ return this . computeExprCost ( wire . sources [ 0 ] ! . expr , visited ) ;
28552856 }
28562857
2857- private canResolveWireCheaply (
2858- wire : Wire ,
2859- visited = new Set < string > ( ) ,
2860- ) : boolean {
2861- if ( isLit ( wire ) ) return true ;
2862-
2863- if ( isPull ( wire ) ) {
2864- if ( ! this . refIsZeroCost ( wRef ( wire ) , visited ) ) return false ;
2865- for ( const fallback of fallbacks ( wire ) ?? [ ] ) {
2866- if (
2867- eRef ( fallback . expr ) &&
2868- ! this . refIsZeroCost ( eRef ( fallback . expr ) , visited )
2869- ) {
2870- return false ;
2871- }
2872- }
2873- if ( catchRef ( wire ) && ! this . refIsZeroCost ( catchRef ( wire ) ! , visited ) ) {
2874- return false ;
2875- }
2876- return true ;
2858+ /**
2859+ * Pessimistic wire cost — sum of all source expression costs plus catch.
2860+ * Represents worst-case cost when all fallback sources fire.
2861+ */
2862+ private computeWireCost ( wire : Wire , visited : Set < string > ) : number {
2863+ let cost = 0 ;
2864+ for ( const source of wire . sources ) {
2865+ cost += this . computeExprCost ( source . expr , visited ) ;
28772866 }
2878-
2879- if ( isTern ( wire ) ) {
2880- if ( ! this . refIsZeroCost ( eRef ( wTern ( wire ) . cond ) , visited ) ) return false ;
2881- if (
2882- ( wTern ( wire ) . then as RefExpr ) . ref &&
2883- ! this . refIsZeroCost ( ( wTern ( wire ) . then as RefExpr ) . ref , visited )
2884- )
2885- return false ;
2886- if (
2887- ( wTern ( wire ) . else as RefExpr ) . ref &&
2888- ! this . refIsZeroCost ( ( wTern ( wire ) . else as RefExpr ) . ref , visited )
2889- )
2890- return false ;
2891- for ( const fallback of fallbacks ( wire ) ?? [ ] ) {
2892- if (
2893- eRef ( fallback . expr ) &&
2894- ! this . refIsZeroCost ( eRef ( fallback . expr ) , visited )
2895- ) {
2896- return false ;
2897- }
2898- }
2899- if ( catchRef ( wire ) && ! this . refIsZeroCost ( catchRef ( wire ) ! , visited ) ) {
2900- return false ;
2901- }
2902- return true ;
2903- }
2904-
2905- if ( isAndW ( wire ) ) {
2906- if ( ! this . refIsZeroCost ( eRef ( wAndOr ( wire ) . left ) , visited ) ) return false ;
2907- if (
2908- eRef ( wAndOr ( wire ) . right ) &&
2909- ! this . refIsZeroCost ( eRef ( wAndOr ( wire ) . right ) , visited )
2910- ) {
2911- return false ;
2912- }
2913- for ( const fallback of fallbacks ( wire ) ?? [ ] ) {
2914- if (
2915- eRef ( fallback . expr ) &&
2916- ! this . refIsZeroCost ( eRef ( fallback . expr ) , visited )
2917- ) {
2918- return false ;
2919- }
2920- }
2921- if ( catchRef ( wire ) && ! this . refIsZeroCost ( catchRef ( wire ) ! , visited ) ) {
2922- return false ;
2923- }
2924- return true ;
2867+ if ( catchRef ( wire ) ) {
2868+ cost += this . computeRefCost ( catchRef ( wire ) ! , visited ) ;
29252869 }
2870+ return cost ;
2871+ }
29262872
2927- if ( isOrW ( wire ) ) {
2928- if ( ! this . refIsZeroCost ( eRef ( wAndOr ( wire ) . left ) , visited ) ) return false ;
2929- if (
2930- eRef ( wAndOr ( wire ) . right ) &&
2931- ! this . refIsZeroCost ( eRef ( wAndOr ( wire ) . right ) , visited )
2932- ) {
2933- return false ;
2934- }
2935- for ( const fallback of fallbacks ( wire ) ?? [ ] ) {
2936- if (
2937- eRef ( fallback . expr ) &&
2938- ! this . refIsZeroCost ( eRef ( fallback . expr ) , visited )
2939- ) {
2940- return false ;
2941- }
2942- }
2943- if ( catchRef ( wire ) && ! this . refIsZeroCost ( catchRef ( wire ) ! , visited ) ) {
2944- return false ;
2945- }
2946- return true ;
2873+ private computeExprCost ( expr : Expression , visited : Set < string > ) : number {
2874+ switch ( expr . type ) {
2875+ case "literal" :
2876+ case "control" :
2877+ return 0 ;
2878+ case "ref" :
2879+ return this . computeRefCost ( expr . ref , visited ) ;
2880+ case "ternary" :
2881+ return Math . max (
2882+ this . computeExprCost ( expr . cond , visited ) ,
2883+ this . computeExprCost ( expr . then , visited ) ,
2884+ this . computeExprCost ( expr . else , visited ) ,
2885+ ) ;
2886+ case "and" :
2887+ case "or" :
2888+ return Math . max (
2889+ this . computeExprCost ( expr . left , visited ) ,
2890+ this . computeExprCost ( expr . right , visited ) ,
2891+ ) ;
29472892 }
2948-
2949- return false ;
29502893 }
29512894
2952- private refIsZeroCost ( ref : NodeRef , visited = new Set < string > ( ) ) : boolean {
2953- if ( ref . element ) return true ;
2895+ private computeRefCost ( ref : NodeRef , visited : Set < string > ) : number {
2896+ if ( ref . element ) return 0 ;
2897+ // Self-module input/context/const — free
29542898 if (
29552899 ref . module === SELF_MODULE &&
29562900 ( ( ref . type === this . bridge . type && ref . field === this . bridge . field ) ||
29572901 ( ref . type === "Context" && ref . field === "context" ) ||
29582902 ( ref . type === "Const" && ref . field === "const" ) )
29592903 ) {
2960- return true ;
2904+ return 0 ;
29612905 }
2962- if ( ref . module . startsWith ( "__define_" ) ) return false ;
29632906
29642907 const key = refTrunkKey ( ref ) ;
2965- if ( visited . has ( key ) ) return false ;
2908+ if ( visited . has ( key ) ) return Infinity ;
29662909 visited . add ( key ) ;
29672910
2911+ // Define — recursive, cheapest incoming wire wins
2912+ if ( ref . module . startsWith ( "__define_" ) ) {
2913+ const incoming = this . bridge . wires . filter (
2914+ ( wire ) => refTrunkKey ( wire . to ) === key ,
2915+ ) ;
2916+ let best = Infinity ;
2917+ for ( const wire of incoming ) {
2918+ best = Math . min ( best , this . computeWireCost ( wire , visited ) ) ;
2919+ }
2920+ return best === Infinity ? 2 : best ;
2921+ }
2922+
2923+ // Local alias — recursive, cheapest incoming wire wins
29682924 if ( ref . module === "__local" ) {
29692925 const incoming = this . bridge . wires . filter (
29702926 ( wire ) => refTrunkKey ( wire . to ) === key ,
29712927 ) ;
2972- return incoming . some ( ( wire ) => this . canResolveWireCheaply ( wire , visited ) ) ;
2928+ let best = Infinity ;
2929+ for ( const wire of incoming ) {
2930+ best = Math . min ( best , this . computeWireCost ( wire , visited ) ) ;
2931+ }
2932+ return best === Infinity ? 2 : best ;
29732933 }
29742934
2975- return false ;
2935+ // External tool — compiler has no metadata, default to async cost
2936+ return 2 ;
29762937 }
29772938
29782939 /**
0 commit comments