|
1 | 1 | use core::alloc::Allocator; |
2 | 2 |
|
3 | | -use super::{ApproxCost, StatementCostVec}; |
| 3 | +use super::{ApproxCost, Cost, StatementCostVec}; |
4 | 4 | use crate::{ |
5 | 5 | body::basic_block::{BasicBlock, BasicBlockId, BasicBlockSlice, BasicBlockVec}, |
6 | 6 | pass::{ |
@@ -124,7 +124,7 @@ impl<A: Allocator> BasicBlockCostAnalysis<'_, A> { |
124 | 124 | let load = range |
125 | 125 | .saturating_mul(config.target_multiplier[target].get()) |
126 | 126 | .midpoint() |
127 | | - .map_or(ApproxCost::INF, From::from); |
| 127 | + .map_or_else(|| ApproxCost::from(Cost::MAX), ApproxCost::from); |
128 | 128 |
|
129 | 129 | BasicBlockTargetCost { base, load } |
130 | 130 | } |
@@ -511,6 +511,45 @@ mod tests { |
511 | 511 | assert!(interpreter_cost > interpreter_base); |
512 | 512 | } |
513 | 513 |
|
| 514 | + /// Unbounded transfer-size estimates should stay expensive but finite, so they remain |
| 515 | + /// valid candidates for solver search. |
| 516 | + #[test] |
| 517 | + fn unbounded_path_premium_stays_finite() { |
| 518 | + let heap = Heap::new(); |
| 519 | + let interner = Interner::new(&heap); |
| 520 | + let env = Environment::new(&heap); |
| 521 | + |
| 522 | + let body = body!(interner, env; [graph::read::filter]@0/2 -> ? { |
| 523 | + decl env: (), vertex: [Opaque sym::path::Entity; ?], val: ?; |
| 524 | + @proj properties = vertex.properties: ?; |
| 525 | + |
| 526 | + bb0() { |
| 527 | + val = load properties; |
| 528 | + return val; |
| 529 | + } |
| 530 | + }); |
| 531 | + |
| 532 | + let targets = make_targets(&body, all_targets()); |
| 533 | + let targets = BasicBlockSlice::from_raw(&targets); |
| 534 | + |
| 535 | + let costs: TargetArray<StatementCostVec<Global>> = |
| 536 | + TargetArray::from_fn(|_| StatementCostVec::from_iter([1].into_iter(), Global)); |
| 537 | + |
| 538 | + let analysis = BasicBlockCostAnalysis { |
| 539 | + vertex: VertexType::Entity, |
| 540 | + assignments: targets, |
| 541 | + costs: &costs, |
| 542 | + }; |
| 543 | + |
| 544 | + let result = analysis.analyze_in(&default_config(), &body.basic_blocks, Global); |
| 545 | + let bb0 = BasicBlockId::new(0); |
| 546 | + |
| 547 | + let interpreter_cost = result.cost(bb0, TargetId::Interpreter); |
| 548 | + let interpreter_base = costs[TargetId::Interpreter].sum_approx(bb0); |
| 549 | + assert!(interpreter_cost > interpreter_base); |
| 550 | + assert!(interpreter_cost.is_finite()); |
| 551 | + } |
| 552 | + |
514 | 553 | /// Paths across multiple blocks are analyzed independently per block. |
515 | 554 | #[test] |
516 | 555 | fn paths_across_blocks_independent() { |
|
0 commit comments