Skip to content

Commit 89f2728

Browse files
Merge pull request #565 from theseus-rs/optimize-jit-lookupswitch
refactor: optimize jit lookupswitch instruction
2 parents 197acb8 + 729a895 commit 89f2728

File tree

1 file changed

+16
-30
lines changed

1 file changed

+16
-30
lines changed

ristretto_jit/src/instruction/branch.rs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::control_flow_graph::append_block_params;
44
use crate::instruction::TRAP_INTERNAL_ERROR;
55
use crate::local_variables::LocalVariables;
66
use crate::operand_stack::OperandStack;
7-
use cranelift::frontend::FunctionBuilder;
7+
use cranelift::frontend::{FunctionBuilder, Switch};
88
use cranelift::prelude::{Block, InstBuilder, IntCC, TrapCode, Value, types};
99
use ristretto_classfile::attributes::{LookupSwitch, TableSwitch};
1010
use std::collections::HashMap;
@@ -622,43 +622,29 @@ pub(crate) fn lookupswitch(
622622
program_counter: usize,
623623
lookup_switch: &LookupSwitch,
624624
) -> Result<()> {
625-
// TODO: evaluate if the lookup switch can be optimized to a jump table.
626625
let index = stack.pop()?;
627-
let block_arguments = stack.as_block_arguments();
628-
let stack_types = stack.to_type_vec(function_builder);
629-
630-
for (&index_value, &offset) in &lookup_switch.pairs {
631-
let else_block = function_builder.create_block();
632-
append_block_params(function_builder, else_block, &stack_types);
633-
634-
// PC = start of tableswitch + offset (signed arithmetic)
635-
let target_address = usize::try_from(i32::try_from(program_counter)?.wrapping_add(offset))?;
636-
let block = *blocks
626+
// Create a Switch for efficient jump table generation; Cranelift will optimize it to use
627+
// branches, jump tables, or a combination of both
628+
let mut switch = Switch::new();
629+
630+
for (case_value, offset) in &lookup_switch.pairs {
631+
let target_address =
632+
usize::try_from(i32::try_from(program_counter)?.saturating_add(*offset))?;
633+
let target_block = *blocks
637634
.get(&target_address)
638635
.ok_or_else(|| InvalidBlockAddress(target_address))?;
639-
let index_value = i64::from(index_value);
640-
let block_address = function_builder.ins().iconst(types::I32, index_value);
641-
let condition_value = function_builder
642-
.ins()
643-
.icmp(IntCC::Equal, index, block_address);
644-
function_builder.ins().brif(
645-
condition_value,
646-
block,
647-
&block_arguments,
648-
else_block,
649-
&block_arguments,
650-
);
651-
function_builder.switch_to_block(else_block);
636+
637+
let case_value = u128::try_from(*case_value)?;
638+
switch.set_entry(case_value, target_block);
652639
}
653640

654-
// PC = start of tableswitch + default (signed arithmetic)
655641
let default_address =
656-
usize::try_from(i32::try_from(program_counter)?.wrapping_add(lookup_switch.default))?;
657-
let block = blocks
642+
usize::try_from(i32::try_from(program_counter)?.saturating_add(lookup_switch.default))?;
643+
let default_block = *blocks
658644
.get(&default_address)
659645
.ok_or_else(|| InvalidBlockAddress(default_address))?;
660-
let block_arguments = stack.as_block_arguments();
661-
function_builder.ins().jump(*block, &block_arguments);
646+
647+
switch.emit(function_builder, index, default_block);
662648
stack.reset(function_builder)?;
663649
Ok(())
664650
}

0 commit comments

Comments
 (0)