Repository navigation
Add CALL_INTRINSIC instruction. #99005
Description
Activity
- addedperformancePerformance or resource usagePerformance or resource usage
on Nov 2, 2022 Related discussion: faster-cpython/ideas#202
What about the other instructions mentioned in faster-cpython/ideas#202?
- LOAD_ASSERTION_ERROR
- IMPORT_NAME
- IMPORT_FROM
- PRINT_EXPR
- PREP_RERAISE_STAR
- RAISE_VARARGS
- BEFORE_ASYNC_WITH
- BEFORE_WITH
Those as well, with a few exceptions:
LOAD_ASSERTION_ERRORwill probably end up inLOAD_COMMON_CONSTor similar.
RAISE_VARARGSis awkward as it takes a variable number of operands.
BEFORE_ASYNC_WITHandBEFORE_WITHcan be lowered: faster-cpython/ideas#398 (comment)A tricky part is that not many of the above instruction take the form of a simple call.
Instruction Stack effect Call-like SETUP_ANNOTATIONS --- Yes, if we make it return a dummy value LOAD_BUILD_CLASS --- cls (+1) Yes MATCH_KEYS subject keys -- subject keys values (+1) No CHECK_EG_MATCH exc type -- exc match (0) No CLEANUP_THROW iter sent exc -- value (-1) Yes IMPORT_NAME level fromlist --- res (-1) Yes IMPORT_FROM from --- from res (+1) No PRINT_EXPR value --- (-1) Yes, if we make it return a dummy value PREP_RERAISE_STAR excs orig --- val (-1) Yes RAISE_VARARGS (1 to 3) --- Maybe? RERAISE exc --- Yes STOPITERATION_ERROR exc -- exc (0) Yes So, instead of passing arguments, we could pass the stack. The instrinsic function would return how many values it left on the stack, or -1 for an error.
The instruction would need to encode the function to be called (4 bits), the arguments taken (2 bits), which fits easily into the one byte oparg.To support
RAISE_VARARGSwe need to passargcountto the function. It is free and adds more flexibility.
With that in mind,CALL_INSTRINSICwould look something like:inst(CALL_INSTRINSIC) { assert(oparg > 256); int argcount = oparg & 15; int func_id = oparg >> 4; functpr func = IntrinsicFunctions[func_id]; int returned_args = func(sp-argcount, argcount); if (returned_args < 0) { /* In event of error, function should not modify stack depth */ goto error; } sp += returned_args - argcount; }One downside of this is we can only determine the stack effect of
CALL_INSTRINSICwith a lookup table.IMPORT_NAMEandIMPORT_FROMtake an operand, so we need to be changed to take the name from the stack.
SoIMPORT_NAME index_of_namewould need to becomeLOAD_CONST name; IMPORT_NAME.Some other instructions that are very rare, but take an operand, that might be nice to turn into intrinsic functions:
- DELETE_DEREF
- DELETE_NAME
- LOAD_CLASSDEREF
Given that we plan to move to a register-based interpreter, the above scheme of adjusting the stack pointer no longer makes sense.
So, I'm going with a simpler approach of adding aCALL_INTRINSIC_1(and maybe aCALL_INTRINSIC_2) instruction which will take 1 (or 2) value(s) from the stack and push one result.All the instruction marked as "call-like" can be implemented this way, for either stack and register VM.
MATCH_KEYS,CHECK_EG_MATCH,IMPORT_FROMMATCH_KEYS,CHECK_EG_MATCH,IMPORT_FROMhave multiple outputs.
Although these produce multiple values, they leave their inputs unchanged.
With a register machine, the compiler handles liveness of the inputs, so we can useCALL_INTRINSICfor these as well.CLEANUP_THROW
This takes three inputs, but it only uses one of those, so the compiler can just discard the other two values, and can thus be implemented with
CALL_INTRINSIC_1.It is nice to see the register VM making things simpler than the stack VM in some cases.
- addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Nov 27, 2023
We have a number of instructions that are complicated and executed fairly rarely. For example
MAP_KEYS,CHECK_EG_MATCH,CLEANUP_THROW.These bulk out the interpreter, possibly slowing things down.
We should move code from these into helper functions, which can be called though a table from
CALL_INTRINSICinstruction.The
CALL_INTRINSICinstruction also provides a means for contributors to add new functionality without a deep understanding of the compiler.Candidates for moving into
CALL_INTRINSICare:Linked PRs
CALL_INTRINSIC_1instruction #100771