Skip to content

Commit 3c445f6

Browse files
committed
py/emitnative: Implement viper unary ops positive, negative and invert.
Signed-off-by: Damien George <damien@micropython.org>
1 parent b50efbd commit 3c445f6

5 files changed

Lines changed: 74 additions & 11 deletions

File tree

py/emitnative.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,15 +2259,38 @@ static void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool with
22592259
}
22602260

22612261
static void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
2262-
vtype_kind_t vtype;
2263-
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
2264-
if (vtype == VTYPE_PYOBJ) {
2262+
vtype_kind_t vtype = peek_vtype(emit, 0);
2263+
if (vtype == VTYPE_INT || vtype == VTYPE_UINT) {
2264+
if (op == MP_UNARY_OP_POSITIVE) {
2265+
// No-operation, just leave the argument on the stack.
2266+
} else if (op == MP_UNARY_OP_NEGATIVE) {
2267+
int reg = REG_RET;
2268+
emit_pre_pop_reg_flexible(emit, &vtype, &reg, reg, reg);
2269+
ASM_NEG_REG(emit->as, reg);
2270+
emit_post_push_reg(emit, vtype, reg);
2271+
} else if (op == MP_UNARY_OP_INVERT) {
2272+
#ifdef ASM_NOT_REG
2273+
int reg = REG_RET;
2274+
emit_pre_pop_reg_flexible(emit, &vtype, &reg, reg, reg);
2275+
ASM_NOT_REG(emit->as, reg);
2276+
#else
2277+
int reg = REG_RET;
2278+
emit_pre_pop_reg_flexible(emit, &vtype, &reg, REG_ARG_1, reg);
2279+
ASM_MOV_REG_IMM(emit->as, REG_ARG_1, -1);
2280+
ASM_XOR_REG_REG(emit->as, reg, REG_ARG_1);
2281+
#endif
2282+
emit_post_push_reg(emit, vtype, reg);
2283+
} else {
2284+
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2285+
MP_ERROR_TEXT("'not' not implemented"), mp_binary_op_method_name[op]);
2286+
}
2287+
} else if (vtype == VTYPE_PYOBJ) {
2288+
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
22652289
emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1);
22662290
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
22672291
} else {
2268-
adjust_stack(emit, 1);
22692292
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2270-
MP_ERROR_TEXT("unary op %q not implemented"), mp_unary_op_method_name[op]);
2293+
MP_ERROR_TEXT("can't do unary op of '%q'"), vtype_to_qstr(vtype));
22712294
}
22722295
}
22732296

tests/micropython/viper_error.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def f():
5050
# incorrect return type
5151
test("@micropython.viper\ndef f() -> int: return []")
5252

53+
# can't do unary op of incompatible type
54+
test("@micropython.viper\ndef f(x:ptr): -x")
55+
5356
# can't do binary op between incompatible types
5457
test("@micropython.viper\ndef f(): 1 + []")
5558
test("@micropython.viper\ndef f(x:int, y:uint): x < y")
@@ -69,9 +72,7 @@ def f():
6972
test("@micropython.viper\ndef f(): raise 1")
7073

7174
# unary ops not implemented
72-
test("@micropython.viper\ndef f(x:int): +x")
73-
test("@micropython.viper\ndef f(x:int): -x")
74-
test("@micropython.viper\ndef f(x:int): ~x")
75+
test("@micropython.viper\ndef f(x:int): not x")
7576

7677
# binary op not implemented
7778
test("@micropython.viper\ndef f(x:uint, y:uint): res = x // y")

tests/micropython/viper_error.py.exp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ ViperTypeError("local 'x' used before type known",)
55
ViperTypeError("local 'x' has type 'int' but source is 'object'",)
66
ViperTypeError("can't implicitly convert 'ptr' to 'bool'",)
77
ViperTypeError("return expected 'int' but got 'object'",)
8+
ViperTypeError("can't do unary op of 'ptr'",)
89
ViperTypeError("can't do binary op between 'int' and 'object'",)
910
ViperTypeError('comparison of int and uint',)
1011
ViperTypeError("can't load from 'int'",)
@@ -15,9 +16,7 @@ ViperTypeError("can't store to 'int'",)
1516
ViperTypeError("can't store 'None'",)
1617
ViperTypeError("can't store 'None'",)
1718
ViperTypeError('must raise an object',)
18-
ViperTypeError('unary op __pos__ not implemented',)
19-
ViperTypeError('unary op __neg__ not implemented',)
20-
ViperTypeError('unary op __invert__ not implemented',)
19+
ViperTypeError("'not' not implemented",)
2120
ViperTypeError('div/mod not implemented for uint',)
2221
ViperTypeError('div/mod not implemented for uint',)
2322
ViperTypeError('binary op not implemented',)

tests/micropython/viper_unop.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# test unary operators
2+
3+
4+
@micropython.viper
5+
def pos(x: int) -> int:
6+
return +x
7+
8+
9+
print(pos(0))
10+
print(pos(1))
11+
print(pos(-2))
12+
13+
14+
@micropython.viper
15+
def neg(x: int) -> int:
16+
return -x
17+
18+
19+
print(neg(0))
20+
print(neg(1))
21+
print(neg(-2))
22+
23+
24+
@micropython.viper
25+
def inv(x: int) -> int:
26+
return ~x
27+
28+
29+
print(inv(0))
30+
print(inv(1))
31+
print(inv(-2))
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
0
2+
1
3+
-2
4+
0
5+
-1
6+
2
7+
-1
8+
-2
9+
1

0 commit comments

Comments
 (0)