Skip to content

CodeGenPrepare, X86: Support sinking phi nodes. #141716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2822,6 +2822,11 @@ class PHINode : public Instruction {
/// non-undef value.
bool hasConstantOrUndefValue() const;

/// If the specified PHI node (possibly via other PHI nodes) merges together
/// the same or identical (i.e. Instruction::isIdenticalTo() returns true)
/// values, return one of the values, otherwise return null.
Value *hasIdenticalValue();

/// If the PHI node is complete which means all of its parent's predecessors
/// have incoming value in this PHI, return true, otherwise return false.
bool isComplete() const {
Expand Down
17 changes: 13 additions & 4 deletions llvm/lib/CodeGen/CodeGenPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7739,9 +7739,14 @@ bool CodeGenPrepare::tryToSinkFreeOperands(Instruction *I) {

for (Use *U : reverse(OpsToSink)) {
auto *UI = cast<Instruction>(U->get());
if (isa<PHINode>(UI))
continue;
if (UI->getParent() == TargetBB) {
if (auto *PN = dyn_cast<PHINode>(UI)) {
auto *I0 = dyn_cast<Instruction>(PN->hasIdenticalValue());
if (!I0)
continue;
if (I0->getParent() == TargetBB &&
InstOrdering[I0] < InstOrdering[InsertPoint])
InsertPoint = I0;
} else if (UI->getParent() == TargetBB) {
if (InstOrdering[UI] < InstOrdering[InsertPoint])
InsertPoint = UI;
continue;
Expand All @@ -7753,7 +7758,11 @@ bool CodeGenPrepare::tryToSinkFreeOperands(Instruction *I) {
DenseMap<Instruction *, Instruction *> NewInstructions;
for (Use *U : ToReplace) {
auto *UI = cast<Instruction>(U->get());
Instruction *NI = UI->clone();
Instruction *NI;
if (auto *PN = dyn_cast<PHINode>(UI))
NI = cast<Instruction>(PN->hasIdenticalValue())->clone();
else
NI = UI->clone();

if (IsHugeFunc) {
// Now we clone an instruction, its operands' defs may sink to this BB
Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <cassert>
#include <cstdint>
#include <optional>
#include <set>
#include <vector>

using namespace llvm;
Expand Down Expand Up @@ -239,6 +240,40 @@ bool PHINode::hasConstantOrUndefValue() const {
return true;
}

/// If the specified PHI node (possibly via other PHI nodes) merges together the
/// same or identical (i.e. Instruction::isIdenticalTo() returns true) values,
/// return one of the values, otherwise return null.
Value *PHINode::hasIdenticalValue() {
std::vector<PHINode *> Worklist;
std::set<PHINode *> Seen;
Value *Result = nullptr;
Worklist.push_back(this);
while (!Worklist.empty()) {
PHINode *PN = Worklist.back();
Worklist.pop_back();
if (!Seen.insert(PN).second)
continue;
for (Value *V : PN->incoming_values()) {
if (auto *PN = dyn_cast<PHINode>(V)) {
Worklist.push_back(PN);
continue;
}
if (!Result) {
Result = V;
continue;
}
if (V == Result)
continue;
if (auto *I = dyn_cast<Instruction>(V))
if (auto *ResultI = dyn_cast<Instruction>(Result))
if (I->isIdenticalTo(ResultI))
continue;
return nullptr;
}
}
return Result;
}

//===----------------------------------------------------------------------===//
// LandingPadInst Implementation
//===----------------------------------------------------------------------===//
Expand Down
13 changes: 10 additions & 3 deletions llvm/lib/Target/X86/X86TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7167,15 +7167,22 @@ bool X86TTIImpl::isProfitableToSinkOperands(Instruction *I,
}
if (ShiftAmountOpNum == -1)
return false;
auto *ShiftAmount = &I->getOperandUse(ShiftAmountOpNum);
auto *ShiftAmountUse = &I->getOperandUse(ShiftAmountOpNum);

Value *ShiftAmount = ShiftAmountUse->get();
if (auto *PN = dyn_cast<PHINode>(ShiftAmount)) {
ShiftAmount = PN->hasIdenticalValue();
if (!ShiftAmount)
return false;
}

// A uniform shift amount in a vector shift or funnel shift may be much
// cheaper than a generic variable vector shift, so make that pattern visible
// to SDAG by sinking the shuffle instruction next to the shift.
auto *Shuf = dyn_cast<ShuffleVectorInst>(ShiftAmount);
if (Shuf && getSplatIndex(Shuf->getShuffleMask()) >= 0 &&
isVectorShiftByScalarCheap(I->getType())) {
Ops.push_back(ShiftAmount);
Ops.push_back(ShiftAmountUse);
return true;
}

Expand All @@ -7186,7 +7193,7 @@ bool X86TTIImpl::isProfitableToSinkOperands(Instruction *I,
// instruction's immediate operand.
if (auto *CI = dyn_cast<CastInst>(ShiftAmount)) {
if (isa<ConstantExpr>(CI->getOperand(0))) {
Ops.push_back(ShiftAmount);
Ops.push_back(ShiftAmountUse);
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
; Make sure that if a phi with identical inputs gets created it gets undone by CodeGenPrepare.

; RUN: opt -codegenprepare -S < %s | FileCheck %s

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@__typeid__ZTS1S_global_addr = external hidden global [0 x i8], code_model "small"
@__typeid__ZTS1S_align = external hidden global [0 x i8], !absolute_symbol !0
@__typeid__ZTS1S_size_m1 = external hidden global [0 x i8], !absolute_symbol !1

; Check that we recover the third pair of zexts from the phi.

; CHECK: define void @f4
define void @f4(i1 noundef zeroext %0, ptr noundef %1, ptr noundef %2, ptr noundef %3) #1 {
br i1 %0, label %5, label %18

5:
%6 = load ptr, ptr %1, align 8
%7 = ptrtoint ptr %6 to i64
%8 = sub i64 %7, ptrtoint (ptr @__typeid__ZTS1S_global_addr to i64)
; CHECK: zext {{.*}} @__typeid__ZTS1S_align
%9 = zext nneg i8 ptrtoint (ptr @__typeid__ZTS1S_align to i8) to i64
%10 = lshr i64 %8, %9
; CHECK: zext {{.*}} @__typeid__ZTS1S_align
%11 = zext nneg i8 sub (i8 64, i8 ptrtoint (ptr @__typeid__ZTS1S_align to i8)) to i64
%12 = shl i64 %8, %11
%13 = or i64 %10, %12
%14 = icmp ugt i64 %13, ptrtoint (ptr @__typeid__ZTS1S_size_m1 to i64)
br i1 %14, label %15, label %16

15:
tail call void @llvm.ubsantrap(i8 2) #5
unreachable

16:
%17 = load ptr, ptr %6, align 8
tail call void %17(ptr noundef nonnull align 8 dereferenceable(8) %1)
br label %31

18:
%19 = load ptr, ptr %2, align 8
%20 = ptrtoint ptr %19 to i64
%21 = sub i64 %20, ptrtoint (ptr @__typeid__ZTS1S_global_addr to i64)
; CHECK: zext {{.*}} @__typeid__ZTS1S_align
%22 = zext nneg i8 ptrtoint (ptr @__typeid__ZTS1S_align to i8) to i64
%23 = lshr i64 %21, %22
; CHECK: zext {{.*}} @__typeid__ZTS1S_align
%24 = zext nneg i8 sub (i8 64, i8 ptrtoint (ptr @__typeid__ZTS1S_align to i8)) to i64
%25 = shl i64 %21, %24
%26 = or i64 %23, %25
%27 = icmp ugt i64 %26, ptrtoint (ptr @__typeid__ZTS1S_size_m1 to i64)
br i1 %27, label %28, label %29

28:
tail call void @llvm.ubsantrap(i8 2) #5
unreachable

29:
%30 = load ptr, ptr %19, align 8
tail call void %30(ptr noundef nonnull align 8 dereferenceable(8) %2)
br label %31

31:
%32 = phi i64 [ %24, %29 ], [ %11, %16 ]
%33 = phi i64 [ %22, %29 ], [ %9, %16 ]
%34 = load ptr, ptr %3, align 8
%35 = ptrtoint ptr %34 to i64
%36 = sub i64 %35, ptrtoint (ptr @__typeid__ZTS1S_global_addr to i64)
; CHECK: zext {{.*}} @__typeid__ZTS1S_align
%37 = lshr i64 %36, %33
; CHECK: zext {{.*}} @__typeid__ZTS1S_align
%38 = shl i64 %36, %32
%39 = or i64 %37, %38
%40 = icmp ugt i64 %39, ptrtoint (ptr @__typeid__ZTS1S_size_m1 to i64)
br i1 %40, label %41, label %42

41:
tail call void @llvm.ubsantrap(i8 2) #5
unreachable

42:
%43 = load ptr, ptr %34, align 8
tail call void %43(ptr noundef nonnull align 8 dereferenceable(8) %3)
ret void
}

declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.ubsantrap(i8 immarg)

!0 = !{i64 0, i64 256}
!1 = !{i64 0, i64 128}
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.