class Stacklang::Function
- Stacklang::Function
- Reference
- Object
Overview
TODO handle copy with index in a temporary register with a beq loop ?
Included Modules
Defined in:
stacklang/compiler/function/assembly.crstacklang/compiler/function/assignment.cr
stacklang/compiler/function/binary.cr
stacklang/compiler/function/call.cr
stacklang/compiler/function/compile.cr
stacklang/compiler/function/expressions.cr
stacklang/compiler/function/function.cr
stacklang/compiler/function/leaf.cr
stacklang/compiler/function/move.cr
stacklang/compiler/function/statements.cr
stacklang/compiler/function/unary.cr
Constant Summary
-
GPR =
[Registers::R1, Registers::R2, Registers::R3, Registers::R4, Registers::R5, Registers::R6]
-
Register free to be used for temporary values and cache
-
RETURN_ADRESS_REGISTER =
Registers::R6
-
Per ABI
-
STACK_REGISTER =
Registers::R7
-
Per ABI
Constructors
-
.new(ast : Stacklang::AST::Function, unit : Stacklang::Unit)
Compute the prototype of the function.
Instance Method Summary
- #add(a : Registers, b : Registers, c : Registers)
- #addi(a : Registers, b : Registers, imm : Int32 | String | Memory)
-
#assemble_immediate(immediate : Int32 | String | Memory, kind : Kind)
Helper function for assembling immediate value.
- #ast : Stacklang::AST::Function
- #beq(a : Registers, b : Registers, imm : Int32 | String | Memory)
-
#cache(variable, excludes) : Registers
Cache a variable in a register.
-
#check_termination(body : Array(AST::Statement))
Check a block to ensure that it terminates.
-
#compile : RiSC16::Object::Section
Generate the section representing the instructions for the compiled functions.
-
#compile_access(access : AST::Access, into : Registers | Memory | Nil) : Type::Any
Compile the value of an access and move it's value if necessary.
-
#compile_access_lvalue(access : AST::Access) : Tuple(Memory, Type::Any) | Nil
Get the memory location and type represented an access.
- #compile_addition(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST, soustract = false) : Type::Any
-
#compile_addressable_unary(operand : AST::Expression, into : Registers | Memory | Nil, node : AST) : Type::Any
Compile &() expression.
-
#compile_any_unary(unary : AST::Unary, into : Registers | Memory | Nil) : Type::Any
Compile a unary operator value, and move it's value if necessary.
-
#compile_assignment(left_side : AST::Expression, right_side : AST::Expression, into : Registers | Memory | Nil) : Type::Any
Compile an assignement of any value to any other value.
-
#compile_assignment_or_binary(binary : AST::Binary, into : Registers | Memory | Nil) : Type::Any
Compile a binary operator value, and move it's value if necessary.
- #compile_binary(binary : AST::Binary, into : Registers | Memory | Nil) : Type::Any
- #compile_binary_to_call(binary : AST::Binary, into : Registers | Memory | Nil) : Type::Any
- #compile_bitwise_and(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST) : Type::Any
- #compile_bitwise_or(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST) : Type::Any
-
#compile_call(call : AST::Call, into : Registers | Memory | Nil) : Type::Any
Compile a call.
- #compile_comparator(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST, superior_to = false, or_equal = false) : Type::Any
-
#compile_equal(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST, neq = false) : Type::Any
TODO Add long type equal ? TODO: Allow ptr comparison ?
-
#compile_expression(expression : AST::Expression, into : Registers | Memory | Nil) : Type::Any
Compile the value of any expression and move it's value if necessary.
-
#compile_global(global : Unit::Global, into : Registers | Memory | Nil) : Type::Any
Generate code necessary to move a global variable value in any location.
-
#compile_global_lvalue(global : Unit::Global) : Memory
Get the memory location of a global.
-
#compile_identifier(identifier : AST::Identifier, into : Registers | Memory | Nil) : Type::Any
Generate code necessary to move any value represened by an identifier in any location.
-
#compile_identifier_lvalue(identifier : AST::Identifier) : Tuple(Memory, Type::Any)
Get the memory location represented by an identifier.
-
#compile_if(if_node : AST::If | AST::While, loop = false)
Compile a if or while statement.
-
#compile_literal(literal : AST::Literal, into : Registers | Memory | Nil) : Type::Any
Generate code necessary to move a single-word literal value in any location.
-
#compile_logic_and(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST) : Type::Any
TODO Allow ptr comparison ? FIXME: should not compute right side if left side is falsy
-
#compile_logic_or(left_side : Tuple(Registers, Type::Any), right_side : Tuple(Registers, Type::Any), into : Registers | Memory, node : AST) : Type::Any
TODO Allow ptr comparison ? FIXME: should not compute right side if left side is truthy
-
#compile_lvalue(expression : AST::Expression) : Tuple(Memory, Type::Any) | Nil
Get the memory location represented by an expression.
-
#compile_operator(operator : AST::Operator, into : Registers | Memory | Nil) : Type::Any
Compile the value of any operation and move it's value if necessary.
-
#compile_ptr_unary(operand : AST::Expression, into : Registers | Memory | Nil, node : AST) : Type::Any
Compile dereferencement expression.
-
#compile_return(ret : AST::Return)
Compile the value of any expression and move it's value in the function return memory location.
-
#compile_sizeof(ast : AST::Sizeof, into : Registers | Memory | Nil) : Type::Any
Generate code necessary to move a sizeof literal value in any location.
-
#compile_statement(statement)
Compile any statement.
- #compile_sugar_assignment(binary : AST::Binary, into : Registers | Memory | Nil) : Type::Any
- #compile_table_access(binary : AST::Binary, into : Registers | Memory | Nil) : Type::Any
-
#compile_value_unary(unary : AST::Unary, into : Registers | Memory | Nil) : Type::Any
Compile unary operator operating on word values.
-
#compile_variable(variable : Variable, into : Registers | Memory | Nil) : Type::Any
Generate code necessary to move a variable value in any location.
-
#compile_variable_lvalue(variable : Variable) : Memory
Get the memory location of a variable.
- #error(error, node = nil)
-
#extern : Bool
Allow to skip compilation of prototypes only
-
#grab_register(excludes = [] of Registers)
Grab a register not excluded, free to use.
- #is_free_to_use(register)
- #jalr(a : Registers, b : Registers)
- #lli(a : Registers, imm : Int32 | String | Memory)
- #lui(a : Registers, imm : Int32 | String | Memory)
- #lw(a : Registers, b : Registers, imm : Int32 | String | Memory)
-
#move(memory : Memory | Registers, constraint : Type::Any, into : Memory | Registers, force_to_memory = false)
This is the big one.
- #movi(a : Registers, imm : Int32 | String | Memory)
- #name
- #nand(a : Registers, b : Registers, c : Registers)
-
#predict_movi(a : Registers, imm : Int32 | String | Memory)
Do nothing but predict the size a movi macro instruction will take in instructions
- #predict_size(&)
-
#prototype : Stacklang::Function::Prototype
Allow to share the prototype of the function to external symbols.
-
#store(variable)
Ensure a variable value is written to ram and not in a cache so the register can be used for something else.
-
#store_all
Ensure all variables avlues are written to the ram, including temporaries.
- #sw(a : Registers, b : Registers, imm : Int32 | String | Memory)
-
#with_temporary(register : Registers, constraint : Type::Any, &)
Run a computation step while ensuring a register value is kept or cached in stack.
Constructor Detail
Compute the prototype of the function.
Example of a stack frame for a simple function: fun foobar(param1, param2):_ { var a; }
+----------------------+ <- Stack Pointer (R7) value within function | a | +----------------------+ | param1 | +----------------------+ | param2 | +----------------------+ <- Used internaly to store return address | reserved (always) | +----------------------+ | return value | +----------------------+ <- Stack Pointer (R7) value from caller
Instance Method Detail
Helper function for assembling immediate value. It provide a value for the immediate, or store the reference for linking if the value is a symbol.
Cache a variable in a register.
Used to fetch temporary variables, or to get the actual value of a variable.
If the variable can be cached (restricted or temporary), the register is kept linked to
the variable so next time we need the value of the variable, we can reuse this register.
If the register is needed for something else, it will be automatically unlinked and persisted to ram (by #grab_register
).
Generate the section representing the instructions for the compiled functions.
TODO find a way to ensure every path end with a return.
Compile the value of an access and move it's value if necessary.
Get the memory location and type represented an access. This work by obtaining a memory location for its subvalue and adding the accessed field offset.
Compile &() expression.
Compile a unary operator value, and move it's value if necessary.
Compile an assignement of any value to any other value. The left side of the assignement must be solvable to a memory location (a lvalue). The written value can also be written to another location (An assignement do have a type and an expression).
Compile a binary operator value, and move it's value if necessary.
Compile a call. This cause all variable cached in registers to be stacked.
TODO Add long type equal ?
TODO Allow ptr comparison ?
Compile the value of any expression and move it's value if necessary.
Generate code necessary to move a global variable value in any location.
Get the memory location of a global.
Generate code necessary to move any value represened by an identifier in any location.
Get the memory location represented by an identifier.
Compile a if or while statement.
Generate code necessary to move a single-word literal value in any location.
TODO Allow ptr comparison ?
FIXME should not compute right side if left side is falsy
TODO Allow ptr comparison ?
FIXME should not compute right side if left side is truthy
Get the memory location represented by an expression. This is limited to global, variable, dereferenced pointer and access to them.
TODO Optimization when we do not need the Memory target and only care for side effect ?
Compile the value of any operation and move it's value if necessary.
Compile dereferencement expression.
It has it's own case instead of being in #compile_value_unary
to simplify error display.
Compile the value of any expression and move it's value in the function return memory location. Move the stack back and jump to return address.
Generate code necessary to move a sizeof literal value in any location.
Compile unary operator operating on word values.
Generate code necessary to move a variable value in any location.
Get the memory location of a variable.
Grab a register not excluded, free to use. If the grabbed register is used as a cache for a variable, or is holding a temporary value, the var is written to the stack so value is not lost.
This is the big one. Move a bunch of memory from a source to a destination. It handle a wide range of case:
- If the source value is in a register
- If the source value is found at an address represented by an offset relative to an address in a register
- If the source value is a variable that is cached in a register
- If the source value is found at an address represented by an offset relative to a address in a variable
- If the destination is a register
- If the destination address is represented by an offset relative to an address in a register
- If the destination address is represented by an offset relative to an address in a variable
- If the destination is a variable that is or could be cached in a register All variable cache optimisation where a variable memory destination is not really written to thanks to caching within register can be disabled by setting force_to_memory to true. That should be usefull only when storing a var because it's cache register is needed for something else.
Do nothing but predict the size a movi macro instruction will take in instructions
Allow to share the prototype of the function to external symbols.
Ensure a variable value is written to ram and not in a cache so the register can be used for something else.
Run a computation step while ensuring a register value is kept or cached in stack. To be used with #uncache or #move.