1 module vayne.code.emitter; 2 3 4 import std.algorithm; 5 import std.array; 6 import std.string; 7 8 import vayne.ast.node; 9 import vayne.ast.printer; 10 import vayne.op; 11 import vayne.source.source; 12 import vayne.source.token; 13 14 15 private alias Value = Operand; 16 17 18 enum Guard = q{ 19 auto __refs = reduce!((a, b) => a + b)(0, refs_); 20 scope (success) { 21 auto refs = reduce!((a, b) => a + b)(0, refs_); 22 assert((refs == __refs) || (refs == 1 + __refs), "leaking registers!"); 23 } 24 auto __scopes = scopes_.length; 25 scope (success) { 26 auto scopes = scopes_.length; 27 assert(scopes == __scopes, "leaking scopes!"); 28 } 29 }; 30 31 32 struct Emitter { 33 auto instrs() const { 34 return instrs_; 35 } 36 37 auto locs() const { 38 return locs_; 39 } 40 41 auto registerCount() const { 42 return registers_; 43 } 44 45 auto constantCount() const { 46 return cast(uint)constants_.length; 47 } 48 49 static struct ConstantSlot { 50 enum Type : ubyte { 51 Null, 52 Boolean, 53 String, 54 Integer, 55 Float, 56 } 57 58 Type type; 59 string value; 60 } 61 62 auto constants() const { 63 return constants_; 64 } 65 66 void emitModule(Module node) { 67 assert(scopes_.empty); 68 assert(registers_ == 0); 69 70 foreach (child; node.children) 71 emitStatement(child); 72 73 assert(scopes_.empty); 74 assert(!registers_ || reduce!((a, b) => a + b)(0, refs_) == 0); 75 assert(registers_ == frees_.length); 76 } 77 78 private: 79 Value emitExpression(Node node) { 80 debug mixin(Guard); 81 82 assert(node !is null); 83 if (auto expr = cast(Expression)node) { 84 return emitExpression(expr.children[0]); 85 } else if (auto konst = cast(Constant)node) { 86 return emitConstant(konst); 87 } else if (auto ident = cast(Identifier)node) { 88 return emitIdentifier(ident); 89 } else if (auto binop = cast(BinaryOp)node) { 90 return emitBinaryOp(binop); 91 } else if (auto uniop = cast(UnaryOp)node) { 92 return emitUnaryOp(uniop); 93 } else if (auto preop = cast(PrefixOp)node) { 94 return emitPrefixOp(preop); 95 } else if (auto sufop = cast(SuffixOp)node) { 96 return emitSuffixOp(sufop); 97 } else if (auto condexpr = cast(ConditionalExpression)node) { 98 return emitConditionalExpression(condexpr); 99 } else if (auto indexop = cast(IndexOp)node) { 100 return emitIndexOp(indexop); 101 } else if (auto sliceop = cast(SliceOp)node) { 102 return emitSliceOp(sliceop); 103 } else if (auto dispatchop = cast(DispatchOp)node) { 104 return emitDispatchOp(dispatchop); 105 } else if (auto call = cast(FunctionCall)node) { 106 return emitFunctionCall(call); 107 } else { 108 assert(false, "unimplemented expression " ~ typeid(node).toString); 109 } 110 } 111 112 auto emitConstant(Constant node) { 113 debug mixin(Guard); 114 115 assert((node.tok.kind == Token.Kind.Literal) || (node.tok.kind == Token.Kind.Keyword)); 116 117 if (node.tok.kind == Token.Kind.Literal) { 118 final switch (node.tok.kindLiteral) with (Token.LiteralKind) { 119 case Char: 120 case String: 121 return constant(ConstantSlot.Type.String, node.tok.unescaped); 122 case Bin: 123 return constant(ConstantSlot.Type.Integer, node.tok.value); 124 case Oct: 125 return constant(ConstantSlot.Type.Integer, node.tok.value); 126 case Dec: 127 return constant(ConstantSlot.Type.Integer, node.tok.value); 128 case Hex: 129 return constant(ConstantSlot.Type.Integer, node.tok.value); 130 case Float: 131 return constant(ConstantSlot.Type.Float, node.tok.value); 132 } 133 } else { 134 final switch (node.tok.kindKeyword) with (Token.KeywordKind) { 135 case True: 136 return constant(ConstantSlot.Type.Boolean, "true"); 137 case False: 138 return constant(ConstantSlot.Type.Boolean, "false"); 139 case Null: 140 return constant(ConstantSlot.Type.Null, "null"); 141 case In: 142 case Def: 143 case Undef: 144 case As: 145 assert(false, "unimplemented keyword kind constant " ~ node.tok.kindKeyword); 146 } 147 } 148 } 149 150 auto emitIdentifier(Identifier node) { 151 debug mixin(Guard); 152 153 return findSymbol(node.tok.value, node.tok.loc); 154 } 155 156 auto emitUnaryOp(UnaryOp node) { 157 debug mixin(Guard); 158 159 auto expr = emitExpression(node.children[0]); 160 switch (node.tok.name) { 161 case "-": 162 auto target = registerize(node.tok.loc, expr); 163 emit(OpCode.Minus, node.tok.loc, target); 164 return target; 165 case "!": 166 auto target = registerize(node.tok.loc, expr); 167 emit(OpCode.Not, node.tok.loc, target); 168 return target; 169 case "+": 170 return expr; 171 default: 172 assert(false, "unimplemented unary op " ~ node.tok.toString); 173 } 174 } 175 176 auto emitPrefixOp(PrefixOp node) { 177 debug mixin(Guard); 178 179 auto expr = registerize(node.tok.loc, emitExpression(node.children[0])); 180 scope(exit) release(expr); 181 182 switch (node.tok.name) { 183 case "++": 184 auto target = register(); 185 emit(OpCode.Increment, node.tok.loc, expr); 186 emit(OpCode.Move, node.tok.loc, target, expr); 187 return target; 188 case "--": 189 auto target = register(); 190 emit(OpCode.Decrement, node.tok.loc, expr); 191 emit(OpCode.Move, node.tok.loc, target, expr); 192 return target; 193 default: 194 assert(false, "unimplemented prefix op " ~ node.tok.toString); 195 } 196 } 197 198 auto emitSuffixOp(SuffixOp node) { 199 debug mixin(Guard); 200 201 auto expr = registerize(node.tok.loc, emitExpression(node.children[0])); 202 scope(exit) release(expr); 203 204 switch (node.tok.name) { 205 case "++": 206 auto target = register(); 207 emit(OpCode.Move, node.tok.loc, target, expr); 208 emit(OpCode.Increment, node.tok.loc, expr); 209 return target; 210 case "--": 211 auto target = register(); 212 emit(OpCode.Move, node.tok.loc, target, expr); 213 emit(OpCode.Decrement, node.tok.loc, expr); 214 return target; 215 default: 216 assert(false, "unimplemented suffix op " ~ node.tok.toString); 217 } 218 } 219 220 auto emitBinaryOp(BinaryOp node) { 221 debug mixin(Guard); 222 223 { 224 switch (node.tok.name) { 225 case "&&": 226 case "||": 227 auto target = register(); 228 auto lhs = emitExpression(node.children[0]); 229 emit(OpCode.Test, node.tok.loc, target, lhs); 230 release(lhs); 231 232 size_t jumpShortCircuit = placeholder(node.tok.loc); 233 234 auto rhs = emitExpression(node.children[1]); 235 emit(OpCode.Test, node.tok.loc, target, rhs); 236 release(rhs); 237 238 emitAt((node.tok.name == "&&") ? OpCode.JumpIfZero : OpCode.JumpIfNotZero, node.tok.loc, jumpShortCircuit, Value(Value.Kind.Immediate, ip), target); 239 return target; 240 default: 241 break; 242 } 243 } 244 245 { 246 auto lhs = emitExpression(node.children[0]); 247 auto rhs = emitExpression(node.children[1]); 248 scope (exit) release(lhs, rhs); 249 250 auto target = register(); 251 252 switch (node.tok.name) { 253 case "==": 254 emit(OpCode.Equal, node.tok.loc, target, lhs, rhs); 255 break; 256 case "!=": 257 emit(OpCode.NotEqual, node.tok.loc, target, lhs, rhs); 258 break; 259 case ">": 260 emit(OpCode.Greater, node.tok.loc, target, lhs, rhs); 261 break; 262 case ">=": 263 emit(OpCode.GreaterOrEqual, node.tok.loc, target, lhs, rhs); 264 break; 265 case "<": 266 emit(OpCode.Less, node.tok.loc, target, lhs, rhs); 267 break; 268 case "<=": 269 emit(OpCode.LessOrEqual, node.tok.loc, target, lhs, rhs); 270 break; 271 case "+": 272 emit(OpCode.Add, node.tok.loc, target, lhs, rhs); 273 break; 274 case "-": 275 emit(OpCode.Subtract, node.tok.loc, target, lhs, rhs); 276 break; 277 case "*": 278 emit(OpCode.Multiply, node.tok.loc, target, lhs, rhs); 279 break; 280 case "/": 281 emit(OpCode.Divide, node.tok.loc, target, lhs, rhs); 282 break; 283 case "%": 284 emit(OpCode.Remainder, node.tok.loc, target, lhs, rhs); 285 break; 286 case "~": 287 emit(OpCode.Concat, node.tok.loc, target, lhs, rhs); 288 break; 289 case "^^": 290 emit(OpCode.Power, node.tok.loc, target, lhs, rhs); 291 break; 292 case "in": 293 emit(OpCode.TestKey, node.tok.loc, target, rhs, lhs); 294 break; 295 default: 296 assert(false, "unimplemented binary op " ~ node.tok.toString); 297 } 298 299 return target; 300 } 301 } 302 303 auto emitConditionalExpression(ConditionalExpression node) { 304 debug mixin(Guard); 305 306 auto target = registerize(node.tok.loc, emitExpression(node.children[0])); 307 308 emit(OpCode.Test, node.tok.loc, target, target); 309 auto jz = placeholder(node.tok.loc); 310 311 auto trueCase = emitExpression(node.children[1]); 312 emit(OpCode.Move, node.tok.loc, target, trueCase); 313 release(trueCase); 314 315 auto jmp = placeholder(node.tok.loc); 316 auto ipfalse = ip; 317 318 auto falseCase = emitExpression(node.children[2]); 319 emit(OpCode.Move, node.tok.loc, target, falseCase); 320 release(falseCase); 321 322 emitAt(OpCode.JumpIfZero, node.tok.loc, jz, Value(Value.Kind.Immediate, ipfalse), target); 323 emitAt(OpCode.Jump, node.tok.loc, jmp, Value(Value.Kind.Immediate, ip)); 324 325 assert(!canFind(frees_, target.value)); 326 assert(refs_[target.value] > 0); 327 328 return target; 329 } 330 331 auto emitIndexOp(IndexOp node) { 332 debug mixin(Guard); 333 334 auto target = registerize(node.tok.loc, emitExpression(node.children[0])); 335 auto index = emitExpression(node.children[1]); 336 scope(exit) release(index); 337 338 emit(OpCode.Element, node.tok.loc, target, target, index); 339 return target; 340 } 341 342 auto emitSliceOp(SliceOp node) { 343 debug mixin(Guard); 344 345 auto target = registerize(node.tok.loc, emitExpression(node.children[0])); 346 auto start = emitExpression(node.children[1]); 347 auto end = emitExpression(node.children[2]); 348 scope (exit) release(start, end); 349 350 emit(OpCode.Slice, node.tok.loc, target, target, start, end); 351 return target; 352 } 353 354 auto emitDispatchOp(DispatchOp node) { 355 debug mixin(Guard); 356 357 auto obj = emitExpression(node.children[0]); 358 scope (exit) release(obj); 359 360 auto key = constant(ConstantSlot.Type.String, node.target.value); 361 362 auto target = register(); 363 emit(OpCode.Element, node.tok.loc, target, obj, key); 364 return target; 365 } 366 367 auto emitDispatchOpForCall(DispatchOp node, Value obj) { 368 auto expr = emitExpression(node.children[0]); 369 scope (exit) release(expr); 370 371 auto key = constant(ConstantSlot.Type.String, node.target.value); 372 373 emit(OpCode.Move, node.tok.loc, obj, expr); 374 375 auto target = register(); 376 emit(OpCode.Dispatch, node.tok.loc, target, expr, key); 377 return target; 378 } 379 380 auto emitFunctionCall(FunctionCall node) { 381 debug mixin(Guard); 382 383 auto result = register(); 384 auto dispatched = (cast(DispatchOp)node.children[0] !is null); 385 auto args = node.children[1..$]; 386 387 if (!dispatched) { 388 auto func = emitExpression(node.children[0]); 389 scope (exit) release(func); 390 391 if (args.length) { 392 auto base = registers(args.length); 393 394 foreach (i, arg; args) { 395 auto argValue = emitExpression(arg); 396 emit(OpCode.Move, node.tok.loc, Value(Value.Kind.Register, base.value + cast(uint)i), argValue); 397 release(argValue); 398 } 399 400 emit(OpCode.Call, node.tok.loc, result, func, base, Value(Value.Kind.Immediate, cast(uint)args.length)); 401 402 foreach (i; 0..args.length) 403 release(Value(Value.Kind.Register, base.value + cast(uint)i)); 404 } else { 405 emit(OpCode.Call, node.tok.loc, result, func, Value(Value.Kind.Register, 0), Value(Value.Kind.Immediate, 0)); 406 } 407 } else { 408 auto base = registers(1 + args.length); 409 410 foreach (i, arg; args) { 411 auto argValue = emitExpression(arg); 412 emit(OpCode.Move, node.tok.loc, Value(Value.Kind.Register, base.value + 1 + cast(uint)i), argValue); 413 release(argValue); 414 } 415 416 auto func = emitDispatchOpForCall(cast(DispatchOp)node.children[0], base); 417 scope(exit) release(func); 418 emit(OpCode.DispatchCall, node.tok.loc, result, func, base, Value(Value.Kind.Immediate, 1 + cast(uint)args.length)); 419 420 foreach (i; 0..args.length + 1) 421 release(Value(Value.Kind.Register, base.value + cast(uint)i)); 422 } 423 return result; 424 } 425 426 void emitOutput(Output node) { 427 debug mixin(Guard); 428 429 auto expr = emitExpression(node.children[0]); 430 emit(OpCode.Output, node.tok.loc, expr); 431 release(expr); 432 } 433 434 void emitStatement(Node node) { 435 debug mixin(Guard); 436 437 if (auto output = cast(Output)node) { 438 emitOutput(output); 439 } else if (auto ifstmt = cast(IfStatement)node) { 440 emitIfStatement(ifstmt); 441 } else if (auto loopstmt = cast(LoopStatement)node) { 442 emitLoopStatement(loopstmt); 443 } else if (auto call = cast(FunctionCall)node) { 444 release(emitFunctionCall(call)); 445 } else if (auto withstmt = cast(WithStatement)node) { 446 emitWithStatement(withstmt); 447 } else if (auto stmtblock = cast(StatementBlock)node) { 448 emitStatementBlock(stmtblock); 449 } else { 450 assert(false, "unimplemented statement " ~ node.tok.toString); 451 } 452 } 453 454 void emitStatementBlock(StatementBlock node) { 455 debug mixin(Guard); 456 457 foreach (child; node.children) 458 emitStatement(child); 459 } 460 461 void emitWithStatement(WithStatement node) { 462 debug mixin(Guard); 463 464 Value[] exprs; 465 exprs.reserve(node.children.length - 1); 466 467 pushScope(); 468 469 uint scopes; 470 foreach (i, childNode; node.children[0..$-1]) { 471 auto child = cast(WithExpression)childNode; 472 assert(child !is null); 473 474 auto expr = emitExpression(child.children[0]); 475 476 if (child.name.empty) { 477 ++scopes; 478 emit(OpCode.PushScope, child.tok.loc, expr); 479 } else { 480 auto copy = register(); 481 scope(exit) release(copy); 482 483 emit(OpCode.Move, child.tok.loc, copy, expr); 484 swap(copy, expr); 485 486 addSymbol(child.name.value, aquire(expr)); 487 } 488 489 exprs ~= expr; 490 } 491 492 emitStatement(node.children[$ - 1]); 493 if (scopes) 494 emit(OpCode.PopScope, node.tok.loc, Value(Value.Kind.Immediate, scopes)); 495 496 foreach (expr; exprs) 497 release(expr); 498 499 popScope(); 500 } 501 502 void emitIfStatement(IfStatement node) { 503 debug mixin(Guard); 504 505 auto expr = emitExpression(node.children[0]); 506 auto cond = register(); 507 508 emit(OpCode.Test, node.tok.loc, cond, expr); 509 release(expr); 510 511 size_t jumpTrueCase = placeholder(node.tok.loc); 512 release(cond); 513 514 assert(canFind(frees_, cond.value)); 515 assert(refs_[cond.value] == 0); 516 517 emitStatement(node.children[1]); 518 519 size_t jumpFalseCase; 520 if (node.children[2] !is null) 521 jumpFalseCase = placeholder(node.tok.loc); 522 523 emitAt(OpCode.JumpIfZero, node.tok.loc, jumpTrueCase, Value(Value.Kind.Immediate, ip), cond); 524 if (node.children[2] !is null) { 525 emitStatement(node.children[2]); 526 emitAt(OpCode.Jump, node.tok.loc, jumpFalseCase, Value(Value.Kind.Immediate, ip)); 527 } 528 } 529 530 void emitLoopStatement(LoopStatement node) { 531 debug mixin(Guard); 532 533 auto body_ = cast(StatementBlock)node.children[2]; 534 assert(body_ !is null); 535 536 pushScope(); 537 538 if (node.children[1]) { 539 // numeric range 540 auto end = emitExpression(node.children[1]); 541 auto it = registerize(node.tok.loc, emitExpression(node.children[0])); 542 auto value = it; 543 544 if (!node.key.empty) 545 addSymbol(node.key.value, aquire(it)); 546 if (!node.value.empty) 547 addSymbol(node.value.value, aquire(value)); 548 549 auto test = ip; 550 auto cond = register(); 551 emit(OpCode.Less, node.tok.loc, cond, it, end); 552 size_t jumpBody = placeholder(node.tok.loc); 553 release(cond); 554 555 emitStatementBlock(body_); 556 emit(OpCode.Increment, node.tok.loc, it); 557 emit(OpCode.Jump, node.tok.loc, Value(Value.Kind.Immediate, test)); 558 emitAt(OpCode.JumpIfZero, node.tok.loc, jumpBody, Value(Value.Kind.Immediate, ip), cond); 559 release(it, end); 560 } else { 561 // array / object 562 auto obj = emitExpression(node.children[0]); 563 auto keys = register(); 564 auto len = register(); 565 566 emit(OpCode.Keys, node.tok.loc, keys, obj); 567 emit(OpCode.Length, node.tok.loc, len, keys); 568 569 auto it = registerize(node.tok.loc, constant(ConstantSlot.Type.Integer, "0")); 570 auto key = register(); 571 auto value = register(); 572 573 if (!node.key.empty) 574 addSymbol(node.key.value, aquire(key)); 575 if (!node.value.empty) 576 addSymbol(node.value.value, aquire(value)); 577 578 auto test = ip; 579 auto cond = register(); 580 emit(OpCode.Less, node.tok.loc, cond, it, len); 581 size_t jumpBody = placeholder(node.tok.loc); 582 release(cond); 583 584 emit(OpCode.Element, node.tok.loc, key, keys, it); 585 emit(OpCode.Element, node.tok.loc, value, obj, key); 586 587 emitStatementBlock(body_); 588 emit(OpCode.Increment, node.tok.loc, it); 589 emit(OpCode.Jump, node.tok.loc, Value(Value.Kind.Immediate, test)); 590 emitAt(OpCode.JumpIfZero, node.tok.loc, jumpBody, Value(Value.Kind.Immediate, ip), cond); 591 release(it, keys, len, obj, key, value); 592 } 593 594 popScope(); 595 } 596 597 Value register() { 598 if (frees_.empty) { 599 refs_ ~= cast(size_t)1; 600 return Value(Value.Kind.Register, registers_++); 601 } 602 auto free = frees_.back; 603 frees_.popBack; 604 605 assert(free < registers_); 606 assert(refs_[free] == 0); 607 ++refs_[free]; 608 return Value(Value.Kind.Register, free); 609 } 610 611 auto registers(size_t count) { 612 if (count == 1) { 613 return register(); 614 } else if (count > 1) { 615 auto index = registers_; 616 617 if (frees_.length >= count) { 618 frees_.sort(); 619 620 uint start = 0; 621 while (start + count <= frees_.length) { 622 if (frees_[start + count - 1] == frees_[start] + count - 1) 623 break; 624 ++start; 625 } 626 627 if (start + count <= frees_.length) { 628 index = frees_[start]; 629 630 frees_ = frees_[0..start] ~ frees_[start + count..$]; // TODO: find starting from the end, then manually copy + pop 631 } 632 } 633 634 if (index == registers_) { 635 registers_ += count; 636 refs_.length = registers_; 637 } 638 639 foreach (i; index..index + count) { 640 assert(refs_[i] == 0); 641 refs_[i] = 1; 642 } 643 644 return Value(Value.Kind.Register, index); 645 } 646 647 return Value(Value.Kind.Register, uint.max); 648 } 649 650 auto aquire(Value v) { 651 assert(!frees_.canFind(v.value), format("aquiring freed register %s", v.value)); 652 if (v.kind == Value.Kind.Register) 653 ++refs_[v.value]; 654 return v; 655 } 656 657 void release(Values...)(Values values) { 658 foreach (v; values) { 659 if (v.kind == Value.Kind.Register) { 660 if (refs_[v.value] > 0) { 661 --refs_[v.value]; 662 if (refs_[v.value] == 0) { 663 assert(!frees_.canFind(v.value), format("double releasing register %s", v.value)); 664 frees_ ~= v.value; 665 } 666 } else { 667 assert(false, format("double releasing register %s", v.value)); 668 } 669 } 670 } 671 } 672 673 auto constant(ConstantSlot.Type type, string value) { 674 auto map = indexConstants_[type]; 675 if (auto pvalue = value in map) 676 return Value(Value.Kind.Constant, *pvalue); 677 678 auto slot = cast(uint)constants_.length; 679 indexConstants_[type][value] = slot; 680 constants_ ~= ConstantSlot(type, value); 681 682 return Value(Value.Kind.Constant, slot); 683 } 684 685 auto registerize(SourceLoc loc, Value value) { 686 if (value.kind != Value.Kind.Register) { 687 assert(value.kind == Value.Kind.Constant); 688 689 auto target = register(); 690 emit(OpCode.Move, loc, target, value); 691 return target; 692 } 693 return value; 694 } 695 696 auto placeholder(SourceLoc loc) { 697 instrs_ ~= Instr(OpCode.Nop); 698 locs_ ~= loc; 699 return cast(uint)instrs_.length - 1; 700 } 701 702 auto ip() const { 703 return cast(uint)instrs_.length; 704 } 705 706 auto emit(Args...)(OpCode op, SourceLoc loc, Args args) { 707 instrs_ ~= Instr(op, args); 708 locs_ ~= loc; 709 return instrs_.length - 1; 710 } 711 712 auto emitAt(Args...)(OpCode op, SourceLoc loc, size_t at, Args args) { 713 instrs_[at] = Instr(op, args); 714 locs_[at] = loc; 715 } 716 717 void pushScope() { 718 ++scopes_.length; 719 } 720 721 void addSymbol(string name, Value value) { 722 assert(!name.empty); 723 724 foreach_reverse(s; scopes_) { 725 if (auto pvalue = name in s) 726 throw new Exception(format("symbol %s shadows symbol with same name %s", name, name)); 727 } 728 scopes_.back[name] = value; 729 } 730 731 Value findSymbol(string name, SourceLoc loc) { 732 foreach_reverse (s; scopes_) { 733 if (auto pvalue = name in s) 734 return aquire(*pvalue); 735 } 736 737 auto result = register(); 738 emit(OpCode.LookUp, loc, result, constant(ConstantSlot.Type.String, name)); 739 return result; 740 } 741 742 void popScope() { 743 foreach (k, v; scopes_.back) 744 release(v); 745 --scopes_.length; 746 } 747 748 uint[] frees_; 749 uint[] refs_; 750 uint registers_; 751 752 Value[string][] scopes_; 753 754 ConstantSlot[] constants_; 755 uint[string][5] indexConstants_; 756 757 Instr[] instrs_; 758 SourceLoc[] locs_; 759 }