Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Optimize constant iterable before GET_ITER to LOAD_CONST tuple
Convert BUILD_LIST/SET 0 + LOAD_CONST + LIST_EXTEND/SET_UPDATE + GET_ITER
to just LOAD_CONST (tuple) + GET_ITER, matching CPython's optimization
for constant list/set literals in for-loop iterables.

Also fix is_name_imported to use method mode for function-local imports,
and improve __static_attributes__ accuracy (skip @classmethod/@staticmethod,
handle tuple/list unpacking targets).
  • Loading branch information
youknowone committed Mar 25, 2026
commit d1641dd9c7d4f3134ae55ca39c540d3f135ba50a
45 changes: 45 additions & 0 deletions crates/codegen/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ impl CodeInfo {
self.fold_tuple_constants();
self.fold_list_constants();
self.fold_set_constants();
self.remove_nops(); // remove NOPs from folding before iterable optimization
self.fold_const_iterable_for_iter();
self.convert_to_load_small_int();
self.remove_unused_consts();
self.remove_nops();
Expand Down Expand Up @@ -878,6 +880,49 @@ impl CodeInfo {
}
}

/// Convert constant list/set construction before GET_ITER to just LOAD_CONST tuple.
/// BUILD_LIST 0 + LOAD_CONST (tuple) + LIST_EXTEND 1 + GET_ITER
/// → LOAD_CONST (tuple) + GET_ITER
/// Also handles BUILD_SET 0 + LOAD_CONST + SET_UPDATE 1 + GET_ITER.
fn fold_const_iterable_for_iter(&mut self) {
for block in &mut self.blocks {
let mut i = 0;
while i + 3 < block.instructions.len() {
let is_build = matches!(
block.instructions[i].instr.real(),
Some(Instruction::BuildList { .. } | Instruction::BuildSet { .. })
) && u32::from(block.instructions[i].arg) == 0;

let is_const = matches!(
block.instructions[i + 1].instr.real(),
Some(Instruction::LoadConst { .. })
);

let is_extend = matches!(
block.instructions[i + 2].instr.real(),
Some(Instruction::ListExtend { .. } | Instruction::SetUpdate { .. })
) && u32::from(block.instructions[i + 2].arg) == 1;

let is_iter = matches!(
block.instructions[i + 3].instr.real(),
Some(Instruction::GetIter)
);

if is_build && is_const && is_extend && is_iter {
// Replace: BUILD_X 0 → NOP, keep LOAD_CONST, LIST_EXTEND → NOP
let loc = block.instructions[i].location;
block.instructions[i].instr = Instruction::Nop.into();
block.instructions[i].location = loc;
block.instructions[i + 2].instr = Instruction::Nop.into();
block.instructions[i + 2].location = loc;
i += 4;
} else {
i += 1;
}
}
}
}

/// Fold constant set literals: LOAD_CONST* + BUILD_SET N →
/// BUILD_SET 0 + LOAD_CONST (frozenset-as-tuple) + SET_UPDATE 1
fn fold_set_constants(&mut self) {
Expand Down