|
56 | 56 | KeepAlive, |
57 | 57 | LoadAddress, |
58 | 58 | LoadErrorValue, |
| 59 | + LoadGlobal, |
59 | 60 | LoadLiteral, |
60 | 61 | LoadMem, |
61 | 62 | LoadStatic, |
|
108 | 109 | is_int_rprimitive, |
109 | 110 | is_list_rprimitive, |
110 | 111 | is_none_rprimitive, |
| 112 | + is_object_rprimitive, |
111 | 113 | is_set_rprimitive, |
112 | 114 | is_short_int_rprimitive, |
113 | 115 | is_str_rprimitive, |
@@ -1318,6 +1320,14 @@ def none_object(self) -> Value: |
1318 | 1320 | """Load Python None value (type: object_rprimitive).""" |
1319 | 1321 | return self.add(LoadAddress(none_object_op.type, none_object_op.src, line=-1)) |
1320 | 1322 |
|
| 1323 | + def true_object(self) -> Value: |
| 1324 | + """Load Python True object (type: object_rprimitive).""" |
| 1325 | + return self.add(LoadGlobal(object_rprimitive, "Py_True")) |
| 1326 | + |
| 1327 | + def false_object(self) -> Value: |
| 1328 | + """Load Python False object (type: object_rprimitive).""" |
| 1329 | + return self.add(LoadGlobal(object_rprimitive, "Py_False")) |
| 1330 | + |
1321 | 1331 | def load_int(self, value: int) -> Value: |
1322 | 1332 | """Load a tagged (Python) integer literal value.""" |
1323 | 1333 | if value > MAX_LITERAL_SHORT_INT or value < MIN_LITERAL_SHORT_INT: |
@@ -1663,12 +1673,39 @@ def _non_specialized_unary_op(self, value: Value, op: str, line: int) -> Value: |
1663 | 1673 | assert target, "Unsupported unary operation: %s" % op |
1664 | 1674 | return target |
1665 | 1675 |
|
1666 | | - def unary_not(self, value: Value, line: int) -> Value: |
1667 | | - """Perform unary 'not'.""" |
| 1676 | + def unary_not(self, value: Value, line: int, *, likely_bool: bool = False) -> Value: |
| 1677 | + """Perform unary 'not'. |
| 1678 | +
|
| 1679 | + Args: |
| 1680 | + likely_bool: The operand is likely a bool value, even if the type is something |
| 1681 | + more general, so specialize for bool values |
| 1682 | + """ |
1668 | 1683 | typ = value.type |
1669 | 1684 | if is_bool_or_bit_rprimitive(typ): |
1670 | 1685 | mask = Integer(1, typ, line) |
1671 | 1686 | return self.int_op(typ, value, mask, IntOp.XOR, line) |
| 1687 | + if likely_bool and is_object_rprimitive(typ): |
| 1688 | + # First quickly check if it's a bool, and otherwise fall back to generic op. |
| 1689 | + res = Register(bit_rprimitive) |
| 1690 | + false, not_false, true, other = BasicBlock(), BasicBlock(), BasicBlock(), BasicBlock() |
| 1691 | + out = BasicBlock() |
| 1692 | + cmp = self.add(ComparisonOp(value, self.true_object(), ComparisonOp.EQ, line)) |
| 1693 | + self.add(Branch(cmp, false, not_false, Branch.BOOL)) |
| 1694 | + self.activate_block(false) |
| 1695 | + self.add(Assign(res, self.false())) |
| 1696 | + self.goto(out) |
| 1697 | + self.activate_block(not_false) |
| 1698 | + cmp = self.add(ComparisonOp(value, self.false_object(), ComparisonOp.EQ, line)) |
| 1699 | + self.add(Branch(cmp, true, other, Branch.BOOL)) |
| 1700 | + self.activate_block(true) |
| 1701 | + self.add(Assign(res, self.true())) |
| 1702 | + self.goto(out) |
| 1703 | + self.activate_block(other) |
| 1704 | + val = self._non_specialized_unary_op(value, "not", line) |
| 1705 | + self.add(Assign(res, val)) |
| 1706 | + self.goto(out) |
| 1707 | + self.activate_block(out) |
| 1708 | + return res |
1672 | 1709 | return self._non_specialized_unary_op(value, "not", line) |
1673 | 1710 |
|
1674 | 1711 | def unary_minus(self, value: Value, line: int) -> Value: |
|
0 commit comments