Skip to main content

luaur_compiler/methods/
compiler_compile_expr_binary.rs

1use crate::enums::type_constant_folding::Type;
2use crate::records::compiler::Compiler;
3use crate::records::constant::Constant;
4use crate::records::reg_scope::RegScope;
5use luaur_ast::records::ast_expr_binary::{AstExprBinary, AstExprBinaryOp};
6use luaur_common::enums::luau_bytecode_type::LuauBytecodeType;
7use luaur_common::enums::luau_opcode::LuauOpcode;
8use luaur_common::macros::luau_assert::LUAU_ASSERT;
9
10impl Compiler {
11    pub fn compile_expr_binary(
12        &mut self,
13        expr: *mut AstExprBinary,
14        target: u8,
15        _target_temp: bool,
16    ) {
17        unsafe {
18            let expr_ref = &*expr;
19            let mut rs = self.reg_scope_compiler();
20
21            match expr_ref.op {
22                AstExprBinaryOp::Add
23                | AstExprBinaryOp::Sub
24                | AstExprBinaryOp::Mul
25                | AstExprBinaryOp::Div
26                | AstExprBinaryOp::FloorDiv
27                | AstExprBinaryOp::Mod
28                | AstExprBinaryOp::Pow => {
29                    let rc = self.get_constant_number(expr_ref.right);
30                    if rc >= 0 && rc <= 255 {
31                        let rl = self.compile_expr_auto(expr_ref.left, &mut rs);
32                        (*self.bytecode).emit_abc(
33                            self.get_binary_op_arith(expr_ref.op, true),
34                            target,
35                            rl,
36                            rc as u8,
37                        );
38                        self.hint_temporary_expr_reg_type(
39                            expr_ref.left,
40                            rl as i32,
41                            LuauBytecodeType(2),
42                            1,
43                        );
44                    } else {
45                        if expr_ref.op == AstExprBinaryOp::Sub
46                            || expr_ref.op == AstExprBinaryOp::Div
47                        {
48                            let lc = self.get_constant_number(expr_ref.left);
49                            if lc >= 0 && lc <= 255 {
50                                let rr = self.compile_expr_auto(expr_ref.right, &mut rs);
51                                let op = if expr_ref.op == AstExprBinaryOp::Sub {
52                                    LuauOpcode::LOP_SUBRK
53                                } else {
54                                    LuauOpcode::LOP_DIVRK
55                                };
56                                (*self.bytecode).emit_abc(op, target, lc as u8, rr);
57                                self.hint_temporary_expr_reg_type(
58                                    expr_ref.right,
59                                    rr as i32,
60                                    LuauBytecodeType(2),
61                                    1,
62                                );
63                                return;
64                            }
65                        } else if self.options.optimization_level >= 2
66                            && (expr_ref.op == AstExprBinaryOp::Add
67                                || expr_ref.op == AstExprBinaryOp::Mul)
68                        {
69                            // Optimization: replace k*r with r*k when r is known to be a number (otherwise
70                            // metamethods may be called). For vectors this only makes sense for multiplication
71                            // since number+vector is an error.
72                            if let Some(ty) = self
73                                .expr_types
74                                .find(&(expr as *mut luaur_ast::records::ast_expr::AstExpr))
75                                .copied()
76                            {
77                                if ty == LuauBytecodeType(2)
78                                    || (ty == LuauBytecodeType(8)
79                                        && expr_ref.op == AstExprBinaryOp::Mul)
80                                {
81                                    let lc = self.get_constant_number(expr_ref.left);
82                                    if lc >= 0 && lc <= 255 {
83                                        let rr = self.compile_expr_auto(expr_ref.right, &mut rs);
84                                        (*self.bytecode).emit_abc(
85                                            self.get_binary_op_arith(expr_ref.op, true),
86                                            target,
87                                            rr,
88                                            lc as u8,
89                                        );
90                                        self.hint_temporary_expr_reg_type(
91                                            expr_ref.right,
92                                            rr as i32,
93                                            LuauBytecodeType(2),
94                                            1,
95                                        );
96                                        return;
97                                    }
98                                }
99                            }
100                        }
101                        let rl = self.compile_expr_auto(expr_ref.left, &mut rs);
102                        let rr = self.compile_expr_auto(expr_ref.right, &mut rs);
103                        (*self.bytecode).emit_abc(
104                            self.get_binary_op_arith(expr_ref.op, false),
105                            target,
106                            rl,
107                            rr,
108                        );
109                        self.hint_temporary_expr_reg_type(
110                            expr_ref.left,
111                            rl as i32,
112                            LuauBytecodeType(2),
113                            1,
114                        );
115                        self.hint_temporary_expr_reg_type(
116                            expr_ref.right,
117                            rr as i32,
118                            LuauBytecodeType(2),
119                            1,
120                        );
121                    }
122                }
123                AstExprBinaryOp::Concat => {
124                    let mut args = vec![expr_ref.left, expr_ref.right];
125                    self.unroll_concats(&mut args);
126                    let regs = self.alloc_reg(expr as *mut _, args.len() as u32);
127                    for (i, &arg) in args.iter().enumerate() {
128                        self.compile_expr_temp(arg, regs + i as u8);
129                    }
130                    (*self.bytecode).emit_abc(
131                        LuauOpcode::LOP_CONCAT,
132                        target,
133                        regs,
134                        regs + args.len() as u8 - 1,
135                    );
136                }
137                AstExprBinaryOp::CompareNe
138                | AstExprBinaryOp::CompareEq
139                | AstExprBinaryOp::CompareLt
140                | AstExprBinaryOp::CompareLe
141                | AstExprBinaryOp::CompareGt
142                | AstExprBinaryOp::CompareGe => {
143                    let jump_label = self.compile_compare_jump(expr, false);
144                    (*self.bytecode).emit_abc(LuauOpcode::LOP_LOADB, target, 0, 1);
145                    let then_label = (*self.bytecode).emit_label();
146                    (*self.bytecode).emit_abc(LuauOpcode::LOP_LOADB, target, 1, 0);
147                    self.patch_jump(expr as *mut _, jump_label, then_label);
148                }
149                AstExprBinaryOp::And | AstExprBinaryOp::Or => {
150                    self.compile_expr_and_or(expr, target, _target_temp);
151                }
152                _ => LUAU_ASSERT!(false),
153            }
154        }
155    }
156}