diff --git a/lib/Target/AVR/AVRISelLowering.cpp b/lib/Target/AVR/AVRISelLowering.cpp index 3116eb2a503..e95a41472bf 100644 --- a/lib/Target/AVR/AVRISelLowering.cpp +++ b/lib/Target/AVR/AVRISelLowering.cpp @@ -1634,6 +1634,15 @@ AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, MachineFunction *MF = MBB->getParent(); const BasicBlock *LLVM_BB = MBB->getBasicBlock(); + MachineBasicBlock *FallThrough = MBB->getFallThrough(); + + // If the current basic block falls through to another basic block, + // we must insert an unconditional branch to the fallthrough destination + // if we are to insert basic blocks at the prior fallthrough point. + if (FallThrough != nullptr) { + BuildMI(MBB, dl, TII.get(AVR::RJMPk)).addMBB(FallThrough); + } + MachineBasicBlock *trueMBB = MF->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *falseMBB = MF->CreateMachineBasicBlock(LLVM_BB); diff --git a/test/CodeGen/AVR/avr-rust-issue-123.ll b/test/CodeGen/AVR/avr-rust-issue-123.ll new file mode 100644 index 00000000000..b2e4bf0e144 --- /dev/null +++ b/test/CodeGen/AVR/avr-rust-issue-123.ll @@ -0,0 +1,74 @@ +; RUN: llc -O1 < %s -march=avr | FileCheck %s + +; This test ensures that the Select8/Select16 expansion +; pass inserts an unconditional branch to the previous adjacent +; basic block when inserting new basic blocks when the +; prior block has a fallthrough. +; +; Before this bug was fixed, Select8/Select16 expansion +; would leave a dangling fallthrough to an undefined block. +; +; The BranchFolding pass would later rearrange the basic +; blocks based on predecessor/successor list assumptions +; which were made incorrect due to the invalid Select +; expansion. + +; More information in +; https://github.com/avr-rust/rust/issues/123. + +%UInt8 = type <{ i8 }> +%UInt32 = type <{ i32 }> +%Sb = type <{ i1 }> + +@delayFactor = hidden global %UInt8 zeroinitializer, align 1 +@delay = hidden global %UInt32 zeroinitializer, align 4 +@flag = hidden global %Sb zeroinitializer, align 1 + +declare void @eeprom_write(i16, i8) + +; CHECK-LABEL: update_register +define hidden void @update_register(i8 %arg, i8 %arg1) { +entry: + ; CHECK: push [[PRELUDER:r[0-9]+]] + ; CHECK: cpi r24, 7 + switch i8 %arg, label %bb7 [ + i8 6, label %bb + i8 7, label %bb6 + ] + +; CHECK-NOT: ret +bb: ; preds = %entry + %tmp = icmp ugt i8 %arg1, 90 + %tmp2 = icmp ult i8 %arg1, 5 + %. = select i1 %tmp2, i8 5, i8 %arg1 + %tmp3 = select i1 %tmp, i8 90, i8 %. + ; CHECK: sts delayFactor, r{{[0-9]+}} + store i8 %tmp3, i8* getelementptr inbounds (%UInt8, %UInt8* @delayFactor, i64 0, i32 0), align 1 + %tmp4 = zext i8 %tmp3 to i32 + %tmp5 = mul nuw nsw i32 %tmp4, 100 + ; CHECK: sts delay+3, r{{[0-9]+}} + ; CHECK-NEXT: sts delay+2, r{{[0-9]+}} + ; CHECK-NEXT: sts delay+1, r{{[0-9]+}} + ; CHECK-NEXT: sts delay, r{{[0-9]+}} + store i32 %tmp5, i32* getelementptr inbounds (%UInt32, %UInt32* @delay, i64 0, i32 0), align 4 + tail call void @eeprom_write(i16 34, i8 %tmp3) + br label %bb7 + +bb6: ; preds = %entry + %not. = icmp ne i8 %arg1, 0 + %.2 = zext i1 %not. to i8 + store i1 %not., i1* getelementptr inbounds (%Sb, %Sb* @flag, i64 0, i32 0), align 1 + + ; CHECK: call eeprom_write + tail call void @eeprom_write(i16 35, i8 %.2) + br label %bb7 + + ; CHECK: LBB0_{{[0-9]+}} + ; CHECK: pop [[PRELUDER]] + ; CHECK-NEXT: ret +bb7: ; preds = %bb6, %bb, %entry + ret void +} +; CHECK-NOT: LBB0_{{[0-9]+}}: +; CHECK-LABEL: .Lfunc_end0 +; CHECK: .size update_register, .Lfunc_end0-update_register