aboutsummaryrefslogtreecommitdiff
path: root/hobgoblin/src/patio/instructions.hob
diff options
context:
space:
mode:
Diffstat (limited to 'hobgoblin/src/patio/instructions.hob')
-rw-r--r--hobgoblin/src/patio/instructions.hob253
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;
+}