Index: include/llvm/CodeGen/MachineRegisterInfo.h =================================================================== --- include/llvm/CodeGen/MachineRegisterInfo.h +++ include/llvm/CodeGen/MachineRegisterInfo.h @@ -561,9 +561,14 @@ } /// hasOneNonDBGUse - Return true if there is exactly one non-Debug - /// instruction using the specified register. + /// use of the specified register. bool hasOneNonDBGUse(unsigned RegNo) const; + /// hasOneNonDBGUse - Return true if there is exactly one non-Debug + /// instruction using the specified register. Said instruction may have + /// multiple uses. + bool hasOneNonDBGUser(unsigned RegNo) const; + /// replaceRegWith - Replace all instances of FromReg with ToReg in the /// machine function. This is like llvm-level X->replaceAllUsesWith(Y), /// except that it also changes any definitions of the register as well. Index: lib/CodeGen/MachineRegisterInfo.cpp =================================================================== --- lib/CodeGen/MachineRegisterInfo.cpp +++ lib/CodeGen/MachineRegisterInfo.cpp @@ -423,6 +423,13 @@ return ++UI == use_nodbg_end(); } +bool MachineRegisterInfo::hasOneNonDBGUser(unsigned RegNo) const { + use_instr_nodbg_iterator UI = use_instr_nodbg_begin(RegNo); + if (UI == use_instr_nodbg_end()) + return false; + return ++UI == use_instr_nodbg_end(); +} + /// clearKillFlags - Iterate over all the uses of the given register and /// clear the kill flag from the MachineOperand. This function is used by /// optimization passes which extend register lifetimes and need only Index: lib/CodeGen/PeepholeOptimizer.cpp =================================================================== --- lib/CodeGen/PeepholeOptimizer.cpp +++ lib/CodeGen/PeepholeOptimizer.cpp @@ -1316,12 +1316,12 @@ return false; unsigned Reg = MI.getOperand(0).getReg(); - // To reduce compilation time, we check MRI->hasOneNonDBGUse when inserting + // To reduce compilation time, we check MRI->hasOneNonDBGUser when inserting // loads. It should be checked when processing uses of the load, since // uses can be removed during peephole. if (!MI.getOperand(0).getSubReg() && TargetRegisterInfo::isVirtualRegister(Reg) && - MRI->hasOneNonDBGUse(Reg)) { + MRI->hasOneNonDBGUser(Reg)) { FoldAsLoadDefCandidates.insert(Reg); return true; } Index: test/CodeGen/X86/peephole-fold-testrr.mir =================================================================== --- test/CodeGen/X86/peephole-fold-testrr.mir +++ test/CodeGen/X86/peephole-fold-testrr.mir @@ -0,0 +1,88 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -run-pass=peephole-opt -mtriple=x86_64-- %s -o - | FileCheck %s + +--- | + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + define i32 @atomic(i8** %arg) { + %load = load atomic i8*, i8** %arg unordered, align 8 + %cmp = icmp eq i8* %load, null + %zext = zext i1 %cmp to i32 + ret i32 %zext + } + + define i32 @nonatomic_unoptimized(i8** %arg) { + %load = load i8*, i8** %arg, align 8 + %cmp = icmp eq i8* %load, null + %zext = zext i1 %cmp to i32 + ret i32 %zext + } + +... +--- +name: atomic +alignment: 4 +tracksRegLiveness: true +registers: + - { id: 0, class: gr64 } + - { id: 1, class: gr64 } + - { id: 2, class: gr8 } + - { id: 3, class: gr32 } +liveins: + - { reg: '$rdi', virtual-reg: '%0' } +machineFunctionInfo: {} +body: | + bb.0 (%ir-block.0): + liveins: $rdi + + ; CHECK-LABEL: name: atomic + ; CHECK: liveins: $rdi + ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK: CMP64mi8 [[COPY]], 1, $noreg, 0, $noreg, 0, implicit-def $eflags :: (load unordered 8 from %ir.arg) + ; CHECK: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK: [[MOVZX32rr8_:%[0-9]+]]:gr32 = MOVZX32rr8 killed [[SETCCr]] + ; CHECK: $eax = COPY [[MOVZX32rr8_]] + ; CHECK: RET 0, $eax + %0:gr64 = COPY $rdi + %1:gr64 = MOV64rm %0, 1, $noreg, 0, $noreg :: (load unordered 8 from %ir.arg) + TEST64rr %1, %1, implicit-def $eflags + %2:gr8 = SETCCr 4, implicit $eflags + %3:gr32 = MOVZX32rr8 killed %2 + $eax = COPY %3 + RET 0, $eax + +... +--- +name: nonatomic_unoptimized +alignment: 4 +tracksRegLiveness: true +registers: + - { id: 0, class: gr64 } + - { id: 1, class: gr64 } + - { id: 2, class: gr8 } + - { id: 3, class: gr32 } +liveins: + - { reg: '$rdi', virtual-reg: '%0' } +machineFunctionInfo: {} +body: | + bb.0 (%ir-block.0): + liveins: $rdi + + ; CHECK-LABEL: name: nonatomic_unoptimized + ; CHECK: liveins: $rdi + ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK: CMP64mi8 [[COPY]], 1, $noreg, 0, $noreg, 0, implicit-def $eflags :: (load 8 from %ir.arg) + ; CHECK: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags + ; CHECK: [[MOVZX32rr8_:%[0-9]+]]:gr32 = MOVZX32rr8 killed [[SETCCr]] + ; CHECK: $eax = COPY [[MOVZX32rr8_]] + ; CHECK: RET 0, $eax + %0:gr64 = COPY $rdi + %1:gr64 = MOV64rm %0, 1, $noreg, 0, $noreg :: (load 8 from %ir.arg) + TEST64rr %1, %1, implicit-def $eflags + %2:gr8 = SETCCr 4, implicit $eflags + %3:gr32 = MOVZX32rr8 killed %2 + $eax = COPY %3 + RET 0, $eax + +...