Skip to content

Commit 27dca03

Browse files
committed
[DirectX] Legalize Freeze
legalize free by emulating what freeze would have done."
1 parent ad12323 commit 27dca03

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

llvm/lib/Target/DirectX/DXILLegalizePass.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "DXILLegalizePass.h"
1010
#include "DirectX.h"
11+
#include "llvm/Analysis/ValueTracking.h"
1112
#include "llvm/IR/Function.h"
1213
#include "llvm/IR/IRBuilder.h"
1314
#include "llvm/IR/InstIterator.h"
@@ -20,6 +21,71 @@
2021

2122
using namespace llvm;
2223

24+
// The goal here will be to emulate freeze by Forcing SSA materialization.
25+
// We will do this by making the input bound to a real SSA value,
26+
// not a symbolic poison or undef. The implementation creates a dummy
27+
// control-flow split that always takes PathA and forces the inputs
28+
// through a phi node. Creating a dimond CFG makes the compiler
29+
// commit to one value for the input.
30+
// entry(%x)
31+
// |
32+
// +---+---+
33+
// | |
34+
// pathA(%x) pathB(%x)
35+
// | |
36+
// \______/
37+
// |
38+
// merge
39+
// %frozen = phi [ %x, %pathA ], [ %x, %pathB ]
40+
41+
static void lowerFreeze(FreezeInst *FI) {
42+
Type *Ty = FI->getType();
43+
LLVMContext &Ctx = FI->getContext();
44+
BasicBlock *OrigBB = FI->getParent();
45+
Value *Input = FI->getOperand(0);
46+
Function *F = FI->getFunction();
47+
48+
// Split the block to isolate the freeze instruction
49+
BasicBlock *MergeBB = OrigBB->splitBasicBlock(FI->getNextNode(), "merge");
50+
51+
// Remove the unconditional branch inserted by splitBasicBlock
52+
OrigBB->getTerminator()->eraseFromParent();
53+
BasicBlock *PathA = BasicBlock::Create(Ctx, "pathA", F, MergeBB);
54+
BasicBlock *PathB = BasicBlock::Create(Ctx, "pathB", F, MergeBB);
55+
56+
IRBuilder<> Builder(OrigBB);
57+
Builder.CreateCondBr(ConstantInt::getTrue(Ctx), PathA, PathB);
58+
59+
IRBuilder<> BuilderA(PathA);
60+
BuilderA.CreateBr(MergeBB);
61+
IRBuilder<> BuilderB(PathB);
62+
BuilderB.CreateBr(MergeBB);
63+
64+
IRBuilder<> BuilderMerge(&MergeBB->front());
65+
PHINode *Phi = BuilderMerge.CreatePHI(Ty, 2, "frozen");
66+
Phi->addIncoming(Input, PathA);
67+
Phi->addIncoming(Input, PathB);
68+
69+
FI->replaceAllUsesWith(Phi);
70+
}
71+
72+
static void legalizeFreeze(Instruction &I,
73+
SmallVectorImpl<Instruction *> &ToRemove,
74+
DenseMap<Value *, Value *>) {
75+
auto *FI = dyn_cast<FreezeInst>(&I);
76+
if (!FI)
77+
return;
78+
79+
Value *Input = FI->getOperand(0);
80+
81+
if (isGuaranteedNotToBeUndefOrPoison(Input))
82+
FI->replaceAllUsesWith(Input);
83+
else
84+
lowerFreeze(FI);
85+
86+
ToRemove.push_back(FI);
87+
}
88+
2389
static void fixI8TruncUseChain(Instruction &I,
2490
SmallVectorImpl<Instruction *> &ToRemove,
2591
DenseMap<Value *, Value *> &ReplacedValues) {
@@ -169,6 +235,7 @@ class DXILLegalizationPipeline {
169235
void initializeLegalizationPipeline() {
170236
LegalizationPipeline.push_back(fixI8TruncUseChain);
171237
LegalizationPipeline.push_back(downcastI64toI32InsertExtractElements);
238+
LegalizationPipeline.push_back(legalizeFreeze);
172239
}
173240
};
174241

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
3+
; RUN: opt -S -passes='dxil-legalize' -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
4+
5+
6+
define i32 @test_remove_freeze(i32 %x) {
7+
; CHECK-LABEL: define i32 @test_remove_freeze(
8+
; CHECK-SAME: i32 [[X:%.*]]) {
9+
; CHECK-NEXT: [[ENTRY:.*:]]
10+
; CHECK-NEXT: br i1 true, label %[[PATHA:.*]], label %[[PATHB:.*]]
11+
; CHECK: [[PATHA]]:
12+
; CHECK-NEXT: br label %[[MERGE:.*]]
13+
; CHECK: [[PATHB]]:
14+
; CHECK-NEXT: br label %[[MERGE]]
15+
; CHECK: [[MERGE]]:
16+
; CHECK-NEXT: [[FROZEN:%.*]] = phi i32 [ [[X]], %[[PATHA]] ], [ [[X]], %[[PATHB]] ]
17+
; CHECK-NEXT: [[Y:%.*]] = add i32 [[FROZEN]], 1
18+
; CHECK-NEXT: ret i32 [[Y]]
19+
;
20+
entry:
21+
%f = freeze i32 %x
22+
%y = add i32 %f, 1
23+
ret i32 %y
24+
}
25+
26+
define i32 @test_remove_freeze_safe(i32 %x) {
27+
; CHECK-LABEL: define i32 @test_remove_freeze_safe(
28+
; CHECK-SAME: i32 [[X:%.*]]) {
29+
; CHECK-NEXT: [[ENTRY:.*:]]
30+
; CHECK-NEXT: [[FROZEN:%.*]] = add i32 1, 0
31+
; CHECK-NEXT: [[Y:%.*]] = add i32 [[FROZEN]], 1
32+
; CHECK-NEXT: ret i32 [[Y]]
33+
;
34+
entry:
35+
%safe = add i32 1, 0
36+
%f = freeze i32 %safe
37+
%y = add i32 %f, 1
38+
ret i32 %y
39+
}
40+
41+
define i32 @test_freeze_poison() {
42+
; CHECK-LABEL: define i32 @test_freeze_poison() {
43+
; CHECK-NEXT: [[ENTRY:.*:]]
44+
; CHECK-NEXT: [[X1:%.*]] = select i1 true, i32 42, i32 poison
45+
; CHECK-NEXT: br i1 true, label %[[PATHA:.*]], label %[[PATHB:.*]]
46+
; CHECK: [[PATHA]]:
47+
; CHECK-NEXT: br label %[[MERGE:.*]]
48+
; CHECK: [[PATHB]]:
49+
; CHECK-NEXT: br label %[[MERGE]]
50+
; CHECK: [[MERGE]]:
51+
; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X1]], %[[PATHA]] ], [ [[X1]], %[[PATHB]] ]
52+
; CHECK-NEXT: [[Y:%.*]] = add i32 [[X]], 1
53+
; CHECK-NEXT: ret i32 [[Y]]
54+
;
55+
entry:
56+
%x = select i1 true, i32 42, i32 poison
57+
%f = freeze i32 %x
58+
%y = add i32 %f, 1
59+
ret i32 %y
60+
}
61+
62+
define i32 @test_freeze_undef() {
63+
; CHECK-LABEL: define i32 @test_freeze_undef() {
64+
; CHECK-NEXT: [[ENTRY:.*:]]
65+
; CHECK-NEXT: [[X:%.*]] = select i1 undef, i32 42, i32 2
66+
; CHECK-NEXT: br i1 true, label %[[PATHA:.*]], label %[[PATHB:.*]]
67+
; CHECK: [[PATHA]]:
68+
; CHECK-NEXT: br label %[[MERGE:.*]]
69+
; CHECK: [[PATHB]]:
70+
; CHECK-NEXT: br label %[[MERGE]]
71+
; CHECK: [[MERGE]]:
72+
; CHECK-NEXT: [[FROZEN:%.*]] = phi i32 [ [[X]], %[[PATHA]] ], [ [[X]], %[[PATHB]] ]
73+
; CHECK-NEXT: [[Y:%.*]] = add i32 [[FROZEN]], 1
74+
; CHECK-NEXT: ret i32 [[Y]]
75+
;
76+
entry:
77+
%x = select i1 undef, i32 42, i32 2
78+
%f = freeze i32 %x
79+
%y = add i32 %f, 1
80+
ret i32 %y
81+
}

0 commit comments

Comments
 (0)