Skip to content

Commit

Permalink
[FastISel] Don't trivially kill extractvalues (PR49467)
Browse files Browse the repository at this point in the history
All extractvalues of the same value at the same index will map to
the same register, so even if one specific extractvalue only has
one use, we should not mark it as a trivial kill, as there may be
more extractvalues later.

Fixes https://bugs.llvm.org/show_bug.cgi?id=49467.

Differential Revision: https://reviews.llvm.org/D98145

(cherry picked from commit 55ae279)
  • Loading branch information
nikic authored and tstellar committed Mar 29, 2021
1 parent e89cdf8 commit f05b649
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
5 changes: 4 additions & 1 deletion llvm/include/llvm/CodeGen/FastISel.h
Expand Up @@ -490,7 +490,10 @@ class FastISel {
/// - \c Add has a constant operand.
bool canFoldAddIntoGEP(const User *GEP, const Value *Add);

/// Test whether the given value has exactly one use.
/// Test whether the register associated with this value has exactly one use,
/// in which case that single use is killing. Note that multiple IR values
/// may map onto the same register, in which case this is not the same as
/// checking that an IR value has one use.
bool hasTrivialKill(const Value *V);

/// Create a machine mem operand from the given instruction.
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
Expand Up @@ -261,12 +261,16 @@ bool FastISel::hasTrivialKill(const Value *V) {
if (GEP->hasAllZeroIndices() && !hasTrivialKill(GEP->getOperand(0)))
return false;

// Casts and extractvalues may be trivially coalesced by fast-isel.
if (I->getOpcode() == Instruction::BitCast ||
I->getOpcode() == Instruction::PtrToInt ||
I->getOpcode() == Instruction::IntToPtr ||
I->getOpcode() == Instruction::ExtractValue)
return false;

// Only instructions with a single use in the same basic block are considered
// to have trivial kills.
return I->hasOneUse() &&
!(I->getOpcode() == Instruction::BitCast ||
I->getOpcode() == Instruction::PtrToInt ||
I->getOpcode() == Instruction::IntToPtr) &&
cast<Instruction>(*I->user_begin())->getParent() == I->getParent();
}

Expand Down
27 changes: 27 additions & 0 deletions llvm/test/CodeGen/X86/pr49467.ll
@@ -0,0 +1,27 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -O0 -fast-isel -verify-machineinstrs -mtriple=x86_64 < %s | FileCheck %s

declare { i8*, i64 } @get()

declare void @use(i8*, i64)

define void @test(i64* %p) nounwind {
; CHECK-LABEL: test:
; CHECK: # %bb.0:
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: movq %rdi, (%rsp) # 8-byte Spill
; CHECK-NEXT: callq get@PLT
; CHECK-NEXT: movq (%rsp), %rdi # 8-byte Reload
; CHECK-NEXT: movq %rdx, %rsi
; CHECK-NEXT: movq %rsi, (%rdi)
; CHECK-NEXT: # implicit-def: $rdi
; CHECK-NEXT: callq use@PLT
; CHECK-NEXT: popq %rax
; CHECK-NEXT: retq
%struct = call { i8*, i64 } @get()
%struct.1 = extractvalue { i8*, i64 } %struct, 1
store i64 %struct.1, i64* %p, align 8
%struct.2 = extractvalue { i8*, i64 } %struct, 1
call void @use(i8* undef, i64 %struct.2)
ret void
}

0 comments on commit f05b649

Please sign in to comment.