R600/SI: Fold immediates when shrinking instructions
authorTom Stellard <thomas.stellard@amd.com>
Fri, 1 Aug 2014 00:32:33 +0000 (00:32 +0000)
committerTom Stellard <thomas.stellard@amd.com>
Fri, 1 Aug 2014 00:32:33 +0000 (00:32 +0000)
This will prevent us from using extra MOV instructions once we prefer
selecting 64-bit instructions.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@214464 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/R600/SIInstrInfo.cpp
lib/Target/R600/SIInstrInfo.h
lib/Target/R600/SIShrinkInstructions.cpp
test/CodeGen/R600/vop-shrink.ll

index fc395ee49194682e96ef4744b0a06edd5ddaff4a..c6be2e46999ab37d9dd0eadd81ff297f2a2f08fb 100644 (file)
@@ -1736,7 +1736,7 @@ void SIInstrInfo::reserveIndirectRegisters(BitVector &Reserved,
     Reserved.set(AMDGPU::VReg_512RegClass.getRegister(Index));
 }
 
-const MachineOperand *SIInstrInfo::getNamedOperand(const MachineInstr& MI,
+MachineOperand *SIInstrInfo::getNamedOperand(MachineInstr &MI,
                                                    unsigned OperandName) const {
   int Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), OperandName);
   if (Idx == -1)
index 48d6ca5fcf34b071a1fd51b65a6a4ef348cb08fa..e3888cf2c314b2c15e3d1b52c5458827ec092e52 100644 (file)
@@ -187,8 +187,7 @@ public:
 
   /// \brief Returns the operand named \p Op.  If \p MI does not have an
   /// operand named \c Op, this function returns nullptr.
-  const MachineOperand *getNamedOperand(const MachineInstr& MI,
-                                        unsigned OperandName) const;
+  MachineOperand *getNamedOperand(MachineInstr &MI, unsigned OperandName) const;
 };
 
 namespace AMDGPU {
index 745c4b65644df897027302cd55a77397dc734de9..529248b1557ff92b7579b47956a46934fc6ae4d0 100644 (file)
@@ -15,6 +15,7 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Function.h"
 #include "llvm/Support/Debug.h"
@@ -24,6 +25,8 @@
 
 STATISTIC(NumInstructionsShrunk,
           "Number of 64-bit instruction reduced to 32-bit.");
+STATISTIC(NumLiteralConstantsFolded,
+          "Number of literal constants folded into 32-bit instructions.");
 
 namespace llvm {
   void initializeSIShrinkInstructionsPass(PassRegistry&);
@@ -109,6 +112,70 @@ static bool canShrink(MachineInstr &MI, const SIInstrInfo *TII,
   return !Clamp || Clamp->getImm() == 0;
 }
 
+/// \brief This function checks \p MI for operands defined by a move immediate
+/// instruction and then folds the literal constant into the instruction if it
+/// can.  This function assumes that \p MI is a VOP1, VOP2, or VOPC instruction
+/// and will only fold literal constants if we are still in SSA.
+static void foldImmediates(MachineInstr &MI, const SIInstrInfo *TII,
+                           MachineRegisterInfo &MRI, bool TryToCommute = true) {
+
+  if (!MRI.isSSA())
+    return;
+
+  assert(TII->isVOP1(MI.getOpcode()) || TII->isVOP2(MI.getOpcode()) ||
+         TII->isVOPC(MI.getOpcode()));
+
+  const SIRegisterInfo &TRI = TII->getRegisterInfo();
+  MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
+
+  // Only one literal constant is allowed per instruction, so if src0 is a
+  // literal constant then we can't do any folding.
+  if (Src0->isImm() && TII->isLiteralConstant(*Src0))
+    return;
+
+
+  // Literal constants and SGPRs can only be used in Src0, so if Src0 is an
+  // SGPR, we cannot commute the instruction, so we can't fold any literal
+  // constants.
+  if (Src0->isReg() && !isVGPR(Src0, TRI, MRI))
+    return;
+
+  // Try to fold Src0
+  if (Src0->isReg()) {
+    unsigned Reg = Src0->getReg();
+    MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
+    if (Def && Def->isMoveImmediate()) {
+      MachineOperand &MovSrc = Def->getOperand(1);
+      bool ConstantFolded = false;
+
+      if (MovSrc.isImm() && isUInt<32>(MovSrc.getImm())) {
+        Src0->ChangeToImmediate(MovSrc.getImm());
+        ConstantFolded = true;
+      } else if (MovSrc.isFPImm()) {
+        const APFloat &APF = MovSrc.getFPImm()->getValueAPF();
+        if (&APF.getSemantics() == &APFloat::IEEEsingle) {
+          MRI.removeRegOperandFromUseList(Src0);
+          Src0->ChangeToImmediate(APF.bitcastToAPInt().getZExtValue());
+          ConstantFolded = true;
+        }
+      }
+      if (ConstantFolded) {
+        for (MachineOperand &Use : MRI.use_operands(Reg))
+          Use.getParent()->dump();
+        if (MRI.use_empty(Reg))
+          Def->eraseFromParent();
+        ++NumLiteralConstantsFolded;
+        return;
+      }
+    }
+  }
+
+  // We have failed to fold src0, so commute the instruction and try again.
+  if (TryToCommute && MI.isCommutable() && TII->commuteInstruction(&MI))
+    foldImmediates(MI, TII, MRI, false);
+
+}
+
 bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
   MachineRegisterInfo &MRI = MF.getRegInfo();
   const SIInstrInfo *TII = static_cast<const SIInstrInfo *>(
@@ -167,27 +234,28 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
       }
 
       // We can shrink this instruction
-      DEBUG(dbgs() << "Shrinking "; MI.dump(); dbgs() << "\n";);
+      DEBUG(dbgs() << "Shrinking "; MI.dump(); dbgs() << '\n';);
 
-      MachineInstrBuilder MIB =
+      MachineInstrBuilder Inst32 =
           BuildMI(MBB, I, MI.getDebugLoc(), TII->get(Op32));
 
       // dst
-      MIB.addOperand(MI.getOperand(0));
+      Inst32.addOperand(MI.getOperand(0));
 
-      MIB.addOperand(*TII->getNamedOperand(MI, AMDGPU::OpName::src0));
+      Inst32.addOperand(*TII->getNamedOperand(MI, AMDGPU::OpName::src0));
 
       const MachineOperand *Src1 =
           TII->getNamedOperand(MI, AMDGPU::OpName::src1);
       if (Src1)
-        MIB.addOperand(*Src1);
+        Inst32.addOperand(*Src1);
 
-      for (const MachineOperand &MO : MI.implicit_operands())
-        MIB.addOperand(MO);
-
-      DEBUG(dbgs() << "e32 MI = "; MI.dump(); dbgs() << "\n";);
       ++NumInstructionsShrunk;
       MI.eraseFromParent();
+
+      foldImmediates(*Inst32, TII, MRI);
+      DEBUG(dbgs() << "e32 MI = " << *Inst32 << '\n');
+
+
     }
   }
   return false;
index 54e588d8084268bbb62ff3d1c4739a699f22d918..f8bc2b4f78f2b95b0608239f7b5c61579b861e0e 100644 (file)
@@ -34,6 +34,20 @@ endif:                                            ; preds = %else, %if
   ret void
 }
 
+; Test that we fold an immediate that was illegal for a 64-bit op into the
+; 32-bit op when we shrink it.
+
+; FUNC-LABEL: @add_fold
+; SI: V_ADD_F32_e32 v{{[0-9]+}}, 0x44800000
+define void @add_fold(float addrspace(1)* %out) {
+entry:
+  %tmp = call i32 @llvm.r600.read.tidig.x()
+  %tmp1 = uitofp i32 %tmp to float
+  %tmp2 = fadd float %tmp1, 1.024000e+03
+  store float %tmp2, float addrspace(1)* %out
+  ret void
+}
+
 ; Function Attrs: nounwind readnone
 declare i32 @llvm.r600.read.tidig.x() #0