Appearance
| 1 | namespace IR.Values is | |
| 2 | use System.Reflection.Metadata.ILOpCode | |
| 3 | ||
| 4 | // A single operand-less IL instruction. | |
| 5 | class INSTRUCTION: Value is | |
| 6 | op_code: ILOpCode | |
| 7 | ||
| 8 | init(op_code: ILOpCode) is | |
| 9 | super.init() | |
| 10 | ||
| 11 | self.op_code = op_code | |
| 12 | si | |
| 13 | ||
| 14 | gen(context: IR.CONTEXT) is | |
| 15 | context.current_srm_body_emitter!.op(op_code) | |
| 16 | si | |
| 17 | ||
| 18 | to_string() -> string => "{op_code}" | |
| 19 | si | |
| 20 | ||
| 21 | // Constructs one of the built-in integer range structs from the | |
| 22 | // two bounds already on the stack. Its constructor is not reachable | |
| 23 | // from a Function symbol, so the reference is built from the range | |
| 24 | // type and the known (int, int) signature. | |
| 25 | class NEW_RANGE: Value is | |
| 26 | type: Semantic.Types.Type | |
| 27 | ||
| 28 | init(type: Semantic.Types.Type) is | |
| 29 | super.init() | |
| 30 | ||
| 31 | self.type = type | |
| 32 | si | |
| 33 | ||
| 34 | gen(context: IR.CONTEXT) is | |
| 35 | let body = context.current_srm_body_emitter! | |
| 36 | body.new_object(context.resolve_range_constructor(type)) | |
| 37 | si | |
| 38 | ||
| 39 | to_string() -> string => "new-range:[{type}]()" | |
| 40 | si | |
| 41 | ||
| 42 | // The stack-depth bound a method body reserves. | |
| 43 | // | |
| 44 | // Metadata carries the bound in the body header rather than as an | |
| 45 | // instruction, and the emitter reserves the same depth for every | |
| 46 | // body it writes, so nothing is encoded where this value sits. It | |
| 47 | // stays a value rather than being dropped from the block because | |
| 48 | // the walk that builds the block does not know that. | |
| 49 | class MAX_STACK: Value is | |
| 50 | depth: int | |
| 51 | ||
| 52 | init(depth: int) is | |
| 53 | super.init() | |
| 54 | ||
| 55 | self.depth = depth | |
| 56 | si | |
| 57 | ||
| 58 | gen(context: IR.CONTEXT) is | |
| 59 | si | |
| 60 | ||
| 61 | to_string() -> string => ".maxstack {depth}" | |
| 62 | si | |
| 63 | ||
| 64 | // Marks the position a branch names. | |
| 65 | class MARK_LABEL: Value is | |
| 66 | label: IR.LABEL | |
| 67 | ||
| 68 | init(label: IR.LABEL) is | |
| 69 | super.init() | |
| 70 | ||
| 71 | self.label = label | |
| 72 | si | |
| 73 | ||
| 74 | gen(context: IR.CONTEXT) is | |
| 75 | let body = context.current_srm_body_emitter! | |
| 76 | body.mark_label(label) | |
| 77 | si | |
| 78 | ||
| 79 | to_string() -> string => "{label}:" | |
| 80 | si | |
| 81 | ||
| 82 | // A branch to a label. | |
| 83 | // | |
| 84 | // The long-form opcode is not the final encoding: the encoder | |
| 85 | // narrows it to the short form once the eventual offset is known. | |
| 86 | class BRANCH_TO: Value is | |
| 87 | op_code: ILOpCode | |
| 88 | label: IR.LABEL | |
| 89 | ||
| 90 | init(op_code: ILOpCode, label: IR.LABEL) is | |
| 91 | super.init() | |
| 92 | ||
| 93 | self.op_code = op_code | |
| 94 | self.label = label | |
| 95 | si | |
| 96 | ||
| 97 | gen(context: IR.CONTEXT) is | |
| 98 | context.current_srm_body_emitter!.branch(op_code, label) | |
| 99 | si | |
| 100 | ||
| 101 | to_string() -> string => "{op_code} {label}" | |
| 102 | si | |
| 103 | si |