diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/llvm/lib/Target/AVR/AVRInstrInfo.cpp index afba66b2e69b..744aa723c416 100644 --- a/llvm/lib/Target/AVR/AVRInstrInfo.cpp +++ b/llvm/lib/Target/AVR/AVRInstrInfo.cpp @@ -402,7 +402,7 @@ unsigned AVRInstrInfo::insertBranch(MachineBasicBlock &MBB, ArrayRef Cond, const DebugLoc &DL, int *BytesAdded) const { - assert(!BytesAdded && "code size not handled"); + if (BytesAdded) *BytesAdded = 0; // Shouldn't be a fall through. assert(TBB && "insertBranch must not be told to insert a fallthrough"); @@ -411,19 +411,24 @@ unsigned AVRInstrInfo::insertBranch(MachineBasicBlock &MBB, if (Cond.empty()) { assert(!FBB && "Unconditional branch with multiple successors!"); - BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(TBB); + auto &MI = *BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(TBB); + if (BytesAdded) + *BytesAdded += getInstSizeInBytes(MI); return 1; } // Conditional branch. unsigned Count = 0; AVRCC::CondCodes CC = (AVRCC::CondCodes)Cond[0].getImm(); - BuildMI(&MBB, DL, getBrCond(CC)).addMBB(TBB); + auto &CondMI = *BuildMI(&MBB, DL, getBrCond(CC)).addMBB(TBB); + + if (BytesAdded) *BytesAdded += getInstSizeInBytes(CondMI); ++Count; if (FBB) { // Two-way Conditional branch. Insert the second branch. - BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(FBB); + auto &MI = *BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(FBB); + if (BytesAdded) *BytesAdded += getInstSizeInBytes(MI); ++Count; } @@ -432,7 +437,7 @@ unsigned AVRInstrInfo::insertBranch(MachineBasicBlock &MBB, unsigned AVRInstrInfo::removeBranch(MachineBasicBlock &MBB, int *BytesRemoved) const { - assert(!BytesRemoved && "code size not handled"); + if (BytesRemoved) *BytesRemoved = 0; MachineBasicBlock::iterator I = MBB.end(); unsigned Count = 0; @@ -450,6 +455,7 @@ unsigned AVRInstrInfo::removeBranch(MachineBasicBlock &MBB, } // Remove the branch. + if (BytesRemoved) *BytesRemoved += getInstSizeInBytes(*I); I->eraseFromParent(); I = MBB.end(); ++Count; @@ -494,5 +500,61 @@ unsigned AVRInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { } } +MachineBasicBlock * +AVRInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + default: + llvm_unreachable("unexpected opcode!"); + case AVR::JMPk: + case AVR::CALLk: + case AVR::RCALLk: + case AVR::RJMPk: + case AVR::BREQk: + case AVR::BRNEk: + case AVR::BRSHk: + case AVR::BRLOk: + case AVR::BRMIk: + case AVR::BRPLk: + case AVR::BRGEk: + case AVR::BRLTk: + return MI.getOperand(0).getMBB(); + case AVR::BRBSsk: + case AVR::BRBCsk: + return MI.getOperand(1).getMBB(); + case AVR::SBRCRrB: + case AVR::SBRSRrB: + case AVR::SBICAb: + case AVR::SBISAb: + llvm_unreachable("unimplemented branch instructions"); + } +} + +bool AVRInstrInfo::isBranchOffsetInRange(unsigned BranchOp, + int64_t BrOffset) const { + + switch (BranchOp) { + default: + llvm_unreachable("unexpected opcode!"); + case AVR::JMPk: + case AVR::CALLk: + assert(BrOffset >= 0 && "offset must be absolute address"); + return isUIntN(16, BrOffset); + case AVR::RCALLk: + case AVR::RJMPk: + return isIntN(13, BrOffset); + case AVR::BRBSsk: + case AVR::BRBCsk: + case AVR::BREQk: + case AVR::BRNEk: + case AVR::BRSHk: + case AVR::BRLOk: + case AVR::BRMIk: + case AVR::BRPLk: + case AVR::BRGEk: + case AVR::BRLTk: + return isIntN(7, BrOffset); + } +} + } // end of namespace llvm diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.h b/llvm/lib/Target/AVR/AVRInstrInfo.h index c5105dafe5eb..f42d34fb2848 100644 --- a/llvm/lib/Target/AVR/AVRInstrInfo.h +++ b/llvm/lib/Target/AVR/AVRInstrInfo.h @@ -103,6 +103,10 @@ public: bool reverseBranchCondition(SmallVectorImpl &Cond) const override; + MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override; + + bool isBranchOffsetInRange(unsigned BranchOpc, + int64_t BrOffset) const override; private: const AVRRegisterInfo RI; }; diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/llvm/lib/Target/AVR/AVRTargetMachine.cpp index 91d2a8737b87..a9d61ffc952c 100644 --- a/llvm/lib/Target/AVR/AVRTargetMachine.cpp +++ b/llvm/lib/Target/AVR/AVRTargetMachine.cpp @@ -66,6 +66,7 @@ public: bool addInstSelector() override; void addPreSched2() override; + void addPreEmitPass() override; void addPreRegAlloc() override; }; } // namespace @@ -115,4 +116,9 @@ void AVRPassConfig::addPreSched2() { addPass(createAVRExpandPseudoPass()); } +void AVRPassConfig::addPreEmitPass() { + // Must run branch selection immediately preceding the asm printer. + addPass(&BranchRelaxationPassID); +} + } // end of namespace llvm diff --git a/llvm/test/CodeGen/AVR/branch-relaxation.ll b/llvm/test/CodeGen/AVR/branch-relaxation.ll new file mode 100644 index 000000000000..d6f07f653576 --- /dev/null +++ b/llvm/test/CodeGen/AVR/branch-relaxation.ll @@ -0,0 +1,96 @@ +; RUN: llc < %s -march=avr | FileCheck %s + +; CHECKC-LABEL: relax_breq +; CHECK: cpi r{{[0-9]+}}, 0 +; CHECK: brne LBB0_1 +; CHECK: rjmp LBB0_2 +; LBB0_1: + +define i8 @relax_breq(i1 %a) { +entry-block: + br i1 %a, label %hello, label %finished + +hello: + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + br label %finished +finished: + ret i8 3 +} + +; CHECKC-LABEL: no_relax_breq +; CHECK: cpi r{{[0-9]+}}, 0 +; CHECK: breq [[END_BB:LBB[0-9]+_[0-9]+]] +; CHECK: nop +; ... +; LBB0_1: +define i8 @no_relax_breq(i1 %a) { +entry-block: + br i1 %a, label %hello, label %finished + +hello: + ; There are not enough NOPs to require relaxation. + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + call void asm sideeffect "nop", ""() + br label %finished +finished: + ret i8 3 +} + diff --git a/llvm/test/CodeGen/AVR/ctlz.ll b/llvm/test/CodeGen/AVR/ctlz.ll index 4f73e846b1f1..8659550baf90 100644 --- a/llvm/test/CodeGen/AVR/ctlz.ll +++ b/llvm/test/CodeGen/AVR/ctlz.ll @@ -10,7 +10,8 @@ declare i8 @llvm.ctlz.i8(i8) ; CHECK-LABEL: count_leading_zeros: ; CHECK: cpi [[RESULT:r[0-9]+]], 0 -; CHECK: breq LBB0_1 +; CHECK: brne LBB0_1 +; CHECK: rjmp LBB0_2 ; CHECK: mov [[SCRATCH:r[0-9]+]], {{.*}}[[RESULT]] ; CHECK: lsr {{.*}}[[SCRATCH]] ; CHECK: or {{.*}}[[SCRATCH]], {{.*}}[[RESULT]] @@ -43,6 +44,6 @@ declare i8 @llvm.ctlz.i8(i8) ; CHECK: add {{.*}}[[RESULT]], {{.*}}[[SCRATCH]] ; CHECK: andi {{.*}}[[RESULT]], 15 ; CHECK: ret -; CHECK: LBB0_1: +; CHECK: LBB0_2: ; CHECK: ldi {{.*}}[[RESULT]], 8 ; CHECK: ret diff --git a/llvm/test/CodeGen/AVR/cttz.ll b/llvm/test/CodeGen/AVR/cttz.ll index 2501566275ea..02d36954f526 100644 --- a/llvm/test/CodeGen/AVR/cttz.ll +++ b/llvm/test/CodeGen/AVR/cttz.ll @@ -10,7 +10,7 @@ declare i8 @llvm.cttz.i8(i8) ; CHECK-LABEL: count_trailing_zeros: ; CHECK: cpi [[RESULT:r[0-9]+]], 0 -; CHECK: breq LBB0_1 +; CHECK: breq [[END_BB:LBB[0-9]+_[0-9]+]] ; CHECK: mov [[SCRATCH:r[0-9]+]], {{.*}}[[RESULT]] ; CHECK: dec {{.*}}[[SCRATCH]] ; CHECK: com {{.*}}[[RESULT]] @@ -34,7 +34,7 @@ declare i8 @llvm.cttz.i8(i8) ; CHECK: andi {{.*}}[[SCRATCH]], 15 ; CHECK: mov {{.*}}[[RESULT]], {{.*}}[[SCRATCH]] ; CHECK: ret -; CHECK: LBB0_1: +; CHECK: [[END_BB]]: ; CHECK: ldi {{.*}}[[SCRATCH]], 8 ; CHECK: mov {{.*}}[[RESULT]], {{.*}}[[SCRATCH]] ; CHECK: ret diff --git a/llvm/test/CodeGen/AVR/select-mbb-placement-bug.ll b/llvm/test/CodeGen/AVR/select-mbb-placement-bug.ll index ca7ec1ab831c..aca9502b5dfb 100644 --- a/llvm/test/CodeGen/AVR/select-mbb-placement-bug.ll +++ b/llvm/test/CodeGen/AVR/select-mbb-placement-bug.ll @@ -8,9 +8,9 @@ define internal fastcc void @loopy() { ; ; https://github.com/avr-rust/rust/issues/49 -; CHECK: LBB0_1: -; CHECK: LBB0_2: -; CHECK-NOT: LBB0_3: +; CHECK: LBB0_{{[0-9]+}}: +; CHECK: LBB0_{{[0-9]+}}: +; CHECK-NOT: LBB0_{{[0-9]+}}: start: br label %bb7.preheader