13dac3a9bSDimitry Andric //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//
23dac3a9bSDimitry Andric //
33dac3a9bSDimitry Andric //                     The LLVM Compiler Infrastructure
43dac3a9bSDimitry Andric //
53dac3a9bSDimitry Andric // This file is distributed under the University of Illinois Open Source
63dac3a9bSDimitry Andric // License. See LICENSE.TXT for details.
73dac3a9bSDimitry Andric //
83dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
93dac3a9bSDimitry Andric ///
103dac3a9bSDimitry Andric /// \file
114ba319b5SDimitry Andric /// This file contains the WebAssembly implementation of the
123dac3a9bSDimitry Andric /// TargetInstrInfo class.
133dac3a9bSDimitry Andric ///
143dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
153dac3a9bSDimitry Andric 
163dac3a9bSDimitry Andric #include "WebAssemblyInstrInfo.h"
173dac3a9bSDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
183ca95b02SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
193dac3a9bSDimitry Andric #include "WebAssemblySubtarget.h"
203dac3a9bSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
213dac3a9bSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
223dac3a9bSDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
233dac3a9bSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
243dac3a9bSDimitry Andric using namespace llvm;
253dac3a9bSDimitry Andric 
263dac3a9bSDimitry Andric #define DEBUG_TYPE "wasm-instr-info"
273dac3a9bSDimitry Andric 
287d523365SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR
297d523365SDimitry Andric #include "WebAssemblyGenInstrInfo.inc"
307d523365SDimitry Andric 
WebAssemblyInstrInfo(const WebAssemblySubtarget & STI)313dac3a9bSDimitry Andric WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)
327d523365SDimitry Andric     : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN,
334ba319b5SDimitry Andric                               WebAssembly::ADJCALLSTACKUP,
344ba319b5SDimitry Andric                               WebAssembly::CATCHRET),
357d523365SDimitry Andric       RI(STI.getTargetTriple()) {}
367d523365SDimitry Andric 
isReallyTriviallyReMaterializable(const MachineInstr & MI,AliasAnalysis * AA) const373ca95b02SDimitry Andric bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(
383ca95b02SDimitry Andric     const MachineInstr &MI, AliasAnalysis *AA) const {
393ca95b02SDimitry Andric   switch (MI.getOpcode()) {
403ca95b02SDimitry Andric   case WebAssembly::CONST_I32:
413ca95b02SDimitry Andric   case WebAssembly::CONST_I64:
423ca95b02SDimitry Andric   case WebAssembly::CONST_F32:
433ca95b02SDimitry Andric   case WebAssembly::CONST_F64:
443ca95b02SDimitry Andric     // isReallyTriviallyReMaterializableGeneric misses these because of the
453ca95b02SDimitry Andric     // ARGUMENTS implicit def, so we manualy override it here.
463ca95b02SDimitry Andric     return true;
473ca95b02SDimitry Andric   default:
483ca95b02SDimitry Andric     return false;
493ca95b02SDimitry Andric   }
503ca95b02SDimitry Andric }
513ca95b02SDimitry Andric 
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,unsigned DestReg,unsigned SrcReg,bool KillSrc) const527d523365SDimitry Andric void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
537d523365SDimitry Andric                                        MachineBasicBlock::iterator I,
543ca95b02SDimitry Andric                                        const DebugLoc &DL, unsigned DestReg,
557d523365SDimitry Andric                                        unsigned SrcReg, bool KillSrc) const {
567d523365SDimitry Andric   // This method is called by post-RA expansion, which expects only pregs to
577d523365SDimitry Andric   // exist. However we need to handle both here.
587d523365SDimitry Andric   auto &MRI = MBB.getParent()->getRegInfo();
593ca95b02SDimitry Andric   const TargetRegisterClass *RC =
603ca95b02SDimitry Andric       TargetRegisterInfo::isVirtualRegister(DestReg)
613ca95b02SDimitry Andric           ? MRI.getRegClass(DestReg)
623ca95b02SDimitry Andric           : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
637d523365SDimitry Andric 
64d88c1a5aSDimitry Andric   unsigned CopyOpcode;
657d523365SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
66d88c1a5aSDimitry Andric     CopyOpcode = WebAssembly::COPY_I32;
677d523365SDimitry Andric   else if (RC == &WebAssembly::I64RegClass)
68d88c1a5aSDimitry Andric     CopyOpcode = WebAssembly::COPY_I64;
697d523365SDimitry Andric   else if (RC == &WebAssembly::F32RegClass)
70d88c1a5aSDimitry Andric     CopyOpcode = WebAssembly::COPY_F32;
717d523365SDimitry Andric   else if (RC == &WebAssembly::F64RegClass)
72d88c1a5aSDimitry Andric     CopyOpcode = WebAssembly::COPY_F64;
73*b5893f02SDimitry Andric   else if (RC == &WebAssembly::V128RegClass)
74*b5893f02SDimitry Andric     CopyOpcode = WebAssembly::COPY_V128;
757d523365SDimitry Andric   else
767d523365SDimitry Andric     llvm_unreachable("Unexpected register class");
777d523365SDimitry Andric 
78d88c1a5aSDimitry Andric   BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)
797d523365SDimitry Andric       .addReg(SrcReg, KillSrc ? RegState::Kill : 0);
807d523365SDimitry Andric }
817d523365SDimitry Andric 
commuteInstructionImpl(MachineInstr & MI,bool NewMI,unsigned OpIdx1,unsigned OpIdx2) const82*b5893f02SDimitry Andric MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(
83*b5893f02SDimitry Andric     MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {
843ca95b02SDimitry Andric   // If the operands are stackified, we can't reorder them.
853ca95b02SDimitry Andric   WebAssemblyFunctionInfo &MFI =
863ca95b02SDimitry Andric       *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
873ca95b02SDimitry Andric   if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||
883ca95b02SDimitry Andric       MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))
893ca95b02SDimitry Andric     return nullptr;
903ca95b02SDimitry Andric 
913ca95b02SDimitry Andric   // Otherwise use the default implementation.
923ca95b02SDimitry Andric   return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
933ca95b02SDimitry Andric }
943ca95b02SDimitry Andric 
957d523365SDimitry Andric // Branch analysis.
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool) const963ca95b02SDimitry Andric bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
977d523365SDimitry Andric                                          MachineBasicBlock *&TBB,
987d523365SDimitry Andric                                          MachineBasicBlock *&FBB,
997d523365SDimitry Andric                                          SmallVectorImpl<MachineOperand> &Cond,
1007d523365SDimitry Andric                                          bool /*AllowModify*/) const {
1017d523365SDimitry Andric   bool HaveCond = false;
1027d523365SDimitry Andric   for (MachineInstr &MI : MBB.terminators()) {
1037d523365SDimitry Andric     switch (MI.getOpcode()) {
1047d523365SDimitry Andric     default:
1057d523365SDimitry Andric       // Unhandled instruction; bail out.
1067d523365SDimitry Andric       return true;
1077d523365SDimitry Andric     case WebAssembly::BR_IF:
1087d523365SDimitry Andric       if (HaveCond)
1097d523365SDimitry Andric         return true;
110444ed5c5SDimitry Andric       // If we're running after CFGStackify, we can't optimize further.
1113ca95b02SDimitry Andric       if (!MI.getOperand(0).isMBB())
112444ed5c5SDimitry Andric         return true;
1137d523365SDimitry Andric       Cond.push_back(MachineOperand::CreateImm(true));
1143ca95b02SDimitry Andric       Cond.push_back(MI.getOperand(1));
1153ca95b02SDimitry Andric       TBB = MI.getOperand(0).getMBB();
1167d523365SDimitry Andric       HaveCond = true;
1177d523365SDimitry Andric       break;
1187d523365SDimitry Andric     case WebAssembly::BR_UNLESS:
1197d523365SDimitry Andric       if (HaveCond)
1207d523365SDimitry Andric         return true;
121444ed5c5SDimitry Andric       // If we're running after CFGStackify, we can't optimize further.
1223ca95b02SDimitry Andric       if (!MI.getOperand(0).isMBB())
123444ed5c5SDimitry Andric         return true;
1247d523365SDimitry Andric       Cond.push_back(MachineOperand::CreateImm(false));
1253ca95b02SDimitry Andric       Cond.push_back(MI.getOperand(1));
1263ca95b02SDimitry Andric       TBB = MI.getOperand(0).getMBB();
1277d523365SDimitry Andric       HaveCond = true;
1287d523365SDimitry Andric       break;
1297d523365SDimitry Andric     case WebAssembly::BR:
130444ed5c5SDimitry Andric       // If we're running after CFGStackify, we can't optimize further.
131444ed5c5SDimitry Andric       if (!MI.getOperand(0).isMBB())
132444ed5c5SDimitry Andric         return true;
1337d523365SDimitry Andric       if (!HaveCond)
1347d523365SDimitry Andric         TBB = MI.getOperand(0).getMBB();
1357d523365SDimitry Andric       else
1367d523365SDimitry Andric         FBB = MI.getOperand(0).getMBB();
1377d523365SDimitry Andric       break;
1387d523365SDimitry Andric     }
1397d523365SDimitry Andric     if (MI.isBarrier())
1407d523365SDimitry Andric       break;
1417d523365SDimitry Andric   }
1427d523365SDimitry Andric 
1437d523365SDimitry Andric   return false;
1447d523365SDimitry Andric }
1457d523365SDimitry Andric 
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const146d88c1a5aSDimitry Andric unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,
147d88c1a5aSDimitry Andric                                             int *BytesRemoved) const {
148d88c1a5aSDimitry Andric   assert(!BytesRemoved && "code size not handled");
149d88c1a5aSDimitry Andric 
1507d523365SDimitry Andric   MachineBasicBlock::instr_iterator I = MBB.instr_end();
1517d523365SDimitry Andric   unsigned Count = 0;
1527d523365SDimitry Andric 
1537d523365SDimitry Andric   while (I != MBB.instr_begin()) {
1547d523365SDimitry Andric     --I;
1554ba319b5SDimitry Andric     if (I->isDebugInstr())
1567d523365SDimitry Andric       continue;
1577d523365SDimitry Andric     if (!I->isTerminator())
1587d523365SDimitry Andric       break;
1597d523365SDimitry Andric     // Remove the branch.
1607d523365SDimitry Andric     I->eraseFromParent();
1617d523365SDimitry Andric     I = MBB.instr_end();
1627d523365SDimitry Andric     ++Count;
1637d523365SDimitry Andric   }
1647d523365SDimitry Andric 
1657d523365SDimitry Andric   return Count;
1667d523365SDimitry Andric }
1677d523365SDimitry Andric 
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const168*b5893f02SDimitry Andric unsigned WebAssemblyInstrInfo::insertBranch(
169*b5893f02SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
170*b5893f02SDimitry Andric     ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
171d88c1a5aSDimitry Andric   assert(!BytesAdded && "code size not handled");
172d88c1a5aSDimitry Andric 
1737d523365SDimitry Andric   if (Cond.empty()) {
1747d523365SDimitry Andric     if (!TBB)
1757d523365SDimitry Andric       return 0;
1767d523365SDimitry Andric 
1777d523365SDimitry Andric     BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);
1787d523365SDimitry Andric     return 1;
1797d523365SDimitry Andric   }
1807d523365SDimitry Andric 
1817d523365SDimitry Andric   assert(Cond.size() == 2 && "Expected a flag and a successor block");
1827d523365SDimitry Andric 
1837d523365SDimitry Andric   if (Cond[0].getImm()) {
1847a7e6055SDimitry Andric     BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
1857d523365SDimitry Andric   } else {
1867a7e6055SDimitry Andric     BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
1877d523365SDimitry Andric   }
1887d523365SDimitry Andric   if (!FBB)
1897d523365SDimitry Andric     return 1;
1907d523365SDimitry Andric 
1917d523365SDimitry Andric   BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);
1927d523365SDimitry Andric   return 2;
1937d523365SDimitry Andric }
1947d523365SDimitry Andric 
reverseBranchCondition(SmallVectorImpl<MachineOperand> & Cond) const195d88c1a5aSDimitry Andric bool WebAssemblyInstrInfo::reverseBranchCondition(
1967d523365SDimitry Andric     SmallVectorImpl<MachineOperand> &Cond) const {
1977d523365SDimitry Andric   assert(Cond.size() == 2 && "Expected a flag and a successor block");
1987d523365SDimitry Andric   Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
1997d523365SDimitry Andric   return false;
2007d523365SDimitry Andric }
201