Skip to content
Open
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
35 changes: 30 additions & 5 deletions lib/Transforms/Scalar/Reassociate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ namespace {
AU.setPreservesCFG();
}
private:
void BuildRankMap(Function &F);
bool BuildRankMap(Function &F); // HLSL Change
unsigned getRank(Value *V);
void canonicalizeOperands(Instruction *I);
void ReassociateExpression(BinaryOperator *I);
Expand Down Expand Up @@ -315,28 +315,47 @@ static bool isUnmovableInstruction(Instruction *I) {
}
}

void Reassociate::BuildRankMap(Function &F) {
bool Reassociate::BuildRankMap(Function &F) { // HLSL Change
const unsigned MaxSubRank = 0xFFFF; // HLSL Change
unsigned i = 2;

// Assign distinct ranks to function arguments.
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) {
// HLSL Change Begin - Bail out if the 16-bit argument rank overflows.
if (i == MaxSubRank) {
return false;
}
// HLSL Change End
ValueRankMap[&*I] = ++i;
DEBUG(dbgs() << "Calculated Rank[" << I->getName() << "] = " << i << "\n");
}

ReversePostOrderTraversal<Function*> RPOT(&F);
for (ReversePostOrderTraversal<Function*>::rpo_iterator I = RPOT.begin(),
E = RPOT.end(); I != E; ++I) {
// HLSL Change Begin - Bail out if the 16-bit block rank overflows.
if (i == MaxSubRank) {
return false;
}
// HLSL Change End
BasicBlock *BB = *I;
unsigned BBRank = RankMap[BB] = ++i << 16;

// Walk the basic block, adding precomputed ranks for any instructions that
// we cannot move. This ensures that the ranks for these instructions are
// all different in the block.
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
if (isUnmovableInstruction(I))
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
if (isUnmovableInstruction(I)) {
// HLSL Change Begin - Bail out if the 16-bit per-block rank overflows.
if ((BBRank & MaxSubRank) == MaxSubRank) {
return false;
}
// HLSL Change End
ValueRankMap[&*I] = ++BBRank;
}
}
}
return true; // HLSL Change
}

unsigned Reassociate::getRank(Value *V) {
Expand Down Expand Up @@ -2393,7 +2412,13 @@ bool Reassociate::runOnFunction(Function &F) {
return false;

// Calculate the rank map for F
BuildRankMap(F);
// HLSL Change Begin - Skip reassociation if 16-bit rank fields overflow.
if (!BuildRankMap(F)) {
RankMap.clear();
ValueRankMap.clear();
return false;
Comment thread
s-perron marked this conversation as resolved.
Resolved
}
// HLSL Change End

if (HLSLEnableAggressiveReassociation) { // HLSL Change
// Build the pair map before running reassociate.
Expand Down
106 changes: 106 additions & 0 deletions tools/clang/test/DXC/Passes/reassociate/rank-overflow.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
; RUN: opt < %s -always-inline -reassociate -S | FileCheck %s

; Check that Reassociate skips functions that exceed the 16-bit per-block
; instruction rank limit or the 16-bit basic-block rank limit, preserving
; l1 - l2 across an intervening store, while still optimizing subsequent
; functions in the module.

declare void @barrier()

define internal void @b0() alwaysinline { call void @barrier() ret void }
define internal void @b1() alwaysinline { call void @b0() call void @b0() ret void }
define internal void @b2() alwaysinline { call void @b1() call void @b1() ret void }
define internal void @b3() alwaysinline { call void @b2() call void @b2() ret void }
define internal void @b4() alwaysinline { call void @b3() call void @b3() ret void }
define internal void @b5() alwaysinline { call void @b4() call void @b4() ret void }
define internal void @b6() alwaysinline { call void @b5() call void @b5() ret void }
define internal void @b7() alwaysinline { call void @b6() call void @b6() ret void }
define internal void @b8() alwaysinline { call void @b7() call void @b7() ret void }
define internal void @b9() alwaysinline { call void @b8() call void @b8() ret void }
define internal void @b10() alwaysinline { call void @b9() call void @b9() ret void }
define internal void @b11() alwaysinline { call void @b10() call void @b10() ret void }
define internal void @b12() alwaysinline { call void @b11() call void @b11() ret void }
define internal void @b13() alwaysinline { call void @b12() call void @b12() ret void }
define internal void @b14() alwaysinline { call void @b13() call void @b13() ret void }
define internal void @b15() alwaysinline { call void @b14() call void @b14() ret void }
define internal void @b16() alwaysinline { call void @b15() call void @b15() ret void }

define internal void @c0(i1 %c) alwaysinline {
br i1 %c, label %t, label %m
t:
call void @barrier()
br label %m
m:
ret void
}
define internal void @c1(i1 %c) alwaysinline { call void @c0(i1 %c) call void @c0(i1 %c) ret void }
define internal void @c2(i1 %c) alwaysinline { call void @c1(i1 %c) call void @c1(i1 %c) ret void }
define internal void @c3(i1 %c) alwaysinline { call void @c2(i1 %c) call void @c2(i1 %c) ret void }
define internal void @c4(i1 %c) alwaysinline { call void @c3(i1 %c) call void @c3(i1 %c) ret void }
define internal void @c5(i1 %c) alwaysinline { call void @c4(i1 %c) call void @c4(i1 %c) ret void }
define internal void @c6(i1 %c) alwaysinline { call void @c5(i1 %c) call void @c5(i1 %c) ret void }
define internal void @c7(i1 %c) alwaysinline { call void @c6(i1 %c) call void @c6(i1 %c) ret void }
define internal void @c8(i1 %c) alwaysinline { call void @c7(i1 %c) call void @c7(i1 %c) ret void }
define internal void @c9(i1 %c) alwaysinline { call void @c8(i1 %c) call void @c8(i1 %c) ret void }
define internal void @c10(i1 %c) alwaysinline { call void @c9(i1 %c) call void @c9(i1 %c) ret void }
define internal void @c11(i1 %c) alwaysinline { call void @c10(i1 %c) call void @c10(i1 %c) ret void }
define internal void @c12(i1 %c) alwaysinline { call void @c11(i1 %c) call void @c11(i1 %c) ret void }
define internal void @c13(i1 %c) alwaysinline { call void @c12(i1 %c) call void @c12(i1 %c) ret void }
define internal void @c14(i1 %c) alwaysinline { call void @c13(i1 %c) call void @c13(i1 %c) ret void }
define internal void @c15(i1 %c) alwaysinline { call void @c14(i1 %c) call void @c14(i1 %c) ret void }

; CHECK-LABEL: define i32 @test_inst_overflow(
; CHECK: %l1 = load i32, i32* %p
; CHECK-NEXT: br i1 %c, label %then, label %exit
; CHECK: then:
; CHECK-NEXT: store i32 %v, i32* %q
; CHECK-NEXT: %l2 = load i32, i32* %p
; CHECK-NEXT: %add = add i32 %base, %l1
; CHECK-NEXT: %sub = sub i32 %add, %l2
; CHECK-NEXT: br label %exit
; CHECK: exit:
; CHECK-NEXT: %res = phi i32 [ %l1, %entry ], [ %sub, %then ]
; CHECK-NEXT: ret i32 %res
define i32 @test_inst_overflow(i32* %p, i32* %q, i32 %v, i32 %base, i1 %c) {
entry:
call void @b16()
%l1 = load i32, i32* %p
br i1 %c, label %then, label %exit

then:
store i32 %v, i32* %q
%l2 = load i32, i32* %p
%add = add i32 %base, %l1
%sub = sub i32 %add, %l2
br label %exit

exit:
%res = phi i32 [ %l1, %entry ], [ %sub, %then ]
ret i32 %res
}

; CHECK-LABEL: define i32 @test_block_overflow(
; CHECK: %l1 = load i32, i32* %p
; CHECK: store i32 %v, i32* %q
; CHECK-NEXT: %l2 = load i32, i32* %p
; CHECK-NEXT: %add = add i32 %base, %l1
; CHECK-NEXT: %sub = sub i32 %add, %l2
; CHECK-NEXT: ret i32 %sub
define i32 @test_block_overflow(i32* %p, i32* %q, i32 %v, i32 %base, i1 %c) {
entry:
%l1 = load i32, i32* %p
call void @c15(i1 %c)
store i32 %v, i32* %q
%l2 = load i32, i32* %p
%add = add i32 %base, %l1
%sub = sub i32 %add, %l2
ret i32 %sub
}

; CHECK-LABEL: define i32 @small(
; CHECK-NEXT: ret i32 %b
define i32 @small(i32 %a, i32 %b) {
%sum = add i32 %b, %a
%diff = sub i32 %sum, %a
ret i32 %diff
}
Loading