llvm.org GIT mirror llvm / d519e42
Merging r351523: ------------------------------------------------------------------------ r351523 | dylanmckay | 2019-01-17 22:10:41 -0800 (Thu, 17 Jan 2019) | 12 lines [AVR] Expand 8/16-bit multiplication to libcalls on MCUs that don't have hardware MUL This change modifies the LLVM ISel lowering settings so that 8-bit/16-bit multiplication is expanded to calls into the compiler runtime library if the MCU being targeted does not support multiplication in hardware. Before this, MUL instructions would be generated on CPUs like the ATtiny85, triggering a CPU reset due to an illegal instruction at runtime. First raised in https://github.com/avr-rust/rust/issues/124. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_80@361551 91177308-0d34-0410-b5e6-96231b3b80d8 Tom Stellard 3 months ago
9 changed file(s) with 98 addition(s) and 45 deletion(s). Raw diff Collapse all Expand all
2525
2626 #include "AVR.h"
2727 #include "AVRMachineFunctionInfo.h"
28 #include "AVRSubtarget.h"
2829 #include "AVRTargetMachine.h"
2930 #include "MCTargetDesc/AVRMCTargetDesc.h"
3031
3132 namespace llvm {
3233
33 AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm)
34 : TargetLowering(tm) {
34 AVRTargetLowering::AVRTargetLowering(const AVRTargetMachine &TM,
35 const AVRSubtarget &STI)
36 : TargetLowering(TM), Subtarget(STI) {
3537 // Set up the register classes.
3638 addRegisterClass(MVT::i8, &AVR::GPR8RegClass);
3739 addRegisterClass(MVT::i16, &AVR::DREGSRegClass);
3840
3941 // Compute derived properties from the register classes.
40 computeRegisterProperties(tm.getSubtargetImpl()->getRegisterInfo());
42 computeRegisterProperties(Subtarget.getRegisterInfo());
4143
4244 setBooleanContents(ZeroOrOneBooleanContent);
4345 setBooleanVectorContents(ZeroOrOneBooleanContent);
161163 // Expand 16 bit multiplications.
162164 setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
163165 setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
166
167 // Expand multiplications to libcalls when there is
168 // no hardware MUL.
169 if (!Subtarget.supportsMultiplication()) {
170 setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand);
171 setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand);
172 }
164173
165174 for (MVT VT : MVT::integer_valuetypes()) {
166175 setOperationAction(ISD::MULHS, VT, Expand);
12701279
12711280 // Add a register mask operand representing the call-preserved registers.
12721281 const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
1273 const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo();
1282 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
12741283 const uint32_t *Mask =
12751284 TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
12761285 assert(Mask && "Missing call preserved mask for calling convention");
14331442 MachineFunction *F = BB->getParent();
14341443 MachineRegisterInfo &RI = F->getRegInfo();
14351444 const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
1436 const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
1445 const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
14371446 DebugLoc dl = MI.getDebugLoc();
14381447
14391448 switch (MI.getOpcode()) {
15741583 MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
15751584 MachineBasicBlock *BB) const {
15761585 const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
1577 const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
1586 const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
15781587 MachineBasicBlock::iterator I(MI);
15791588 ++I; // in any case insert *after* the mul instruction
15801589 if (isCopyMulResult(I))
18371846 AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
18381847 StringRef Constraint,
18391848 MVT VT) const {
1840 auto STI = static_cast(this->getTargetMachine())
1841 .getSubtargetImpl();
1842
18431849 // We only support i8 and i16.
18441850 //
18451851 //:FIXME: remove this assert for now since it gets sometimes executed
18831889 }
18841890 }
18851891
1886 return TargetLowering::getRegForInlineAsmConstraint(STI->getRegisterInfo(),
1887 Constraint, VT);
1892 return TargetLowering::getRegForInlineAsmConstraint(
1893 Subtarget.getRegisterInfo(), Constraint, VT);
18881894 }
18891895
18901896 void AVRTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
6363
6464 } // end of namespace AVRISD
6565
66 class AVRSubtarget;
6667 class AVRTargetMachine;
6768
6869 /// Performs target lowering for the AVR.
6970 class AVRTargetLowering : public TargetLowering {
7071 public:
71 explicit AVRTargetLowering(AVRTargetMachine &TM);
72 explicit AVRTargetLowering(const AVRTargetMachine &TM,
73 const AVRSubtarget &STI);
7274
7375 public:
7476 MVT getScalarShiftAmountTy(const DataLayout &, EVT LHSTy) const override {
163165 const SDLoc &dl, SelectionDAG &DAG,
164166 SmallVectorImpl &InVals) const;
165167
168 protected:
169
170 const AVRSubtarget &Subtarget;
171
166172 private:
167173 MachineBasicBlock *insertShift(MachineInstr &MI, MachineBasicBlock *BB) const;
168174 MachineBasicBlock *insertMul(MachineInstr &MI, MachineBasicBlock *BB) const;
2828 namespace llvm {
2929
3030 AVRSubtarget::AVRSubtarget(const Triple &TT, const std::string &CPU,
31 const std::string &FS, AVRTargetMachine &TM)
31 const std::string &FS, const AVRTargetMachine &TM)
3232 : AVRGenSubtargetInfo(TT, CPU, FS), InstrInfo(), FrameLowering(),
33 TLInfo(TM), TSInfo(),
33 TLInfo(TM, initializeSubtargetDependencies(CPU, FS, TM)), TSInfo(),
3434
3535 // Subtarget features
3636 m_hasSRAM(false), m_hasJMPCALL(false), m_hasIJMPCALL(false),
4343 ParseSubtargetFeatures(CPU, FS);
4444 }
4545
46 AVRSubtarget &
47 AVRSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS,
48 const TargetMachine &TM) {
49 // Parse features string.
50 ParseSubtargetFeatures(CPU, FS);
51 return *this;
52 }
53
4654 } // end of namespace llvm
3636 //! \param FS The feature string.
3737 //! \param TM The target machine.
3838 AVRSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
39 AVRTargetMachine &TM);
39 const AVRTargetMachine &TM);
4040
4141 const AVRInstrInfo *getInstrInfo() const override { return &InstrInfo; }
4242 const TargetFrameLowering *getFrameLowering() const override { return &FrameLowering; }
4747 /// Parses a subtarget feature string, setting appropriate options.
4848 /// \note Definition of function is auto generated by `tblgen`.
4949 void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
50
51 AVRSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS,
52 const TargetMachine &TM);
5053
5154 // Subtarget feature getters.
5255 // See AVR.td for details.
0 ; RUN: llc -mattr=mul,movw < %s -march=avr | FileCheck %s
1
2 ; Tests lowering of multiplication to hardware instructions.
3
4 define i8 @mult8(i8 %a, i8 %b) {
5 ; CHECK-LABEL: mult8:
6 ; CHECK: muls r22, r24
7 ; CHECK: clr r1
8 ; CHECK: mov r24, r0
9 %mul = mul i8 %b, %a
10 ret i8 %mul
11 }
12
13 define i16 @mult16(i16 %a, i16 %b) {
14 ; CHECK-LABEL: mult16:
15 ; CHECK: muls r22, r25
16 ; CHECK: mov r18, r0
17 ; CHECK: mul r22, r24
18 ; CHECK: mov r19, r0
19 ; CHECK: mov r20, r1
20 ; CHECK: clr r1
21 ; CHECK: add r20, r18
22 ; CHECK: muls r23, r24
23 ; CHECK: clr r1
24 ; CHECK: mov r22, r0
25 ; CHECK: add r22, r20
26 ; :TODO: finish after reworking shift instructions
27 %mul = mul nsw i16 %b, %a
28 ret i16 %mul
29 }
+0
-28
test/CodeGen/AVR/mul.ll less more
None ; RUN: llc -mattr=mul,movw < %s -march=avr | FileCheck %s
1
2 define i8 @mult8(i8 %a, i8 %b) {
3 ; CHECK-LABEL: mult8:
4 ; CHECK: muls r22, r24
5 ; CHECK: clr r1
6 ; CHECK: mov r24, r0
7 %mul = mul i8 %b, %a
8 ret i8 %mul
9 }
10
11 define i16 @mult16(i16 %a, i16 %b) {
12 ; CHECK-LABEL: mult16:
13 ; CHECK: muls r22, r25
14 ; CHECK: mov r18, r0
15 ; CHECK: mul r22, r24
16 ; CHECK: mov r19, r0
17 ; CHECK: mov r20, r1
18 ; CHECK: clr r1
19 ; CHECK: add r20, r18
20 ; CHECK: muls r23, r24
21 ; CHECK: clr r1
22 ; CHECK: mov r22, r0
23 ; CHECK: add r22, r20
24 ; :TODO: finish after reworking shift instructions
25 %mul = mul nsw i16 %b, %a
26 ret i16 %mul
27 }
None ; RUN: llc < %s -march=avr | FileCheck %s
0 ; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
11
22 define i1 @signed_multiplication_did_overflow(i8, i8) unnamed_addr {
33 ; CHECK-LABEL: signed_multiplication_did_overflow:
0 ; RUN: llc -mattr=avr6,-mul < %s -march=avr | FileCheck %s
1 ; RUN: llc -mcpu=attiny85 < %s -march=avr | FileCheck %s
2 ; RUN: llc -mcpu=ata5272 < %s -march=avr | FileCheck %s
3 ; RUN: llc -mcpu=attiny861a < %s -march=avr | FileCheck %s
4 ; RUN: llc -mcpu=at90usb82 < %s -march=avr | FileCheck %s
5
6 ; Tests lowering of multiplication to compiler support routines.
7
8 ; CHECK-LABEL: mul8:
9 define i8 @mul8(i8 %a, i8 %b) {
10 ; CHECK: mov r25, r24
11 ; CHECK: mov r24, r22
12 ; CHECK: mov r22, r25
13 ; CHECK: call __mulqi3
14 %mul = mul i8 %b, %a
15 ret i8 %mul
16 }
17
18 ; CHECK-LABEL: mul16:
19 define i16 @mul16(i16 %a, i16 %b) {
20 ; CHECK: movw r18, r24
21 ; CHECK: movw r24, r22
22 ; CHECK: movw r22, r18
23 ; CHECK: call __mulhi3
24 %mul = mul nsw i16 %b, %a
25 ret i16 %mul
26 }
27
None ; RUN: llc < %s -march=avr | FileCheck %s
0 ; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
11
22 define i1 @unsigned_multiplication_did_overflow(i8, i8) unnamed_addr {
33 ; CHECK-LABEL: unsigned_multiplication_did_overflow: