iter 23.3.2-fixup: emit_compare_ladder helper + drop unused test param
This commit is contained in:
@@ -2519,31 +2519,10 @@ impl<'a> Emitter<'a> {
|
||||
let n = self.locals.len();
|
||||
let a_ssa = self.locals[n - 2].1.clone();
|
||||
let b_ssa = self.locals[n - 1].1.clone();
|
||||
let lt_test = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {lt_test} = icmp slt i64 {a_ssa}, {b_ssa}\n"
|
||||
));
|
||||
let id = self.fresh_id();
|
||||
let lt_label = format!("cmp_lt_{id}");
|
||||
let after_lt_label = format!("cmp_after_lt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {lt_test}, label %{lt_label}, label %{after_lt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(<_label, "LT")?;
|
||||
self.start_block(&after_lt_label);
|
||||
let eq_test = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {eq_test} = icmp eq i64 {a_ssa}, {b_ssa}\n"
|
||||
));
|
||||
let eq_label = format!("cmp_eq_{id}");
|
||||
let gt_label = format!("cmp_gt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {eq_test}, label %{eq_label}, label %{gt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(&eq_label, "EQ")?;
|
||||
self.emit_ordering_arm(>_label, "GT")?;
|
||||
self.body.push_str("}\n\n");
|
||||
self.block_terminated = true;
|
||||
self.emit_compare_ladder(
|
||||
&format!("icmp slt i64 {a_ssa}, {b_ssa}"),
|
||||
&format!("icmp eq i64 {a_ssa}, {b_ssa}"),
|
||||
)?;
|
||||
Ok(true)
|
||||
}
|
||||
"compare__Bool" => {
|
||||
@@ -2556,31 +2535,10 @@ impl<'a> Emitter<'a> {
|
||||
let n = self.locals.len();
|
||||
let a_ssa = self.locals[n - 2].1.clone();
|
||||
let b_ssa = self.locals[n - 1].1.clone();
|
||||
let lt_test = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {lt_test} = icmp ult i1 {a_ssa}, {b_ssa}\n"
|
||||
));
|
||||
let id = self.fresh_id();
|
||||
let lt_label = format!("cmp_lt_{id}");
|
||||
let after_lt_label = format!("cmp_after_lt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {lt_test}, label %{lt_label}, label %{after_lt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(<_label, "LT")?;
|
||||
self.start_block(&after_lt_label);
|
||||
let eq_test = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {eq_test} = icmp eq i1 {a_ssa}, {b_ssa}\n"
|
||||
));
|
||||
let eq_label = format!("cmp_eq_{id}");
|
||||
let gt_label = format!("cmp_gt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {eq_test}, label %{eq_label}, label %{gt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(&eq_label, "EQ")?;
|
||||
self.emit_ordering_arm(>_label, "GT")?;
|
||||
self.body.push_str("}\n\n");
|
||||
self.block_terminated = true;
|
||||
self.emit_compare_ladder(
|
||||
&format!("icmp ult i1 {a_ssa}, {b_ssa}"),
|
||||
&format!("icmp eq i1 {a_ssa}, {b_ssa}"),
|
||||
)?;
|
||||
Ok(true)
|
||||
}
|
||||
"compare__Str" => {
|
||||
@@ -2597,31 +2555,10 @@ impl<'a> Emitter<'a> {
|
||||
self.body.push_str(&format!(
|
||||
" {cmp_res} = call i32 @ail_str_compare(ptr {a_ssa}, ptr {b_ssa})\n"
|
||||
));
|
||||
let lt_test = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {lt_test} = icmp slt i32 {cmp_res}, 0\n"
|
||||
));
|
||||
let id = self.fresh_id();
|
||||
let lt_label = format!("cmp_lt_{id}");
|
||||
let after_lt_label = format!("cmp_after_lt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {lt_test}, label %{lt_label}, label %{after_lt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(<_label, "LT")?;
|
||||
self.start_block(&after_lt_label);
|
||||
let eq_test = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {eq_test} = icmp eq i32 {cmp_res}, 0\n"
|
||||
));
|
||||
let eq_label = format!("cmp_eq_{id}");
|
||||
let gt_label = format!("cmp_gt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {eq_test}, label %{eq_label}, label %{gt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(&eq_label, "EQ")?;
|
||||
self.emit_ordering_arm(>_label, "GT")?;
|
||||
self.body.push_str("}\n\n");
|
||||
self.block_terminated = true;
|
||||
self.emit_compare_ladder(
|
||||
&format!("icmp slt i32 {cmp_res}, 0"),
|
||||
&format!("icmp eq i32 {cmp_res}, 0"),
|
||||
)?;
|
||||
Ok(true)
|
||||
}
|
||||
_ => Ok(false),
|
||||
@@ -2653,6 +2590,52 @@ impl<'a> Emitter<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Iter 23.3: emit the labelled three-way branch ladder shared
|
||||
/// across all three `compare__T` intercept arms. Given two
|
||||
/// instruction RHS strings (the LT-test and the EQ-test, e.g.
|
||||
/// `"icmp slt i64 %a, %b"`), assigns each to a fresh SSA, wires
|
||||
/// them into LT-block / EQ-block / GT-block via
|
||||
/// `emit_ordering_arm`, and closes the fn body. The EQ-test
|
||||
/// must be emitted INSIDE the `after_lt_label` block (not before
|
||||
/// the LT-branch), so the helper takes the RHS as a string and
|
||||
/// performs the SSA assignment itself at the correct point. The
|
||||
/// two test instructions vary per arm (`icmp slt i64` /
|
||||
/// `icmp ult i1` / `icmp slt i32` etc.); any per-arm prep
|
||||
/// (e.g. `compare__Str`'s `@ail_str_compare` call) must be
|
||||
/// emitted by the caller before invoking this helper.
|
||||
fn emit_compare_ladder(
|
||||
&mut self,
|
||||
lt_test_instr: &str,
|
||||
eq_test_instr: &str,
|
||||
) -> Result<()> {
|
||||
let lt_test_ssa = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {lt_test_ssa} = {lt_test_instr}\n"
|
||||
));
|
||||
let id = self.fresh_id();
|
||||
let lt_label = format!("cmp_lt_{id}");
|
||||
let after_lt_label = format!("cmp_after_lt_{id}");
|
||||
let eq_label = format!("cmp_eq_{id}");
|
||||
let gt_label = format!("cmp_gt_{id}");
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {lt_test_ssa}, label %{lt_label}, label %{after_lt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(<_label, "LT")?;
|
||||
self.start_block(&after_lt_label);
|
||||
let eq_test_ssa = self.fresh_ssa();
|
||||
self.body.push_str(&format!(
|
||||
" {eq_test_ssa} = {eq_test_instr}\n"
|
||||
));
|
||||
self.body.push_str(&format!(
|
||||
" br i1 {eq_test_ssa}, label %{eq_label}, label %{gt_label}\n"
|
||||
));
|
||||
self.emit_ordering_arm(&eq_label, "EQ")?;
|
||||
self.emit_ordering_arm(>_label, "GT")?;
|
||||
self.body.push_str("}\n\n");
|
||||
self.block_terminated = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Iter 16e: lower a `==` call after the two operands have been
|
||||
/// emitted. Dispatches on the resolved AIL type of the arg side
|
||||
/// (both sides have the same type after typecheck). The `_a_ll`
|
||||
@@ -3849,7 +3832,7 @@ mod tests {
|
||||
/// the test does not depend on prelude auto-injection.
|
||||
#[test]
|
||||
fn compare_int_mono_symbol_emits_branch_ladder() {
|
||||
let m = synth_compare_module("compare__Int", Type::int(), "i64");
|
||||
let m = synth_compare_module("compare__Int", Type::int());
|
||||
let ir = emit_ir(&m).unwrap();
|
||||
assert!(
|
||||
ir.contains("icmp slt i64"),
|
||||
@@ -3866,7 +3849,7 @@ mod tests {
|
||||
/// Bool ordering false < true); the EQ-test uses `icmp eq i1`.
|
||||
#[test]
|
||||
fn compare_bool_mono_symbol_emits_branch_ladder() {
|
||||
let m = synth_compare_module("compare__Bool", Type::bool_(), "i1");
|
||||
let m = synth_compare_module("compare__Bool", Type::bool_());
|
||||
let ir = emit_ir(&m).unwrap();
|
||||
assert!(
|
||||
ir.contains("icmp ult i1"),
|
||||
@@ -3883,7 +3866,7 @@ mod tests {
|
||||
/// else GT.
|
||||
#[test]
|
||||
fn compare_str_mono_symbol_emits_ail_str_compare_call() {
|
||||
let m = synth_compare_module("compare__Str", Type::str_(), "ptr");
|
||||
let m = synth_compare_module("compare__Str", Type::str_());
|
||||
let ir = emit_ir(&m).unwrap();
|
||||
assert!(
|
||||
ir.contains("call i32 @ail_str_compare("),
|
||||
@@ -3904,7 +3887,7 @@ mod tests {
|
||||
/// instance-fn shell (the intercept overrides the body), and the
|
||||
/// entry module's `main` is a Unit no-op so `emit_ir` returns a
|
||||
/// well-formed program. Used by the three `compare_*` tests above.
|
||||
fn synth_compare_module(fn_name: &str, param_ail_ty: Type, _llvm_param_ty: &str) -> Module {
|
||||
fn synth_compare_module(fn_name: &str, param_ail_ty: Type) -> Module {
|
||||
let ordering = Def::Type(TypeDef {
|
||||
name: "Ordering".into(),
|
||||
vars: vec![],
|
||||
|
||||
Reference in New Issue
Block a user