<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi Kevin <div><br></div><div>thanks for taking care of this. The fails are puzzling to me since they do not reproduce on my machine.</div><div><br></div><div>Gerolf</div><div><div><div>On Aug 3, 2014, at 10:21 PM, Kevin Qin <<a href="mailto:kevinqindev@gmail.com">kevinqindev@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div dir="ltr"><span style="font-family:arial,sans-serif;font-size:13.63636302947998px">Hi Gerolf,</span><div><span style="font-family:arial,sans-serif;font-size:13.63636302947998px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13.63636302947998px">Because it broke the "make check" for 7 hours, so I get it reverted at </span><font face="arial, sans-serif">r214697. Please fix regressions and commit again.</font></div>
<div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Thanks,</font></div><div><font face="arial, sans-serif">Kevin</font></div></div>
<div class="gmail_extra"><br><br><div class="gmail_quote">2014-08-04 11:28 GMT+08:00 Kevin Qin <span dir="ltr"><<a href="mailto:kevinqindev@gmail.com" target="_blank">kevinqindev@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">Hi Gerolf,<div><br></div><div>This commit got make check failed for <span style="color:rgb(50,50,50);font-family:Arial,宋体,微软雅黑;font-size:14px;line-height:16px;white-space:nowrap">several</span>  hours,  would you please have a look?<br>

</div><div><br></div><div>They are</div><div><div>    LLVM :: CodeGen/AArch64/arm64-neon-mul-div.ll</div><div>    LLVM :: CodeGen/AArch64/dp-3source.ll</div></div><div><br></div><div><br></div><div><br></div><div>Thanks,</div>

<div>Kevin</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">2014-08-04 6:03 GMT+08:00 Gerolf Hoflehner <span dir="ltr"><<a href="mailto:ghoflehner@apple.com" target="_blank">ghoflehner@apple.com</a>></span>:<div>
<div class="h5"><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ghoflehner<br>
Date: Sun Aug  3 17:03:40 2014<br>
New Revision: 214669<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=214669&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=214669&view=rev</a><br>
Log:<br>
MachineCombiner Pass for selecting faster instruction<br>
 sequence -  AArch64 target support<br>
<br>
 This patch turns off madd/msub generation in the DAGCombiner and generates<br>
 them in the MachineCombiner instead. It replaces the original code sequence<br>
 with the combined sequence when it is beneficial to do so.<br>
<br>
 When there is no machine model support it always generates the madd/msub<br>
 instruction. This is true also when the objective is to optimize for code<br>
 size: when the combined sequence is shorter is always chosen and does not<br>
 get evaluated.<br>
<br>
 When there is a machine model the combined instruction sequence<br>
 is evaluated for critical path and resource length using machine<br>
 trace metrics and the original code sequence is replaced when it is<br>
 determined to be faster.<br>
<br>
 <a href="rdar://16319955">rdar://16319955</a><br>
<br>
<br>
Added:<br>
    llvm/trunk/lib/Target/AArch64/AArch64MachineCombinerPattern.h<br>
    llvm/trunk/test/CodeGen/AArch64/madd-lohi.ll<br>
Modified:<br>
    llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td<br>
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp<br>
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h<br>
    llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp<br>
    llvm/trunk/test/CodeGen/AArch64/arm64-neon-mul-div.ll<br>
    llvm/trunk/test/CodeGen/AArch64/dp-3source.ll<br>
    llvm/trunk/test/CodeGen/AArch64/mul-lohi.ll<br>
<br>
Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td (original)<br>
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td Sun Aug  3 17:03:40 2014<br>
@@ -1351,14 +1351,15 @@ class BaseMulAccum<bit isSub, bits<3> op<br>
 }<br>
<br>
 multiclass MulAccum<bit isSub, string asm, SDNode AccNode> {<br>
+  // MADD/MSUB generation is decided by MachineCombiner.cpp<br>
   def Wrrr : BaseMulAccum<isSub, 0b000, GPR32, GPR32, asm,<br>
-      [(set GPR32:$Rd, (AccNode GPR32:$Ra, (mul GPR32:$Rn, GPR32:$Rm)))]>,<br>
+      [/*(set GPR32:$Rd, (AccNode GPR32:$Ra, (mul GPR32:$Rn, GPR32:$Rm)))*/]>,<br>
       Sched<[WriteIM32, ReadIM, ReadIM, ReadIMA]> {<br>
     let Inst{31} = 0;<br>
   }<br>
<br>
   def Xrrr : BaseMulAccum<isSub, 0b000, GPR64, GPR64, asm,<br>
-      [(set GPR64:$Rd, (AccNode GPR64:$Ra, (mul GPR64:$Rn, GPR64:$Rm)))]>,<br>
+      [/*(set GPR64:$Rd, (AccNode GPR64:$Ra, (mul GPR64:$Rn, GPR64:$Rm)))*/]>,<br>
       Sched<[WriteIM64, ReadIM, ReadIM, ReadIMA]> {<br>
     let Inst{31} = 1;<br>
   }<br>
<br>
Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp (original)<br>
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp Sun Aug  3 17:03:40 2014<br>
@@ -14,6 +14,7 @@<br>
 #include "AArch64InstrInfo.h"<br>
 #include "AArch64Subtarget.h"<br>
 #include "MCTargetDesc/AArch64AddressingModes.h"<br>
+#include "AArch64MachineCombinerPattern.h"<br>
 #include "llvm/CodeGen/MachineFrameInfo.h"<br>
 #include "llvm/CodeGen/MachineInstrBuilder.h"<br>
 #include "llvm/CodeGen/MachineMemOperand.h"<br>
@@ -697,17 +698,12 @@ static bool UpdateOperandRegClass(Machin<br>
   return true;<br>
 }<br>
<br>
-/// optimizeCompareInstr - Convert the instruction supplying the argument to the<br>
-/// comparison into one that sets the zero bit in the flags register.<br>
-bool AArch64InstrInfo::optimizeCompareInstr(<br>
-    MachineInstr *CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask,<br>
-    int CmpValue, const MachineRegisterInfo *MRI) const {<br>
-<br>
-  // Replace SUBSWrr with SUBWrr if NZCV is not used.<br>
-  int Cmp_NZCV = CmpInstr->findRegisterDefOperandIdx(AArch64::NZCV, true);<br>
-  if (Cmp_NZCV != -1) {<br>
+/// convertFlagSettingOpcode - return opcode that does not<br>
+/// set flags when possible. The caller is responsible to do<br>
+/// the actual substitution and legality checking.<br>
+static unsigned convertFlagSettingOpcode(MachineInstr *MI) {<br>
     unsigned NewOpc;<br>
-    switch (CmpInstr->getOpcode()) {<br>
+    switch (MI->getOpcode()) {<br>
     default:<br>
       return false;<br>
     case AArch64::ADDSWrr:      NewOpc = AArch64::ADDWrr; break;<br>
@@ -727,7 +723,22 @@ bool AArch64InstrInfo::optimizeCompareIn<br>
     case AArch64::SUBSXrs:      NewOpc = AArch64::SUBXrs; break;<br>
     case AArch64::SUBSXrx:      NewOpc = AArch64::SUBXrx; break;<br>
     }<br>
+    return NewOpc;<br>
+}<br>
<br>
+/// optimizeCompareInstr - Convert the instruction supplying the argument to the<br>
+/// comparison into one that sets the zero bit in the flags register.<br>
+bool AArch64InstrInfo::optimizeCompareInstr(<br>
+    MachineInstr *CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask,<br>
+    int CmpValue, const MachineRegisterInfo *MRI) const {<br>
+<br>
+  // Replace SUBSWrr with SUBWrr if NZCV is not used.<br>
+  int Cmp_NZCV = CmpInstr->findRegisterDefOperandIdx(AArch64::NZCV, true);<br>
+  if (Cmp_NZCV != -1) {<br>
+    unsigned Opc = CmpInstr->getOpcode();<br>
+    unsigned NewOpc = convertFlagSettingOpcode(CmpInstr);<br>
+    if (NewOpc == Opc)<br>
+      return false;<br>
     const MCInstrDesc &MCID = get(NewOpc);<br>
     CmpInstr->setDesc(MCID);<br>
     CmpInstr->RemoveOperand(Cmp_NZCV);<br>
@@ -2185,3 +2196,448 @@ void AArch64InstrInfo::getNoopForMachoTa<br>
   NopInst.setOpcode(AArch64::HINT);<br>
   NopInst.addOperand(MCOperand::CreateImm(0));<br>
 }<br>
+/// useMachineCombiner - return true when a target supports MachineCombiner<br>
+bool AArch64InstrInfo::useMachineCombiner(void) const {<br>
+  // AArch64 supports the combiner<br>
+  return true;<br>
+}<br>
+//<br>
+// True when Opc sets flag<br>
+static bool isCombineInstrSettingFlag(unsigned Opc) {<br>
+  switch (Opc) {<br>
+  case AArch64::ADDSWrr:<br>
+  case AArch64::ADDSWri:<br>
+  case AArch64::ADDSXrr:<br>
+  case AArch64::ADDSXri:<br>
+  case AArch64::SUBSWrr:<br>
+  case AArch64::SUBSXrr:<br>
+  // Note: MSUB Wd,Wn,Wm,Wi -> Wd = Wi - WnxWm, not Wd=WnxWm - Wi.<br>
+  case AArch64::SUBSWri:<br>
+  case AArch64::SUBSXri:<br>
+    return true;<br>
+  default:<br>
+    break;<br>
+  }<br>
+  return false;<br>
+}<br>
+//<br>
+// 32b Opcodes that can be combined with a MUL<br>
+static bool isCombineInstrCandidate32(unsigned Opc) {<br>
+  switch (Opc) {<br>
+  case AArch64::ADDWrr:<br>
+  case AArch64::ADDWri:<br>
+  case AArch64::SUBWrr:<br>
+  case AArch64::ADDSWrr:<br>
+  case AArch64::ADDSWri:<br>
+  case AArch64::SUBSWrr:<br>
+  // Note: MSUB Wd,Wn,Wm,Wi -> Wd = Wi - WnxWm, not Wd=WnxWm - Wi.<br>
+  case AArch64::SUBWri:<br>
+  case AArch64::SUBSWri:<br>
+    return true;<br>
+  default:<br>
+    break;<br>
+  }<br>
+  return false;<br>
+}<br>
+//<br>
+// 64b Opcodes that can be combined with a MUL<br>
+static bool isCombineInstrCandidate64(unsigned Opc) {<br>
+  switch (Opc) {<br>
+  case AArch64::ADDXrr:<br>
+  case AArch64::ADDXri:<br>
+  case AArch64::SUBXrr:<br>
+  case AArch64::ADDSXrr:<br>
+  case AArch64::ADDSXri:<br>
+  case AArch64::SUBSXrr:<br>
+  // Note: MSUB Wd,Wn,Wm,Wi -> Wd = Wi - WnxWm, not Wd=WnxWm - Wi.<br>
+  case AArch64::SUBXri:<br>
+  case AArch64::SUBSXri:<br>
+    return true;<br>
+  default:<br>
+    break;<br>
+  }<br>
+  return false;<br>
+}<br>
+//<br>
+// Opcodes that can be combined with a MUL<br>
+static bool isCombineInstrCandidate(unsigned Opc) {<br>
+  return (isCombineInstrCandidate32(Opc) || isCombineInstrCandidate64(Opc));<br>
+}<br>
+<br>
+static bool canCombineWithMUL(MachineBasicBlock &MBB, MachineOperand &MO,<br>
+                              unsigned MulOpc, unsigned ZeroReg) {<br>
+  MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();<br>
+  MachineInstr *MI = nullptr;<br>
+  // We need a virtual register definition.<br>
+  if (MO.isReg() && TargetRegisterInfo::isVirtualRegister(MO.getReg()))<br>
+    MI = MRI.getUniqueVRegDef(MO.getReg());<br>
+  // And it needs to be in the trace (otherwise, it won't have a depth).<br>
+  if (!MI || MI->getParent() != &MBB || (unsigned)MI->getOpcode() != MulOpc)<br>
+    return false;<br>
+<br>
+  assert(MI->getNumOperands() >= 4 && MI->getOperand(0).isReg() &&<br>
+         MI->getOperand(1).isReg() && MI->getOperand(2).isReg() &&<br>
+         MI->getOperand(3).isReg() && "MAdd/MSub must have a least 4 regs");<br>
+<br>
+  // The third input reg must be zero.<br>
+  if (MI->getOperand(3).getReg() != ZeroReg)<br>
+    return false;<br>
+<br>
+  // Must only used by the user we combine with.<br>
+  if (!MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))<br>
+    return false;<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+/// hasPattern - return true when there is potentially a faster code sequence<br>
+/// for an instruction chain ending in \p Root. All potential patterns are<br>
+/// listed<br>
+/// in the \p Pattern vector. Pattern should be sorted in priority order since<br>
+/// the pattern evaluator stops checking as soon as it finds a faster sequence.<br>
+<br>
+bool AArch64InstrInfo::hasPattern(<br>
+    MachineInstr &Root,<br>
+    SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Pattern) const {<br>
+  unsigned Opc = Root.getOpcode();<br>
+  MachineBasicBlock &MBB = *Root.getParent();<br>
+  bool Found = false;<br>
+<br>
+  if (!isCombineInstrCandidate(Opc))<br>
+    return 0;<br>
+  if (isCombineInstrSettingFlag(Opc)) {<br>
+    int Cmp_NZCV = Root.findRegisterDefOperandIdx(AArch64::NZCV, true);<br>
+    // When NZCV is live bail out.<br>
+    if (Cmp_NZCV == -1)<br>
+      return 0;<br>
+    unsigned NewOpc = convertFlagSettingOpcode(&Root);<br>
+    // When opcode can't change bail out.<br>
+    // CHECKME: do we miss any cases for opcode conversion?<br>
+    if (NewOpc == Opc)<br>
+      return 0;<br>
+    Opc = NewOpc;<br>
+  }<br>
+<br>
+  switch (Opc) {<br>
+  default:<br>
+    break;<br>
+  case AArch64::ADDWrr:<br>
+    assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&<br>
+           "ADDWrr does not have register operands");<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDWrrr,<br>
+                          AArch64::WZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULADDW_OP1);<br>
+      Found = true;<br>
+    }<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(2), AArch64::MADDWrrr,<br>
+                          AArch64::WZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULADDW_OP2);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::ADDXrr:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDXrrr,<br>
+                          AArch64::XZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULADDX_OP1);<br>
+      Found = true;<br>
+    }<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(2), AArch64::MADDXrrr,<br>
+                          AArch64::XZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULADDX_OP2);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::SUBWrr:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDWrrr,<br>
+                          AArch64::WZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULSUBW_OP1);<br>
+      Found = true;<br>
+    }<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(2), AArch64::MADDWrrr,<br>
+                          AArch64::WZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULSUBW_OP2);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::SUBXrr:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDXrrr,<br>
+                          AArch64::XZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULSUBX_OP1);<br>
+      Found = true;<br>
+    }<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(2), AArch64::MADDXrrr,<br>
+                          AArch64::XZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULSUBX_OP2);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::ADDWri:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDWrrr,<br>
+                          AArch64::WZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULADDWI_OP1);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::ADDXri:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDXrrr,<br>
+                          AArch64::XZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULADDXI_OP1);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::SUBWri:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDWrrr,<br>
+                          AArch64::WZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULSUBWI_OP1);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  case AArch64::SUBXri:<br>
+    if (canCombineWithMUL(MBB, Root.getOperand(1), AArch64::MADDXrrr,<br>
+                          AArch64::XZR)) {<br>
+      Pattern.push_back(MachineCombinerPattern::MC_MULSUBXI_OP1);<br>
+      Found = true;<br>
+    }<br>
+    break;<br>
+  }<br>
+  return Found;<br>
+}<br>
+<br>
+/// genMadd - Generate madd instruction and combine mul and add.<br>
+/// Example:<br>
+///  MUL I=A,B,0<br>
+///  ADD R,I,C<br>
+///  ==> MADD R,A,B,C<br>
+/// \param Root is the ADD instruction<br>
+/// \param [out] InsInstr is a vector of machine instructions and will<br>
+/// contain the generated madd instruction<br>
+/// \param IdxMulOpd is index of operand in Root that is the result of<br>
+/// the MUL. In the example above IdxMulOpd is 1.<br>
+/// \param MaddOpc the opcode fo the madd instruction<br>
+static MachineInstr *genMadd(MachineFunction &MF, MachineRegisterInfo &MRI,<br>
+                             const TargetInstrInfo *TII, MachineInstr &Root,<br>
+                             SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+                             unsigned IdxMulOpd, unsigned MaddOpc) {<br>
+  assert(IdxMulOpd == 1 || IdxMulOpd == 2);<br>
+<br>
+  unsigned IdxOtherOpd = IdxMulOpd == 1 ? 2 : 1;<br>
+  MachineInstr *MUL = MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());<br>
+  MachineOperand R = Root.getOperand(0);<br>
+  MachineOperand A = MUL->getOperand(1);<br>
+  MachineOperand B = MUL->getOperand(2);<br>
+  MachineOperand C = Root.getOperand(IdxOtherOpd);<br>
+  MachineInstrBuilder MIB = BuildMI(MF, Root.getDebugLoc(), TII->get(MaddOpc))<br>
+                                .addOperand(R)<br>
+                                .addOperand(A)<br>
+                                .addOperand(B)<br>
+                                .addOperand(C);<br>
+  // Insert the MADD<br>
+  InsInstrs.push_back(MIB);<br>
+  return MUL;<br>
+}<br>
+<br>
+/// genMaddR - Generate madd instruction and combine mul and add using<br>
+/// an extra virtual register<br>
+/// Example - an ADD intermediate needs to be stored in a register:<br>
+///   MUL I=A,B,0<br>
+///   ADD R,I,Imm<br>
+///   ==> ORR  V, ZR, Imm<br>
+///   ==> MADD R,A,B,V<br>
+/// \param Root is the ADD instruction<br>
+/// \param [out] InsInstr is a vector of machine instructions and will<br>
+/// contain the generated madd instruction<br>
+/// \param IdxMulOpd is index of operand in Root that is the result of<br>
+/// the MUL. In the example above IdxMulOpd is 1.<br>
+/// \param MaddOpc the opcode fo the madd instruction<br>
+/// \param VR is a virtual register that holds the value of an ADD operand<br>
+/// (V in the example above).<br>
+static MachineInstr *genMaddR(MachineFunction &MF, MachineRegisterInfo &MRI,<br>
+                              const TargetInstrInfo *TII, MachineInstr &Root,<br>
+                              SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+                              unsigned IdxMulOpd, unsigned MaddOpc,<br>
+                              unsigned VR) {<br>
+  assert(IdxMulOpd == 1 || IdxMulOpd == 2);<br>
+<br>
+  MachineInstr *MUL = MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());<br>
+  MachineOperand R = Root.getOperand(0);<br>
+  MachineOperand A = MUL->getOperand(1);<br>
+  MachineOperand B = MUL->getOperand(2);<br>
+  MachineInstrBuilder MIB = BuildMI(MF, Root.getDebugLoc(), TII->get(MaddOpc))<br>
+                                .addOperand(R)<br>
+                                .addOperand(A)<br>
+                                .addOperand(B)<br>
+                                .addReg(VR);<br>
+  // Insert the MADD<br>
+  InsInstrs.push_back(MIB);<br>
+  return MUL;<br>
+}<br>
+/// genAlternativeCodeSequence - when hasPattern() finds a pattern<br>
+/// this function generates the instructions that could replace the<br>
+/// original code sequence<br>
+void AArch64InstrInfo::genAlternativeCodeSequence(<br>
+    MachineInstr &Root, MachineCombinerPattern::MC_PATTERN Pattern,<br>
+    SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+    SmallVectorImpl<MachineInstr *> &DelInstrs,<br>
+    DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const {<br>
+  MachineBasicBlock &MBB = *Root.getParent();<br>
+  MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();<br>
+  MachineFunction &MF = *MBB.getParent();<br>
+  const TargetInstrInfo *TII = MF.getTarget().getInstrInfo();<br>
+<br>
+  MachineInstr *MUL;<br>
+  unsigned Opc;<br>
+  switch (Pattern) {<br>
+  default:<br>
+    // signal error.<br>
+    break;<br>
+  case MachineCombinerPattern::MC_MULADDW_OP1:<br>
+  case MachineCombinerPattern::MC_MULADDX_OP1:<br>
+    // MUL I=A,B,0<br>
+    // ADD R,I,C<br>
+    // ==> MADD R,A,B,C<br>
+    // --- Create(MADD);<br>
+    Opc = Pattern == MachineCombinerPattern::MC_MULADDW_OP1 ? AArch64::MADDWrrr<br>
+                                                            : AArch64::MADDXrrr;<br>
+    MUL = genMadd(MF, MRI, TII, Root, InsInstrs, 1, Opc);<br>
+    break;<br>
+  case MachineCombinerPattern::MC_MULADDW_OP2:<br>
+  case MachineCombinerPattern::MC_MULADDX_OP2:<br>
+    // MUL I=A,B,0<br>
+    // ADD R,C,I<br>
+    // ==> MADD R,A,B,C<br>
+    // --- Create(MADD);<br>
+    Opc = Pattern == MachineCombinerPattern::MC_MULADDW_OP2 ? AArch64::MADDWrrr<br>
+                                                            : AArch64::MADDXrrr;<br>
+    MUL = genMadd(MF, MRI, TII, Root, InsInstrs, 2, Opc);<br>
+    break;<br>
+  case MachineCombinerPattern::MC_MULADDWI_OP1:<br>
+  case MachineCombinerPattern::MC_MULADDXI_OP1:<br>
+    // MUL I=A,B,0<br>
+    // ADD R,I,Imm<br>
+    // ==> ORR  V, ZR, Imm<br>
+    // ==> MADD R,A,B,V<br>
+    // --- Create(MADD);<br>
+    {<br>
+      const TargetRegisterClass *RC =<br>
+          MRI.getRegClass(Root.getOperand(1).getReg());<br>
+      unsigned NewVR = MRI.createVirtualRegister(RC);<br>
+      unsigned BitSize, OrrOpc, ZeroReg;<br>
+      if (Pattern == MachineCombinerPattern::MC_MULADDWI_OP1) {<br>
+        BitSize = 32;<br>
+        OrrOpc = AArch64::ORRWri;<br>
+        ZeroReg = AArch64::WZR;<br>
+        Opc = AArch64::MADDWrrr;<br>
+      } else {<br>
+        OrrOpc = AArch64::ORRXri;<br>
+        BitSize = 64;<br>
+        ZeroReg = AArch64::XZR;<br>
+        Opc = AArch64::MADDXrrr;<br>
+      }<br>
+      uint64_t Imm = Root.getOperand(2).getImm();<br>
+<br>
+      if (Root.getOperand(3).isImm()) {<br>
+        unsigned val = Root.getOperand(3).getImm();<br>
+        Imm = Imm << val;<br>
+      }<br>
+      uint64_t UImm = Imm << (64 - BitSize) >> (64 - BitSize);<br>
+      uint64_t Encoding;<br>
+<br>
+      if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) {<br>
+        MachineInstrBuilder MIB1 =<br>
+            BuildMI(MF, Root.getDebugLoc(), TII->get(OrrOpc))<br>
+                .addOperand(MachineOperand::CreateReg(NewVR, RegState::Define))<br>
+                .addReg(ZeroReg)<br>
+                .addImm(Encoding);<br>
+        InsInstrs.push_back(MIB1);<br>
+        InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));<br>
+        MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR);<br>
+      }<br>
+    }<br>
+    break;<br>
+  case MachineCombinerPattern::MC_MULSUBW_OP1:<br>
+  case MachineCombinerPattern::MC_MULSUBX_OP1: {<br>
+    // MUL I=A,B,0<br>
+    // SUB R,I, C<br>
+    // ==> SUB  V, 0, C<br>
+    // ==> MADD R,A,B,V // = -C + A*B<br>
+    // --- Create(MADD);<br>
+    const TargetRegisterClass *RC =<br>
+        MRI.getRegClass(Root.getOperand(1).getReg());<br>
+    unsigned NewVR = MRI.createVirtualRegister(RC);<br>
+    unsigned SubOpc, ZeroReg;<br>
+    if (Pattern == MachineCombinerPattern::MC_MULSUBW_OP1) {<br>
+      SubOpc = AArch64::SUBWrr;<br>
+      ZeroReg = AArch64::WZR;<br>
+      Opc = AArch64::MADDWrrr;<br>
+    } else {<br>
+      SubOpc = AArch64::SUBXrr;<br>
+      ZeroReg = AArch64::XZR;<br>
+      Opc = AArch64::MADDXrrr;<br>
+    }<br>
+    // SUB NewVR, 0, C<br>
+    MachineInstrBuilder MIB1 =<br>
+        BuildMI(MF, Root.getDebugLoc(), TII->get(SubOpc))<br>
+            .addOperand(MachineOperand::CreateReg(NewVR, RegState::Define))<br>
+            .addReg(ZeroReg)<br>
+            .addOperand(Root.getOperand(2));<br>
+    InsInstrs.push_back(MIB1);<br>
+    InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));<br>
+    MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR);<br>
+  } break;<br>
+  case MachineCombinerPattern::MC_MULSUBW_OP2:<br>
+  case MachineCombinerPattern::MC_MULSUBX_OP2:<br>
+    // MUL I=A,B,0<br>
+    // SUB R,C,I<br>
+    // ==> MSUB R,A,B,C (computes C - A*B)<br>
+    // --- Create(MSUB);<br>
+    Opc = Pattern == MachineCombinerPattern::MC_MULSUBW_OP2 ? AArch64::MSUBWrrr<br>
+                                                            : AArch64::MSUBXrrr;<br>
+    MUL = genMadd(MF, MRI, TII, Root, InsInstrs, 2, Opc);<br>
+    break;<br>
+  case MachineCombinerPattern::MC_MULSUBWI_OP1:<br>
+  case MachineCombinerPattern::MC_MULSUBXI_OP1: {<br>
+    // MUL I=A,B,0<br>
+    // SUB R,I, Imm<br>
+    // ==> ORR  V, ZR, -Imm<br>
+    // ==> MADD R,A,B,V // = -Imm + A*B<br>
+    // --- Create(MADD);<br>
+    const TargetRegisterClass *RC =<br>
+        MRI.getRegClass(Root.getOperand(1).getReg());<br>
+    unsigned NewVR = MRI.createVirtualRegister(RC);<br>
+    unsigned BitSize, OrrOpc, ZeroReg;<br>
+    if (Pattern == MachineCombinerPattern::MC_MULSUBWI_OP1) {<br>
+      BitSize = 32;<br>
+      OrrOpc = AArch64::ORRWri;<br>
+      ZeroReg = AArch64::WZR;<br>
+      Opc = AArch64::MADDWrrr;<br>
+    } else {<br>
+      OrrOpc = AArch64::ORRXri;<br>
+      BitSize = 64;<br>
+      ZeroReg = AArch64::XZR;<br>
+      Opc = AArch64::MADDXrrr;<br>
+    }<br>
+    int Imm = Root.getOperand(2).getImm();<br>
+    if (Root.getOperand(3).isImm()) {<br>
+      unsigned val = Root.getOperand(3).getImm();<br>
+      Imm = Imm << val;<br>
+    }<br>
+    uint64_t UImm = -Imm << (64 - BitSize) >> (64 - BitSize);<br>
+    uint64_t Encoding;<br>
+    if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) {<br>
+      MachineInstrBuilder MIB1 =<br>
+          BuildMI(MF, Root.getDebugLoc(), TII->get(OrrOpc))<br>
+              .addOperand(MachineOperand::CreateReg(NewVR, RegState::Define))<br>
+              .addReg(ZeroReg)<br>
+              .addImm(Encoding);<br>
+      InsInstrs.push_back(MIB1);<br>
+      InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));<br>
+      MUL = genMaddR(MF, MRI, TII, Root, InsInstrs, 1, Opc, NewVR);<br>
+    }<br>
+  } break;<br>
+  }<br>
+  // Record MUL and ADD/SUB for deletion<br>
+  DelInstrs.push_back(MUL);<br>
+  DelInstrs.push_back(&Root);<br>
+<br>
+  return;<br>
+}<br>
<br>
Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h (original)<br>
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h Sun Aug  3 17:03:40 2014<br>
@@ -17,6 +17,7 @@<br>
 #include "AArch64.h"<br>
 #include "AArch64RegisterInfo.h"<br>
 #include "llvm/Target/TargetInstrInfo.h"<br>
+#include "llvm/CodeGen/MachineCombinerPattern.h"<br>
<br>
 #define GET_INSTRINFO_HEADER<br>
 #include "AArch64GenInstrInfo.inc"<br>
@@ -156,9 +157,26 @@ public:<br>
   bool optimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg,<br>
                             unsigned SrcReg2, int CmpMask, int CmpValue,<br>
                             const MachineRegisterInfo *MRI) const override;<br>
+  /// hasPattern - return true when there is potentially a faster code sequence<br>
+  /// for an instruction chain ending in <Root>. All potential patterns are<br>
+  /// listed<br>
+  /// in the <Pattern> array.<br>
+  virtual bool hasPattern(<br>
+      MachineInstr &Root,<br>
+      SmallVectorImpl<MachineCombinerPattern::MC_PATTERN> &Pattern) const;<br>
+<br>
+  /// genAlternativeCodeSequence - when hasPattern() finds a pattern<br>
+  /// this function generates the instructions that could replace the<br>
+  /// original code sequence<br>
+  virtual void genAlternativeCodeSequence(<br>
+      MachineInstr &Root, MachineCombinerPattern::MC_PATTERN P,<br>
+      SmallVectorImpl<MachineInstr *> &InsInstrs,<br>
+      SmallVectorImpl<MachineInstr *> &DelInstrs,<br>
+      DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const;<br>
+  /// useMachineCombiner - AArch64 supports MachineCombiner<br>
+  virtual bool useMachineCombiner(void) const;<br>
<br>
   bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override;<br>
-<br>
 private:<br>
   void instantiateCondBranch(MachineBasicBlock &MBB, DebugLoc DL,<br>
                              MachineBasicBlock *TBB,<br>
<br>
Added: llvm/trunk/lib/Target/AArch64/AArch64MachineCombinerPattern.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64MachineCombinerPattern.h?rev=214669&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64MachineCombinerPattern.h?rev=214669&view=auto</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/AArch64/AArch64MachineCombinerPattern.h (added)<br>
+++ llvm/trunk/lib/Target/AArch64/AArch64MachineCombinerPattern.h Sun Aug  3 17:03:40 2014<br>
@@ -0,0 +1,42 @@<br>
+//===- AArch64MachineCombinerPattern.h                                    -===//<br>
+//===- AArch64 instruction pattern supported by combiner                  -===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This file defines instruction pattern supported by combiner<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_TARGET_AArch64MACHINECOMBINERPATTERN_H<br>
+#define LLVM_TARGET_AArch64MACHINECOMBINERPATTERN_H<br>
+<br>
+namespace llvm {<br>
+<br>
+/// Enumeration of instruction pattern supported by machine combiner<br>
+///<br>
+///<br>
+namespace MachineCombinerPattern {<br>
+enum MC_PATTERN : int {<br>
+  MC_NONE = 0,<br>
+  MC_MULADDW_OP1 = 1,<br>
+  MC_MULADDW_OP2 = 2,<br>
+  MC_MULSUBW_OP1 = 3,<br>
+  MC_MULSUBW_OP2 = 4,<br>
+  MC_MULADDWI_OP1 = 5,<br>
+  MC_MULSUBWI_OP1 = 6,<br>
+  MC_MULADDX_OP1 = 7,<br>
+  MC_MULADDX_OP2 = 8,<br>
+  MC_MULSUBX_OP1 = 9,<br>
+  MC_MULSUBX_OP2 = 10,<br>
+  MC_MULADDXI_OP1 = 11,<br>
+  MC_MULSUBXI_OP1 = 12<br>
+};<br>
+} // end namespace MachineCombinerPattern<br>
+} // end namespace llvm<br>
+<br>
+#endif<br>
<br>
Modified: llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp (original)<br>
+++ llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp Sun Aug  3 17:03:40 2014<br>
@@ -24,6 +24,10 @@ static cl::opt<bool><br>
 EnableCCMP("aarch64-ccmp", cl::desc("Enable the CCMP formation pass"),<br>
            cl::init(true), cl::Hidden);<br>
<br>
+static cl::opt<bool> EnableMCR("aarch64-mcr",<br>
+                               cl::desc("Enable the machine combiner pass"),<br>
+                               cl::init(true), cl::Hidden);<br>
+<br>
 static cl::opt<bool><br>
 EnableStPairSuppress("aarch64-stp-suppress", cl::desc("Suppress STP for AArch64"),<br>
                      cl::init(true), cl::Hidden);<br>
@@ -174,6 +178,8 @@ bool AArch64PassConfig::addInstSelector(<br>
 bool AArch64PassConfig::addILPOpts() {<br>
   if (EnableCCMP)<br>
     addPass(createAArch64ConditionalCompares());<br>
+  if (EnableMCR)<br>
+    addPass(&MachineCombinerID);<br>
   addPass(&EarlyIfConverterID);<br>
   if (EnableStPairSuppress)<br>
     addPass(createAArch64StorePairSuppressPass());<br>
<br>
Modified: llvm/trunk/test/CodeGen/AArch64/arm64-neon-mul-div.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/arm64-neon-mul-div.ll?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/arm64-neon-mul-div.ll?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/test/CodeGen/AArch64/arm64-neon-mul-div.ll (original)<br>
+++ llvm/trunk/test/CodeGen/AArch64/arm64-neon-mul-div.ll Sun Aug  3 17:03:40 2014<br>
@@ -1,4 +1,4 @@<br>
-; RUN: llc < %s -verify-machineinstrs -mtriple=arm64-none-linux-gnu -mattr=+neon | FileCheck %s<br>
+; RUN: llc < %s -verify-machineinstrs -mtriple=arm64-none-linux-gnu -mattr=+neon -mcpu=cyclone | FileCheck %s<br>
 ; arm64 has its own copy of this because of the intrinsics<br>
<br>
 define <8 x i8> @mul8xi8(<8 x i8> %A, <8 x i8> %B) {<br>
@@ -450,8 +450,8 @@ define <1 x i32> @srem1x32(<1 x i32> %A,<br>
 define <2 x i32> @srem2x32(<2 x i32> %A, <2 x i32> %B) {<br>
 ; CHECK-LABEL: srem2x32:<br>
 ; CHECK: sdiv {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
-; CHECK: sdiv {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
 ; CHECK: msub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
+; CHECK: sdiv {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
 ; CHECK: msub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
        %tmp3 = srem <2 x i32> %A, %B;<br>
        ret <2 x i32> %tmp3<br>
@@ -482,8 +482,8 @@ define <1 x i64> @srem1x64(<1 x i64> %A,<br>
 define <2 x i64> @srem2x64(<2 x i64> %A, <2 x i64> %B) {<br>
 ; CHECK-LABEL: srem2x64:<br>
 ; CHECK: sdiv {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
-; CHECK: sdiv {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
 ; CHECK: msub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
+; CHECK: sdiv {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
 ; CHECK: msub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
        %tmp3 = srem <2 x i64> %A, %B;<br>
        ret <2 x i64> %tmp3<br>
@@ -612,8 +612,8 @@ define <1 x i32> @urem1x32(<1 x i32> %A,<br>
 define <2 x i32> @urem2x32(<2 x i32> %A, <2 x i32> %B) {<br>
 ; CHECK-LABEL: urem2x32:<br>
 ; CHECK: udiv {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
-; CHECK: udiv {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
 ; CHECK: msub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
+; CHECK: udiv {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
 ; CHECK: msub {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}, {{w[0-9]+}}<br>
        %tmp3 = urem <2 x i32> %A, %B;<br>
        ret <2 x i32> %tmp3<br>
@@ -644,8 +644,8 @@ define <1 x i64> @urem1x64(<1 x i64> %A,<br>
 define <2 x i64> @urem2x64(<2 x i64> %A, <2 x i64> %B) {<br>
 ; CHECK-LABEL: urem2x64:<br>
 ; CHECK: udiv {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
-; CHECK: udiv {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
 ; CHECK: msub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
+; CHECK: udiv {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
 ; CHECK: msub {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}, {{x[0-9]+}}<br>
        %tmp3 = urem <2 x i64> %A, %B;<br>
        ret <2 x i64> %tmp3<br>
<br>
Modified: llvm/trunk/test/CodeGen/AArch64/dp-3source.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/dp-3source.ll?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/dp-3source.ll?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/test/CodeGen/AArch64/dp-3source.ll (original)<br>
+++ llvm/trunk/test/CodeGen/AArch64/dp-3source.ll Sun Aug  3 17:03:40 2014<br>
@@ -1,4 +1,4 @@<br>
-; RUN: llc -verify-machineinstrs -o - %s -mtriple=arm64-apple-ios7.0 | FileCheck %s<br>
+; RUN: llc -verify-machineinstrs -o - %s -mtriple=arm64-apple-ios7.0 -mcpu=cyclone | FileCheck %s<br>
<br>
 define i32 @test_madd32(i32 %val0, i32 %val1, i32 %val2) {<br>
 ; CHECK-LABEL: test_madd32:<br>
<br>
Added: llvm/trunk/test/CodeGen/AArch64/madd-lohi.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/madd-lohi.ll?rev=214669&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/madd-lohi.ll?rev=214669&view=auto</a><br>


==============================================================================<br>
--- llvm/trunk/test/CodeGen/AArch64/madd-lohi.ll (added)<br>
+++ llvm/trunk/test/CodeGen/AArch64/madd-lohi.ll Sun Aug  3 17:03:40 2014<br>
@@ -0,0 +1,19 @@<br>
+; RUN: llc -mtriple=arm64-apple-ios7.0 %s -o - | FileCheck %s<br>
+; RUN: llc -mtriple=aarch64_be-linux-gnu %s -o - | FileCheck --check-prefix=CHECK-BE %s<br>
+<br>
+define i128 @test_128bitmul(i128 %lhs, i128 %rhs) {<br>
+; CHECK-LABEL: test_128bitmul:<br>
+; CHECK-DAG: umulh [[CARRY:x[0-9]+]], x0, x2<br>
+; CHECK-DAG: madd [[PART1:x[0-9]+]], x0, x3, [[CARRY]]<br>
+; CHECK: madd x1, x1, x2, [[PART1]]<br>
+; CHECK: mul x0, x0, x2<br>
+<br>
+; CHECK-BE-LABEL: test_128bitmul:<br>
+; CHECK-BE-DAG: umulh [[CARRY:x[0-9]+]], x1, x3<br>
+; CHECK-BE-DAG: madd [[PART1:x[0-9]+]], x1, x2, [[CARRY]]<br>
+; CHECK-BE: madd x0, x0, x3, [[PART1]]<br>
+; CHECK-BE: mul x1, x1, x3<br>
+<br>
+  %prod = mul i128 %lhs, %rhs<br>
+  ret i128 %prod<br>
+}<br>
<br>
Modified: llvm/trunk/test/CodeGen/AArch64/mul-lohi.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/mul-lohi.ll?rev=214669&r1=214668&r2=214669&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/mul-lohi.ll?rev=214669&r1=214668&r2=214669&view=diff</a><br>


==============================================================================<br>
--- llvm/trunk/test/CodeGen/AArch64/mul-lohi.ll (original)<br>
+++ llvm/trunk/test/CodeGen/AArch64/mul-lohi.ll Sun Aug  3 17:03:40 2014<br>
@@ -1,17 +1,16 @@<br>
-; RUN: llc -mtriple=arm64-apple-ios7.0 %s -o - | FileCheck %s<br>
-; RUN: llc -mtriple=aarch64_be-linux-gnu %s -o - | FileCheck --check-prefix=CHECK-BE %s<br>
-<br>
+; RUN: llc -mtriple=arm64-apple-ios7.0 -mcpu=cyclone %s -o - | FileCheck %s<br>
+; RUN: llc -mtriple=aarch64_be-linux-gnu -mcpu=cyclone %s -o - | FileCheck --check-prefix=CHECK-BE %s<br>
 define i128 @test_128bitmul(i128 %lhs, i128 %rhs) {<br>
 ; CHECK-LABEL: test_128bitmul:<br>
+; CHECK-DAG: mul [[PART1:x[0-9]+]], x0, x3<br>
 ; CHECK-DAG: umulh [[CARRY:x[0-9]+]], x0, x2<br>
-; CHECK-DAG: madd [[PART1:x[0-9]+]], x0, x3, [[CARRY]]<br>
-; CHECK: madd x1, x1, x2, [[PART1]]<br>
+; CHECK: mul [[PART2:x[0-9]+]], x1, x2<br>
 ; CHECK: mul x0, x0, x2<br>
<br>
 ; CHECK-BE-LABEL: test_128bitmul:<br>
+; CHECK-BE-DAG: mul [[PART1:x[0-9]+]], x1, x2<br>
 ; CHECK-BE-DAG: umulh [[CARRY:x[0-9]+]], x1, x3<br>
-; CHECK-BE-DAG: madd [[PART1:x[0-9]+]], x1, x2, [[CARRY]]<br>
-; CHECK-BE: madd x0, x0, x3, [[PART1]]<br>
+; CHECK-BE: mul [[PART2:x[0-9]+]], x0, x3<br>
 ; CHECK-BE: mul x1, x1, x3<br>
<br>
   %prod = mul i128 %lhs, %rhs<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><span class="HOEnZb"><font color="#888888"><br><br clear="all"><div><br></div>-- <br><div dir="ltr">Best Regards,<div><br></div><div>Kevin Qin</div></div>
</font></span></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div dir="ltr">Best Regards,<div><br></div><div>Kevin Qin</div></div>
</div>
</blockquote></div><br></div></body></html>