Procedures#
-
struct UNIT_Procedure#
A container of instructions representing a function that will eventually be compiled by UNIT.
-
UNIT_Context *context#
The context being used by this procedure.
-
const char *name#
The name of the procedure.
-
UNIT_Context *context#
Lifecycle#
-
UNIT_Status UNIT_Procedure_Init(UNIT_Procedure *procedure, UNIT_Context *context, const char *name)#
Initialize a procedure. On success,
UNIT_Procedure_Clear()must be called later to free memory allocated by this function.- Parameters:
procedure – A pointer to a procedure. Memory at this location will be overwritten.
context – The context that will be used when interacting with the procedure. This must be valid for the lifetime of the procedure.
name – A string indicating the name of the procedure. This string is copied internally.
- Returns:
Indicator whether the call was successful. See
UNIT_FAILED.
Example# 1UNIT_Context context; 2UNIT_Context_Init(&context); 3 4UNIT_Procedure procedure; 5if (UNIT_FAILED(UNIT_Procedure_Init(&procedure, &context, "main"))) { 6 UNIT_PrintError(&context, stderr); 7 UNIT_Context_Clear(&context); 8 return -1; 9} 10 11// Must call UNIT_Procedure_Clear() later.
-
UNIT_Procedure *UNIT_Procedure_New(UNIT_Context *context, const char *name)#
Create a new heap-allocated procedure. On success,
UNIT_Procedure_Free()must be called later.- Parameters:
context – The context that will be used when interacting with the procedure.
name – The name of the procedure. Copied internally.
- Returns:
A heap-allocated procedure, or
NULLon failure.
-
void UNIT_Procedure_Clear(UNIT_Procedure *procedure)#
Free memory allocated by
UNIT_Procedure_Init().- Parameters:
procedure – The procedure to clear.
-
void UNIT_Procedure_Free(UNIT_Procedure *procedure)#
Free memory allocated by
UNIT_Procedure_New(). Safe to call withNULL.- Parameters:
procedure – The procedure to free, or
NULL.
Emitting instructions#
-
UNIT_Status UNIT_Procedure_AddOperation(UNIT_Procedure *procedure, UNIT_OperationCode instruction, int64_t argument)#
Add a stack instruction to the procedure. This is the general-purpose function for emitting most instructions. Some instructions require specialized functions instead (see below).
- Parameters:
procedure – The procedure to add the instruction to.
instruction – The opcode. See Operation codes.
argument – The operand. Meaning depends on the instruction.
- Returns:
Indicator whether the call was successful.
Example# // return 42 UNIT_Procedure_AddOperation(&proc, UNIT_OP_LOAD_INTEGER, 42); UNIT_Procedure_AddOperation(&proc, UNIT_OP_RETURN_VALUE, 0);
-
UNIT_Status UNIT_Procedure_AddStringLoad(UNIT_Procedure *procedure, const char *str)#
Push a string constant onto the stack. The string is copied internally.
- Parameters:
procedure – The procedure.
str – The string to push.
Example# UNIT_Procedure_AddStringLoad(&proc, "hello %s\n");
-
UNIT_Status UNIT_Procedure_AddCallName(UNIT_Procedure *procedure, const char *name, UNIT_Size num_arguments)#
Call an external function by name. The top num_arguments stack items are passed as arguments (first pushed = first argument). The return value is pushed onto the stack.
This emits both
UNIT_OP_PREPARE_CALLandUNIT_OP_CALL_NAMEinternally.- Parameters:
procedure – The procedure.
name – The function name. Resolved via
dlsymat link time or JIT time. SeeUNIT_SymbolMap_RegisterSymbol()for custom resolution.num_arguments – The number of arguments to pass.
Example# // printf("%d\n", 42) UNIT_Procedure_AddStringLoad(&proc, "%d\n"); UNIT_Procedure_AddOperation(&proc, UNIT_OP_LOAD_INTEGER, 42); UNIT_Procedure_AddCallName(&proc, "printf", 2); UNIT_Procedure_AddOperation(&proc, UNIT_OP_POP, 0);
-
UNIT_Status UNIT_Procedure_AddCallProcedure(UNIT_Procedure *self, UNIT_Procedure *target, uint8_t nargs)#
Call another UNIT procedure. The subprocedure will be translated and compiled during compilation of this procedure.
- Parameters:
self – The calling procedure.
target – The procedure to call.
nargs – The number of arguments to pass.
Example# UNIT_Procedure_AddOperation(&proc, UNIT_OP_LOAD_INTEGER, 5); UNIT_Procedure_AddCallProcedure(&main_proc, &factorial_proc, 1);
Local Variables#
-
UNIT_Status UNIT_Procedure_CreateLocal(UNIT_Procedure *procedure, const char *name, UNIT_Local *local_ptr)#
Create a named local variable. The index is assigned automatically. The returned
UNIT_Localhandle can be used withUNIT_Procedure_AddStoreName()andUNIT_Procedure_AddLoadName().- Parameters:
procedure – The procedure.
name – A descriptive name for the variable. Copied internally.
local_ptr – Output parameter receiving the local handle.
Example# UNIT_Local x; UNIT_Procedure_CreateLocal(&proc, "x", &x); UNIT_Procedure_AddOperation(&proc, UNIT_OP_LOAD_INTEGER, 42); UNIT_Procedure_AddStoreName(&proc, x); UNIT_Procedure_AddLoadName(&proc, x);
-
UNIT_Status UNIT_Procedure_AddStoreName(UNIT_Procedure *procedure, UNIT_Local local)#
Pop the top of the stack into a local variable by handle. This is equivalent to
UNIT_OP_STORE_LOCALbut uses the handle fromUNIT_Procedure_CreateLocal().- Parameters:
procedure – The procedure.
local – The local variable handle.
-
UNIT_Status UNIT_Procedure_AddLoadName(UNIT_Procedure *procedure, UNIT_Local local)#
Push a local variable onto the stack by handle.
- Parameters:
procedure – The procedure.
local – The local variable handle.
Jump Labels#
-
struct UNIT_JumpLabel#
A jump target, created by
UNIT_Procedure_CreateJumpLabel().-
const char *name#
The label name (heap-allocated, owned by the procedure).
-
int32_t id#
The label ID.
-
const char *name#
-
UNIT_JumpLabel *UNIT_Procedure_CreateJumpLabel(UNIT_Procedure *procedure, const char *name)#
Create a jump target. The label must later be placed with
UNIT_Procedure_UseLabel().- Parameters:
procedure – The procedure.
name – A descriptive name for the label. Copied internally.
- Returns:
A pointer to the label, or
NULLon failure. The label is owned by the procedure and must not be freed by the caller.
-
UNIT_Status UNIT_Procedure_UseLabel(UNIT_Procedure *procedure, UNIT_JumpLabel *jump_label)#
Place a label at the current position in the instruction stream. All jumps to this label will target the next instruction emitted.
- Parameters:
procedure – The procedure.
jump_label – The label to place.
-
UNIT_Status UNIT_Procedure_AddJump(UNIT_Procedure *procedure, UNIT_OperationCode instruction, UNIT_JumpLabel *jump_label)#
Emit a jump instruction targeting the given label. The instruction must be one of
UNIT_OP_JUMP,UNIT_OP_JUMP_IF_TRUE, orUNIT_OP_JUMP_IF_FALSE.- Parameters:
procedure – The procedure.
instruction – The jump opcode.
jump_label – The target label.
Example# UNIT_JumpLabel *end = UNIT_Procedure_CreateJumpLabel(&proc, "end"); UNIT_Procedure_AddOperation(&proc, UNIT_OP_LOAD_INTEGER, 0); UNIT_Procedure_AddOperation(&proc, UNIT_OP_COMPARE_EQUAL, 0); UNIT_Procedure_AddJump(&proc, UNIT_OP_JUMP_IF_TRUE, end); // ... code skipped when condition is true ... UNIT_Procedure_UseLabel(&proc, end); // ... continues here ...
Flags#
-
void UNIT_Procedure_SetFlags(UNIT_Procedure *procedure, UNIT_Flags flags)#
Set procedure flags. Flags can be combined with bitwise OR.
- Parameters:
procedure – The procedure.
flags – Bitwise OR of flag constants.
-
UNIT_Flags UNIT_Procedure_GetFlags(const UNIT_Procedure *procedure)#
Return the current procedure flags.
- Parameters:
procedure – The procedure.
- Returns:
The current flags.
-
UNIT_FLAG_NONE#
No flags. This is always
0.
-
UNIT_FLAG_NO_OPTIMIZE_TRANSLATION#
Skip register IR optimization (move coalescing, dead move elimination, forward copy propagation) during compilation.
-
UNIT_FLAG_FORCE_NO_INLINE#
Prevent this procedure from being inlined into callers, regardless of size.
-
UNIT_FLAG_FORCE_INLINE#
Always inline this procedure into callers, regardless of size.
-
UNIT_FLAG_PRINT_TRANSLATION_PREOP#
Print the register IR to stderr before optimization runs. Useful for debugging.
-
UNIT_FLAG_PRINT_TRANSLATION_POSTOP#
Print the register IR to stderr after optimization runs. Useful for debugging.
UNIT_Procedure_SetFlags(&proc, UNIT_FLAG_FORCE_NO_INLINE | UNIT_FLAG_NO_OPTIMIZE_TRANSLATION);
Optimization#
-
UNIT_Status UNIT_Procedure_Optimize(UNIT_Procedure *procedure)#
Run stack IR optimization passes on the procedure. This includes: inlining, constant folding, dead store elimination, and local variable optimization. Call this before
UNIT_Compile().Multiple iterations are run automatically until no further changes occur.
- Parameters:
procedure – The procedure to optimize.
Example# UNIT_Procedure_Optimize(&proc);
Debugging#
-
UNIT_Status UNIT_Procedure_PrintInstructions(const UNIT_Procedure *procedure, FILE *stream, int8_t visualize_stack_effect)#
Print the stack IR to a file stream.
- Parameters:
procedure – The procedure.
stream – The output stream (e.g.
stdout).visualize_stack_effect – If nonzero, show the stack state after each instruction.
Example# UNIT_Procedure_PrintInstructions(&proc, stdout, /*visualize_stack_effect=*/1);
-
const char *UNIT_OperationCode_GetName(UNIT_OperationCode instruction)#
Return the name of an opcode as a string (e.g.
"LOAD_INTEGER").- Parameters:
instruction – The opcode.
- Returns:
A static string. Must not be freed.