@@ -568,6 +568,138 @@ static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
568568 return DoneMBB;
569569}
570570
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+
571703static MachineBasicBlock *
572704LowerCallResults (MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
573705 const WebAssemblySubtarget *Subtarget,
@@ -725,6 +857,14 @@ MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
725857 case WebAssembly::FP_TO_UINT_I64_F64:
726858 return LowerFPToInt (MI, DL, BB, TII, true , true , true ,
727859 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 );
728868 case WebAssembly::CALL_RESULTS:
729869 case WebAssembly::RET_CALL_RESULTS:
730870 return LowerCallResults (MI, DL, BB, Subtarget, TII);
0 commit comments