diff --git a/lib/Target/AVR/AVRISelLowering.cpp b/lib/Target/AVR/AVRISelLowering.cpp index 04f97471001..3fc8032e73e 100644 --- a/lib/Target/AVR/AVRISelLowering.cpp +++ b/lib/Target/AVR/AVRISelLowering.cpp @@ -137,8 +137,11 @@ AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm) // Expand 16 bit multiplications. setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand); setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand); - setOperationAction(ISD::MULHS, MVT::i16, Expand); - setOperationAction(ISD::MULHU, MVT::i16, Expand); + + for (MVT VT : MVT::integer_valuetypes()) { + setOperationAction(ISD::MULHS, VT, Expand); + setOperationAction(ISD::MULHU, VT, Expand); + } // Runtime library functions { @@ -232,6 +235,12 @@ const char *AVRTargetLowering::getTargetNodeName(unsigned Opcode) const { } } +EVT AVRTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &, + EVT VT) const { + assert(!VT.isVector() && "No AVR SetCC type for vectors!"); + return MVT::i8; +} + SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { //:TODO: this function has to be completely rewritten to produce optimal // code, for now it's producing very long but correct code. @@ -1474,9 +1483,12 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr *MI, } inline bool isCopyMulResult(MachineBasicBlock::iterator const &I) { - unsigned SrcReg = I->getOperand(1).getReg(); - return I->getOpcode() == AVR::COPY && - (SrcReg == AVR::R0 || SrcReg == AVR::R1); + if (I->getOpcode() == AVR::COPY) { + unsigned SrcReg = I->getOperand(1).getReg(); + return (SrcReg == AVR::R0 || SrcReg == AVR::R1); + } + + return false; } // The mul instructions wreak havock on our zero_reg R1. We need to clear it diff --git a/lib/Target/AVR/AVRISelLowering.h b/lib/Target/AVR/AVRISelLowering.h index 7355c051787..3d5a7c9d498 100644 --- a/lib/Target/AVR/AVRISelLowering.h +++ b/lib/Target/AVR/AVRISelLowering.h @@ -94,6 +94,9 @@ class AVRTargetLowering : public TargetLowering { bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, + EVT VT) const override; + MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const override; diff --git a/test/CodeGen/AVR/issue-cannot-select-mulhs.ll b/test/CodeGen/AVR/issue-cannot-select-mulhs.ll deleted file mode 100644 index ba4d7a3fcba..00000000000 --- a/test/CodeGen/AVR/issue-cannot-select-mulhs.ll +++ /dev/null @@ -1,33 +0,0 @@ -; RUN: llc < %s -march=avr | FileCheck %s -; XFAIL: * - -define fastcc void @foo(i32) unnamed_addr { -; CHECK-LABEL: foo: -entry-block: - br i1 undef, label %return, label %next - -next: ; preds = %entry-block - %1 = trunc i32 %0 to i8 - br label %exit - -exit: ; preds = %match_case1, %next - %result.0282 = phi i8 [ %5, %match_case1 ], [ 0, %next ] - %2 = icmp ult i32 undef, %0 - br i1 %2, label %match_case0, label %return - -match_case0: ; preds = %exit - %3 = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %result.0282, i8 %1) - %4 = extractvalue { i8, i1 } %3, 1 - %brmerge = or i1 %4, undef - br i1 %brmerge, label %return, label %match_case1 - -match_case1: ; preds = %match_case0 - %5 = extractvalue { i8, i1 } undef, 0 - br label %exit - -return: ; preds = %match_case0, %exit, %entry-block - ret void -} - -; Function Attrs: nounwind readnone -declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) diff --git a/test/CodeGen/AVR/smul-with-overflow.ll b/test/CodeGen/AVR/smul-with-overflow.ll new file mode 100644 index 00000000000..745e93005cc --- /dev/null +++ b/test/CodeGen/AVR/smul-with-overflow.ll @@ -0,0 +1,31 @@ +; RUN: llc < %s -march=avr | FileCheck %s + +define i1 @signed_multiplication_did_overflow(i8, i8) unnamed_addr { +; CHECK-LABEL: signed_multiplication_did_overflow: +entry-block: + %2 = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %0, i8 %1) + %3 = extractvalue { i8, i1 } %2, 1 + ret i1 %3 + +; Multiply, fill the low byte with the sign of the low byte via +; arithmetic shifting, compare it to the high byte. +; +; CHECK: muls r24, r22 +; CHECK: mov [[HIGH:r[0-9]+]], r1 +; CHECK: mov [[LOW:r[0-9]+]], r0 +; CHECK: asr {{.*}}[[LOW]] +; CHECK: asr {{.*}}[[LOW]] +; CHECK: asr {{.*}}[[LOW]] +; CHECK: asr {{.*}}[[LOW]] +; CHECK: asr {{.*}}[[LOW]] +; CHECK: asr {{.*}}[[LOW]] +; CHECK: asr {{.*}}[[LOW]] +; CHECK: ldi [[RET:r[0-9]+]], 1 +; CHECK: cp {{.*}}[[HIGH]], {{.*}}[[LOW]] +; CHECK: brne [[LABEL:LBB[_0-9]+]] +; CHECK: ldi {{.*}}[[RET]], 0 +; CHECK: {{.*}}[[LABEL]] +; CHECK: ret +} + +declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) diff --git a/test/CodeGen/AVR/umul-with-overflow.ll b/test/CodeGen/AVR/umul-with-overflow.ll new file mode 100644 index 00000000000..aa8b10a313d --- /dev/null +++ b/test/CodeGen/AVR/umul-with-overflow.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s -march=avr | FileCheck %s + +define i1 @unsigned_multiplication_did_overflow(i8, i8) unnamed_addr { +; CHECK-LABEL: unsigned_multiplication_did_overflow: +entry-block: + %2 = tail call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %0, i8 %1) + %3 = extractvalue { i8, i1 } %2, 1 + ret i1 %3 + +; Multiply, return if the high byte is zero +; +; CHECK: mul r{{[0-9]+}}, r{{[0-9]+}} +; CHECK: mov [[HIGH:r[0-9]+]], r1 +; CHECK: ldi [[RET:r[0-9]+]], 1 +; CHECK: cpi {{.*}}[[HIGH]], 0 +; CHECK: brne [[LABEL:LBB[_0-9]+]] +; CHECK: ldi {{.*}}[[RET]], 0 +; CHECK: {{.*}}[[LABEL]] +; CHECK: ret +} + +declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8)