Index: llvm/include/llvm/CodeGen/LivePhysRegs.h =================================================================== --- llvm/include/llvm/CodeGen/LivePhysRegs.h +++ llvm/include/llvm/CodeGen/LivePhysRegs.h @@ -137,6 +137,9 @@ /// Live out registers are the union of the live-in registers of the successor /// blocks and pristine registers. Live out registers of the end block are the /// callee saved registers. + /// If a register is not added by this method, it is guaranteed to not be + /// live out from MBB, although a sub-register may be. This is true + /// both before and after regalloc. void addLiveOuts(const MachineBasicBlock &MBB); /// Adds all live-out registers of basic block \p MBB but skips pristine Index: llvm/lib/CodeGen/MachineVerifier.cpp =================================================================== --- llvm/lib/CodeGen/MachineVerifier.cpp +++ llvm/lib/CodeGen/MachineVerifier.cpp @@ -2312,6 +2312,32 @@ if (LiveInts) verifyLiveIntervals(); + // Check live-in list of each MBB. If a register is live into MBB, check + // that the register is in regsLiveOut of each predecessor block. Since + // this must come from a definition in the predecesssor or its live-in + // list, this will catch a live-through case where the predecessor does not + // have the register in its live-in list. This currently only checks + // registers that have no aliases, are not allocatable and are not + // reserved, which could mean a condition code register for instance. + if (MRI->tracksLiveness()) + for (const auto &MBB : *MF) + for (MachineBasicBlock::RegisterMaskPair P : MBB.liveins()) { + MCPhysReg LiveInReg = P.PhysReg; + bool hasAliases = MCRegAliasIterator(LiveInReg, TRI, false).isValid(); + if (hasAliases || isAllocatable(LiveInReg) || isReserved(LiveInReg)) + continue; + for (const MachineBasicBlock *Pred : MBB.predecessors()) { + BBInfo &PInfo = MBBInfoMap[Pred]; + if (!PInfo.regsLiveOut.count(LiveInReg)) { + report("Live in register not found to be live out from predecessor.", + &MBB); + errs() << TRI->getName(LiveInReg) + << " not found to be live out from " + << printMBBReference(*Pred) << "\n"; + } + } + } + for (auto CSInfo : MF->getCallSitesInfo()) if (!CSInfo.first->isCall()) report("Call site info referencing instruction that is not call", MF); Index: llvm/test/CodeGen/X86/copy-eflags-02.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/copy-eflags-02.ll @@ -0,0 +1,111 @@ +; RUN: llc -o - -mtriple=i686-unknown-unknown %s | FileCheck %s --check-prefixes=ALL,X32 +; RUN: llc -o - -mtriple=x86_64-unknown-unknown %s | FileCheck %s --check-prefixes=ALL,X64 +; +; Test patterns that require preserving and restoring flags. + +; XFAIL: * +; +; This function fails with expensive checks enabled since it will result in a +; live-in list containing $eflags which was killed in the predecessor block. +; +; https://reviews.llvm.org/D68267 contains the machine verifier improvement +; that exposed this bug as well as a discussion of how to handle it in +; X86FlagsCopyLowering.cpp. +; +; https://reviews.llvm.org/D71375 is a suggested patch for X86FlagsCopyLowering.cpp. +; +; Reported on: https://bugs.llvm.org/show_bug.cgi?id=44462 +; +; When this has been fixed, this function could be put back into copy-eflags.ll. + +; Test a function that gets special select lowering into CFG with copied EFLAGS +; threaded across the CFG. This requires our EFLAGS copy rewriting to handle +; cross-block rewrites in at least some narrow cases. +define void @PR37100(i8 %arg1, i16 %arg2, i64 %arg3, i8 %arg4, i8* %ptr1, i32* %ptr2, i32 %x) nounwind { +; X32-LABEL: PR37100: +; X32: # %bb.0: # %bb +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: pushl %edi +; X32-NEXT: pushl %esi +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: movl {{[0-9]+}}(%esp), %ebx +; X32-NEXT: movl {{[0-9]+}}(%esp), %ebp +; X32-NEXT: movb {{[0-9]+}}(%esp), %ch +; X32-NEXT: movb {{[0-9]+}}(%esp), %cl +; X32-NEXT: jmp .LBB3_1 +; X32-NEXT: .p2align 4, 0x90 +; X32-NEXT: .LBB3_5: # %bb1 +; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 +; X32-NEXT: movl %esi, %eax +; X32-NEXT: cltd +; X32-NEXT: idivl %edi +; X32-NEXT: .LBB3_1: # %bb1 +; X32-NEXT: # =>This Inner Loop Header: Depth=1 +; X32-NEXT: movsbl %cl, %eax +; X32-NEXT: movl %eax, %edx +; X32-NEXT: sarl $31, %edx +; X32-NEXT: cmpl %eax, {{[0-9]+}}(%esp) +; X32-NEXT: movl {{[0-9]+}}(%esp), %eax +; X32-NEXT: sbbl %edx, %eax +; X32-NEXT: setl %al +; X32-NEXT: setl %dl +; X32-NEXT: movzbl %dl, %edi +; X32-NEXT: negl %edi +; X32-NEXT: testb %al, %al +; X32-NEXT: jne .LBB3_3 +; X32-NEXT: # %bb.2: # %bb1 +; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 +; X32-NEXT: movb %ch, %cl +; X32-NEXT: .LBB3_3: # %bb1 +; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 +; X32-NEXT: movb %cl, (%ebp) +; X32-NEXT: movl (%ebx), %edx +; X32-NEXT: testb %al, %al +; X32-NEXT: jne .LBB3_5 +; X32-NEXT: # %bb.4: # %bb1 +; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 +; X32-NEXT: movl %edx, %edi +; X32-NEXT: jmp .LBB3_5 +; +; X64-LABEL: PR37100: +; X64: # %bb.0: # %bb +; X64-NEXT: movq %rdx, %rsi +; X64-NEXT: movl {{[0-9]+}}(%rsp), %r10d +; X64-NEXT: movzbl %cl, %r11d +; X64-NEXT: .p2align 4, 0x90 +; X64-NEXT: .LBB3_1: # %bb1 +; X64-NEXT: # =>This Inner Loop Header: Depth=1 +; X64-NEXT: movsbq %dil, %rax +; X64-NEXT: xorl %ecx, %ecx +; X64-NEXT: cmpq %rax, %rsi +; X64-NEXT: setl %cl +; X64-NEXT: negl %ecx +; X64-NEXT: cmpq %rax, %rsi +; X64-NEXT: movzbl %al, %edi +; X64-NEXT: cmovgel %r11d, %edi +; X64-NEXT: movb %dil, (%r8) +; X64-NEXT: cmovgel (%r9), %ecx +; X64-NEXT: movl %r10d, %eax +; X64-NEXT: cltd +; X64-NEXT: idivl %ecx +; X64-NEXT: jmp .LBB3_1 +bb: + br label %bb1 + +bb1: + %tmp = phi i8 [ %tmp8, %bb1 ], [ %arg1, %bb ] + %tmp2 = phi i16 [ %tmp12, %bb1 ], [ %arg2, %bb ] + %tmp3 = icmp sgt i16 %tmp2, 7 + %tmp4 = select i1 %tmp3, i16 %tmp2, i16 7 + %tmp5 = sext i8 %tmp to i64 + %tmp6 = icmp slt i64 %arg3, %tmp5 + %tmp7 = sext i1 %tmp6 to i32 + %tmp8 = select i1 %tmp6, i8 %tmp, i8 %arg4 + store volatile i8 %tmp8, i8* %ptr1 + %tmp9 = load volatile i32, i32* %ptr2 + %tmp10 = select i1 %tmp6, i32 %tmp7, i32 %tmp9 + %tmp11 = srem i32 %x, %tmp10 + %tmp12 = trunc i32 %tmp11 to i16 + br label %bb1 +} Index: llvm/test/CodeGen/X86/copy-eflags.ll =================================================================== --- llvm/test/CodeGen/X86/copy-eflags.ll +++ llvm/test/CodeGen/X86/copy-eflags.ll @@ -195,98 +195,6 @@ ret void } -; Test a function that gets special select lowering into CFG with copied EFLAGS -; threaded across the CFG. This requires our EFLAGS copy rewriting to handle -; cross-block rewrites in at least some narrow cases. -define void @PR37100(i8 %arg1, i16 %arg2, i64 %arg3, i8 %arg4, i8* %ptr1, i32* %ptr2, i32 %x) nounwind { -; X32-LABEL: PR37100: -; X32: # %bb.0: # %bb -; X32-NEXT: pushl %ebp -; X32-NEXT: pushl %ebx -; X32-NEXT: pushl %edi -; X32-NEXT: pushl %esi -; X32-NEXT: movl {{[0-9]+}}(%esp), %esi -; X32-NEXT: movl {{[0-9]+}}(%esp), %ebx -; X32-NEXT: movl {{[0-9]+}}(%esp), %ebp -; X32-NEXT: movb {{[0-9]+}}(%esp), %ch -; X32-NEXT: movb {{[0-9]+}}(%esp), %cl -; X32-NEXT: jmp .LBB3_1 -; X32-NEXT: .p2align 4, 0x90 -; X32-NEXT: .LBB3_5: # %bb1 -; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 -; X32-NEXT: movl %esi, %eax -; X32-NEXT: cltd -; X32-NEXT: idivl %edi -; X32-NEXT: .LBB3_1: # %bb1 -; X32-NEXT: # =>This Inner Loop Header: Depth=1 -; X32-NEXT: movsbl %cl, %eax -; X32-NEXT: movl %eax, %edx -; X32-NEXT: sarl $31, %edx -; X32-NEXT: cmpl %eax, {{[0-9]+}}(%esp) -; X32-NEXT: movl {{[0-9]+}}(%esp), %eax -; X32-NEXT: sbbl %edx, %eax -; X32-NEXT: setl %al -; X32-NEXT: setl %dl -; X32-NEXT: movzbl %dl, %edi -; X32-NEXT: negl %edi -; X32-NEXT: testb %al, %al -; X32-NEXT: jne .LBB3_3 -; X32-NEXT: # %bb.2: # %bb1 -; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 -; X32-NEXT: movb %ch, %cl -; X32-NEXT: .LBB3_3: # %bb1 -; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 -; X32-NEXT: movb %cl, (%ebp) -; X32-NEXT: movl (%ebx), %edx -; X32-NEXT: testb %al, %al -; X32-NEXT: jne .LBB3_5 -; X32-NEXT: # %bb.4: # %bb1 -; X32-NEXT: # in Loop: Header=BB3_1 Depth=1 -; X32-NEXT: movl %edx, %edi -; X32-NEXT: jmp .LBB3_5 -; -; X64-LABEL: PR37100: -; X64: # %bb.0: # %bb -; X64-NEXT: movq %rdx, %rsi -; X64-NEXT: movl {{[0-9]+}}(%rsp), %r10d -; X64-NEXT: movzbl %cl, %r11d -; X64-NEXT: .p2align 4, 0x90 -; X64-NEXT: .LBB3_1: # %bb1 -; X64-NEXT: # =>This Inner Loop Header: Depth=1 -; X64-NEXT: movsbq %dil, %rax -; X64-NEXT: xorl %ecx, %ecx -; X64-NEXT: cmpq %rax, %rsi -; X64-NEXT: setl %cl -; X64-NEXT: negl %ecx -; X64-NEXT: cmpq %rax, %rsi -; X64-NEXT: movzbl %al, %edi -; X64-NEXT: cmovgel %r11d, %edi -; X64-NEXT: movb %dil, (%r8) -; X64-NEXT: cmovgel (%r9), %ecx -; X64-NEXT: movl %r10d, %eax -; X64-NEXT: cltd -; X64-NEXT: idivl %ecx -; X64-NEXT: jmp .LBB3_1 -bb: - br label %bb1 - -bb1: - %tmp = phi i8 [ %tmp8, %bb1 ], [ %arg1, %bb ] - %tmp2 = phi i16 [ %tmp12, %bb1 ], [ %arg2, %bb ] - %tmp3 = icmp sgt i16 %tmp2, 7 - %tmp4 = select i1 %tmp3, i16 %tmp2, i16 7 - %tmp5 = sext i8 %tmp to i64 - %tmp6 = icmp slt i64 %arg3, %tmp5 - %tmp7 = sext i1 %tmp6 to i32 - %tmp8 = select i1 %tmp6, i8 %tmp, i8 %arg4 - store volatile i8 %tmp8, i8* %ptr1 - %tmp9 = load volatile i32, i32* %ptr2 - %tmp10 = select i1 %tmp6, i32 %tmp7, i32 %tmp9 - %tmp11 = srem i32 %x, %tmp10 - %tmp12 = trunc i32 %tmp11 to i16 - br label %bb1 -} - ; Use a particular instruction pattern in order to lower to the post-RA pseudo ; used to lower SETB into an SBB pattern in order to make sure that kind of ; usage of a copied EFLAGS continues to work. Index: llvm/test/MachineVerifier/live-ins-01.mir =================================================================== --- /dev/null +++ llvm/test/MachineVerifier/live-ins-01.mir @@ -0,0 +1,57 @@ +# RUN: not llc -o - %s -mtriple=s390x-linux-gnu -mcpu=z14 -run-pass none 2>&1 | FileCheck %s +# REQUIRES: systemz-registered-target + +# Test that a the machine verifier reports an error when a register in +# liveins is not liveout from predecessor. + +--- +name: f1 +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $r2l, $r3l + + %1:gr32bit = COPY $r3l + %0:gr32bit = COPY $r2l + CHIMux %0, 0, implicit-def $cc + + bb.1: + liveins: $cc + + bb.2: + liveins: $cc + + %2:grx32bit = LOCRMux %1, %0, 14, 8, implicit $cc + $r2l = COPY %2 + Return implicit $r2l +... + +# CHECK: *** Bad machine code: Live in register not found to be live out from predecessor. *** +# CHECK:- function: f2 +# CHECK:- basic block: %bb.2 +# CHECK:CC not found to be live out from %bb.1 +--- +name: f2 +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $r2l, $r3l + + %1:gr32bit = COPY $r3l + %0:gr32bit = COPY $r2l + CHIMux %0, 0, implicit-def $cc + + bb.1: + liveins: $cc + KILL killed $cc + + bb.2: + liveins: $cc + + %2:grx32bit = LOCRMux %1, %0, 14, 8, implicit $cc + $r2l = COPY %2 + Return implicit $r2l + +... Index: llvm/test/MachineVerifier/live-ins-02.mir =================================================================== --- /dev/null +++ llvm/test/MachineVerifier/live-ins-02.mir @@ -0,0 +1,32 @@ +# RUN: not llc -o - %s -mtriple=s390x-linux-gnu -mcpu=z14 -run-pass none 2>&1 | FileCheck %s +# REQUIRES: systemz-registered-target + +# Test that a the machine verifier reports an error when a register in +# liveins is not liveout from predecessor. + +--- +name: f1 +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $r2l, $r3l + + %1:gr32bit = COPY $r3l + %0:gr32bit = COPY $r2l + CHIMux %0, 0, implicit-def $cc + + bb.1: + + bb.2: + liveins: $cc + + %2:grx32bit = LOCRMux %1, %0, 14, 8, implicit $cc + $r2l = COPY %2 + Return implicit $r2l +... + +# CHECK: *** Bad machine code: Live in register not found to be live out from predecessor. *** +# CHECK:- function: f1 +# CHECK:- basic block: %bb.2 +# CHECK:CC not found to be live out from %bb.1 Index: llvm/test/MachineVerifier/live-ins-03.mir =================================================================== --- /dev/null +++ llvm/test/MachineVerifier/live-ins-03.mir @@ -0,0 +1,36 @@ +# RUN: not llc -o - %s -mtriple=s390x-linux-gnu -mcpu=z14 -run-pass none 2>&1 | FileCheck %s +# REQUIRES: systemz-registered-target + +# Test that a the machine verifier reports an error when a register in +# liveins is not liveout from predecessor. + +--- +name: f1 +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $r2l, $r3l + + %1:gr32bit = COPY $r3l + %0:gr32bit = COPY $r2l + CHIMux %0, 0, implicit-def $cc + + bb.1: + liveins: $cc + BRC 14, 8, %bb.3, implicit $cc + + bb.2: + + bb.3: + liveins: $cc + + %2:grx32bit = LOCRMux %1, %0, 14, 8, implicit $cc + $r2l = COPY %2 + Return implicit $r2l +... + +# CHECK: *** Bad machine code: Live in register not found to be live out from predecessor. *** +# CHECK:- function: f1 +# CHECK:- basic block: %bb.3 +# CHECK:CC not found to be live out from %bb.2