diff options
Diffstat (limited to 'hobgoblin/src/patio/instructions.hob')
| -rw-r--r-- | hobgoblin/src/patio/instructions.hob | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/hobgoblin/src/patio/instructions.hob b/hobgoblin/src/patio/instructions.hob new file mode 100644 index 00000000..c6f33976 --- /dev/null +++ b/hobgoblin/src/patio/instructions.hob @@ -0,0 +1,253 @@ +import {Source} from ../sources; +import {PatioLocalRef, PatioOperand} from ./operands; +import {PatioDataLayout} from ./types; + +sum PatioInstruction { + variant PatioBlock; + variant PatioBoolToInt; + variant PatioCall; + variant PatioCallPointer; + variant PatioDataPtrToInt; + variant PatioIf; + variant PatioIntAdd; + variant PatioIntEquals; + variant PatioIntNotEqual; + variant PatioIntSub; + variant PatioIntToBool; + variant PatioIntToDataPtr; + variant PatioLocalStore; + variant PatioLoop; + variant PatioLoopBreak; + variant PatioLoopContinue; + variant PatioMemoryLoad; + variant PatioMemoryStore; + variant PatioReturn; + variant PatioSwitch; + variant PatioThrow; + variant PatioTry; + variant PatioUnreachable; + variant PatioVarLoad; + variant PatioVarStore; +} + +/// Execute the instructions in the body of the block. The results may be used in +/// the parent scope, but any other variables (as distinct from values) are no +/// longer in use. +struct PatioBlock { + field body: List[PatioInstruction]; + field results: List[PatioOperand]; + field source: Source; +} + +struct PatioBoolToInt { + field destination: PatioLocalRef; + field value: PatioOperand; + field source: Source; +} + +/// Call the function with the given name, and store the returned values in the +/// destination locals. +struct PatioCall { + field destinations: List[PatioLocalRef]; + field functionName: String; + field args: List[PatioOperand]; + field source: Source; +} + +/// Call the function pointed to by the function pointer with the given +/// arguments, and store the returned values in the destination locals. +struct PatioCallPointer { + field destinations: List[PatioLocalRef]; + field functionPointer: PatioOperand; + field args: List[PatioOperand]; + field source: Source; +} + +struct PatioDataPtrToInt { + field destination: PatioLocalRef; + field value: PatioOperand; + field source: Source; +} + +/// If the condition is true, execute the instructions in the "true" body, +/// otherwise execute the instructions in the "false" body. +/// +/// Each block must have the same number of results as destinations. Each result is +/// assigned to the destination with the same index. +struct PatioIf { + field destinations: List[PatioLocalRef]; + field condition: PatioOperand; + field trueBody: PatioBlock; + field falseBody: PatioBlock; + field source: Source; +} + +struct PatioIntAdd { + field destination: PatioLocalRef; + field left: PatioOperand; + field right: PatioOperand; + field source: Source; +} + +struct PatioIntEquals { + field destination: PatioLocalRef; + field left: PatioOperand; + field right: PatioOperand; + field source: Source; +} + +/// Compare the left and right operands. If they are equal, store false in the +/// destination, otherwise store true in the destination. +struct PatioIntNotEqual { + field destination: PatioLocalRef; + field left: PatioOperand; + field right: PatioOperand; + field source: Source; +} + +/// Calculate the left operand minus the right operand, and store the result in +/// the destination. +struct PatioIntSub { + field destination: PatioLocalRef; + field left: PatioOperand; + field right: PatioOperand; + field source: Source; +} + +struct PatioIntToBool { + field destination: PatioLocalRef; + field value: PatioOperand; + field source: Source; +} + +struct PatioIntToDataPtr { + field destination: PatioLocalRef; + field value: PatioOperand; + field source: Source; +} + +/// Store the given value in the destination local. +struct PatioLocalStore { + field destination: PatioLocalRef; + field value: PatioOperand; + field source: Source; +} + +/// Execute the body. The `continue` instruction can jump back to the +/// start of the body. The `break` instruction can jump to the end of +/// the body. +struct PatioLoop { + field body: List[PatioInstruction]; + field source: Source; +} + +/// Jump to the end of the enclosing `loop` instruction's body. +struct PatioLoopBreak { + field source: Source; +} + +/// Jump to the start of the enclosing `loop` instruction's body. +struct PatioLoopContinue { + field source: Source; +} + +/// Load the value at the given offset from the given pointer and store it in the +/// destination local. +struct PatioMemoryLoad { + field destination: PatioLocalRef; + field pointer: PatioOperand; + field layout: PatioDataLayout; + field elementOffsets: List[Int32]; + field source: Source; +} + +/// Store the given value at the given offset from the given pointer. +struct PatioMemoryStore { + field pointer: PatioOperand; + field layout: PatioDataLayout; + field elementOffsets: List[Int32]; + field value: PatioOperand; + field source: Source; +} + +/// Return with the given values from the current function. +struct PatioReturn { + field values: List[PatioOperand]; + field source: Source; +} + +/// Find a case with a value matching that of the instruction's value. If such a +/// case is found, execute the body of that case, otherwise execute the default +/// body. +/// +/// Each block must have the same number of results as destinations. Each result +/// is assigned to the destination with the same index. +struct PatioSwitch { + field destinations: List[PatioLocalRef]; + field value: PatioOperand; + field cases: List[PatioSwitchCase]; + field defaultBody: PatioBlock; + field source: Source; +} + +struct PatioSwitchCase { + field value: Int32; + field body: PatioBlock; + field source: Source; +} + +/// Search the stack for an exception handler with a catch clause matching the +/// thrown exception type. Unwind the stack up to and including this exception +/// handler, and run the body of the catch clause. If no such exception handler +/// is found, the process should abort. +struct PatioThrow { + field exceptionTypeName: String; + field value: PatioOperand; + field source: Source; +} + +/// Push an exception handler with the given catch clauses onto the control flow +/// stack, and then execute the instructions in its body. +/// +/// If the exception handler catches an exception, the body of the corresponding +/// is executed instead. +/// +/// Each block (that is, the body of the try and the body of each catch clause) +/// must have the same number of results as destinations. Each result is assigned to +/// the destination with the same index. +struct PatioTry { + field destinations: List[PatioLocalRef]; + field catchClauses: List[PatioCatchClause]; + field body: PatioBlock; + field source: Source; +} + +/// A catch clause can accept an exception of a given type. If executed, it will +/// stored the value of the exception in the given destination, and then execute the +/// body. +struct PatioCatchClause { + field exceptionTypeName: String; + field destination: PatioLocalRef; + field body: PatioBlock; + field source: Source; +} + +/// Unreachable instructions have undefined behaviour, and are used to indicate +/// that an instruction sequence is unreachable. +struct PatioUnreachable { + field source: Source; +} + +/// Load the value from the given var and store it in the destination local. +struct PatioVarLoad { + field destination: PatioLocalRef; + field var: PatioLocalRef; + field source: Source; +} + +/// Store the given value in the destination var. +struct PatioVarStore { + field var: PatioLocalRef; + field value: PatioOperand; + field source: Source; +} |
