EmitterContext.cs
1 using ARMeilleure.Diagnostics; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using System; 5 using System.Collections.Generic; 6 using System.Reflection; 7 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 8 9 namespace ARMeilleure.Translation 10 { 11 class EmitterContext 12 { 13 private int _localsCount; 14 15 private readonly Dictionary<Operand, BasicBlock> _irLabels; 16 private readonly IntrusiveList<BasicBlock> _irBlocks; 17 18 private BasicBlock _irBlock; 19 private BasicBlock _ifBlock; 20 21 private bool _needsNewBlock; 22 private BasicBlockFrequency _nextBlockFreq; 23 24 public EmitterContext() 25 { 26 _localsCount = 0; 27 28 _irLabels = new Dictionary<Operand, BasicBlock>(); 29 _irBlocks = new IntrusiveList<BasicBlock>(); 30 31 _needsNewBlock = true; 32 _nextBlockFreq = BasicBlockFrequency.Default; 33 } 34 35 public Operand AllocateLocal(OperandType type) 36 { 37 Operand local = Local(type); 38 39 local.NumberLocal(++_localsCount); 40 41 return local; 42 } 43 44 public Operand Add(Operand op1, Operand op2) 45 { 46 return Add(Instruction.Add, Local(op1.Type), op1, op2); 47 } 48 49 public Operand BitwiseAnd(Operand op1, Operand op2) 50 { 51 return Add(Instruction.BitwiseAnd, Local(op1.Type), op1, op2); 52 } 53 54 public Operand BitwiseExclusiveOr(Operand op1, Operand op2) 55 { 56 return Add(Instruction.BitwiseExclusiveOr, Local(op1.Type), op1, op2); 57 } 58 59 public Operand BitwiseNot(Operand op1) 60 { 61 return Add(Instruction.BitwiseNot, Local(op1.Type), op1); 62 } 63 64 public Operand BitwiseOr(Operand op1, Operand op2) 65 { 66 return Add(Instruction.BitwiseOr, Local(op1.Type), op1, op2); 67 } 68 69 public void Branch(Operand label) 70 { 71 NewNextBlockIfNeeded(); 72 73 BranchToLabel(label, uncond: true, BasicBlockFrequency.Default); 74 } 75 76 public void BranchIf(Operand label, Operand op1, Operand op2, Comparison comp, BasicBlockFrequency falseFreq = default) 77 { 78 Add(Instruction.BranchIf, default, op1, op2, Const((int)comp)); 79 80 BranchToLabel(label, uncond: false, falseFreq); 81 } 82 83 public void BranchIfFalse(Operand label, Operand op1, BasicBlockFrequency falseFreq = default) 84 { 85 BranchIf(label, op1, Const(op1.Type, 0), Comparison.Equal, falseFreq); 86 } 87 88 public void BranchIfTrue(Operand label, Operand op1, BasicBlockFrequency falseFreq = default) 89 { 90 BranchIf(label, op1, Const(op1.Type, 0), Comparison.NotEqual, falseFreq); 91 } 92 93 public Operand ByteSwap(Operand op1) 94 { 95 return Add(Instruction.ByteSwap, Local(op1.Type), op1); 96 } 97 98 public virtual Operand Call(MethodInfo info, params Operand[] callArgs) 99 { 100 IntPtr funcPtr = Delegates.GetDelegateFuncPtr(info); 101 102 OperandType returnType = GetOperandType(info.ReturnType); 103 104 Symbols.Add((ulong)funcPtr.ToInt64(), info.Name); 105 106 return Call(Const(funcPtr.ToInt64()), returnType, callArgs); 107 } 108 109 protected static OperandType GetOperandType(Type type) 110 { 111 if (type == typeof(bool) || type == typeof(byte) || 112 type == typeof(char) || type == typeof(short) || 113 type == typeof(int) || type == typeof(sbyte) || 114 type == typeof(ushort) || type == typeof(uint)) 115 { 116 return OperandType.I32; 117 } 118 else if (type == typeof(long) || type == typeof(ulong)) 119 { 120 return OperandType.I64; 121 } 122 else if (type == typeof(double)) 123 { 124 return OperandType.FP64; 125 } 126 else if (type == typeof(float)) 127 { 128 return OperandType.FP32; 129 } 130 else if (type == typeof(V128)) 131 { 132 return OperandType.V128; 133 } 134 else if (type == typeof(void)) 135 { 136 return OperandType.None; 137 } 138 else 139 { 140 throw new ArgumentException($"Invalid type \"{type.Name}\"."); 141 } 142 } 143 144 public Operand Call(Operand address, OperandType returnType, params Operand[] callArgs) 145 { 146 Operand[] args = new Operand[callArgs.Length + 1]; 147 148 args[0] = address; 149 150 Array.Copy(callArgs, 0, args, 1, callArgs.Length); 151 152 if (returnType != OperandType.None) 153 { 154 return Add(Instruction.Call, Local(returnType), args); 155 } 156 else 157 { 158 return Add(Instruction.Call, default, args); 159 } 160 } 161 162 public void Tailcall(Operand address, params Operand[] callArgs) 163 { 164 Operand[] args = new Operand[callArgs.Length + 1]; 165 166 args[0] = address; 167 168 Array.Copy(callArgs, 0, args, 1, callArgs.Length); 169 170 Add(Instruction.Tailcall, default, args); 171 172 _needsNewBlock = true; 173 } 174 175 public Operand CompareAndSwap(Operand address, Operand expected, Operand desired) 176 { 177 return Add(Instruction.CompareAndSwap, Local(desired.Type), address, expected, desired); 178 } 179 180 public Operand CompareAndSwap16(Operand address, Operand expected, Operand desired) 181 { 182 return Add(Instruction.CompareAndSwap16, Local(OperandType.I32), address, expected, desired); 183 } 184 185 public Operand CompareAndSwap8(Operand address, Operand expected, Operand desired) 186 { 187 return Add(Instruction.CompareAndSwap8, Local(OperandType.I32), address, expected, desired); 188 } 189 190 public Operand ConditionalSelect(Operand op1, Operand op2, Operand op3) 191 { 192 return Add(Instruction.ConditionalSelect, Local(op2.Type), op1, op2, op3); 193 } 194 195 public Operand ConvertI64ToI32(Operand op1) 196 { 197 if (op1.Type != OperandType.I64) 198 { 199 throw new ArgumentException($"Invalid operand type \"{op1.Type}\"."); 200 } 201 202 return Add(Instruction.ConvertI64ToI32, Local(OperandType.I32), op1); 203 } 204 205 public Operand ConvertToFP(OperandType type, Operand op1) 206 { 207 return Add(Instruction.ConvertToFP, Local(type), op1); 208 } 209 210 public Operand ConvertToFPUI(OperandType type, Operand op1) 211 { 212 return Add(Instruction.ConvertToFPUI, Local(type), op1); 213 } 214 215 public Operand Copy(Operand op1) 216 { 217 return Add(Instruction.Copy, Local(op1.Type), op1); 218 } 219 220 public Operand Copy(Operand dest, Operand op1) 221 { 222 if (dest.Kind != OperandKind.Register && 223 (dest.Kind != OperandKind.LocalVariable || dest.GetLocalNumber() == 0)) 224 { 225 throw new ArgumentException($"Destination operand must be a Register or a numbered LocalVariable."); 226 } 227 228 return Add(Instruction.Copy, dest, op1); 229 } 230 231 public Operand CountLeadingZeros(Operand op1) 232 { 233 return Add(Instruction.CountLeadingZeros, Local(op1.Type), op1); 234 } 235 236 public Operand Divide(Operand op1, Operand op2) 237 { 238 return Add(Instruction.Divide, Local(op1.Type), op1, op2); 239 } 240 241 public Operand DivideUI(Operand op1, Operand op2) 242 { 243 return Add(Instruction.DivideUI, Local(op1.Type), op1, op2); 244 } 245 246 public Operand ICompare(Operand op1, Operand op2, Comparison comp) 247 { 248 return Add(Instruction.Compare, Local(OperandType.I32), op1, op2, Const((int)comp)); 249 } 250 251 public Operand ICompareEqual(Operand op1, Operand op2) 252 { 253 return ICompare(op1, op2, Comparison.Equal); 254 } 255 256 public Operand ICompareGreater(Operand op1, Operand op2) 257 { 258 return ICompare(op1, op2, Comparison.Greater); 259 } 260 261 public Operand ICompareGreaterOrEqual(Operand op1, Operand op2) 262 { 263 return ICompare(op1, op2, Comparison.GreaterOrEqual); 264 } 265 266 public Operand ICompareGreaterOrEqualUI(Operand op1, Operand op2) 267 { 268 return ICompare(op1, op2, Comparison.GreaterOrEqualUI); 269 } 270 271 public Operand ICompareGreaterUI(Operand op1, Operand op2) 272 { 273 return ICompare(op1, op2, Comparison.GreaterUI); 274 } 275 276 public Operand ICompareLess(Operand op1, Operand op2) 277 { 278 return ICompare(op1, op2, Comparison.Less); 279 } 280 281 public Operand ICompareLessOrEqual(Operand op1, Operand op2) 282 { 283 return ICompare(op1, op2, Comparison.LessOrEqual); 284 } 285 286 public Operand ICompareLessOrEqualUI(Operand op1, Operand op2) 287 { 288 return ICompare(op1, op2, Comparison.LessOrEqualUI); 289 } 290 291 public Operand ICompareLessUI(Operand op1, Operand op2) 292 { 293 return ICompare(op1, op2, Comparison.LessUI); 294 } 295 296 public Operand ICompareNotEqual(Operand op1, Operand op2) 297 { 298 return ICompare(op1, op2, Comparison.NotEqual); 299 } 300 301 public Operand Load(OperandType type, Operand address) 302 { 303 return Add(Instruction.Load, Local(type), address); 304 } 305 306 public Operand Load16(Operand address) 307 { 308 return Add(Instruction.Load16, Local(OperandType.I32), address); 309 } 310 311 public Operand Load8(Operand address) 312 { 313 return Add(Instruction.Load8, Local(OperandType.I32), address); 314 } 315 316 public Operand LoadArgument(OperandType type, int index) 317 { 318 return Add(Instruction.LoadArgument, Local(type), Const(index)); 319 } 320 321 public void LoadFromContext() 322 { 323 _needsNewBlock = true; 324 325 Add(Instruction.LoadFromContext); 326 } 327 328 public void MemoryBarrier() 329 { 330 Add(Instruction.MemoryBarrier); 331 } 332 333 public Operand Multiply(Operand op1, Operand op2) 334 { 335 return Add(Instruction.Multiply, Local(op1.Type), op1, op2); 336 } 337 338 public Operand Multiply64HighSI(Operand op1, Operand op2) 339 { 340 return Add(Instruction.Multiply64HighSI, Local(OperandType.I64), op1, op2); 341 } 342 343 public Operand Multiply64HighUI(Operand op1, Operand op2) 344 { 345 return Add(Instruction.Multiply64HighUI, Local(OperandType.I64), op1, op2); 346 } 347 348 public Operand Negate(Operand op1) 349 { 350 return Add(Instruction.Negate, Local(op1.Type), op1); 351 } 352 353 public void Return() 354 { 355 Add(Instruction.Return); 356 357 _needsNewBlock = true; 358 } 359 360 public void Return(Operand op1) 361 { 362 Add(Instruction.Return, default, op1); 363 364 _needsNewBlock = true; 365 } 366 367 public Operand RotateRight(Operand op1, Operand op2) 368 { 369 return Add(Instruction.RotateRight, Local(op1.Type), op1, op2); 370 } 371 372 public Operand ShiftLeft(Operand op1, Operand op2) 373 { 374 return Add(Instruction.ShiftLeft, Local(op1.Type), op1, op2); 375 } 376 377 public Operand ShiftRightSI(Operand op1, Operand op2) 378 { 379 return Add(Instruction.ShiftRightSI, Local(op1.Type), op1, op2); 380 } 381 382 public Operand ShiftRightUI(Operand op1, Operand op2) 383 { 384 return Add(Instruction.ShiftRightUI, Local(op1.Type), op1, op2); 385 } 386 387 public Operand SignExtend16(OperandType type, Operand op1) 388 { 389 return Add(Instruction.SignExtend16, Local(type), op1); 390 } 391 392 public Operand SignExtend32(OperandType type, Operand op1) 393 { 394 return Add(Instruction.SignExtend32, Local(type), op1); 395 } 396 397 public Operand SignExtend8(OperandType type, Operand op1) 398 { 399 return Add(Instruction.SignExtend8, Local(type), op1); 400 } 401 402 public void Store(Operand address, Operand value) 403 { 404 Add(Instruction.Store, default, address, value); 405 } 406 407 public void Store16(Operand address, Operand value) 408 { 409 Add(Instruction.Store16, default, address, value); 410 } 411 412 public void Store8(Operand address, Operand value) 413 { 414 Add(Instruction.Store8, default, address, value); 415 } 416 417 public void StoreToContext() 418 { 419 Add(Instruction.StoreToContext); 420 421 _needsNewBlock = true; 422 } 423 424 public Operand Subtract(Operand op1, Operand op2) 425 { 426 return Add(Instruction.Subtract, Local(op1.Type), op1, op2); 427 } 428 429 public Operand VectorCreateScalar(Operand value) 430 { 431 return Add(Instruction.VectorCreateScalar, Local(OperandType.V128), value); 432 } 433 434 public Operand VectorExtract(OperandType type, Operand vector, int index) 435 { 436 return Add(Instruction.VectorExtract, Local(type), vector, Const(index)); 437 } 438 439 public Operand VectorExtract16(Operand vector, int index) 440 { 441 return Add(Instruction.VectorExtract16, Local(OperandType.I32), vector, Const(index)); 442 } 443 444 public Operand VectorExtract8(Operand vector, int index) 445 { 446 return Add(Instruction.VectorExtract8, Local(OperandType.I32), vector, Const(index)); 447 } 448 449 public Operand VectorInsert(Operand vector, Operand value, int index) 450 { 451 return Add(Instruction.VectorInsert, Local(OperandType.V128), vector, value, Const(index)); 452 } 453 454 public Operand VectorInsert16(Operand vector, Operand value, int index) 455 { 456 return Add(Instruction.VectorInsert16, Local(OperandType.V128), vector, value, Const(index)); 457 } 458 459 public Operand VectorInsert8(Operand vector, Operand value, int index) 460 { 461 return Add(Instruction.VectorInsert8, Local(OperandType.V128), vector, value, Const(index)); 462 } 463 464 public Operand VectorOne() 465 { 466 return Add(Instruction.VectorOne, Local(OperandType.V128)); 467 } 468 469 public Operand VectorZero() 470 { 471 return Add(Instruction.VectorZero, Local(OperandType.V128)); 472 } 473 474 public Operand VectorZeroUpper64(Operand vector) 475 { 476 return Add(Instruction.VectorZeroUpper64, Local(OperandType.V128), vector); 477 } 478 479 public Operand VectorZeroUpper96(Operand vector) 480 { 481 return Add(Instruction.VectorZeroUpper96, Local(OperandType.V128), vector); 482 } 483 484 public Operand ZeroExtend16(OperandType type, Operand op1) 485 { 486 return Add(Instruction.ZeroExtend16, Local(type), op1); 487 } 488 489 public Operand ZeroExtend32(OperandType type, Operand op1) 490 { 491 return Add(Instruction.ZeroExtend32, Local(type), op1); 492 } 493 494 public Operand ZeroExtend8(OperandType type, Operand op1) 495 { 496 return Add(Instruction.ZeroExtend8, Local(type), op1); 497 } 498 499 private void NewNextBlockIfNeeded() 500 { 501 if (_needsNewBlock) 502 { 503 NewNextBlock(); 504 } 505 } 506 507 private Operand Add(Instruction inst, Operand dest = default) 508 { 509 NewNextBlockIfNeeded(); 510 511 Operation operation = Operation.Factory.Operation(inst, dest); 512 513 _irBlock.Operations.AddLast(operation); 514 515 return dest; 516 } 517 518 private Operand Add(Instruction inst, Operand dest, Operand[] sources) 519 { 520 NewNextBlockIfNeeded(); 521 522 Operation operation = Operation.Factory.Operation(inst, dest, sources); 523 524 _irBlock.Operations.AddLast(operation); 525 526 return dest; 527 } 528 529 private Operand Add(Instruction inst, Operand dest, Operand source0) 530 { 531 NewNextBlockIfNeeded(); 532 533 Operation operation = Operation.Factory.Operation(inst, dest, source0); 534 535 _irBlock.Operations.AddLast(operation); 536 537 return dest; 538 } 539 540 private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1) 541 { 542 NewNextBlockIfNeeded(); 543 544 Operation operation = Operation.Factory.Operation(inst, dest, source0, source1); 545 546 _irBlock.Operations.AddLast(operation); 547 548 return dest; 549 } 550 551 private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1, Operand source2) 552 { 553 NewNextBlockIfNeeded(); 554 555 Operation operation = Operation.Factory.Operation(inst, dest, source0, source1, source2); 556 557 _irBlock.Operations.AddLast(operation); 558 559 return dest; 560 } 561 562 public Operand AddIntrinsic(Intrinsic intrin, params Operand[] args) 563 { 564 return Add(intrin, Local(OperandType.V128), args); 565 } 566 567 public Operand AddIntrinsicInt(Intrinsic intrin, params Operand[] args) 568 { 569 return Add(intrin, Local(OperandType.I32), args); 570 } 571 572 public Operand AddIntrinsicLong(Intrinsic intrin, params Operand[] args) 573 { 574 return Add(intrin, Local(OperandType.I64), args); 575 } 576 577 public void AddIntrinsicNoRet(Intrinsic intrin, params Operand[] args) 578 { 579 Add(intrin, default, args); 580 } 581 582 private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources) 583 { 584 NewNextBlockIfNeeded(); 585 586 Operation operation = Operation.Factory.Operation(intrin, dest, sources); 587 588 _irBlock.Operations.AddLast(operation); 589 590 return dest; 591 } 592 593 private void BranchToLabel(Operand label, bool uncond, BasicBlockFrequency nextFreq) 594 { 595 if (!_irLabels.TryGetValue(label, out BasicBlock branchBlock)) 596 { 597 branchBlock = new BasicBlock(); 598 599 _irLabels.Add(label, branchBlock); 600 } 601 602 if (uncond) 603 { 604 _irBlock.AddSuccessor(branchBlock); 605 } 606 else 607 { 608 // Defer registration of successor to _irBlock so that the order of successors is correct. 609 _ifBlock = branchBlock; 610 } 611 612 _needsNewBlock = true; 613 _nextBlockFreq = nextFreq; 614 } 615 616 public void MarkLabel(Operand label, BasicBlockFrequency nextFreq = default) 617 { 618 _nextBlockFreq = nextFreq; 619 620 if (_irLabels.TryGetValue(label, out BasicBlock nextBlock)) 621 { 622 nextBlock.Index = _irBlocks.Count; 623 624 _irBlocks.AddLast(nextBlock); 625 626 NextBlock(nextBlock); 627 } 628 else 629 { 630 NewNextBlock(); 631 632 _irLabels.Add(label, _irBlock); 633 } 634 } 635 636 private void NewNextBlock() 637 { 638 BasicBlock block = new(_irBlocks.Count); 639 640 _irBlocks.AddLast(block); 641 642 NextBlock(block); 643 } 644 645 private void NextBlock(BasicBlock nextBlock) 646 { 647 if (_irBlock?.SuccessorsCount == 0 && !EndsWithUnconditional(_irBlock)) 648 { 649 _irBlock.AddSuccessor(nextBlock); 650 651 if (_ifBlock != null) 652 { 653 _irBlock.AddSuccessor(_ifBlock); 654 655 _ifBlock = null; 656 } 657 } 658 659 _irBlock = nextBlock; 660 _irBlock.Frequency = _nextBlockFreq; 661 662 _needsNewBlock = false; 663 _nextBlockFreq = BasicBlockFrequency.Default; 664 } 665 666 private static bool EndsWithUnconditional(BasicBlock block) 667 { 668 Operation last = block.Operations.Last; 669 670 return last != default && 671 (last.Instruction == Instruction.Return || 672 last.Instruction == Instruction.Tailcall); 673 } 674 675 public ControlFlowGraph GetControlFlowGraph() 676 { 677 return new ControlFlowGraph(_irBlocks.First, _irBlocks, _localsCount); 678 } 679 } 680 }