<div dir="ltr">Thanks, Richard! Checked in at r239497.<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jun 10, 2015 at 5:10 PM, Richard Trieu <span dir="ltr"><<a href="mailto:rtrieu@google.com" target="_blank">rtrieu@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Wed, Jun 10, 2015 at 1:32 PM, Sanjay Patel <span dir="ltr"><<a href="mailto:spatel@rotateright.com" target="_blank">spatel@rotateright.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: spatel<br>
Date: Wed Jun 10 15:32:21 2015<br>
New Revision: 239486<br>
<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject-3Frev-3D239486-26view-3Drev&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=mrSGlgUAkGErxb9wAtFAU7V4vjQ9y8k5dplQBUm3E6E&s=q4WEQAAvO_VcTH97_nYcrduyCGwe97WKO1_qjZ6f6Fo&e=" target="_blank">http://llvm.org/viewvc/llvm-project?rev=239486&view=rev</a><br>
Log:<br>
[x86] Add a reassociation optimization to increase ILP via the MachineCombiner pass<br>
<br>
This is a reimplementation of D9780 at the machine instruction level rather than the DAG.<br>
<br>
Use the MachineCombiner pass to reassociate scalar single-precision AVX additions (just a<br>
starting point; see the TODO comments) to increase ILP when it's safe to do so.<br>
<br>
The code is closely based on the existing MachineCombiner optimization that is implemented<br>
for AArch64.<br>
<br>
This patch should not cause the kind of spilling tragedy that led to the reversion of r236031.<br>
<br>
Differential Revision: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__reviews.llvm.org_D10321&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=mrSGlgUAkGErxb9wAtFAU7V4vjQ9y8k5dplQBUm3E6E&s=w2vfWHaoTtaqLhyU5Cj3aSyBw-pAODJ1cHwr1ouQNJ4&e=" target="_blank">http://reviews.llvm.org/D10321</a><br>
<br>
<br>
Modified:<br>
    llvm/trunk/lib/Target/X86/X86InstrInfo.cpp<br>
    llvm/trunk/lib/Target/X86/X86InstrInfo.h<br>
    llvm/trunk/lib/Target/X86/X86TargetMachine.cpp<br>
    llvm/trunk/test/CodeGen/X86/fp-fast.ll<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.cpp<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_lib_Target_X86_X86InstrInfo.cpp-3Frev-3D239486-26r1-3D239485-26r2-3D239486-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=mrSGlgUAkGErxb9wAtFAU7V4vjQ9y8k5dplQBUm3E6E&s=XdhI_f-K9q138Yf5hhIwWYCx_3nJVSaelvUxs5tbyz8&e=" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.cpp?rev=239486&r1=239485&r2=239486&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86InstrInfo.cpp (original)<br>
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.cpp Wed Jun 10 15:32:21 2015<br>
@@ -6226,6 +6226,210 @@ hasHighOperandLatency(const InstrItinera<br>
   return isHighLatencyDef(DefMI->getOpcode());<br>
 }<br>
<br>
+/// If the input instruction is part of a chain of dependent ops that are<br>
+/// suitable for reassociation, return the earlier instruction in the sequence<br>
+/// that defines its first operand, otherwise return a nullptr.<br>
+/// If the instruction's operands must be commuted to be considered a<br>
+/// reassociation candidate, Commuted will be set to true.<br>
+static MachineInstr *isReassocCandidate(const MachineInstr &Inst,<br>
+                                        unsigned AssocOpcode,<br>
+                                        bool checkPrevOneUse,<br>
+                                        bool &Commuted) {<br>
+  if (Inst.getOpcode() != AssocOpcode)<br>
+    return nullptr;<br>
+<br>
+  MachineOperand Op1 = Inst.getOperand(1);<br>
+  MachineOperand Op2 = Inst.getOperand(2);<br>
+<br>
+  const MachineBasicBlock *MBB = Inst.getParent();<br>
+  const MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();<br>
+<br>
+  // We need virtual register definitions.<br>
+  MachineInstr *MI1 = nullptr;<br>
+  MachineInstr *MI2 = nullptr;<br>
+  if (Op1.isReg() && TargetRegisterInfo::isVirtualRegister(Op1.getReg()))<br>
+    MI1 = MRI.getUniqueVRegDef(Op1.getReg());<br>
+  if (Op2.isReg() && TargetRegisterInfo::isVirtualRegister(Op2.getReg()))<br>
+    MI2 = MRI.getUniqueVRegDef(Op2.getReg());<br>
+<br>
+  // And they need to be in the trace (otherwise, they won't have a depth).<br>
+  if (!MI1 || !MI2 || MI1->getParent() != MBB || MI2->getParent() != MBB)<br>
+    return nullptr;<br>
+<br>
+  Commuted = false;<br>
+  if (MI1->getOpcode() != AssocOpcode && MI2->getOpcode() == AssocOpcode) {<br>
+    std::swap(MI1, MI2);<br>
+    Commuted = true;<br>
+  }<br>
+<br>
+  // Avoid reassociating operands when it won't provide any benefit. If both<br>
+  // operands are produced by instructions of this type, we may already<br>
+  // have the optimal sequence.<br>
+  if (MI2->getOpcode() == AssocOpcode)<br>
+    return nullptr;<br>
+<br>
+  // The instruction must only be used by the other instruction that we<br>
+  // reassociate with.<br>
+  if (checkPrevOneUse && !MRI.hasOneNonDBGUse(MI1->getOperand(0).getReg()))<br>
+    return nullptr;<br>
+<br>
+  // We must match a simple chain of dependent ops.<br>
+  // TODO: This check is not necessary for the earliest instruction in the<br>
+  // sequence. Instead of a sequence of 3 dependent instructions with the same<br>
+  // opcode, we only need to find a sequence of 2 dependent instructions with<br>
+  // the same opcode plus 1 other instruction that adds to the height of the<br>
+  // trace.<br>
+  if (MI1->getOpcode() != AssocOpcode)<br>
+    return nullptr;<br>
+<br>
+  return MI1;<br>
+}<br>
+<br>
+/// Select a pattern based on how the operands of each associative operation<br>
+/// need to be commuted.<br>
+static MachineCombinerPattern::MC_PATTERN getPattern(bool CommutePrev,<br>
+                                                     bool CommuteRoot) {<br>
+  if (CommutePrev) {<br>
+    if (CommuteRoot)<br>
+      return MachineCombinerPattern::MC_REASSOC_XA_YB;<br>
+    return MachineCombinerPattern::MC_REASSOC_XA_BY;<br>
+  } else {<br>
+    if (CommuteRoot)<br>
+      return MachineCombinerPattern::MC_REASSOC_AX_YB;<br>
+    return MachineCombinerPattern::MC_REASSOC_AX_BY;<br>
+  }<br>
+}<br>
+<br>
+bool X86InstrInfo::hasPattern(MachineInstr &Root,<br>
+        SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Pattern) const {<br>
+  if (!Root.getParent()->getParent()->getTarget().Options.UnsafeFPMath)<br>
+    return false;<br>
+<br>
+  // TODO: There are many more associative instruction types to match:<br>
+  //       1. Other forms of scalar FP add (non-AVX)<br>
+  //       2. Other data types (double, integer, vectors)<br>
+  //       3. Other math / logic operations (mul, and, or)<br>
+  unsigned AssocOpcode = X86::VADDSSrr;<br>
+<br>
+  // TODO: There is nothing x86-specific here except the instruction type.<br>
+  // This logic could be hoisted into the machine combiner pass itself.<br>
+  bool CommuteRoot;<br>
+  if (MachineInstr *Prev = isReassocCandidate(Root, AssocOpcode, true,<br>
+                                              CommuteRoot)) {<br>
+    bool CommutePrev;<br>
+    if (isReassocCandidate(*Prev, AssocOpcode, false, CommutePrev)) {<br>
+      // We found a sequence of instructions that may be suitable for a<br>
+      // reassociation of operands to increase ILP.<br>
+      Pattern.push_back(getPattern(CommutePrev, CommuteRoot));<br>
+      return true;<br>
+    }<br>
+  }<br>
+<br>
+  return false;<br>
+}<br>
+<br>
+/// Attempt the following reassociation to reduce critical path length:<br>
+///   B = A op X (Prev)<br>
+///   C = B op Y (Root)<br>
+///   ===><br>
+///   B = X op Y<br>
+///   C = A op B<br>
+static void reassociateOps(MachineInstr &Root, MachineInstr &Prev,<br>
+                           MachineCombinerPattern::MC_PATTERN Pattern,<br>
+                           SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+                           SmallVectorImpl<MachineInstr *> &DelInstrs,<br>
+                           DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) {<br>
+  MachineFunction *MF = Root.getParent()->getParent();<br>
+  MachineRegisterInfo &MRI = MF->getRegInfo();<br>
+  const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();<br>
+  const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();<br>
+  const TargetRegisterClass *RC = Root.getRegClassConstraint(0, TII, TRI);<br>
+<br>
+  // This array encodes the operand index for each parameter because the<br>
+  // operands may be commuted. Each row corresponds to a pattern value,<br>
+  // and each column specifies the index of A, B, X, Y.<br>
+  unsigned OpIdx[4][4] = {<br>
+    { 1, 1, 2, 2 },<br>
+    { 1, 2, 2, 1 },<br>
+    { 2, 1, 1, 2 },<br>
+    { 2, 2, 1, 1 }<br>
+  };<br>
+<br>
+  MachineOperand &OpA = Prev.getOperand(OpIdx[Pattern][0]);<br>
+  MachineOperand &OpB = Root.getOperand(OpIdx[Pattern][1]);<br>
+  MachineOperand &OpX = Prev.getOperand(OpIdx[Pattern][2]);<br>
+  MachineOperand &OpY = Root.getOperand(OpIdx[Pattern][3]);<br>
+  MachineOperand &OpC = Root.getOperand(0);<br>
+<br>
+  unsigned RegA = OpA.getReg();<br>
+  unsigned RegB = OpB.getReg();<br>
+  unsigned RegX = OpX.getReg();<br>
+  unsigned RegY = OpY.getReg();<br>
+  unsigned RegC = OpC.getReg();<br>
+<br>
+  if (TargetRegisterInfo::isVirtualRegister(RegA))<br>
+    MRI.constrainRegClass(RegA, RC);<br>
+  if (TargetRegisterInfo::isVirtualRegister(RegB))<br>
+    MRI.constrainRegClass(RegB, RC);<br>
+  if (TargetRegisterInfo::isVirtualRegister(RegX))<br>
+    MRI.constrainRegClass(RegX, RC);<br>
+  if (TargetRegisterInfo::isVirtualRegister(RegY))<br>
+    MRI.constrainRegClass(RegY, RC);<br>
+  if (TargetRegisterInfo::isVirtualRegister(RegC))<br>
+    MRI.constrainRegClass(RegC, RC);<br>
+<br>
+  // Create a new virtual register for the result of (X op Y) instead of<br>
+  // recycling RegB because the MachineCombiner's computation of the critical<br>
+  // path requires a new register definition rather than an existing one.<br>
+  unsigned NewVR = MRI.createVirtualRegister(RC);<br>
+  InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));<br>
+<br>
+  unsigned Opcode = Root.getOpcode();<br>
+  bool KillA = OpA.isKill();<br>
+  bool KillX = OpX.isKill();<br>
+  bool KillY = OpY.isKill();<br>
+<br>
+  // Create new instructions for insertion.<br>
+  MachineInstrBuilder MIB1 =<br>
+    BuildMI(*MF, Prev.getDebugLoc(), TII->get(Opcode), NewVR)<br>
+      .addReg(RegX, getKillRegState(KillX))<br>
+      .addReg(RegY, getKillRegState(KillY));<br>
+  InsInstrs.push_back(MIB1);<br>
+<br>
+  MachineInstrBuilder MIB2 =<br>
+    BuildMI(*MF, Root.getDebugLoc(), TII->get(Opcode), RegC)<br>
+      .addReg(RegA, getKillRegState(KillA))<br>
+      .addReg(NewVR, getKillRegState(true));<br>
+  InsInstrs.push_back(MIB2);<br>
+<br>
+  // Record old instructions for deletion.<br>
+  DelInstrs.push_back(&Prev);<br>
+  DelInstrs.push_back(&Root);<br>
+}<br>
+<br>
+void X86InstrInfo::genAlternativeCodeSequence(<br>
+    MachineInstr &Root,<br>
+    MachineCombinerPattern::MC_PATTERN Pattern,<br>
+    SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+    SmallVectorImpl<MachineInstr *> &DelInstrs,<br>
+    DenseMap<unsigned, unsigned> &InstIdxForVirtReg) const {<br>
+  MachineRegisterInfo &MRI = Root.getParent()->getParent()->getRegInfo();<br>
+<br>
+  // Select the previous instruction in the sequence based on the input pattern.<br>
+  MachineInstr *Prev = nullptr;<br>
+  if (Pattern == MachineCombinerPattern::MC_REASSOC_AX_BY ||<br>
+      Pattern == MachineCombinerPattern::MC_REASSOC_XA_BY)<br>
+    Prev = MRI.getUniqueVRegDef(Root.getOperand(1).getReg());<br>
+  else if (Pattern == MachineCombinerPattern::MC_REASSOC_AX_YB ||<br>
+           Pattern == MachineCombinerPattern::MC_REASSOC_XA_YB)<br>
+    Prev = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());<br>
+  else<br>
+    assert("Unknown pattern for machine combiner");</blockquote></div></div><div>Use llvm_unreachable("msg") instead of assert.  Since string literals are converted to a true bool value, this assert will never be triggered.</div><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> </blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+  reassociateOps(Root, *Prev, Pattern, InsInstrs, DelInstrs, InstIdxForVirtReg);<br>
+  return;<br>
+}<br>
+<br>
 namespace {<br>
   /// Create Global Base Reg pass. This initializes the PIC<br>
   /// global base register for x86-32.<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.h<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_lib_Target_X86_X86InstrInfo.h-3Frev-3D239486-26r1-3D239485-26r2-3D239486-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=mrSGlgUAkGErxb9wAtFAU7V4vjQ9y8k5dplQBUm3E6E&s=5yfbGdjdrJX6Q5rWIISm7YOXHVzzxUe8XAiUvbBQnl0&e=" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.h?rev=239486&r1=239485&r2=239486&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86InstrInfo.h (original)<br>
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.h Wed Jun 10 15:32:21 2015<br>
@@ -26,6 +26,19 @@ namespace llvm {<br>
   class X86RegisterInfo;<br>
   class X86Subtarget;<br>
<br>
+  namespace MachineCombinerPattern {<br>
+    enum MC_PATTERN : int {<br>
+      // These are commutative variants for reassociating a computation chain<br>
+      // of the form:<br>
+      //   B = A op X (Prev)<br>
+      //   C = B op Y (Root)<br>
+      MC_REASSOC_AX_BY = 0,<br>
+      MC_REASSOC_AX_YB = 1,<br>
+      MC_REASSOC_XA_BY = 2,<br>
+      MC_REASSOC_XA_YB = 3,<br>
+    };<br>
+  } // end namespace MachineCombinerPattern<br>
+<br>
 namespace X86 {<br>
   // X86 specific condition code. These correspond to X86_*_COND in<br>
   // X86InstrInfo.td. They must be kept in synch.<br>
@@ -429,6 +442,26 @@ public:<br>
                              const MachineInstr *UseMI,<br>
                              unsigned UseIdx) const override;<br>
<br>
+<br>
+  bool useMachineCombiner() const override {<br>
+    return true;<br>
+  }<br>
+<br>
+  /// Return true when there is potentially a faster code sequence<br>
+  /// for an instruction chain ending in <Root>. All potential patterns are<br>
+  /// output in the <Pattern> array.<br>
+  bool hasPattern(<br>
+      MachineInstr &Root,<br>
+      SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &P) const override;<br>
+<br>
+  /// When hasPattern() finds a pattern, this function generates the<br>
+  /// instructions that could replace the original code sequence.<br>
+  void genAlternativeCodeSequence(<br>
+          MachineInstr &Root, MachineCombinerPattern::MC_PATTERN P,<br>
+          SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+          SmallVectorImpl<MachineInstr *> &DelInstrs,<br>
+          DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const override;<br>
+<br>
   /// analyzeCompare - For a comparison instruction, return the source registers<br>
   /// in SrcReg and SrcReg2 if having two register operands, and the value it<br>
   /// compares against in CmpValue. Return true if the comparison instruction<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86TargetMachine.cpp<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_lib_Target_X86_X86TargetMachine.cpp-3Frev-3D239486-26r1-3D239485-26r2-3D239486-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=mrSGlgUAkGErxb9wAtFAU7V4vjQ9y8k5dplQBUm3E6E&s=9S45eFyMdw4m-6to-oEkbot8zEISeJ8dDCcy8CFcE9U&e=" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetMachine.cpp?rev=239486&r1=239485&r2=239486&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86TargetMachine.cpp (original)<br>
+++ llvm/trunk/lib/Target/X86/X86TargetMachine.cpp Wed Jun 10 15:32:21 2015<br>
@@ -24,6 +24,10 @@<br>
 #include "llvm/Target/TargetOptions.h"<br>
 using namespace llvm;<br>
<br>
+static cl::opt<bool> EnableMachineCombinerPass("x86-machine-combiner",<br>
+                               cl::desc("Enable the machine combiner pass"),<br>
+                               cl::init(true), cl::Hidden);<br>
+<br>
 extern "C" void LLVMInitializeX86Target() {<br>
   // Register the target.<br>
   RegisterTargetMachine<X86TargetMachine> X(TheX86_32Target);<br>
@@ -224,6 +228,8 @@ bool X86PassConfig::addInstSelector() {<br>
<br>
 bool X86PassConfig::addILPOpts() {<br>
   addPass(&EarlyIfConverterID);<br>
+  if (EnableMachineCombinerPass)<br>
+    addPass(&MachineCombinerID);<br>
   return true;<br>
 }<br>
<br>
<br>
Modified: llvm/trunk/test/CodeGen/X86/fp-fast.ll<br>
URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_llvm_trunk_test_CodeGen_X86_fp-2Dfast.ll-3Frev-3D239486-26r1-3D239485-26r2-3D239486-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=mQ4LZ2PUj9hpadE3cDHZnIdEwhEBrbAstXeMaFoB9tg&m=mrSGlgUAkGErxb9wAtFAU7V4vjQ9y8k5dplQBUm3E6E&s=rIja_gyAdsvPYVdTaGNz899I5Ua_gv_sQS9m4Z6f_po&e=" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/fp-fast.ll?rev=239486&r1=239485&r2=239486&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/fp-fast.ll (original)<br>
+++ llvm/trunk/test/CodeGen/X86/fp-fast.ll Wed Jun 10 15:32:21 2015<br>
@@ -114,3 +114,81 @@ define float @test11(float %a) {<br>
   ret float %t2<br>
 }<br>
<br>
+; Verify that the first two adds are independent regardless of how the inputs are<br>
+; commuted. The destination registers are used as source registers for the third add.<br>
+<br>
+define float @reassociate_adds1(float %x0, float %x1, float %x2, float %x3) {<br>
+; CHECK-LABEL: reassociate_adds1:<br>
+; CHECK:       # BB#0:<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm3, %xmm2, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    retq<br>
+  %t0 = fadd float %x0, %x1<br>
+  %t1 = fadd float %t0, %x2<br>
+  %t2 = fadd float %t1, %x3<br>
+  ret float %t2<br>
+}<br>
+<br>
+define float @reassociate_adds2(float %x0, float %x1, float %x2, float %x3) {<br>
+; CHECK-LABEL: reassociate_adds2:<br>
+; CHECK:       # BB#0:<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm3, %xmm2, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    retq<br>
+  %t0 = fadd float %x0, %x1<br>
+  %t1 = fadd float %x2, %t0<br>
+  %t2 = fadd float %t1, %x3<br>
+  ret float %t2<br>
+}<br>
+<br>
+define float @reassociate_adds3(float %x0, float %x1, float %x2, float %x3) {<br>
+; CHECK-LABEL: reassociate_adds3:<br>
+; CHECK:       # BB#0:<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm3, %xmm2, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    retq<br>
+  %t0 = fadd float %x0, %x1<br>
+  %t1 = fadd float %t0, %x2<br>
+  %t2 = fadd float %x3, %t1<br>
+  ret float %t2<br>
+}<br>
+<br>
+define float @reassociate_adds4(float %x0, float %x1, float %x2, float %x3) {<br>
+; CHECK-LABEL: reassociate_adds4:<br>
+; CHECK:       # BB#0:<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm3, %xmm2, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    retq<br>
+  %t0 = fadd float %x0, %x1<br>
+  %t1 = fadd float %x2, %t0<br>
+  %t2 = fadd float %x3, %t1<br>
+  ret float %t2<br>
+}<br>
+<br>
+; Verify that we reassociate some of these ops. The optimal balanced tree of adds is not<br>
+; produced because that would cost more compile time.<br>
+<br>
+define float @reassociate_adds5(float %x0, float %x1, float %x2, float %x3, float %x4, float %x5, float %x6, float %x7) {<br>
+; CHECK-LABEL: reassociate_adds5:<br>
+; CHECK:       # BB#0:<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm3, %xmm2, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm5, %xmm4, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    vaddss %xmm7, %xmm6, %xmm1<br>
+; CHECK-NEXT:    vaddss %xmm1, %xmm0, %xmm0<br>
+; CHECK-NEXT:    retq<br>
+  %t0 = fadd float %x0, %x1<br>
+  %t1 = fadd float %t0, %x2<br>
+  %t2 = fadd float %t1, %x3<br>
+  %t3 = fadd float %t2, %x4<br>
+  %t4 = fadd float %t3, %x5<br>
+  %t5 = fadd float %t4, %x6<br>
+  %t6 = fadd float %t5, %x7<br>
+  ret float %t6<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div>