@@ -568,6 +568,138 @@ static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
568
568
return DoneMBB;
569
569
}
570
570
571
+ // Lower a `MEMCPY` instruction into a CFG triangle around a `MEMORY_COPY`
572
+ // instuction to handle the zero-length case.
573
+ static MachineBasicBlock *LowerMemcpy (MachineInstr &MI, DebugLoc DL,
574
+ MachineBasicBlock *BB,
575
+ const TargetInstrInfo &TII, bool Int64) {
576
+ MachineRegisterInfo &MRI = BB->getParent ()->getRegInfo ();
577
+
578
+ MachineOperand DstMem = MI.getOperand (0 );
579
+ MachineOperand SrcMem = MI.getOperand (1 );
580
+ MachineOperand Dst = MI.getOperand (2 );
581
+ MachineOperand Src = MI.getOperand (3 );
582
+ MachineOperand Len = MI.getOperand (4 );
583
+
584
+ // We're going to add an extra use to `Len` to test if it's zero; that
585
+ // use shouldn't be a kill, even if the original use is.
586
+ MachineOperand NoKillLen = Len;
587
+ NoKillLen.setIsKill (false );
588
+
589
+ // Decide on which `MachineInstr` opcode we're going to use.
590
+ unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
591
+ unsigned MemoryCopy =
592
+ Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
593
+
594
+ // Create two new basic blocks; one for the new `memory.fill` that we can
595
+ // branch over, and one for the rest of the instructions after the original
596
+ // `memory.fill`.
597
+ const BasicBlock *LLVMBB = BB->getBasicBlock ();
598
+ MachineFunction *F = BB->getParent ();
599
+ MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock (LLVMBB);
600
+ MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock (LLVMBB);
601
+
602
+ MachineFunction::iterator It = ++BB->getIterator ();
603
+ F->insert (It, TrueMBB);
604
+ F->insert (It, DoneMBB);
605
+
606
+ // Transfer the remainder of BB and its successor edges to DoneMBB.
607
+ DoneMBB->splice (DoneMBB->begin (), BB, std::next (MI.getIterator ()), BB->end ());
608
+ DoneMBB->transferSuccessorsAndUpdatePHIs (BB);
609
+
610
+ // Connect the CFG edges.
611
+ BB->addSuccessor (TrueMBB);
612
+ BB->addSuccessor (DoneMBB);
613
+ TrueMBB->addSuccessor (DoneMBB);
614
+
615
+ // Create a virtual register for the `Eqz` result.
616
+ unsigned EqzReg;
617
+ EqzReg = MRI.createVirtualRegister (&WebAssembly::I32RegClass);
618
+
619
+ // Erase the original `memory.copy`.
620
+ MI.eraseFromParent ();
621
+
622
+ // Test if `Len` is zero.
623
+ BuildMI (BB, DL, TII.get (Eqz), EqzReg).add (NoKillLen);
624
+
625
+ // Insert a new `memory.copy`.
626
+ BuildMI (TrueMBB, DL, TII.get (MemoryCopy))
627
+ .add (DstMem)
628
+ .add (SrcMem)
629
+ .add (Dst)
630
+ .add (Src)
631
+ .add (Len);
632
+
633
+ // Create the CFG triangle.
634
+ BuildMI (BB, DL, TII.get (WebAssembly::BR_IF)).addMBB (DoneMBB).addReg (EqzReg);
635
+ BuildMI (TrueMBB, DL, TII.get (WebAssembly::BR)).addMBB (DoneMBB);
636
+
637
+ return DoneMBB;
638
+ }
639
+
640
+ // Lower a `MEMSET` instruction into a CFG triangle around a `MEMORY_FILL`
641
+ // instuction to handle the zero-length case.
642
+ static MachineBasicBlock *LowerMemset (MachineInstr &MI, DebugLoc DL,
643
+ MachineBasicBlock *BB,
644
+ const TargetInstrInfo &TII, bool Int64) {
645
+ MachineRegisterInfo &MRI = BB->getParent ()->getRegInfo ();
646
+
647
+ MachineOperand Mem = MI.getOperand (0 );
648
+ MachineOperand Dst = MI.getOperand (1 );
649
+ MachineOperand Val = MI.getOperand (2 );
650
+ MachineOperand Len = MI.getOperand (3 );
651
+
652
+ // We're going to add an extra use to `Len` to test if it's zero; that
653
+ // use shouldn't be a kill, even if the original use is.
654
+ MachineOperand NoKillLen = Len;
655
+ NoKillLen.setIsKill (false );
656
+
657
+ // Decide on which `MachineInstr` opcode we're going to use.
658
+ unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
659
+ unsigned MemoryFill =
660
+ Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
661
+
662
+ // Create two new basic blocks; one for the new `memory.fill` that we can
663
+ // branch over, and one for the rest of the instructions after the original
664
+ // `memory.fill`.
665
+ const BasicBlock *LLVMBB = BB->getBasicBlock ();
666
+ MachineFunction *F = BB->getParent ();
667
+ MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock (LLVMBB);
668
+ MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock (LLVMBB);
669
+
670
+ MachineFunction::iterator It = ++BB->getIterator ();
671
+ F->insert (It, TrueMBB);
672
+ F->insert (It, DoneMBB);
673
+
674
+ // Transfer the remainder of BB and its successor edges to DoneMBB.
675
+ DoneMBB->splice (DoneMBB->begin (), BB, std::next (MI.getIterator ()), BB->end ());
676
+ DoneMBB->transferSuccessorsAndUpdatePHIs (BB);
677
+
678
+ // Connect the CFG edges.
679
+ BB->addSuccessor (TrueMBB);
680
+ BB->addSuccessor (DoneMBB);
681
+ TrueMBB->addSuccessor (DoneMBB);
682
+
683
+ // Create a virtual register for the `Eqz` result.
684
+ unsigned EqzReg;
685
+ EqzReg = MRI.createVirtualRegister (&WebAssembly::I32RegClass);
686
+
687
+ // Erase the original `memory.fill`.
688
+ MI.eraseFromParent ();
689
+
690
+ // Test if `Len` is zero.
691
+ BuildMI (BB, DL, TII.get (Eqz), EqzReg).add (NoKillLen);
692
+
693
+ // Insert a new `memory.copy`.
694
+ BuildMI (TrueMBB, DL, TII.get (MemoryFill)).add (Mem).add (Dst).add (Val).add (Len);
695
+
696
+ // Create the CFG triangle.
697
+ BuildMI (BB, DL, TII.get (WebAssembly::BR_IF)).addMBB (DoneMBB).addReg (EqzReg);
698
+ BuildMI (TrueMBB, DL, TII.get (WebAssembly::BR)).addMBB (DoneMBB);
699
+
700
+ return DoneMBB;
701
+ }
702
+
571
703
static MachineBasicBlock *
572
704
LowerCallResults (MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
573
705
const WebAssemblySubtarget *Subtarget,
@@ -725,6 +857,14 @@ MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
725
857
case WebAssembly::FP_TO_UINT_I64_F64:
726
858
return LowerFPToInt (MI, DL, BB, TII, true , true , true ,
727
859
WebAssembly::I64_TRUNC_U_F64);
860
+ case WebAssembly::MEMCPY_A32:
861
+ return LowerMemcpy (MI, DL, BB, TII, false );
862
+ case WebAssembly::MEMCPY_A64:
863
+ return LowerMemcpy (MI, DL, BB, TII, true );
864
+ case WebAssembly::MEMSET_A32:
865
+ return LowerMemset (MI, DL, BB, TII, false );
866
+ case WebAssembly::MEMSET_A64:
867
+ return LowerMemset (MI, DL, BB, TII, true );
728
868
case WebAssembly::CALL_RESULTS:
729
869
case WebAssembly::RET_CALL_RESULTS:
730
870
return LowerCallResults (MI, DL, BB, Subtarget, TII);
0 commit comments