@@ -14764,6 +14764,54 @@ def f(buffer, pos, last_char):
1476414764 })
1476514765 }
1476614766
14767+ fn non_cache_instructions(code: &CodeObject) -> impl Iterator<Item = &CodeUnit> {
14768+ code.instructions
14769+ .iter()
14770+ .filter(|unit| !matches!(unit.op, Instruction::Cache))
14771+ }
14772+
14773+ fn varname_index(code: &CodeObject, name: &str) -> usize {
14774+ code.varnames
14775+ .iter()
14776+ .position(|varname| varname.as_str() == name)
14777+ .unwrap_or_else(|| panic!("missing {name} local"))
14778+ }
14779+
14780+ fn load_fast_ops_for_var(code: &CodeObject, name: &str) -> Vec<Instruction> {
14781+ let var_idx = varname_index(code, name);
14782+ non_cache_instructions(code)
14783+ .filter_map(|unit| match unit.op {
14784+ Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
14785+ let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
14786+ (usize::from(var_num) == var_idx).then_some(unit.op)
14787+ }
14788+ _ => None,
14789+ })
14790+ .collect()
14791+ }
14792+
14793+ fn count_strong_loads_for_vars(code: &CodeObject, names: &[&str]) -> usize {
14794+ let var_indices = names
14795+ .iter()
14796+ .map(|name| varname_index(code, name))
14797+ .collect::<Vec<_>>();
14798+ non_cache_instructions(code)
14799+ .filter(|unit| match unit.op {
14800+ Instruction::LoadFast { var_num } => {
14801+ let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
14802+ var_indices.contains(&usize::from(var_num))
14803+ }
14804+ _ => false,
14805+ })
14806+ .count()
14807+ }
14808+
14809+ fn count_strong_loads(code: &CodeObject) -> usize {
14810+ non_cache_instructions(code)
14811+ .filter(|unit| matches!(unit.op, Instruction::LoadFast { .. }))
14812+ .count()
14813+ }
14814+
1476714815 fn localsplus_name(code: &CodeObject, idx: usize) -> Option<&str> {
1476814816 if idx < code.varnames.len() {
1476914817 return Some(code.varnames[idx].as_str());
@@ -15241,23 +15289,7 @@ def f(running, errors):
1524115289",
1524215290 );
1524315291 let f = find_code(&code, "f").expect("missing function code");
15244- let errors_idx = f
15245- .varnames
15246- .iter()
15247- .position(|name| name.as_str() == "errors")
15248- .expect("missing errors local");
15249- let errors_loads = f
15250- .instructions
15251- .iter()
15252- .filter(|unit| !matches!(unit.op, Instruction::Cache))
15253- .filter_map(|unit| match unit.op {
15254- Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
15255- let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
15256- (usize::from(var_num) == errors_idx).then_some(unit.op)
15257- }
15258- _ => None,
15259- })
15260- .collect::<Vec<_>>();
15292+ let errors_loads = load_fast_ops_for_var(f, "errors");
1526115293 assert!(
1526215294 errors_loads
1526315295 .iter()
@@ -15284,23 +15316,7 @@ def f(self, cm, value):
1528415316",
1528515317 );
1528615318 let f = find_code(&code, "f").expect("missing function code");
15287- let value_idx = f
15288- .varnames
15289- .iter()
15290- .position(|name| name.as_str() == "value")
15291- .expect("missing value local");
15292- let value_loads = f
15293- .instructions
15294- .iter()
15295- .filter(|unit| !matches!(unit.op, Instruction::Cache))
15296- .filter_map(|unit| match unit.op {
15297- Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
15298- let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
15299- (usize::from(var_num) == value_idx).then_some(unit.op)
15300- }
15301- _ => None,
15302- })
15303- .collect::<Vec<_>>();
15319+ let value_loads = load_fast_ops_for_var(f, "value");
1530415320 assert!(
1530515321 value_loads
1530615322 .iter()
@@ -15336,28 +15352,7 @@ def f(test_cases):
1533615352",
1533715353 );
1533815354 let f = find_code(&code, "f").expect("missing function code");
15339- let src_idx = f
15340- .varnames
15341- .iter()
15342- .position(|name| name.as_str() == "src")
15343- .expect("missing src local");
15344- let dest_idx = f
15345- .varnames
15346- .iter()
15347- .position(|name| name.as_str() == "dest")
15348- .expect("missing dest local");
15349- let strong_src_dest_loads = f
15350- .instructions
15351- .iter()
15352- .filter(|unit| !matches!(unit.op, Instruction::Cache))
15353- .filter(|unit| match unit.op {
15354- Instruction::LoadFast { var_num } => {
15355- let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
15356- usize::from(var_num) == src_idx || usize::from(var_num) == dest_idx
15357- }
15358- _ => false,
15359- })
15360- .count();
15355+ let strong_src_dest_loads = count_strong_loads_for_vars(f, &["src", "dest"]);
1536115356 assert!(
1536215357 strong_src_dest_loads >= 2,
1536315358 "CPython codegen_try_except() emits orelse then USE_LABEL(end) before the following loop try, so optimize_load_fast() leaves fsencode arguments strong; got {strong_src_dest_loads} strong src/dest loads"
@@ -15387,28 +15382,7 @@ def f(self, f, cm):
1538715382",
1538815383 );
1538915384 let f_code = find_code(&code, "f").expect("missing function code");
15390- let self_idx = f_code
15391- .varnames
15392- .iter()
15393- .position(|name| name.as_str() == "self")
15394- .expect("missing self local");
15395- let f_idx = f_code
15396- .varnames
15397- .iter()
15398- .position(|name| name.as_str() == "f")
15399- .expect("missing f local");
15400- let strong_self_or_f_loads = f_code
15401- .instructions
15402- .iter()
15403- .filter(|unit| !matches!(unit.op, Instruction::Cache))
15404- .filter(|unit| match unit.op {
15405- Instruction::LoadFast { var_num } => {
15406- let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
15407- usize::from(var_num) == self_idx || usize::from(var_num) == f_idx
15408- }
15409- _ => false,
15410- })
15411- .count();
15385+ let strong_self_or_f_loads = count_strong_loads_for_vars(f_code, &["self", "f"]);
1541215386 assert!(
1541315387 strong_self_or_f_loads >= 2,
1541415388 "CPython codegen_try_except() emits orelse with nested with cleanup before USE_LABEL(end), so optimize_load_fast() leaves loads in the following try/else strong; got {strong_self_or_f_loads} strong self/f loads"
@@ -15432,12 +15406,7 @@ def f(self, cm):
1543215406",
1543315407 );
1543415408 let f = find_code(&code, "f").expect("missing function code");
15435- let strong_loads = f
15436- .instructions
15437- .iter()
15438- .filter(|unit| !matches!(unit.op, Instruction::Cache))
15439- .filter(|unit| matches!(unit.op, Instruction::LoadFast { .. }))
15440- .count();
15409+ let strong_loads = count_strong_loads(f);
1544115410 assert!(
1544215411 strong_loads >= 3,
1544315412 "CPython codegen_try_finally() inlines a finalbody with codegen_with_inner() cleanup before the with exit label, so optimize_load_fast() leaves successor loads strong; got {strong_loads} strong loads"
0 commit comments