From 86f8719b697be7d6a353432f20495155d07b2754 Mon Sep 17 00:00:00 2001 From: Diego Reis Date: Wed, 2 Apr 2025 09:14:01 -0300 Subject: [PATCH 1/2] core/expr: Extract binary insn emission in a separate function --- core/translate/expr.rs | 470 +++++++++++++++++++++-------------------- 1 file changed, 241 insertions(+), 229 deletions(-) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index a66be0519..feee903b2 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -500,235 +500,7 @@ pub fn translate_expr( translate_expr(program, referenced_tables, e1, e1_reg, resolver)?; translate_expr(program, referenced_tables, e2, e2_reg, resolver)?; - match op { - ast::Operator::NotEquals => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr_zero_or_null( - program, - Insn::Ne { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default(), - }, - target_register, - if_true_label, - e1_reg, - e2_reg, - ); - } - ast::Operator::Equals => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr_zero_or_null( - program, - Insn::Eq { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default(), - }, - target_register, - if_true_label, - e1_reg, - e2_reg, - ); - } - ast::Operator::Less => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr_zero_or_null( - program, - Insn::Lt { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default(), - }, - target_register, - if_true_label, - e1_reg, - e2_reg, - ); - } - ast::Operator::LessEquals => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr_zero_or_null( - program, - Insn::Le { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default(), - }, - target_register, - if_true_label, - e1_reg, - e2_reg, - ); - } - ast::Operator::Greater => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr_zero_or_null( - program, - Insn::Gt { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default(), - }, - target_register, - if_true_label, - e1_reg, - e2_reg, - ); - } - ast::Operator::GreaterEquals => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr_zero_or_null( - program, - Insn::Ge { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default(), - }, - target_register, - if_true_label, - e1_reg, - e2_reg, - ); - } - ast::Operator::Add => { - program.emit_insn(Insn::Add { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::Subtract => { - program.emit_insn(Insn::Subtract { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::Multiply => { - program.emit_insn(Insn::Multiply { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::Divide => { - program.emit_insn(Insn::Divide { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::Modulus => { - program.emit_insn(Insn::Remainder { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::And => { - program.emit_insn(Insn::And { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::Or => { - program.emit_insn(Insn::Or { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::BitwiseAnd => { - program.emit_insn(Insn::BitAnd { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::BitwiseOr => { - program.emit_insn(Insn::BitOr { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::RightShift => { - program.emit_insn(Insn::ShiftRight { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::LeftShift => { - program.emit_insn(Insn::ShiftLeft { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - ast::Operator::Is => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr( - program, - Insn::Eq { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default().null_eq(), - }, - target_register, - if_true_label, - ); - } - ast::Operator::IsNot => { - let if_true_label = program.allocate_label(); - wrap_eval_jump_expr( - program, - Insn::Ne { - lhs: e1_reg, - rhs: e2_reg, - target_pc: if_true_label, - flags: CmpInsFlags::default().null_eq(), - }, - target_register, - if_true_label, - ); - } - #[cfg(feature = "json")] - op @ (ast::Operator::ArrowRight | ast::Operator::ArrowRightShift) => { - let json_func = match op { - ast::Operator::ArrowRight => JsonFunc::JsonArrowExtract, - ast::Operator::ArrowRightShift => JsonFunc::JsonArrowShiftExtract, - _ => unreachable!(), - }; - - program.emit_insn(Insn::Function { - constant_mask: 0, - start_reg: e1_reg, - dest: target_register, - func: FuncCtx { - func: Func::Json(json_func), - arg_count: 2, - }, - }) - } - ast::Operator::Concat => { - program.emit_insn(Insn::Concat { - lhs: e1_reg, - rhs: e2_reg, - dest: target_register, - }); - } - other_unimplemented => todo!("{:?}", other_unimplemented), - } + emit_binary_insn(program, op, e1_reg, e2_reg, target_register)?; Ok(target_register) } ast::Expr::Case { @@ -2141,6 +1913,246 @@ pub fn translate_expr( } } +fn emit_binary_insn( + program: &mut ProgramBuilder, + op: &ast::Operator, + lhs: usize, + rhs: usize, + target_register: usize, +) -> Result<()> { + match op { + ast::Operator::NotEquals => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr_zero_or_null( + program, + Insn::Ne { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default(), + }, + target_register, + if_true_label, + lhs, + rhs, + ); + } + ast::Operator::Equals => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr_zero_or_null( + program, + Insn::Eq { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default(), + }, + target_register, + if_true_label, + lhs, + rhs, + ); + } + ast::Operator::Less => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr_zero_or_null( + program, + Insn::Lt { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default(), + }, + target_register, + if_true_label, + lhs, + rhs, + ); + } + ast::Operator::LessEquals => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr_zero_or_null( + program, + Insn::Le { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default(), + }, + target_register, + if_true_label, + lhs, + rhs, + ); + } + ast::Operator::Greater => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr_zero_or_null( + program, + Insn::Gt { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default(), + }, + target_register, + if_true_label, + lhs, + rhs, + ); + } + ast::Operator::GreaterEquals => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr_zero_or_null( + program, + Insn::Ge { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default(), + }, + target_register, + if_true_label, + lhs, + rhs, + ); + } + ast::Operator::Add => { + program.emit_insn(Insn::Add { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::Subtract => { + program.emit_insn(Insn::Subtract { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::Multiply => { + program.emit_insn(Insn::Multiply { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::Divide => { + program.emit_insn(Insn::Divide { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::Modulus => { + program.emit_insn(Insn::Remainder { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::And => { + program.emit_insn(Insn::And { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::Or => { + program.emit_insn(Insn::Or { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::BitwiseAnd => { + program.emit_insn(Insn::BitAnd { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::BitwiseOr => { + program.emit_insn(Insn::BitOr { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::RightShift => { + program.emit_insn(Insn::ShiftRight { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::LeftShift => { + program.emit_insn(Insn::ShiftLeft { + lhs, + rhs, + dest: target_register, + }); + } + ast::Operator::Is => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr( + program, + Insn::Eq { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default().null_eq(), + }, + target_register, + if_true_label, + ); + } + ast::Operator::IsNot => { + let if_true_label = program.allocate_label(); + wrap_eval_jump_expr( + program, + Insn::Ne { + lhs, + rhs, + target_pc: if_true_label, + flags: CmpInsFlags::default().null_eq(), + }, + target_register, + if_true_label, + ); + } + #[cfg(feature = "json")] + op @ (ast::Operator::ArrowRight | ast::Operator::ArrowRightShift) => { + let json_func = match op { + ast::Operator::ArrowRight => JsonFunc::JsonArrowExtract, + ast::Operator::ArrowRightShift => JsonFunc::JsonArrowShiftExtract, + _ => unreachable!(), + }; + + program.emit_insn(Insn::Function { + constant_mask: 0, + start_reg: lhs, + dest: target_register, + func: FuncCtx { + func: Func::Json(json_func), + arg_count: 2, + }, + }) + } + ast::Operator::Concat => { + program.emit_insn(Insn::Concat { + lhs, + rhs, + dest: target_register, + }); + } + other_unimplemented => todo!("{:?}", other_unimplemented), + } + + Ok(()) +} + /// The base logic for translating LIKE and GLOB expressions. /// The logic for handling "NOT LIKE" is different depending on whether the expression /// is a conditional jump or not. This is why the caller handles the "NOT LIKE" behavior; From 3c531ac5ec8ee707b7fec487b1430edf036b0b97 Mon Sep 17 00:00:00 2001 From: Diego Reis Date: Wed, 2 Apr 2025 09:15:41 -0300 Subject: [PATCH 2/2] core/expr: Reuse register in binary expressions if they're equal --- core/translate/expr.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/translate/expr.rs b/core/translate/expr.rs index feee903b2..cd384391a 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -494,6 +494,15 @@ pub fn translate_expr( match expr { ast::Expr::Between { .. } => todo!(), ast::Expr::Binary(e1, op, e2) => { + // Check if both sides of the expression are identical and reuse the same register if so + if e1 == e2 { + let shared_reg = program.alloc_register(); + translate_expr(program, referenced_tables, e1, shared_reg, resolver)?; + + emit_binary_insn(program, op, shared_reg, shared_reg, target_register)?; + return Ok(target_register); + } + let e1_reg = program.alloc_registers(2); let e2_reg = e1_reg + 1;