mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
gh-105481: add pseudo-instructions to the bytecodes DSL (#105506)
This commit is contained in:
parent
20a56d8bec
commit
58f5227d7c
8 changed files with 507 additions and 267 deletions
|
@ -4,6 +4,7 @@
|
||||||
#include "pycore_code.h" // write_location_entry_start()
|
#include "pycore_code.h" // write_location_entry_start()
|
||||||
#include "pycore_compile.h"
|
#include "pycore_compile.h"
|
||||||
#include "pycore_opcode.h" // _PyOpcode_Caches[] and opcode category macros
|
#include "pycore_opcode.h" // _PyOpcode_Caches[] and opcode category macros
|
||||||
|
#include "opcode_metadata.h" // IS_PSEUDO_INSTR
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_CODE_SIZE 128
|
#define DEFAULT_CODE_SIZE 128
|
||||||
|
@ -338,7 +339,8 @@ static void
|
||||||
write_instr(_Py_CODEUNIT *codestr, instruction *instr, int ilen)
|
write_instr(_Py_CODEUNIT *codestr, instruction *instr, int ilen)
|
||||||
{
|
{
|
||||||
int opcode = instr->i_opcode;
|
int opcode = instr->i_opcode;
|
||||||
assert(!IS_PSEUDO_OPCODE(opcode));
|
assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode));
|
||||||
|
assert(!IS_PSEUDO_INSTR(opcode));
|
||||||
int oparg = instr->i_oparg;
|
int oparg = instr->i_oparg;
|
||||||
assert(HAS_ARG(opcode) || oparg == 0);
|
assert(HAS_ARG(opcode) || oparg == 0);
|
||||||
int caches = _PyOpcode_Caches[opcode];
|
int caches = _PyOpcode_Caches[opcode];
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#define macro(name) static int MACRO_##name
|
#define macro(name) static int MACRO_##name
|
||||||
#define super(name) static int SUPER_##name
|
#define super(name) static int SUPER_##name
|
||||||
#define family(name, ...) static int family_##name
|
#define family(name, ...) static int family_##name
|
||||||
|
#define pseudo(name) static int pseudo_##name
|
||||||
|
|
||||||
// Dummy variables for stack effects.
|
// Dummy variables for stack effects.
|
||||||
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
|
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
|
||||||
|
@ -218,6 +219,10 @@ dummy_func(
|
||||||
SETLOCAL(oparg, value);
|
SETLOCAL(oparg, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pseudo(STORE_FAST_MAYBE_NULL) = {
|
||||||
|
STORE_FAST,
|
||||||
|
};
|
||||||
|
|
||||||
inst(STORE_FAST_LOAD_FAST, (value1 -- value2)) {
|
inst(STORE_FAST_LOAD_FAST, (value1 -- value2)) {
|
||||||
uint32_t oparg1 = oparg >> 4;
|
uint32_t oparg1 = oparg >> 4;
|
||||||
uint32_t oparg2 = oparg & 15;
|
uint32_t oparg2 = oparg & 15;
|
||||||
|
@ -1674,6 +1679,18 @@ dummy_func(
|
||||||
ERROR_IF(res == NULL, error);
|
ERROR_IF(res == NULL, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pseudo(LOAD_SUPER_METHOD) = {
|
||||||
|
LOAD_SUPER_ATTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
pseudo(LOAD_ZERO_SUPER_METHOD) = {
|
||||||
|
LOAD_SUPER_ATTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
pseudo(LOAD_ZERO_SUPER_ATTR) = {
|
||||||
|
LOAD_SUPER_ATTR,
|
||||||
|
};
|
||||||
|
|
||||||
inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) {
|
inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) {
|
||||||
assert(!(oparg & 1));
|
assert(!(oparg & 1));
|
||||||
DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
|
DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
|
||||||
|
@ -1772,6 +1789,10 @@ dummy_func(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pseudo(LOAD_METHOD) = {
|
||||||
|
LOAD_ATTR,
|
||||||
|
};
|
||||||
|
|
||||||
inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
|
inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
|
||||||
PyTypeObject *tp = Py_TYPE(owner);
|
PyTypeObject *tp = Py_TYPE(owner);
|
||||||
assert(type_version != 0);
|
assert(type_version != 0);
|
||||||
|
@ -2142,6 +2163,16 @@ dummy_func(
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pseudo(JUMP) = {
|
||||||
|
JUMP_FORWARD,
|
||||||
|
JUMP_BACKWARD,
|
||||||
|
};
|
||||||
|
|
||||||
|
pseudo(JUMP_NO_INTERRUPT) = {
|
||||||
|
JUMP_FORWARD,
|
||||||
|
JUMP_BACKWARD_NO_INTERRUPT,
|
||||||
|
};
|
||||||
|
|
||||||
inst(ENTER_EXECUTOR, (--)) {
|
inst(ENTER_EXECUTOR, (--)) {
|
||||||
_PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg];
|
_PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg];
|
||||||
Py_INCREF(executor);
|
Py_INCREF(executor);
|
||||||
|
@ -2530,6 +2561,22 @@ dummy_func(
|
||||||
ERROR_IF(res == NULL, error);
|
ERROR_IF(res == NULL, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pseudo(SETUP_FINALLY) = {
|
||||||
|
NOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
pseudo(SETUP_CLEANUP) = {
|
||||||
|
NOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
pseudo(SETUP_WITH) = {
|
||||||
|
NOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
pseudo(POP_BLOCK) = {
|
||||||
|
NOP,
|
||||||
|
};
|
||||||
|
|
||||||
inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) {
|
inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) {
|
||||||
_PyErr_StackItem *exc_info = tstate->exc_info;
|
_PyErr_StackItem *exc_info = tstate->exc_info;
|
||||||
if (exc_info->exc_value != NULL) {
|
if (exc_info->exc_value != NULL) {
|
||||||
|
|
|
@ -134,7 +134,8 @@ enum {
|
||||||
int
|
int
|
||||||
_PyCompile_InstrSize(int opcode, int oparg)
|
_PyCompile_InstrSize(int opcode, int oparg)
|
||||||
{
|
{
|
||||||
assert(!IS_PSEUDO_OPCODE(opcode));
|
assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode));
|
||||||
|
assert(!IS_PSEUDO_INSTR(opcode));
|
||||||
assert(HAS_ARG(opcode) || oparg == 0);
|
assert(HAS_ARG(opcode) || oparg == 0);
|
||||||
int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg);
|
int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg);
|
||||||
int caches = _PyOpcode_Caches[opcode];
|
int caches = _PyOpcode_Caches[opcode];
|
||||||
|
@ -241,9 +242,14 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) {
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_OPCODE 511
|
||||||
|
|
||||||
static int
|
static int
|
||||||
instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc)
|
instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc)
|
||||||
{
|
{
|
||||||
|
assert(0 <= opcode && opcode <= MAX_OPCODE);
|
||||||
|
assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode));
|
||||||
assert(IS_WITHIN_OPCODE_RANGE(opcode));
|
assert(IS_WITHIN_OPCODE_RANGE(opcode));
|
||||||
assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
|
assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
|
||||||
assert(0 <= oparg && oparg < (1 << 30));
|
assert(0 <= oparg && oparg < (1 << 30));
|
||||||
|
@ -1055,6 +1061,7 @@ compiler_addop_name(struct compiler_unit *u, location loc,
|
||||||
arg <<= 1;
|
arg <<= 1;
|
||||||
}
|
}
|
||||||
if (opcode == LOAD_METHOD) {
|
if (opcode == LOAD_METHOD) {
|
||||||
|
assert(SAME_OPCODE_METADATA(LOAD_METHOD, LOAD_ATTR));
|
||||||
opcode = LOAD_ATTR;
|
opcode = LOAD_ATTR;
|
||||||
arg <<= 1;
|
arg <<= 1;
|
||||||
arg |= 1;
|
arg |= 1;
|
||||||
|
@ -1064,15 +1071,18 @@ compiler_addop_name(struct compiler_unit *u, location loc,
|
||||||
arg |= 2;
|
arg |= 2;
|
||||||
}
|
}
|
||||||
if (opcode == LOAD_SUPER_METHOD) {
|
if (opcode == LOAD_SUPER_METHOD) {
|
||||||
|
assert(SAME_OPCODE_METADATA(LOAD_SUPER_METHOD, LOAD_SUPER_ATTR));
|
||||||
opcode = LOAD_SUPER_ATTR;
|
opcode = LOAD_SUPER_ATTR;
|
||||||
arg <<= 2;
|
arg <<= 2;
|
||||||
arg |= 3;
|
arg |= 3;
|
||||||
}
|
}
|
||||||
if (opcode == LOAD_ZERO_SUPER_ATTR) {
|
if (opcode == LOAD_ZERO_SUPER_ATTR) {
|
||||||
|
assert(SAME_OPCODE_METADATA(LOAD_ZERO_SUPER_ATTR, LOAD_SUPER_ATTR));
|
||||||
opcode = LOAD_SUPER_ATTR;
|
opcode = LOAD_SUPER_ATTR;
|
||||||
arg <<= 2;
|
arg <<= 2;
|
||||||
}
|
}
|
||||||
if (opcode == LOAD_ZERO_SUPER_METHOD) {
|
if (opcode == LOAD_ZERO_SUPER_METHOD) {
|
||||||
|
assert(SAME_OPCODE_METADATA(LOAD_ZERO_SUPER_METHOD, LOAD_SUPER_ATTR));
|
||||||
opcode = LOAD_SUPER_ATTR;
|
opcode = LOAD_SUPER_ATTR;
|
||||||
arg <<= 2;
|
arg <<= 2;
|
||||||
arg |= 1;
|
arg |= 1;
|
||||||
|
|
|
@ -416,9 +416,13 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
|
||||||
bool is_forward = last->i_target->b_visited == 0;
|
bool is_forward = last->i_target->b_visited == 0;
|
||||||
switch(last->i_opcode) {
|
switch(last->i_opcode) {
|
||||||
case JUMP:
|
case JUMP:
|
||||||
|
assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD));
|
||||||
|
assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD));
|
||||||
last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
|
last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
case JUMP_NO_INTERRUPT:
|
case JUMP_NO_INTERRUPT:
|
||||||
|
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD));
|
||||||
|
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
|
||||||
last->i_opcode = is_forward ?
|
last->i_opcode = is_forward ?
|
||||||
JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
|
JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
@ -2071,9 +2075,11 @@ _PyCfg_ConvertPseudoOps(basicblock *entryblock)
|
||||||
for (int i = 0; i < b->b_iused; i++) {
|
for (int i = 0; i < b->b_iused; i++) {
|
||||||
cfg_instr *instr = &b->b_instr[i];
|
cfg_instr *instr = &b->b_instr[i];
|
||||||
if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
|
if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
|
||||||
|
assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP));
|
||||||
INSTR_SET_OP0(instr, NOP);
|
INSTR_SET_OP0(instr, NOP);
|
||||||
}
|
}
|
||||||
else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) {
|
else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) {
|
||||||
|
assert(SAME_OPCODE_METADATA(STORE_FAST_MAYBE_NULL, STORE_FAST));
|
||||||
instr->i_opcode = STORE_FAST;
|
instr->i_opcode = STORE_FAST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
506
Python/generated_cases.c.h
generated
506
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,21 @@
|
||||||
// Python/bytecodes.c
|
// Python/bytecodes.c
|
||||||
// Do not edit!
|
// Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
#define IS_PSEUDO_INSTR(OP) \
|
||||||
|
((OP) == STORE_FAST_MAYBE_NULL) || \
|
||||||
|
((OP) == LOAD_SUPER_METHOD) || \
|
||||||
|
((OP) == LOAD_ZERO_SUPER_METHOD) || \
|
||||||
|
((OP) == LOAD_ZERO_SUPER_ATTR) || \
|
||||||
|
((OP) == LOAD_METHOD) || \
|
||||||
|
((OP) == JUMP) || \
|
||||||
|
((OP) == JUMP_NO_INTERRUPT) || \
|
||||||
|
((OP) == SETUP_FINALLY) || \
|
||||||
|
((OP) == SETUP_CLEANUP) || \
|
||||||
|
((OP) == SETUP_WITH) || \
|
||||||
|
((OP) == POP_BLOCK) || \
|
||||||
|
0
|
||||||
|
|
||||||
#ifndef NEED_OPCODE_METADATA
|
#ifndef NEED_OPCODE_METADATA
|
||||||
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
|
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
|
||||||
#else
|
#else
|
||||||
|
@ -29,6 +44,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
|
||||||
return 0;
|
return 0;
|
||||||
case STORE_FAST:
|
case STORE_FAST:
|
||||||
return 1;
|
return 1;
|
||||||
|
case STORE_FAST_MAYBE_NULL:
|
||||||
|
return 1;
|
||||||
case STORE_FAST_LOAD_FAST:
|
case STORE_FAST_LOAD_FAST:
|
||||||
return 1;
|
return 1;
|
||||||
case STORE_FAST_STORE_FAST:
|
case STORE_FAST_STORE_FAST:
|
||||||
|
@ -211,12 +228,20 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
|
||||||
return 3;
|
return 3;
|
||||||
case LOAD_SUPER_ATTR:
|
case LOAD_SUPER_ATTR:
|
||||||
return 3;
|
return 3;
|
||||||
|
case LOAD_SUPER_METHOD:
|
||||||
|
return 3;
|
||||||
|
case LOAD_ZERO_SUPER_METHOD:
|
||||||
|
return 3;
|
||||||
|
case LOAD_ZERO_SUPER_ATTR:
|
||||||
|
return 3;
|
||||||
case LOAD_SUPER_ATTR_ATTR:
|
case LOAD_SUPER_ATTR_ATTR:
|
||||||
return 3;
|
return 3;
|
||||||
case LOAD_SUPER_ATTR_METHOD:
|
case LOAD_SUPER_ATTR_METHOD:
|
||||||
return 3;
|
return 3;
|
||||||
case LOAD_ATTR:
|
case LOAD_ATTR:
|
||||||
return 1;
|
return 1;
|
||||||
|
case LOAD_METHOD:
|
||||||
|
return 1;
|
||||||
case LOAD_ATTR_INSTANCE_VALUE:
|
case LOAD_ATTR_INSTANCE_VALUE:
|
||||||
return 1;
|
return 1;
|
||||||
case LOAD_ATTR_MODULE:
|
case LOAD_ATTR_MODULE:
|
||||||
|
@ -261,6 +286,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
|
||||||
return 0;
|
return 0;
|
||||||
case JUMP_BACKWARD:
|
case JUMP_BACKWARD:
|
||||||
return 0;
|
return 0;
|
||||||
|
case JUMP:
|
||||||
|
return 0;
|
||||||
|
case JUMP_NO_INTERRUPT:
|
||||||
|
return 0;
|
||||||
case ENTER_EXECUTOR:
|
case ENTER_EXECUTOR:
|
||||||
return 0;
|
return 0;
|
||||||
case POP_JUMP_IF_FALSE:
|
case POP_JUMP_IF_FALSE:
|
||||||
|
@ -305,6 +334,14 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
|
||||||
return 1;
|
return 1;
|
||||||
case WITH_EXCEPT_START:
|
case WITH_EXCEPT_START:
|
||||||
return 4;
|
return 4;
|
||||||
|
case SETUP_FINALLY:
|
||||||
|
return 0;
|
||||||
|
case SETUP_CLEANUP:
|
||||||
|
return 0;
|
||||||
|
case SETUP_WITH:
|
||||||
|
return 0;
|
||||||
|
case POP_BLOCK:
|
||||||
|
return 0;
|
||||||
case PUSH_EXC_INFO:
|
case PUSH_EXC_INFO:
|
||||||
return 1;
|
return 1;
|
||||||
case LOAD_ATTR_METHOD_WITH_VALUES:
|
case LOAD_ATTR_METHOD_WITH_VALUES:
|
||||||
|
@ -423,6 +460,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
|
||||||
return 1;
|
return 1;
|
||||||
case STORE_FAST:
|
case STORE_FAST:
|
||||||
return 0;
|
return 0;
|
||||||
|
case STORE_FAST_MAYBE_NULL:
|
||||||
|
return 0;
|
||||||
case STORE_FAST_LOAD_FAST:
|
case STORE_FAST_LOAD_FAST:
|
||||||
return 1;
|
return 1;
|
||||||
case STORE_FAST_STORE_FAST:
|
case STORE_FAST_STORE_FAST:
|
||||||
|
@ -605,12 +644,20 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
|
||||||
return ((oparg & 1) ? 1 : 0) + 1;
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_SUPER_ATTR:
|
case LOAD_SUPER_ATTR:
|
||||||
return ((oparg & 1) ? 1 : 0) + 1;
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
|
case LOAD_SUPER_METHOD:
|
||||||
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
|
case LOAD_ZERO_SUPER_METHOD:
|
||||||
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
|
case LOAD_ZERO_SUPER_ATTR:
|
||||||
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_SUPER_ATTR_ATTR:
|
case LOAD_SUPER_ATTR_ATTR:
|
||||||
return ((oparg & 1) ? 1 : 0) + 1;
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_SUPER_ATTR_METHOD:
|
case LOAD_SUPER_ATTR_METHOD:
|
||||||
return 2;
|
return 2;
|
||||||
case LOAD_ATTR:
|
case LOAD_ATTR:
|
||||||
return ((oparg & 1) ? 1 : 0) + 1;
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
|
case LOAD_METHOD:
|
||||||
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_ATTR_INSTANCE_VALUE:
|
case LOAD_ATTR_INSTANCE_VALUE:
|
||||||
return ((oparg & 1) ? 1 : 0) + 1;
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_ATTR_MODULE:
|
case LOAD_ATTR_MODULE:
|
||||||
|
@ -655,6 +702,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
|
||||||
return 0;
|
return 0;
|
||||||
case JUMP_BACKWARD:
|
case JUMP_BACKWARD:
|
||||||
return 0;
|
return 0;
|
||||||
|
case JUMP:
|
||||||
|
return 0;
|
||||||
|
case JUMP_NO_INTERRUPT:
|
||||||
|
return 0;
|
||||||
case ENTER_EXECUTOR:
|
case ENTER_EXECUTOR:
|
||||||
return 0;
|
return 0;
|
||||||
case POP_JUMP_IF_FALSE:
|
case POP_JUMP_IF_FALSE:
|
||||||
|
@ -699,6 +750,14 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
|
||||||
return 2;
|
return 2;
|
||||||
case WITH_EXCEPT_START:
|
case WITH_EXCEPT_START:
|
||||||
return 5;
|
return 5;
|
||||||
|
case SETUP_FINALLY:
|
||||||
|
return 0;
|
||||||
|
case SETUP_CLEANUP:
|
||||||
|
return 0;
|
||||||
|
case SETUP_WITH:
|
||||||
|
return 0;
|
||||||
|
case POP_BLOCK:
|
||||||
|
return 0;
|
||||||
case PUSH_EXC_INFO:
|
case PUSH_EXC_INFO:
|
||||||
return 2;
|
return 2;
|
||||||
case LOAD_ATTR_METHOD_WITH_VALUES:
|
case LOAD_ATTR_METHOD_WITH_VALUES:
|
||||||
|
@ -797,10 +856,14 @@ struct opcode_metadata {
|
||||||
enum InstructionFormat instr_format;
|
enum InstructionFormat instr_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format)
|
||||||
|
#define SAME_OPCODE_METADATA(OP1, OP2) \
|
||||||
|
(OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2))
|
||||||
|
|
||||||
#ifndef NEED_OPCODE_METADATA
|
#ifndef NEED_OPCODE_METADATA
|
||||||
extern const struct opcode_metadata _PyOpcode_opcode_metadata[256];
|
extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];
|
||||||
#else
|
#else
|
||||||
const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
|
const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
|
||||||
[NOP] = { true, INSTR_FMT_IX },
|
[NOP] = { true, INSTR_FMT_IX },
|
||||||
[RESUME] = { true, INSTR_FMT_IB },
|
[RESUME] = { true, INSTR_FMT_IB },
|
||||||
[INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB },
|
[INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB },
|
||||||
|
@ -811,6 +874,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
|
||||||
[LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB },
|
[LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB },
|
||||||
[LOAD_CONST] = { true, INSTR_FMT_IB },
|
[LOAD_CONST] = { true, INSTR_FMT_IB },
|
||||||
[STORE_FAST] = { true, INSTR_FMT_IB },
|
[STORE_FAST] = { true, INSTR_FMT_IB },
|
||||||
|
[STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB },
|
||||||
[STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB },
|
[STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB },
|
||||||
[STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB },
|
[STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB },
|
||||||
[POP_TOP] = { true, INSTR_FMT_IX },
|
[POP_TOP] = { true, INSTR_FMT_IX },
|
||||||
|
@ -902,9 +966,13 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
|
||||||
[MAP_ADD] = { true, INSTR_FMT_IB },
|
[MAP_ADD] = { true, INSTR_FMT_IB },
|
||||||
[INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 },
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 },
|
||||||
[LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC },
|
[LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC },
|
||||||
|
[LOAD_SUPER_METHOD] = { true, INSTR_FMT_IBC },
|
||||||
|
[LOAD_ZERO_SUPER_METHOD] = { true, INSTR_FMT_IBC },
|
||||||
|
[LOAD_ZERO_SUPER_ATTR] = { true, INSTR_FMT_IBC },
|
||||||
[LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC },
|
[LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC },
|
||||||
[LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC },
|
[LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC },
|
||||||
[LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 },
|
[LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 },
|
||||||
|
[LOAD_METHOD] = { true, INSTR_FMT_IBC00000000 },
|
||||||
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 },
|
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 },
|
||||||
[LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 },
|
[LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 },
|
||||||
[LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 },
|
[LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 },
|
||||||
|
@ -927,6 +995,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
|
||||||
[IMPORT_FROM] = { true, INSTR_FMT_IB },
|
[IMPORT_FROM] = { true, INSTR_FMT_IB },
|
||||||
[JUMP_FORWARD] = { true, INSTR_FMT_IB },
|
[JUMP_FORWARD] = { true, INSTR_FMT_IB },
|
||||||
[JUMP_BACKWARD] = { true, INSTR_FMT_IB },
|
[JUMP_BACKWARD] = { true, INSTR_FMT_IB },
|
||||||
|
[JUMP] = { true, INSTR_FMT_IB },
|
||||||
|
[JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB },
|
||||||
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB },
|
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB },
|
||||||
[POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB },
|
[POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB },
|
||||||
[POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB },
|
[POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB },
|
||||||
|
@ -949,6 +1019,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
|
||||||
[BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX },
|
[BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX },
|
||||||
[BEFORE_WITH] = { true, INSTR_FMT_IX },
|
[BEFORE_WITH] = { true, INSTR_FMT_IX },
|
||||||
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX },
|
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX },
|
||||||
|
[SETUP_FINALLY] = { true, INSTR_FMT_IX },
|
||||||
|
[SETUP_CLEANUP] = { true, INSTR_FMT_IX },
|
||||||
|
[SETUP_WITH] = { true, INSTR_FMT_IX },
|
||||||
|
[POP_BLOCK] = { true, INSTR_FMT_IX },
|
||||||
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX },
|
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX },
|
||||||
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 },
|
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 },
|
||||||
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 },
|
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 },
|
||||||
|
|
|
@ -491,6 +491,15 @@ class MacroInstruction(SuperOrMacroInstruction):
|
||||||
predicted: bool = False
|
predicted: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class PseudoInstruction:
|
||||||
|
"""A pseudo instruction."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
instr_fmt: str
|
||||||
|
targets: list[Instruction]
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class OverriddenInstructionPlaceHolder:
|
class OverriddenInstructionPlaceHolder:
|
||||||
name: str
|
name: str
|
||||||
|
@ -529,7 +538,8 @@ class Analyzer:
|
||||||
self.errors += 1
|
self.errors += 1
|
||||||
|
|
||||||
everything: list[
|
everything: list[
|
||||||
parser.InstDef | parser.Super | parser.Macro | OverriddenInstructionPlaceHolder
|
parser.InstDef | parser.Super | parser.Macro |
|
||||||
|
parser.Pseudo | OverriddenInstructionPlaceHolder
|
||||||
]
|
]
|
||||||
instrs: dict[str, Instruction] # Includes ops
|
instrs: dict[str, Instruction] # Includes ops
|
||||||
supers: dict[str, parser.Super]
|
supers: dict[str, parser.Super]
|
||||||
|
@ -537,6 +547,7 @@ class Analyzer:
|
||||||
macros: dict[str, parser.Macro]
|
macros: dict[str, parser.Macro]
|
||||||
macro_instrs: dict[str, MacroInstruction]
|
macro_instrs: dict[str, MacroInstruction]
|
||||||
families: dict[str, parser.Family]
|
families: dict[str, parser.Family]
|
||||||
|
pseudo_instrs: dict[str, PseudoInstruction]
|
||||||
|
|
||||||
def parse(self) -> None:
|
def parse(self) -> None:
|
||||||
"""Parse the source text.
|
"""Parse the source text.
|
||||||
|
@ -550,6 +561,7 @@ class Analyzer:
|
||||||
self.supers = {}
|
self.supers = {}
|
||||||
self.macros = {}
|
self.macros = {}
|
||||||
self.families = {}
|
self.families = {}
|
||||||
|
self.pseudos = {}
|
||||||
|
|
||||||
instrs_idx: dict[str, int] = dict()
|
instrs_idx: dict[str, int] = dict()
|
||||||
|
|
||||||
|
@ -623,6 +635,9 @@ class Analyzer:
|
||||||
self.everything.append(thing)
|
self.everything.append(thing)
|
||||||
case parser.Family(name):
|
case parser.Family(name):
|
||||||
self.families[name] = thing
|
self.families[name] = thing
|
||||||
|
case parser.Pseudo(name):
|
||||||
|
self.pseudos[name] = thing
|
||||||
|
self.everything.append(thing)
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
typing.assert_never(thing)
|
||||||
if not psr.eof():
|
if not psr.eof():
|
||||||
|
@ -633,7 +648,7 @@ class Analyzer:
|
||||||
|
|
||||||
Raises SystemExit if there is an error.
|
Raises SystemExit if there is an error.
|
||||||
"""
|
"""
|
||||||
self.analyze_supers_and_macros()
|
self.analyze_supers_and_macros_and_pseudos()
|
||||||
self.find_predictions()
|
self.find_predictions()
|
||||||
self.map_families()
|
self.map_families()
|
||||||
self.check_families()
|
self.check_families()
|
||||||
|
@ -745,14 +760,17 @@ class Analyzer:
|
||||||
assert False, f"Unknown instruction {name!r}"
|
assert False, f"Unknown instruction {name!r}"
|
||||||
return cache, input, output
|
return cache, input, output
|
||||||
|
|
||||||
def analyze_supers_and_macros(self) -> None:
|
def analyze_supers_and_macros_and_pseudos(self) -> None:
|
||||||
"""Analyze each super- and macro instruction."""
|
"""Analyze each super-, macro- and pseudo- instruction."""
|
||||||
self.super_instrs = {}
|
self.super_instrs = {}
|
||||||
self.macro_instrs = {}
|
self.macro_instrs = {}
|
||||||
|
self.pseudo_instrs = {}
|
||||||
for name, super in self.supers.items():
|
for name, super in self.supers.items():
|
||||||
self.super_instrs[name] = self.analyze_super(super)
|
self.super_instrs[name] = self.analyze_super(super)
|
||||||
for name, macro in self.macros.items():
|
for name, macro in self.macros.items():
|
||||||
self.macro_instrs[name] = self.analyze_macro(macro)
|
self.macro_instrs[name] = self.analyze_macro(macro)
|
||||||
|
for name, pseudo in self.pseudos.items():
|
||||||
|
self.pseudo_instrs[name] = self.analyze_pseudo(pseudo)
|
||||||
|
|
||||||
def analyze_super(self, super: parser.Super) -> SuperInstruction:
|
def analyze_super(self, super: parser.Super) -> SuperInstruction:
|
||||||
components = self.check_super_components(super)
|
components = self.check_super_components(super)
|
||||||
|
@ -797,6 +815,14 @@ class Analyzer:
|
||||||
macro.name, stack, initial_sp, final_sp, format, macro, parts
|
macro.name, stack, initial_sp, final_sp, format, macro, parts
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction:
|
||||||
|
targets = [self.instrs[target] for target in pseudo.targets]
|
||||||
|
assert targets
|
||||||
|
# Make sure the targets have the same fmt
|
||||||
|
fmts = list(set([t.instr_fmt for t in targets]))
|
||||||
|
assert(len(fmts) == 1)
|
||||||
|
return PseudoInstruction(pseudo.name, fmts[0], targets)
|
||||||
|
|
||||||
def analyze_instruction(
|
def analyze_instruction(
|
||||||
self, instr: Instruction, stack: list[StackEffect], sp: int
|
self, instr: Instruction, stack: list[StackEffect], sp: int
|
||||||
) -> tuple[Component, int]:
|
) -> tuple[Component, int]:
|
||||||
|
@ -875,7 +901,7 @@ class Analyzer:
|
||||||
return stack, -lowest
|
return stack, -lowest
|
||||||
|
|
||||||
def get_stack_effect_info(
|
def get_stack_effect_info(
|
||||||
self, thing: parser.InstDef | parser.Super | parser.Macro
|
self, thing: parser.InstDef | parser.Super | parser.Macro | parser.Pseudo
|
||||||
) -> tuple[AnyInstruction | None, str, str]:
|
) -> tuple[AnyInstruction | None, str, str]:
|
||||||
def effect_str(effects: list[StackEffect]) -> str:
|
def effect_str(effects: list[StackEffect]) -> str:
|
||||||
if getattr(thing, "kind", None) == "legacy":
|
if getattr(thing, "kind", None) == "legacy":
|
||||||
|
@ -932,6 +958,24 @@ class Analyzer:
|
||||||
self.error("Macro has virtual stack growth", thing)
|
self.error("Macro has virtual stack growth", thing)
|
||||||
popped = str(-low)
|
popped = str(-low)
|
||||||
pushed = str(sp - low)
|
pushed = str(sp - low)
|
||||||
|
case parser.Pseudo():
|
||||||
|
instr = self.pseudos[thing.name]
|
||||||
|
popped = pushed = None
|
||||||
|
# Calculate stack effect, and check that it's the the same
|
||||||
|
# for all targets.
|
||||||
|
for target in self.pseudos[thing.name].targets:
|
||||||
|
target_instr = self.instrs.get(target)
|
||||||
|
# Currently target is always an instr. This could change
|
||||||
|
# in the future, e.g., if we have a pseudo targetting a
|
||||||
|
# macro instruction.
|
||||||
|
assert target_instr
|
||||||
|
target_popped = effect_str(target_instr.input_effects)
|
||||||
|
target_pushed = effect_str(target_instr.output_effects)
|
||||||
|
if popped is None and pushed is None:
|
||||||
|
popped, pushed = target_popped, target_pushed
|
||||||
|
else:
|
||||||
|
assert popped == target_popped
|
||||||
|
assert pushed == target_pushed
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
typing.assert_never(thing)
|
||||||
return instr, popped, pushed
|
return instr, popped, pushed
|
||||||
|
@ -992,6 +1036,15 @@ class Analyzer:
|
||||||
format = self.super_instrs[thing.name].instr_fmt
|
format = self.super_instrs[thing.name].instr_fmt
|
||||||
case parser.Macro():
|
case parser.Macro():
|
||||||
format = self.macro_instrs[thing.name].instr_fmt
|
format = self.macro_instrs[thing.name].instr_fmt
|
||||||
|
case parser.Pseudo():
|
||||||
|
format = None
|
||||||
|
for target in self.pseudos[thing.name].targets:
|
||||||
|
target_instr = self.instrs.get(target)
|
||||||
|
assert target_instr
|
||||||
|
if format is None:
|
||||||
|
format = target_instr.instr_fmt
|
||||||
|
else:
|
||||||
|
assert format == target_instr.instr_fmt
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
typing.assert_never(thing)
|
||||||
all_formats.add(format)
|
all_formats.add(format)
|
||||||
|
@ -1007,6 +1060,7 @@ class Analyzer:
|
||||||
self.out.write_raw(self.from_source_files())
|
self.out.write_raw(self.from_source_files())
|
||||||
self.out.write_raw(f"// Do not edit!\n")
|
self.out.write_raw(f"// Do not edit!\n")
|
||||||
|
|
||||||
|
self.write_pseudo_instrs()
|
||||||
|
|
||||||
self.write_stack_effect_functions()
|
self.write_stack_effect_functions()
|
||||||
|
|
||||||
|
@ -1018,12 +1072,17 @@ class Analyzer:
|
||||||
self.out.emit("enum InstructionFormat instr_format;")
|
self.out.emit("enum InstructionFormat instr_format;")
|
||||||
self.out.emit("};")
|
self.out.emit("};")
|
||||||
self.out.emit("")
|
self.out.emit("")
|
||||||
|
self.out.emit("#define OPCODE_METADATA_FMT(OP) "
|
||||||
|
"(_PyOpcode_opcode_metadata[(OP)].instr_format)")
|
||||||
|
self.out.emit("#define SAME_OPCODE_METADATA(OP1, OP2) \\")
|
||||||
|
self.out.emit(" (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2))")
|
||||||
|
self.out.emit("")
|
||||||
|
|
||||||
# Write metadata array declaration
|
# Write metadata array declaration
|
||||||
self.out.emit("#ifndef NEED_OPCODE_METADATA")
|
self.out.emit("#ifndef NEED_OPCODE_METADATA")
|
||||||
self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[256];")
|
self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];")
|
||||||
self.out.emit("#else")
|
self.out.emit("#else")
|
||||||
self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {")
|
self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {")
|
||||||
|
|
||||||
# Write metadata for each instruction
|
# Write metadata for each instruction
|
||||||
for thing in self.everything:
|
for thing in self.everything:
|
||||||
|
@ -1037,6 +1096,8 @@ class Analyzer:
|
||||||
self.write_metadata_for_super(self.super_instrs[thing.name])
|
self.write_metadata_for_super(self.super_instrs[thing.name])
|
||||||
case parser.Macro():
|
case parser.Macro():
|
||||||
self.write_metadata_for_macro(self.macro_instrs[thing.name])
|
self.write_metadata_for_macro(self.macro_instrs[thing.name])
|
||||||
|
case parser.Pseudo():
|
||||||
|
self.write_metadata_for_pseudo(self.pseudo_instrs[thing.name])
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
typing.assert_never(thing)
|
||||||
|
|
||||||
|
@ -1044,6 +1105,13 @@ class Analyzer:
|
||||||
self.out.emit("};")
|
self.out.emit("};")
|
||||||
self.out.emit("#endif")
|
self.out.emit("#endif")
|
||||||
|
|
||||||
|
def write_pseudo_instrs(self) -> None:
|
||||||
|
"""Write the IS_PSEUDO_INSTR macro"""
|
||||||
|
self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) \\")
|
||||||
|
for op in self.pseudos:
|
||||||
|
self.out.emit(f" ((OP) == {op}) || \\")
|
||||||
|
self.out.emit(f" 0")
|
||||||
|
|
||||||
def write_metadata_for_inst(self, instr: Instruction) -> None:
|
def write_metadata_for_inst(self, instr: Instruction) -> None:
|
||||||
"""Write metadata for a single instruction."""
|
"""Write metadata for a single instruction."""
|
||||||
self.out.emit(
|
self.out.emit(
|
||||||
|
@ -1062,6 +1130,12 @@ class Analyzer:
|
||||||
f" [{mac.name}] = {{ true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }},"
|
f" [{mac.name}] = {{ true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }},"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def write_metadata_for_pseudo(self, ps: PseudoInstruction) -> None:
|
||||||
|
"""Write metadata for a macro-instruction."""
|
||||||
|
self.out.emit(
|
||||||
|
f" [{ps.name}] = {{ true, {INSTR_FMT_PREFIX}{ps.instr_fmt} }},"
|
||||||
|
)
|
||||||
|
|
||||||
def write_instructions(self) -> None:
|
def write_instructions(self) -> None:
|
||||||
"""Write instructions to output file."""
|
"""Write instructions to output file."""
|
||||||
with open(self.output_filename, "w") as f:
|
with open(self.output_filename, "w") as f:
|
||||||
|
@ -1077,6 +1151,7 @@ class Analyzer:
|
||||||
n_instrs = 0
|
n_instrs = 0
|
||||||
n_supers = 0
|
n_supers = 0
|
||||||
n_macros = 0
|
n_macros = 0
|
||||||
|
n_pseudos = 0
|
||||||
for thing in self.everything:
|
for thing in self.everything:
|
||||||
match thing:
|
match thing:
|
||||||
case OverriddenInstructionPlaceHolder():
|
case OverriddenInstructionPlaceHolder():
|
||||||
|
@ -1091,12 +1166,14 @@ class Analyzer:
|
||||||
case parser.Macro():
|
case parser.Macro():
|
||||||
n_macros += 1
|
n_macros += 1
|
||||||
self.write_macro(self.macro_instrs[thing.name])
|
self.write_macro(self.macro_instrs[thing.name])
|
||||||
|
case parser.Pseudo():
|
||||||
|
n_pseudos += 1
|
||||||
case _:
|
case _:
|
||||||
typing.assert_never(thing)
|
typing.assert_never(thing)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"Wrote {n_instrs} instructions, {n_supers} supers, "
|
f"Wrote {n_instrs} instructions, {n_supers} supers, {n_macros}"
|
||||||
f"and {n_macros} macros to {self.output_filename}",
|
f" macros and {n_pseudos} pseudos to {self.output_filename}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -136,10 +136,15 @@ class Family(Node):
|
||||||
size: str # Variable giving the cache size in code units
|
size: str # Variable giving the cache size in code units
|
||||||
members: list[str]
|
members: list[str]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Pseudo(Node):
|
||||||
|
name: str
|
||||||
|
targets: list[str] # opcodes this can be replaced by
|
||||||
|
|
||||||
|
|
||||||
class Parser(PLexer):
|
class Parser(PLexer):
|
||||||
@contextual
|
@contextual
|
||||||
def definition(self) -> InstDef | Super | Macro | Family | None:
|
def definition(self) -> InstDef | Super | Macro | Family | Pseudo | None:
|
||||||
if inst := self.inst_def():
|
if inst := self.inst_def():
|
||||||
return inst
|
return inst
|
||||||
if super := self.super_def():
|
if super := self.super_def():
|
||||||
|
@ -148,6 +153,8 @@ class Parser(PLexer):
|
||||||
return macro
|
return macro
|
||||||
if family := self.family_def():
|
if family := self.family_def():
|
||||||
return family
|
return family
|
||||||
|
if pseudo := self.pseudo_def():
|
||||||
|
return pseudo
|
||||||
|
|
||||||
@contextual
|
@contextual
|
||||||
def inst_def(self) -> InstDef | None:
|
def inst_def(self) -> InstDef | None:
|
||||||
|
@ -364,6 +371,23 @@ class Parser(PLexer):
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@contextual
|
||||||
|
def pseudo_def(self) -> Pseudo | None:
|
||||||
|
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "pseudo":
|
||||||
|
size = None
|
||||||
|
if self.expect(lx.LPAREN):
|
||||||
|
if tkn := self.expect(lx.IDENTIFIER):
|
||||||
|
if self.expect(lx.RPAREN):
|
||||||
|
if self.expect(lx.EQUALS):
|
||||||
|
if not self.expect(lx.LBRACE):
|
||||||
|
raise self.make_syntax_error("Expected {")
|
||||||
|
if members := self.members():
|
||||||
|
if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
|
||||||
|
return Pseudo(
|
||||||
|
tkn.text, members
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
def members(self) -> list[str] | None:
|
def members(self) -> list[str] | None:
|
||||||
here = self.getpos()
|
here = self.getpos()
|
||||||
if tkn := self.expect(lx.IDENTIFIER):
|
if tkn := self.expect(lx.IDENTIFIER):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue