|
| 1 | +"""Convert tagged int primitive ops to lower-level ops.""" |
| 2 | + |
1 | 3 | from __future__ import annotations
|
2 | 4 |
|
3 |
| -from mypyc.ir.ops import Value |
| 5 | +from typing import NamedTuple |
| 6 | + |
| 7 | +from mypyc.ir.ops import Assign, BasicBlock, Branch, ComparisonOp, Register, Value |
| 8 | +from mypyc.ir.rtypes import bool_rprimitive, is_short_int_rprimitive |
4 | 9 | from mypyc.irbuild.ll_builder import LowLevelIRBuilder
|
5 | 10 | from mypyc.lower.registry import lower_binary_op
|
| 11 | +from mypyc.primitives.int_ops import int_equal_, int_less_than_ |
| 12 | +from mypyc.primitives.registry import CFunctionDescription |
| 13 | + |
| 14 | + |
| 15 | +# Description for building int comparison ops |
| 16 | +# |
| 17 | +# Fields: |
| 18 | +# binary_op_variant: identify which IntOp to use when operands are short integers |
| 19 | +# c_func_description: the C function to call when operands are tagged integers |
| 20 | +# c_func_negated: whether to negate the C function call's result |
| 21 | +# c_func_swap_operands: whether to swap lhs and rhs when call the function |
| 22 | +class IntComparisonOpDescription(NamedTuple): |
| 23 | + binary_op_variant: int |
| 24 | + c_func_description: CFunctionDescription |
| 25 | + c_func_negated: bool |
| 26 | + c_func_swap_operands: bool |
| 27 | + |
| 28 | + |
| 29 | +# Provide mapping from textual op to short int's op variant and boxed int's description. |
| 30 | +# Note that these are not complete implementations and require extra IR. |
| 31 | +int_comparison_op_mapping: dict[str, IntComparisonOpDescription] = { |
| 32 | + "==": IntComparisonOpDescription(ComparisonOp.EQ, int_equal_, False, False), |
| 33 | + "!=": IntComparisonOpDescription(ComparisonOp.NEQ, int_equal_, True, False), |
| 34 | + "<": IntComparisonOpDescription(ComparisonOp.SLT, int_less_than_, False, False), |
| 35 | + "<=": IntComparisonOpDescription(ComparisonOp.SLE, int_less_than_, True, True), |
| 36 | + ">": IntComparisonOpDescription(ComparisonOp.SGT, int_less_than_, False, True), |
| 37 | + ">=": IntComparisonOpDescription(ComparisonOp.SGE, int_less_than_, True, False), |
| 38 | +} |
| 39 | + |
| 40 | + |
| 41 | +def compare_tagged(self: LowLevelIRBuilder, lhs: Value, rhs: Value, op: str, line: int) -> Value: |
| 42 | + """Compare two tagged integers using given operator (value context).""" |
| 43 | + # generate fast binary logic ops on short ints |
| 44 | + if (is_short_int_rprimitive(lhs.type) or is_short_int_rprimitive(rhs.type)) and op in ( |
| 45 | + "==", |
| 46 | + "!=", |
| 47 | + ): |
| 48 | + quick = True |
| 49 | + else: |
| 50 | + quick = is_short_int_rprimitive(lhs.type) and is_short_int_rprimitive(rhs.type) |
| 51 | + if quick: |
| 52 | + return self.comparison_op(lhs, rhs, int_comparison_op_mapping[op][0], line) |
| 53 | + op_type, c_func_desc, negate_result, swap_op = int_comparison_op_mapping[op] |
| 54 | + result = Register(bool_rprimitive) |
| 55 | + short_int_block, int_block, out = BasicBlock(), BasicBlock(), BasicBlock() |
| 56 | + check_lhs = self.check_tagged_short_int(lhs, line, negated=True) |
| 57 | + if op in ("==", "!="): |
| 58 | + self.add(Branch(check_lhs, int_block, short_int_block, Branch.BOOL)) |
| 59 | + else: |
| 60 | + # for non-equality logical ops (less/greater than, etc.), need to check both sides |
| 61 | + short_lhs = BasicBlock() |
| 62 | + self.add(Branch(check_lhs, int_block, short_lhs, Branch.BOOL)) |
| 63 | + self.activate_block(short_lhs) |
| 64 | + check_rhs = self.check_tagged_short_int(rhs, line, negated=True) |
| 65 | + self.add(Branch(check_rhs, int_block, short_int_block, Branch.BOOL)) |
| 66 | + self.activate_block(int_block) |
| 67 | + if swap_op: |
| 68 | + args = [rhs, lhs] |
| 69 | + else: |
| 70 | + args = [lhs, rhs] |
| 71 | + call = self.call_c(c_func_desc, args, line) |
| 72 | + if negate_result: |
| 73 | + # TODO: introduce UnaryIntOp? |
| 74 | + call_result = self.unary_op(call, "not", line) |
| 75 | + else: |
| 76 | + call_result = call |
| 77 | + self.add(Assign(result, call_result, line)) |
| 78 | + self.goto(out) |
| 79 | + self.activate_block(short_int_block) |
| 80 | + eq = self.comparison_op(lhs, rhs, op_type, line) |
| 81 | + self.add(Assign(result, eq, line)) |
| 82 | + self.goto_and_activate(out) |
| 83 | + return result |
6 | 84 |
|
7 | 85 |
|
8 | 86 | @lower_binary_op("int_eq")
|
9 | 87 | def lower_int_eq(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
10 |
| - return builder.compare_tagged(args[0], args[1], "==", line) |
| 88 | + return compare_tagged(builder, args[0], args[1], "==", line) |
11 | 89 |
|
12 | 90 |
|
13 | 91 | @lower_binary_op("int_ne")
|
14 | 92 | def lower_int_ne(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
15 |
| - return builder.compare_tagged(args[0], args[1], "!=", line) |
| 93 | + return compare_tagged(builder, args[0], args[1], "!=", line) |
16 | 94 |
|
17 | 95 |
|
18 | 96 | @lower_binary_op("int_lt")
|
19 | 97 | def lower_int_lt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
20 |
| - return builder.compare_tagged(args[0], args[1], "<", line) |
| 98 | + return compare_tagged(builder, args[0], args[1], "<", line) |
21 | 99 |
|
22 | 100 |
|
23 | 101 | @lower_binary_op("int_le")
|
24 | 102 | def lower_int_le(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
25 |
| - return builder.compare_tagged(args[0], args[1], "<=", line) |
| 103 | + return compare_tagged(builder, args[0], args[1], "<=", line) |
26 | 104 |
|
27 | 105 |
|
28 | 106 | @lower_binary_op("int_gt")
|
29 | 107 | def lower_int_gt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
30 |
| - return builder.compare_tagged(args[0], args[1], ">", line) |
| 108 | + return compare_tagged(builder, args[0], args[1], ">", line) |
31 | 109 |
|
32 | 110 |
|
33 | 111 | @lower_binary_op("int_ge")
|
34 | 112 | def lower_int_ge(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
35 |
| - return builder.compare_tagged(args[0], args[1], ">=", line) |
| 113 | + return compare_tagged(builder, args[0], args[1], ">=", line) |
0 commit comments