<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>