diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 17e0eecf971..6582a5b2642 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -174,6 +174,16 @@ def MUL : InstARM<(ops IntRegs:$dst, IntRegs:$a, IntRegs:$b), "mul $dst, $a, $b", [(set IntRegs:$dst, (mul IntRegs:$a, IntRegs:$b))]>; +let Defs = [R0] in { + def SMULL : InstARM<(ops IntRegs:$dst, IntRegs:$a, IntRegs:$b), + "smull r12, $dst, $a, $b", + [(set IntRegs:$dst, (mulhs IntRegs:$a, IntRegs:$b))]>; + + def UMULL : InstARM<(ops IntRegs:$dst, IntRegs:$a, IntRegs:$b), + "umull r12, $dst, $a, $b", + [(set IntRegs:$dst, (mulhu IntRegs:$a, IntRegs:$b))]>; +} + def bcond : InstARM<(ops brtarget:$dst, CCOp:$cc), "b$cc $dst", [(armbr bb:$dst, imm:$cc)]>; diff --git a/lib/Target/ARM/ARMMul.cpp b/lib/Target/ARM/ARMMul.cpp index 185fb96783d..474039db277 100644 --- a/lib/Target/ARM/ARMMul.cpp +++ b/lib/Target/ARM/ARMMul.cpp @@ -8,7 +8,7 @@ // //===----------------------------------------------------------------------===// // -// Modify the ARM multiplication instructions so that Rd and Rm are distinct +// Modify the ARM multiplication instructions so that Rd{Hi,Lo} and Rm are distinct // //===----------------------------------------------------------------------===// @@ -39,7 +39,10 @@ bool FixMul::runOnMachineFunction(MachineFunction &MF) { I != E; ++I) { MachineInstr *MI = I; - if (MI->getOpcode() == ARM::MUL) { + int Op = MI->getOpcode(); + if (Op == ARM::MUL || + Op == ARM::SMULL || + Op == ARM::UMULL) { MachineOperand &RdOp = MI->getOperand(0); MachineOperand &RmOp = MI->getOperand(1); MachineOperand &RsOp = MI->getOperand(2); @@ -48,7 +51,7 @@ bool FixMul::runOnMachineFunction(MachineFunction &MF) { unsigned Rm = RmOp.getReg(); unsigned Rs = RsOp.getReg(); - if(Rd == Rm) { + if (Rd == Rm) { Changed = true; if (Rd != Rs) { //Rd and Rm must be distinct, but Rd can be equal to Rs. @@ -56,9 +59,10 @@ bool FixMul::runOnMachineFunction(MachineFunction &MF) { RmOp.setReg(Rs); RsOp.setReg(Rm); } else { - BuildMI(MBB, I, ARM::MOV, 3, ARM::R12).addReg(Rm).addImm(0) + unsigned scratch = Op == ARM::MUL ? ARM::R12 : ARM::R0; + BuildMI(MBB, I, ARM::MOV, 3, scratch).addReg(Rm).addImm(0) .addImm(ARMShift::LSL); - RmOp.setReg(ARM::R12); + RmOp.setReg(scratch); } } } diff --git a/lib/Target/ARM/README.txt b/lib/Target/ARM/README.txt index 06a8cceda54..768a2e6f3e4 100644 --- a/lib/Target/ARM/README.txt +++ b/lib/Target/ARM/README.txt @@ -46,3 +46,8 @@ declare void %g(int, int, int, int, int) Only needs 8 bytes of stack space. We currently allocate 16. ---------------------------------------------------------- + +32 x 32 -> 64 multiplications currently uses two instructions. We +should try to declare smull and umull as returning two values. + +---------------------------------------------------------- diff --git a/test/CodeGen/ARM/long.ll b/test/CodeGen/ARM/long.ll index c01a4cb6130..834f0687101 100644 --- a/test/CodeGen/ARM/long.ll +++ b/test/CodeGen/ARM/long.ll @@ -7,7 +7,9 @@ ; RUN: llvm-as < %s | llc -march=arm | grep "adds" | wc -l | grep 1 && ; RUN: llvm-as < %s | llc -march=arm | grep "adcs" | wc -l | grep 1 && ; RUN: llvm-as < %s | llc -march=arm | grep "subs" | wc -l | grep 1 && -; RUN: llvm-as < %s | llc -march=arm | grep "sbcs" | wc -l | grep 1 +; RUN: llvm-as < %s | llc -march=arm | grep "sbcs" | wc -l | grep 1 && +; RUN: llvm-as < %s | llc -march=arm | grep "smull" | wc -l | grep 1 && +; RUN: llvm-as < %s | llc -march=arm | grep "umull" | wc -l | grep 1 long %f1() { entry: @@ -52,3 +54,19 @@ entry: %tmp = sub long %a, %b ret long %tmp } + +long %f(int %a, int %b) { +entry: + %tmp = cast int %a to long + %tmp1 = cast int %b to long + %tmp2 = mul long %tmp1, %tmp + ret long %tmp2 +} + +ulong %g(uint %a, uint %b) { +entry: + %tmp = cast uint %a to ulong + %tmp1 = cast uint %b to ulong + %tmp2 = mul ulong %tmp1, %tmp + ret ulong %tmp2 +}