Appearance
| 1 | namespace IR is | |
| 2 | use System.Exception; | |
| 3 | ||
| 4 | use Values.Call; | |
| 5 | use Values.Value; | |
| 6 | ||
| 7 | use Values.BLOCK; | |
| 8 | ||
| 9 | class INNATE_OPERATION_GENERATOR( | |
| 10 | _logger: Logging.Logger, | |
| 11 | _boxer: VALUE_BOXER, | |
| 12 | _brancher: IR.BRANCHER | |
| 13 | ) is | |
| 14 | _type_and_operation_handlers: Collections.MAP[string,(INNATE,BLOCK) -> void]; | |
| 15 | _operation_handlers: Collections.MAP[string,(INNATE,BLOCK) -> void]; | |
| 16 | _type_handlers: Collections.MAP[string,(INNATE,BLOCK) -> void]; | |
| 17 | ||
| 18 | init(..) is | |
| 19 | _type_and_operation_handlers = Collections.MAP[string,(INNATE,BLOCK) -> void](); | |
| 20 | _operation_handlers = Collections.MAP[string,(INNATE,BLOCK) -> void](); | |
| 21 | _type_handlers = Collections.MAP[string,(INNATE,BLOCK) -> void](); | |
| 22 | ||
| 23 | _type_and_operation_handlers["compare.order"] = (value: INNATE, context: BLOCK) -> void is gen_compare_order(value, false, context); si; | |
| 24 | _type_and_operation_handlers["compare.uorder"] = (value: INNATE, context: BLOCK) -> void is gen_compare_order(value, true, context); si; | |
| 25 | _type_and_operation_handlers["compare.value"] = (value: INNATE, context: BLOCK) -> void is gen_compare_value(value, context); si; | |
| 26 | _type_and_operation_handlers["compare.reference"] = (value: INNATE, context: BLOCK) -> void is gen_compare_reference(value, context); si; | |
| 27 | ||
| 28 | _type_and_operation_handlers["bool.not"] = (value: INNATE, context: BLOCK) -> void is gen_bool_not(value, context); si; | |
| 29 | _type_and_operation_handlers["reference.read"] = (value: INNATE, context: BLOCK) -> void is gen_reference_read(value, context); si; | |
| 30 | _type_and_operation_handlers["reference.assign"] = (value: INNATE, context: BLOCK) -> void is gen_reference_assign(value, context); si; | |
| 31 | ||
| 32 | _type_handlers["bool"] = (value: INNATE, context: BLOCK) -> void is gen_short_circuit_bool(value, context); si; | |
| 33 | _type_handlers["arithmetic"] = (value: INNATE, context: BLOCK) -> void is gen_arithmetic(value, context); si; | |
| 34 | _type_handlers["arithmetic_decimal"] = (value: INNATE, context: BLOCK) -> void is gen_arithmetic_decimal(value, context); si; | |
| 35 | _type_handlers["compare_decimal"] = (value: INNATE, context: BLOCK) -> void is gen_compare_decimal(value, context); si; | |
| 36 | _type_handlers["string"] = (value: INNATE, context: BLOCK) -> void is gen_string(value, context); si; | |
| 37 | _type_handlers["range"] = (value: INNATE, context: BLOCK) -> void is gen_range(value, context); si; | |
| 38 | ||
| 39 | // _type_handlers["object"] = (value: INNATE, context: CONTEXT) -> void is gen_object(value, context); si; | |
| 40 | si | |
| 41 | ||
| 42 | lower(value: INNATE, block: BLOCK) is | |
| 43 | if !IoC.CONTAINER.instance.build_flags.want_assembler then | |
| 44 | return; | |
| 45 | fi | |
| 46 | ||
| 47 | let innate_name = value.innate_name; | |
| 48 | ||
| 49 | if try_handle(innate_name, _type_and_operation_handlers, value, block) then | |
| 50 | return; | |
| 51 | fi | |
| 52 | ||
| 53 | let operation_name = value.op_name; | |
| 54 | ||
| 55 | if try_handle(operation_name, _operation_handlers, value, block) then | |
| 56 | return; | |
| 57 | fi | |
| 58 | ||
| 59 | let type_name = value.type_name; | |
| 60 | ||
| 61 | if try_handle(type_name, _type_handlers, value, block) then | |
| 62 | return; | |
| 63 | fi | |
| 64 | ||
| 65 | throw System.Exception("unknown innate operation: {value.function.innate_name}"); | |
| 66 | si | |
| 67 | ||
| 68 | try_handle( | |
| 69 | key: string, | |
| 70 | handlers: Collections.Map[string,(INNATE,BLOCK) -> void], | |
| 71 | value: INNATE, | |
| 72 | block: BLOCK) -> bool is | |
| 73 | ||
| 74 | if handlers.contains_key(key) then | |
| 75 | let handler = handlers[key]; | |
| 76 | ||
| 77 | handler(value, block); | |
| 78 | return true; | |
| 79 | fi | |
| 80 | return false; | |
| 81 | si | |
| 82 | ||
| 83 | gen_arithmetic(value: INNATE, block: BLOCK) is | |
| 84 | gen_arguments(value, block); | |
| 85 | ||
| 86 | let operation = value.op_name; | |
| 87 | ||
| 88 | // FIXME: do we need to convert the inputs or outputs? | |
| 89 | block.add(operation); | |
| 90 | si | |
| 91 | ||
| 92 | gen_bool_not(value: INNATE, block: BLOCK) is | |
| 93 | assert value.arguments.count == 1 else "not bool missing arguments"; | |
| 94 | ||
| 95 | gen_arguments(value, block); | |
| 96 | ||
| 97 | block.add("ldc.i4 0"); | |
| 98 | block.add("ceq"); | |
| 99 | si | |
| 100 | ||
| 101 | gen_short_circuit_bool(value: INNATE, block: BLOCK) is | |
| 102 | assert value.arguments.count == 2 else "short circuit bool missing arguments"; | |
| 103 | ||
| 104 | let brancher = _brancher.get_for(block); | |
| 105 | ||
| 106 | let exit = IR.LABEL(); | |
| 107 | let operation = value.op_name; | |
| 108 | ||
| 109 | // push speculative result: | |
| 110 | if operation =~ "and_then" then | |
| 111 | block.add("ldc.i4 0"); | |
| 112 | else | |
| 113 | block.add("ldc.i4 1"); | |
| 114 | fi | |
| 115 | ||
| 116 | // branch to exit if speculative result is correct based on evaluating left argument: | |
| 117 | if operation =~ "and_then" then | |
| 118 | brancher.branch(IR.BRANCH.Z, value.arguments[0], exit); | |
| 119 | else | |
| 120 | brancher.branch(IR.BRANCH.NZ, value.arguments[0], exit); | |
| 121 | fi | |
| 122 | ||
| 123 | // speculative result may not be correct, discard it: | |
| 124 | block.add("pop"); | |
| 125 | ||
| 126 | // result is value of right side: | |
| 127 | gen_argument(value, 1, block); | |
| 128 | ||
| 129 | brancher.label(exit); | |
| 130 | si | |
| 131 | ||
| 132 | gen_compare_order(value: INNATE, is_unsigned: bool, block: BLOCK) is | |
| 133 | assert value.arguments.count == 2 else "compare order missing arguments"; | |
| 134 | ||
| 135 | gen_arguments(value, block); | |
| 136 | ||
| 137 | let actual_operation = value.actual_operation; | |
| 138 | ||
| 139 | let needs_not mut = false; | |
| 140 | let instruction: string mut; | |
| 141 | ||
| 142 | if actual_operation =~ ">" then | |
| 143 | instruction = "cgt"; | |
| 144 | elif actual_operation =~ ">=" then | |
| 145 | instruction = "clt"; | |
| 146 | needs_not = true; | |
| 147 | elif actual_operation =~ "<" then | |
| 148 | instruction = "clt"; | |
| 149 | elif actual_operation =~ "<=" then | |
| 150 | instruction = "cgt"; | |
| 151 | needs_not = true; | |
| 152 | else | |
| 153 | throw System.Exception("unexpected compare order operation: {actual_operation}"); | |
| 154 | fi | |
| 155 | ||
| 156 | if is_unsigned then | |
| 157 | instruction = "{instruction}.un"; | |
| 158 | fi | |
| 159 | ||
| 160 | block.add(instruction); | |
| 161 | ||
| 162 | if needs_not then | |
| 163 | block.add("ldc.i4 0"); | |
| 164 | block.add("ceq"); | |
| 165 | fi | |
| 166 | si | |
| 167 | ||
| 168 | gen_string(value: INNATE, block: BLOCK) is | |
| 169 | let innate_name = value.function.innate_name; | |
| 170 | ||
| 171 | if innate_name =~ "string.equals" then | |
| 172 | gen_arguments(value, block); | |
| 173 | ||
| 174 | block.add("call bool string::op_Equality(string, string)"); | |
| 175 | ||
| 176 | if value.actual_operation =~ "!~" then | |
| 177 | block.add("ldc.i4 0"); | |
| 178 | block.add("ceq"); | |
| 179 | fi | |
| 180 | else | |
| 181 | throw System.Exception("unexpected string innate operation: {innate_name}"); | |
| 182 | fi | |
| 183 | si | |
| 184 | ||
| 185 | gen_compare_reference(value: INNATE, block: BLOCK) is | |
| 186 | assert value.arguments.count == 2 else "compare reference missing arguments"; | |
| 187 | ||
| 188 | let left mut = value.arguments[0]; | |
| 189 | let right mut = value.arguments[1]; | |
| 190 | ||
| 191 | if left.is_value_type != right.is_value_type then | |
| 192 | left = _boxer.box_if_value(left); | |
| 193 | right = _boxer.box_if_value(right); | |
| 194 | fi | |
| 195 | ||
| 196 | block.add(left); | |
| 197 | block.add(right); | |
| 198 | ||
| 199 | block.add("ceq"); | |
| 200 | ||
| 201 | if value.actual_operation =~ "!=" then | |
| 202 | block.add("ldc.i4 0"); | |
| 203 | block.add("ceq"); | |
| 204 | fi | |
| 205 | si | |
| 206 | ||
| 207 | gen_compare_value(value: INNATE, block: BLOCK) is | |
| 208 | assert value.arguments.count == 2 else "compare value missing arguments"; | |
| 209 | ||
| 210 | gen_arguments(value, block); | |
| 211 | ||
| 212 | block.add("ceq"); | |
| 213 | ||
| 214 | if value.actual_operation =~ "!=" then | |
| 215 | block.add("ldc.i4 0"); | |
| 216 | block.add("ceq"); | |
| 217 | fi | |
| 218 | si | |
| 219 | ||
| 220 | gen_range(value: INNATE, block: BLOCK) is | |
| 221 | assert value.arguments.count == 2 else "create range incorrect arguments"; | |
| 222 | ||
| 223 | gen_arguments(value, block); | |
| 224 | ||
| 225 | let prefix = "['ghul-runtime']"; | |
| 226 | ||
| 227 | if value.op_name =~ "inclusive" then | |
| 228 | block.add("newobj instance void valuetype {prefix}'Ghul'.'INT_RANGE_INCLUSIVE'::'.ctor'(int32,int32)"); | |
| 229 | elif value.op_name =~ "exclusive" then | |
| 230 | block.add("newobj instance void valuetype {prefix}'Ghul'.'INT_RANGE'::'.ctor'(int32,int32)"); | |
| 231 | else | |
| 232 | throw Exception("unexpected range innate operation: {value.innate_name}"); | |
| 233 | fi | |
| 234 | si | |
| 235 | ||
| 236 | gen_reference_read(value: INNATE, context: BLOCK) is | |
| 237 | // TODO | |
| 238 | si | |
| 239 | ||
| 240 | gen_reference_assign(value: INNATE, context: BLOCK) is | |
| 241 | // TODO | |
| 242 | si | |
| 243 | ||
| 244 | gen_arithmetic_decimal(value: INNATE, block: BLOCK) is | |
| 245 | gen_arguments(value, block); | |
| 246 | ||
| 247 | let decimal_il = "valuetype ['System.Runtime']'System'.'Decimal'"; | |
| 248 | let op = value.op_name; | |
| 249 | ||
| 250 | let method_name: string mut; | |
| 251 | let is_unary mut = false; | |
| 252 | ||
| 253 | if op =~ "neg" then | |
| 254 | method_name = "op_UnaryNegation"; | |
| 255 | is_unary = true; | |
| 256 | elif op =~ "add" then | |
| 257 | method_name = "op_Addition"; | |
| 258 | elif op =~ "sub" then | |
| 259 | method_name = "op_Subtraction"; | |
| 260 | elif op =~ "mul" then | |
| 261 | method_name = "op_Multiply"; | |
| 262 | elif op =~ "div" then | |
| 263 | method_name = "op_Division"; | |
| 264 | else | |
| 265 | throw System.Exception("unexpected arithmetic_decimal operation: {op}"); | |
| 266 | fi | |
| 267 | ||
| 268 | if is_unary then | |
| 269 | block.add("call {decimal_il} {decimal_il}::{method_name}({decimal_il})"); | |
| 270 | else | |
| 271 | block.add("call {decimal_il} {decimal_il}::{method_name}({decimal_il}, {decimal_il})"); | |
| 272 | fi | |
| 273 | si | |
| 274 | ||
| 275 | gen_compare_decimal(value: INNATE, block: BLOCK) is | |
| 276 | gen_arguments(value, block); | |
| 277 | ||
| 278 | let decimal_il = "valuetype ['System.Runtime']'System'.'Decimal'"; | |
| 279 | let op = value.op_name; | |
| 280 | ||
| 281 | if op =~ "equality" then | |
| 282 | block.add("call bool {decimal_il}::op_Equality({decimal_il}, {decimal_il})"); | |
| 283 | ||
| 284 | if value.actual_operation =~ "!=" then | |
| 285 | block.add("ldc.i4 0"); | |
| 286 | block.add("ceq"); | |
| 287 | fi | |
| 288 | ||
| 289 | return; | |
| 290 | fi | |
| 291 | ||
| 292 | if op =~ "order" then | |
| 293 | let actual = value.actual_operation; | |
| 294 | let method_name: string mut; | |
| 295 | ||
| 296 | if actual =~ ">" then | |
| 297 | method_name = "op_GreaterThan"; | |
| 298 | elif actual =~ ">=" then | |
| 299 | method_name = "op_GreaterThanOrEqual"; | |
| 300 | elif actual =~ "<" then | |
| 301 | method_name = "op_LessThan"; | |
| 302 | elif actual =~ "<=" then | |
| 303 | method_name = "op_LessThanOrEqual"; | |
| 304 | else | |
| 305 | throw System.Exception("unexpected compare_decimal.order operation: {actual}"); | |
| 306 | fi | |
| 307 | ||
| 308 | block.add("call bool {decimal_il}::{method_name}({decimal_il}, {decimal_il})"); | |
| 309 | ||
| 310 | return; | |
| 311 | fi | |
| 312 | ||
| 313 | throw System.Exception("unexpected compare_decimal operation: {op}"); | |
| 314 | si | |
| 315 | ||
| 316 | gen_argument(value: INNATE, index: int, block: BLOCK) is | |
| 317 | block.add(value.arguments[index]); | |
| 318 | si | |
| 319 | ||
| 320 | gen_arguments(value: INNATE, block: BLOCK) is | |
| 321 | for a in value.arguments do | |
| 322 | block.add(a); | |
| 323 | od | |
| 324 | si | |
| 325 | si | |
| 326 | si |