Skip to content

Commit b2073a0

Browse files
agattidpgeorge
authored andcommitted
py/emitinlinextensa: Refactor handling of selected opcodes.
This commit refactors handling of opcodes whose composition can be easily defined as an entry in a table, so there's only one bit of code handling those opcodes rather than several small bits with overlapping functionalities. Two opcodes, RER and WER have been added to that table for completeness, although they're gated behind the uncommon opcodes configuration define. Still, despite two new opcodes, the final binary is smaller by about 160 bytes. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent 71b6a85 commit b2073a0

1 file changed

Lines changed: 116 additions & 148 deletions

File tree

py/emitinlinextensa.c

Lines changed: 116 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -168,57 +168,79 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
168168
return 0;
169169
}
170170

171-
#define RRR (0)
172-
#define RRI8 (1)
173-
#define RRI8_B (2)
171+
static const qstr_short_t BRANCH_OPCODE_NAMES[] = {
172+
MP_QSTR_bnone, MP_QSTR_beq, MP_QSTR_blt, MP_QSTR_bltu, MP_QSTR_ball,
173+
MP_QSTR_bbc, MP_QSTR_, MP_QSTR_, MP_QSTR_bany, MP_QSTR_bne,
174+
MP_QSTR_bge, MP_QSTR_bgeu, MP_QSTR_bnall, MP_QSTR_bbs,
175+
};
176+
177+
#define RRR_R0 (1 << 4)
178+
#define RRR_R1 (2 << 4)
179+
#define RRR_R2 (3 << 4)
180+
181+
#define RRR (0)
182+
#define RRI8 (1)
174183

175-
typedef struct _opcode_table_3arg_t {
184+
static const struct opcode_entry_t {
176185
qstr_short_t name;
177-
uint8_t type;
178-
uint8_t a0 : 4;
179-
uint8_t a1 : 4;
180-
} opcode_table_3arg_t;
181-
182-
static const opcode_table_3arg_t opcode_table_3arg[] = {
183-
// arithmetic opcodes: reg, reg, reg
184-
{MP_QSTR_and_, RRR, 0, 1},
185-
{MP_QSTR_or_, RRR, 0, 2},
186-
{MP_QSTR_xor, RRR, 0, 3},
187-
{MP_QSTR_add, RRR, 0, 8},
188-
{MP_QSTR_sub, RRR, 0, 12},
189-
{MP_QSTR_mull, RRR, 2, 8},
190-
{MP_QSTR_addx2, RRR, 0, 9},
191-
{MP_QSTR_addx4, RRR, 0, 10},
192-
{MP_QSTR_addx8, RRR, 0, 11},
193-
{MP_QSTR_subx2, RRR, 0, 13},
194-
{MP_QSTR_subx4, RRR, 0, 14},
195-
{MP_QSTR_subx8, RRR, 0, 15},
196-
{MP_QSTR_src, RRR, 1, 8},
197-
198-
// load/store/addi opcodes: reg, reg, imm
199-
// upper nibble of type encodes the range of the immediate arg
200-
{MP_QSTR_l8ui, RRI8 | 0x10, 2, 0},
201-
{MP_QSTR_l16ui, RRI8 | 0x30, 2, 1},
202-
{MP_QSTR_l32i, RRI8 | 0x50, 2, 2},
203-
{MP_QSTR_s8i, RRI8 | 0x10, 2, 4},
204-
{MP_QSTR_s16i, RRI8 | 0x30, 2, 5},
205-
{MP_QSTR_s32i, RRI8 | 0x50, 2, 6},
206-
{MP_QSTR_l16si, RRI8 | 0x30, 2, 9},
207-
{MP_QSTR_addi, RRI8 | 0x00, 2, 12},
208-
209-
// branch opcodes: reg, reg, label
210-
{MP_QSTR_ball, RRI8_B, ASM_XTENSA_CC_ALL, 0},
211-
{MP_QSTR_bany, RRI8_B, ASM_XTENSA_CC_ANY, 0},
212-
{MP_QSTR_bbc, RRI8_B, ASM_XTENSA_CC_BC, 0},
213-
{MP_QSTR_bbs, RRI8_B, ASM_XTENSA_CC_BS, 0},
214-
{MP_QSTR_beq, RRI8_B, ASM_XTENSA_CC_EQ, 0},
215-
{MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0},
216-
{MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0},
217-
{MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0},
218-
{MP_QSTR_bltu, RRI8_B, ASM_XTENSA_CC_LTU, 0},
219-
{MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0},
220-
{MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0},
221-
{MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0},
186+
uint16_t operands : 2;
187+
uint16_t op2 : 4;
188+
uint16_t op1 : 4;
189+
uint16_t op0 : 4;
190+
// 2 bits available here
191+
uint32_t r : 6;
192+
uint32_t s : 6;
193+
uint32_t t : 6;
194+
uint32_t shift : 4;
195+
uint32_t kind : 1;
196+
// 13 bits available here
197+
} OPCODE_TABLE[] = {
198+
{ MP_QSTR_abs_, 2, 6, 0, 0, RRR_R0, 1, RRR_R1, 0, RRR },
199+
{ MP_QSTR_add, 3, 8, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
200+
{ MP_QSTR_addi, 3, 0, 0, 2, 12, RRR_R1, RRR_R0, 0, RRI8 },
201+
{ MP_QSTR_addx2, 3, 9, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
202+
{ MP_QSTR_addx4, 3, 10, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
203+
{ MP_QSTR_addx8, 3, 11, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
204+
{ MP_QSTR_and_, 3, 1, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
205+
{ MP_QSTR_callx0, 1, 0, 0, 0, 0, RRR_R0, 12, 0, RRR },
206+
{ MP_QSTR_jx, 1, 0, 0, 0, 0, RRR_R0, 10, 0, RRR },
207+
{ MP_QSTR_l16si, 3, 0, 0, 2, 9, RRR_R1, RRR_R0, 3, RRI8 },
208+
{ MP_QSTR_l16ui, 3, 0, 0, 2, 1, RRR_R1, RRR_R0, 3, RRI8 },
209+
{ MP_QSTR_l32i, 3, 0, 0, 2, 2, RRR_R1, RRR_R0, 5, RRI8 },
210+
{ MP_QSTR_l8ui, 3, 0, 0, 2, 0, RRR_R1, RRR_R0, 1, RRI8 },
211+
{ MP_QSTR_mull, 3, 8, 2, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
212+
{ MP_QSTR_neg, 2, 6, 0, 0, RRR_R0, 0, RRR_R1, 0, RRR },
213+
{ MP_QSTR_nop, 0, 0, 0, 0, 2, 0, 15, 0, RRR },
214+
{ MP_QSTR_nsa, 2, 4, 0, 0, 14, RRR_R1, RRR_R0, 0, RRR },
215+
{ MP_QSTR_nsau, 2, 4, 0, 0, 15, RRR_R1, RRR_R0, 0, RRR },
216+
{ MP_QSTR_or_, 3, 2, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
217+
{ MP_QSTR_s16i, 3, 0, 0, 2, 5, RRR_R1, RRR_R0, 3, RRI8 },
218+
{ MP_QSTR_s32i, 3, 0, 0, 2, 6, RRR_R1, RRR_R0, 5, RRI8 },
219+
{ MP_QSTR_s8i, 3, 0, 0, 2, 4, RRR_R1, RRR_R0, 1, RRI8 },
220+
{ MP_QSTR_sll, 2, 10, 1, 0, RRR_R0, RRR_R1, 0, 0, RRR },
221+
{ MP_QSTR_sra, 2, 11, 1, 0, RRR_R0, 0, RRR_R1, 0, RRR },
222+
{ MP_QSTR_src, 3, 8, 1, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
223+
{ MP_QSTR_srl, 2, 9, 1, 0, RRR_R0, 0, RRR_R1, 0, RRR },
224+
{ MP_QSTR_ssa8b, 1, 4, 0, 0, 3, RRR_R0, 0, 0, RRR },
225+
{ MP_QSTR_ssa8l, 1, 4, 0, 0, 2, RRR_R0, 0, 0, RRR },
226+
{ MP_QSTR_ssl, 1, 4, 0, 0, 1, RRR_R0, 0, 0, RRR },
227+
{ MP_QSTR_ssr, 1, 4, 0, 0, 0, RRR_R0, 0, 0, RRR },
228+
{ MP_QSTR_sub, 3, 12, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
229+
{ MP_QSTR_subx2, 3, 13, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
230+
{ MP_QSTR_subx4, 3, 14, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
231+
{ MP_QSTR_subx8, 3, 15, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
232+
{ MP_QSTR_xor, 3, 3, 0, 0, RRR_R0, RRR_R1, RRR_R2, 0, RRR },
233+
#if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
234+
{ MP_QSTR_dsync, 0, 0, 0, 0, 2, 0, 3, 0, RRR },
235+
{ MP_QSTR_esync, 0, 0, 0, 0, 2, 0, 2, 0, RRR },
236+
{ MP_QSTR_extw, 0, 0, 0, 0, 2, 0, 13, 0, RRR },
237+
{ MP_QSTR_ill, 0, 0, 0, 0, 2, 0, 0, 0, RRR },
238+
{ MP_QSTR_isync, 0, 0, 0, 0, 2, 0, 0, 0, RRR },
239+
{ MP_QSTR_memw, 0, 0, 0, 0, 2, 0, 12, 0, RRR },
240+
{ MP_QSTR_rer, 2, 4, 0, 0, 6, RRR_R1, RRR_R0, 0, RRR },
241+
{ MP_QSTR_rsync, 0, 0, 0, 0, 2, 0, 1, 0, RRR },
242+
{ MP_QSTR_wer, 2, 4, 0, 0, 7, RRR_R1, RRR_R0, 0, RRR },
243+
#endif
222244
};
223245

224246
// The index of the first four qstrs matches the CCZ condition value to be
@@ -228,75 +250,64 @@ static const qstr_short_t BCCZ_OPCODES[] = {
228250
MP_QSTR_beqz_n, MP_QSTR_bnez_n
229251
};
230252

231-
#if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
232-
typedef struct _single_opcode_t {
233-
qstr_short_t name;
234-
uint16_t value;
235-
} single_opcode_t;
236-
237-
static const single_opcode_t NOARGS_OPCODES[] = {
238-
{MP_QSTR_dsync, 0x2030},
239-
{MP_QSTR_esync, 0x2020},
240-
{MP_QSTR_extw, 0x20D0},
241-
{MP_QSTR_ill, 0x0000},
242-
{MP_QSTR_isync, 0x2000},
243-
{MP_QSTR_memw, 0x20C0},
244-
{MP_QSTR_rsync, 0x2010},
245-
};
246-
#endif
247-
248253
static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) {
249254
size_t op_len;
250255
const char *op_str = (const char *)qstr_data(op, &op_len);
251256

257+
for (size_t index = 0; index < MP_ARRAY_SIZE(OPCODE_TABLE); index++) {
258+
const struct opcode_entry_t *entry = &OPCODE_TABLE[index];
259+
if (entry->name == op) {
260+
if (n_args != entry->operands) {
261+
goto unknown_op;
262+
}
263+
264+
uint32_t op24 = ((entry->r & 0x0F) << 12) | ((entry->s & 0x0F) << 8) | ((entry->t & 0x0F) << 4) | entry->op0;
265+
if (entry->kind == RRR) {
266+
op24 |= (entry->op2 << 20) | (entry->op1 << 16);
267+
} else {
268+
int min = 0;
269+
int max = 0;
270+
int shift = entry->shift;
271+
if (shift > 0) {
272+
shift >>= 1;
273+
max = 0xFF << shift;
274+
} else {
275+
min = -128;
276+
max = 127;
277+
}
278+
uint32_t immediate = get_arg_i(emit, op_str, pn_args[2], min, max);
279+
op24 |= ((immediate >> shift) & 0xFF) << 16;
280+
}
281+
if (entry->r >= RRR_R0) {
282+
op24 |= get_arg_reg(emit, op_str, pn_args[(entry->r >> 4) - 1]) << 12;
283+
}
284+
if (entry->s >= RRR_R0) {
285+
op24 |= get_arg_reg(emit, op_str, pn_args[(entry->s >> 4) - 1]) << 8;
286+
}
287+
if (entry->t >= RRR_R0) {
288+
op24 |= get_arg_reg(emit, op_str, pn_args[(entry->t >> 4) - 1]) << 4;
289+
}
290+
asm_xtensa_op24(&emit->as, op24);
291+
return;
292+
}
293+
}
294+
252295
if (n_args == 0) {
253296
if (op == MP_QSTR_ret_n || op == MP_QSTR_ret) {
254297
asm_xtensa_op_ret_n(&emit->as);
255298
return;
256-
} else if (op == MP_QSTR_nop) {
257-
asm_xtensa_op24(&emit->as, 0x20F0);
258-
return;
259299
} else if (op == MP_QSTR_nop_n) {
260300
asm_xtensa_op16(&emit->as, 0xF03D);
261301
return;
262302
}
263-
#if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
264-
for (size_t index = 0; index < MP_ARRAY_SIZE(NOARGS_OPCODES); index++) {
265-
const single_opcode_t *opcode = &NOARGS_OPCODES[index];
266-
if (op == opcode->name) {
267-
asm_xtensa_op24(&emit->as, opcode->value);
268-
return;
269-
}
270-
}
271-
#endif
272-
273303
goto unknown_op;
274-
275304
} else if (n_args == 1) {
276-
if (op == MP_QSTR_callx0) {
277-
uint r0 = get_arg_reg(emit, op_str, pn_args[0]);
278-
asm_xtensa_op_callx0(&emit->as, r0);
279-
} else if (op == MP_QSTR_j) {
305+
if (op == MP_QSTR_j) {
280306
int label = get_arg_label(emit, op_str, pn_args[0]);
281307
asm_xtensa_j_label(&emit->as, label);
282-
} else if (op == MP_QSTR_jx) {
283-
uint r0 = get_arg_reg(emit, op_str, pn_args[0]);
284-
asm_xtensa_op_jx(&emit->as, r0);
285-
} else if (op == MP_QSTR_ssl) {
286-
mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
287-
asm_xtensa_op_ssl(&emit->as, r0);
288-
} else if (op == MP_QSTR_ssr) {
289-
mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
290-
asm_xtensa_op_ssr(&emit->as, r0);
291308
} else if (op == MP_QSTR_ssai) {
292309
mp_uint_t sa = get_arg_i(emit, op_str, pn_args[0], 0, 31);
293310
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 4, sa & 0x0F, (sa >> 4) & 0x01));
294-
} else if (op == MP_QSTR_ssa8b) {
295-
mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
296-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 3, r0, 0));
297-
} else if (op == MP_QSTR_ssa8l) {
298-
mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
299-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 2, r0, 0));
300311
} else if (op == MP_QSTR_call0) {
301312
mp_uint_t label = get_arg_label(emit, op_str, pn_args[0]);
302313
asm_xtensa_call0(&emit->as, label);
@@ -310,7 +321,6 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
310321
} else {
311322
goto unknown_op;
312323
}
313-
314324
} else if (n_args == 2) {
315325
uint r0 = get_arg_reg(emit, op_str, pn_args[0]);
316326
for (size_t index = 0; index < MP_ARRAY_SIZE(BCCZ_OPCODES); index++) {
@@ -328,27 +338,6 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
328338
// for convenience we emit l32r if the integer doesn't fit in movi
329339
uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0);
330340
asm_xtensa_mov_reg_i32(&emit->as, r0, imm);
331-
} else if (op == MP_QSTR_abs_) {
332-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
333-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 1, r1));
334-
} else if (op == MP_QSTR_neg) {
335-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
336-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 0, r1));
337-
} else if (op == MP_QSTR_sll) {
338-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
339-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, r0, r1, 0));
340-
} else if (op == MP_QSTR_sra) {
341-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
342-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, r0, 0, r1));
343-
} else if (op == MP_QSTR_srl) {
344-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
345-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 9, r0, 0, r1));
346-
} else if (op == MP_QSTR_nsa) {
347-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
348-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 14, r1, r0));
349-
} else if (op == MP_QSTR_nsau) {
350-
mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
351-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 15, r1, r0));
352341
} else if (op == MP_QSTR_l32r) {
353342
mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]);
354343
asm_xtensa_l32r(&emit->as, r0, label);
@@ -377,34 +366,13 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
377366
{
378367
goto unknown_op;
379368
}
380-
381369
} else if (n_args == 3) {
382-
// search table for 3 arg instructions
383-
for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) {
384-
const opcode_table_3arg_t *o = &opcode_table_3arg[i];
385-
if (op == o->name) {
386-
uint r0 = get_arg_reg(emit, op_str, pn_args[0]);
387-
uint r1 = get_arg_reg(emit, op_str, pn_args[1]);
388-
if (o->type == RRR) {
389-
uint r2 = get_arg_reg(emit, op_str, pn_args[2]);
390-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2));
391-
} else if (o->type == RRI8_B) {
392-
int label = get_arg_label(emit, op_str, pn_args[2]);
393-
asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label);
394-
} else {
395-
int shift, min, max;
396-
if ((o->type & 0xf0) == 0) {
397-
shift = 0;
398-
min = -128;
399-
max = 127;
400-
} else {
401-
shift = (o->type & 0xf0) >> 5;
402-
min = 0;
403-
max = 0xff << shift;
404-
}
405-
uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max);
406-
asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff));
407-
}
370+
for (size_t index = 0; index < MP_ARRAY_SIZE(BRANCH_OPCODE_NAMES); index++) {
371+
if (BRANCH_OPCODE_NAMES[index] == op) {
372+
int r0 = get_arg_reg(emit, op_str, pn_args[0]);
373+
int r1 = get_arg_reg(emit, op_str, pn_args[1]);
374+
int label = get_arg_label(emit, op_str, pn_args[2]);
375+
asm_xtensa_bcc_reg_reg_label(&emit->as, index, r0, r1, label);
408376
return;
409377
}
410378
}

0 commit comments

Comments
 (0)