llvm.org GIT mirror llvm / 8adf4eb
AMDGPU: Fix breaking IR on instructions with multiple pointer operands The promote alloca pass would attempt to promote an alloca with a select, icmp, or phi user, even though the other operand was from a non-promotable source, producing a select on two different pointer types. Only do this if we know that both operands derive from the same alloca. In the future we should be able to relax this to an alloca which will also be promoted. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269265 91177308-0d34-0410-b5e6-96231b3b80d8 Matt Arsenault 3 years ago
4 changed file(s) with 401 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
3131 private:
3232 const TargetMachine *TM;
3333 Module *Mod;
34 const DataLayout *DL;
3435 MDNode *MaxWorkGroupSizeRange;
3536
3637 // FIXME: This should be per-kernel.
4142
4243 std::pair getLocalSizeYZ(IRBuilder<> &Builder);
4344 Value *getWorkitemID(IRBuilder<> &Builder, unsigned N);
45
46 /// BaseAlloca is the alloca root the search started from.
47 /// Val may be that alloca or a recursive user of it.
48 bool collectUsesWithPtrTypes(Value *BaseAlloca,
49 Value *Val,
50 std::vector &WorkList) const;
51
52 /// Val is a derived pointer from Alloca. OpIdx0/OpIdx1 are the operand
53 /// indices to an instruction with 2 pointer inputs (e.g. select, icmp).
54 /// Returns true if both operands are derived from the same alloca. Val should
55 /// be the same value as one of the input operands of UseInst.
56 bool binaryOpIsDerivedFromSameAlloca(Value *Alloca, Value *Val,
57 Instruction *UseInst,
58 int OpIdx0, int OpIdx1) const;
4459
4560 public:
4661 static char ID;
4964 FunctionPass(ID),
5065 TM(TM_),
5166 Mod(nullptr),
67 DL(nullptr),
5268 MaxWorkGroupSizeRange(nullptr),
5369 LocalMemAvailable(0),
5470 IsAMDGCN(false),
6278 }
6379
6480 void handleAlloca(AllocaInst &I);
81
82 void getAnalysisUsage(AnalysisUsage &AU) const override {
83 AU.setPreservesCFG();
84 FunctionPass::getAnalysisUsage(AU);
85 }
6586 };
6687
6788 } // End anonymous namespace
79100 return false;
80101
81102 Mod = &M;
103 DL = &Mod->getDataLayout();
82104
83105 // The maximum workitem id.
84106 //
130152 continue;
131153
132154 if (Use->getParent()->getParent() == &F) {
133 LocalMemAvailable -=
134 Mod->getDataLayout().getTypeAllocSize(GV.getValueType());
155 LocalMemAvailable -= DL->getTypeAllocSize(GV.getValueType());
135156 break;
136157 }
137158 }
427448 }
428449 }
429450
430 static bool collectUsesWithPtrTypes(Value *Val, std::vector &WorkList) {
451 bool AMDGPUPromoteAlloca::binaryOpIsDerivedFromSameAlloca(Value *BaseAlloca,
452 Value *Val,
453 Instruction *Inst,
454 int OpIdx0,
455 int OpIdx1) const {
456 // Figure out which operand is the one we might not be promoting.
457 Value *OtherOp = Inst->getOperand(OpIdx0);
458 if (Val == OtherOp)
459 OtherOp = Inst->getOperand(OpIdx1);
460
461 Value *OtherObj = GetUnderlyingObject(OtherOp, *DL);
462 if (!isa(OtherObj))
463 return false;
464
465 // TODO: We should be able to replace undefs with the right pointer type.
466
467 // TODO: If we know the other base object is another promotable
468 // alloca, not necessarily this alloca, we can do this. The
469 // important part is both must have the same address space at
470 // the end.
471 if (OtherObj != BaseAlloca) {
472 DEBUG(dbgs() << "Found a binary instruction with another alloca object\n");
473 return false;
474 }
475
476 return true;
477 }
478
479 bool AMDGPUPromoteAlloca::collectUsesWithPtrTypes(
480 Value *BaseAlloca,
481 Value *Val,
482 std::vector &WorkList) const {
483
431484 for (User *User : Val->users()) {
432485 if (std::find(WorkList.begin(), WorkList.end(), User) != WorkList.end())
433486 continue;
440493 continue;
441494 }
442495
443 Instruction *UseInst = dyn_cast(User);
444 if (UseInst && UseInst->getOpcode() == Instruction::PtrToInt)
496 Instruction *UseInst = cast(User);
497 if (UseInst->getOpcode() == Instruction::PtrToInt)
445498 return false;
446499
447 if (StoreInst *SI = dyn_cast_or_null(UseInst)) {
500 if (StoreInst *SI = dyn_cast(UseInst)) {
448501 if (SI->isVolatile())
449502 return false;
450503
460513 } else if (AtomicCmpXchgInst *CAS
461514 = dyn_cast_or_null(UseInst)) {
462515 if (CAS->isVolatile())
516 return false;
517 }
518
519 // Only promote a select if we know that the other select operand
520 // is from another pointer that will also be promoted.
521 if (ICmpInst *ICmp = dyn_cast(UseInst)) {
522 if (!binaryOpIsDerivedFromSameAlloca(BaseAlloca, Val, ICmp, 0, 1))
463523 return false;
464524 }
465525
473533 return false;
474534 }
475535
536 // Only promote a select if we know that the other select operand is from
537 // another pointer that will also be promoted.
538 if (SelectInst *SI = dyn_cast(UseInst)) {
539 if (!binaryOpIsDerivedFromSameAlloca(BaseAlloca, Val, SI, 1, 2))
540 return false;
541 }
542
543 // Repeat for phis.
544 if (PHINode *Phi = dyn_cast(UseInst)) {
545 // TODO: Handle more complex cases. We should be able to replace loops
546 // over arrays.
547 switch (Phi->getNumIncomingValues()) {
548 case 1:
549 break;
550 case 2:
551 if (!binaryOpIsDerivedFromSameAlloca(BaseAlloca, Val, Phi, 0, 1))
552 return false;
553 break;
554 default:
555 return false;
556 }
557 }
558
476559 WorkList.push_back(User);
477 if (!collectUsesWithPtrTypes(User, WorkList))
560 if (!collectUsesWithPtrTypes(BaseAlloca, User, WorkList))
478561 return false;
479562 }
480563
515598
516599 std::vector WorkList;
517600
518 if (!collectUsesWithPtrTypes(&I, WorkList)) {
601 if (!collectUsesWithPtrTypes(&I, &I, WorkList)) {
519602 DEBUG(dbgs() << " Do not know how to convert all uses\n");
520603 return;
521604 }
0 ; RUN: opt -S -mtriple=amdgcn-unknown-amdhsa -mcpu=kaveri -amdgpu-promote-alloca < %s | FileCheck %s
1
2 ; This normally would be fixed by instcombine to be compare to the GEP
3 ; indices
4
5 ; CHECK-LABEL: @lds_promoted_alloca_icmp_same_derived_pointer(
6 ; CHECK: [[ARRAYGEP:%[0-9]+]] = getelementptr inbounds [256 x [16 x i32]], [256 x [16 x i32]] addrspace(3)* @lds_promoted_alloca_icmp_same_derived_pointer.alloca, i32 0, i32 %{{[0-9]+}}
7 ; CHECK: %ptr0 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* [[ARRAYGEP]], i32 0, i32 %a
8 ; CHECK: %ptr1 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* [[ARRAYGEP]], i32 0, i32 %b
9 ; CHECK: %cmp = icmp eq i32 addrspace(3)* %ptr0, %ptr1
10 define void @lds_promoted_alloca_icmp_same_derived_pointer(i32 addrspace(1)* %out, i32 %a, i32 %b) #0 {
11 %alloca = alloca [16 x i32], align 4
12 %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %a
13 %ptr1 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %b
14 %cmp = icmp eq i32* %ptr0, %ptr1
15 %zext = zext i1 %cmp to i32
16 store volatile i32 %zext, i32 addrspace(1)* %out
17 ret void
18 }
19
20 ; CHECK-LABEL: @lds_promoted_alloca_icmp_unknown_ptr(
21 ; CHECK: %alloca = alloca [16 x i32], align 4
22 ; CHECK: %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %a
23 ; CHECK: %ptr1 = call i32* @get_unknown_pointer()
24 ; CHECK: %cmp = icmp eq i32* %ptr0, %ptr1
25 define void @lds_promoted_alloca_icmp_unknown_ptr(i32 addrspace(1)* %out, i32 %a, i32 %b) #0 {
26 %alloca = alloca [16 x i32], align 4
27 %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %a
28 %ptr1 = call i32* @get_unknown_pointer()
29 %cmp = icmp eq i32* %ptr0, %ptr1
30 %zext = zext i1 %cmp to i32
31 store volatile i32 %zext, i32 addrspace(1)* %out
32 ret void
33 }
34
35 declare i32* @get_unknown_pointer() #0
36
37 attributes #0 = { nounwind }
0 ; RUN: opt -S -mtriple=amdgcn-unknown-amdhsa -mcpu=kaveri -amdgpu-promote-alloca < %s | FileCheck %s
1
2
3 ; CHECK-LABEL: @branch_ptr_var_same_alloca(
4 ; CHECK: getelementptr inbounds [256 x [64 x i32]], [256 x [64 x i32]] addrspace(3)* @branch_ptr_var_same_alloca.alloca, i32 0, i32 %{{[0-9]+}}
5
6 ; CHECK: if:
7 ; CHECK: %arrayidx0 = getelementptr inbounds [64 x i32], [64 x i32] addrspace(3)* %{{[0-9]+}}, i32 0, i32 %a
8
9 ; CHECK: else:
10 ; CHECK: %arrayidx1 = getelementptr inbounds [64 x i32], [64 x i32] addrspace(3)* %15, i32 0, i32 %b
11
12 ; CHECK: endif:
13 ; CHECK: %phi.ptr = phi i32 addrspace(3)* [ %arrayidx0, %if ], [ %arrayidx1, %else ]
14 ; CHECK: store i32 0, i32 addrspace(3)* %phi.ptr, align 4
15 define void @branch_ptr_var_same_alloca(i32 %a, i32 %b) #0 {
16 entry:
17 %alloca = alloca [64 x i32], align 4
18 br i1 undef, label %if, label %else
19
20 if:
21 %arrayidx0 = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 %a
22 br label %endif
23
24 else:
25 %arrayidx1 = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 %b
26 br label %endif
27
28 endif:
29 %phi.ptr = phi i32* [ %arrayidx0, %if ], [ %arrayidx1, %else ]
30 store i32 0, i32* %phi.ptr, align 4
31 ret void
32 }
33
34 ; CHECK-LABEL: @one_phi_value(
35 ; CHECK: getelementptr inbounds [256 x [64 x i32]], [256 x [64 x i32]] addrspace(3)* @one_phi_value.alloca, i32 0, i32 %14
36 ; CHECK: %arrayidx0 = getelementptr inbounds [64 x i32], [64 x i32] addrspace(3)* %{{[0-9]+}}, i32 0, i32 %a
37
38 ; CHECK: br label %exit
39 ; CHECK: %phi.ptr = phi i32 addrspace(3)* [ %arrayidx0, %entry ]
40 ; CHECK: store i32 0, i32 addrspace(3)* %phi.ptr, align 4
41 define void @one_phi_value(i32 %a) #0 {
42 entry:
43 %alloca = alloca [64 x i32], align 4
44 %arrayidx0 = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 %a
45 br label %exit
46
47 exit:
48 %phi.ptr = phi i32* [ %arrayidx0, %entry ]
49 store i32 0, i32* %phi.ptr, align 4
50 ret void
51 }
52
53 ; CHECK-LABEL: @branch_ptr_alloca_unknown_obj(
54 ; CHECK: %alloca = alloca [64 x i32], align 4
55
56 ; CHECK: if:
57 ; CHECK: %arrayidx0 = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 %a
58
59 ; CHECK: else:
60 ; CHECK: %arrayidx1 = call i32* @get_unknown_pointer()
61
62 ; CHECK: endif:
63 ; CHECK: %phi.ptr = phi i32* [ %arrayidx0, %if ], [ %arrayidx1, %else ]
64 ; CHECK: store i32 0, i32* %phi.ptr, align 4
65 define void @branch_ptr_alloca_unknown_obj(i32 %a, i32 %b) #0 {
66 entry:
67 %alloca = alloca [64 x i32], align 4
68 br i1 undef, label %if, label %else
69
70 if:
71 %arrayidx0 = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 %a
72 br label %endif
73
74 else:
75 %arrayidx1 = call i32* @get_unknown_pointer()
76 br label %endif
77
78 endif:
79 %phi.ptr = phi i32* [ %arrayidx0, %if ], [ %arrayidx1, %else ]
80 store i32 0, i32* %phi.ptr, align 4
81 ret void
82 }
83
84 ; kernel void ptr_induction_var_same_alloca(void)
85 ; {
86 ; int alloca[64];
87 ; int i = 0;
88
89 ; #pragma nounroll
90 ; for (int* p = &alloca[2], *e = &alloca[48]; p != e; ++p, ++i)
91 ; {
92 ; *p = i;
93 ; }
94 ; }
95
96 ; FIXME: This should be promotable. We need to use
97 ; GetUnderlyingObjects when looking at the icmp user.
98
99 ; CHECK-LABEL: @ptr_induction_var_same_alloca(
100 ; CHECK: %alloca = alloca [64 x i32], align 4
101 ; CHECK: phi i32* [ %arrayidx, %entry ], [ %incdec.ptr, %for.body ]
102 define void @ptr_induction_var_same_alloca() #0 {
103 entry:
104 %alloca = alloca [64 x i32], align 4
105 %arrayidx = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 2
106 %arrayidx1 = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 48
107 br label %for.body
108
109 for.cond.cleanup: ; preds = %for.body
110 ret void
111
112 for.body: ; preds = %for.body, %entry
113 %i.09 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
114 %p.08 = phi i32* [ %arrayidx, %entry ], [ %incdec.ptr, %for.body ]
115 store i32 %i.09, i32* %p.08, align 4
116 %incdec.ptr = getelementptr inbounds i32, i32* %p.08, i32 1
117 %inc = add nuw nsw i32 %i.09, 1
118 %cmp = icmp eq i32* %incdec.ptr, %arrayidx1
119 br i1 %cmp, label %for.cond.cleanup, label %for.body
120 }
121
122
123 ; extern int* get_unknown_pointer(void);
124
125 ; kernel void ptr_induction_var_alloca_unknown(void)
126 ; {
127 ; int alloca[64];
128 ; int i = 0;
129 ;
130 ; for (int* p = &alloca[2], *e = get_unknown_pointer(); p != e; ++p, ++i)
131 ; {
132 ; *p = i;
133 ; }
134 ; }
135
136 ; CHECK-LABEL: @ptr_induction_var_alloca_unknown(
137 ; CHECK: %alloca = alloca [64 x i32], align 4
138 ; CHECK: %p.08 = phi i32* [ %incdec.ptr, %for.body ], [ %arrayidx, %for.body.preheader ]
139 ; CHECK: %cmp = icmp eq i32* %incdec.ptr, %call
140 define void @ptr_induction_var_alloca_unknown() #0 {
141 entry:
142 %alloca = alloca [64 x i32], align 4
143 %arrayidx = getelementptr inbounds [64 x i32], [64 x i32]* %alloca, i32 0, i32 2
144 %call = tail call i32* @get_unknown_pointer() #2
145 %cmp.7 = icmp eq i32* %arrayidx, %call
146 br i1 %cmp.7, label %for.cond.cleanup, label %for.body.preheader
147
148 for.body.preheader: ; preds = %entry
149 br label %for.body
150
151 for.cond.cleanup.loopexit: ; preds = %for.body
152 br label %for.cond.cleanup
153
154 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry
155 ret void
156
157 for.body: ; preds = %for.body, %for.body.preheader
158 %i.09 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ]
159 %p.08 = phi i32* [ %incdec.ptr, %for.body ], [ %arrayidx, %for.body.preheader ]
160 store i32 %i.09, i32* %p.08, align 4
161 %incdec.ptr = getelementptr inbounds i32, i32* %p.08, i32 1
162 %inc = add nuw nsw i32 %i.09, 1
163 %cmp = icmp eq i32* %incdec.ptr, %call
164 br i1 %cmp, label %for.cond.cleanup.loopexit, label %for.body
165 }
166
167 declare i32* @get_unknown_pointer() #0
168
169 attributes #0 = { nounwind }
0 ; RUN: opt -S -mtriple=amdgcn-unknown-amdhsa -mcpu=kaveri -amdgpu-promote-alloca < %s | FileCheck %s
1
2 ; CHECK-LABEL: @lds_promoted_alloca_select_invalid_pointer_operand(
3 ; CHECK: %alloca = alloca i32
4 ; CHECK: select i1 undef, i32* undef, i32* %alloca
5 define void @lds_promoted_alloca_select_invalid_pointer_operand() #0 {
6 %alloca = alloca i32, align 4
7 %select = select i1 undef, i32* undef, i32* %alloca
8 store i32 0, i32* %select, align 4
9 ret void
10 }
11
12 ; CHECK-LABEL: @lds_promote_alloca_select_two_derived_pointers(
13 ; CHECK: [[ARRAYGEP:%[0-9]+]] = getelementptr inbounds [256 x [16 x i32]], [256 x [16 x i32]] addrspace(3)* @lds_promote_alloca_select_two_derived_pointers.alloca, i32 0, i32 %{{[0-9]+}}
14 ; CHECK: %ptr0 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* [[ARRAYGEP]], i32 0, i32 %a
15 ; CHECK: %ptr1 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* [[ARRAYGEP]], i32 0, i32 %b
16 ; CHECK: %select = select i1 undef, i32 addrspace(3)* %ptr0, i32 addrspace(3)* %ptr1
17 ; CHECK: store i32 0, i32 addrspace(3)* %select, align 4
18 define void @lds_promote_alloca_select_two_derived_pointers(i32 %a, i32 %b) #0 {
19 %alloca = alloca [16 x i32], align 4
20 %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %a
21 %ptr1 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %b
22 %select = select i1 undef, i32* %ptr0, i32* %ptr1
23 store i32 0, i32* %select, align 4
24 ret void
25 }
26
27 ; FIXME: This should be promotable but requires knowing that both will be promoted first.
28
29 ; CHECK-LABEL: @lds_promote_alloca_select_two_allocas(
30 ; CHECK: %alloca0 = alloca i32, i32 16, align 4
31 ; CHECK: %alloca1 = alloca i32, i32 16, align 4
32 ; CHECK: %ptr0 = getelementptr inbounds i32, i32* %alloca0, i32 %a
33 ; CHECK: %ptr1 = getelementptr inbounds i32, i32* %alloca1, i32 %b
34 ; CHECK: %select = select i1 undef, i32* %ptr0, i32* %ptr1
35 define void @lds_promote_alloca_select_two_allocas(i32 %a, i32 %b) #0 {
36 %alloca0 = alloca i32, i32 16, align 4
37 %alloca1 = alloca i32, i32 16, align 4
38 %ptr0 = getelementptr inbounds i32, i32* %alloca0, i32 %a
39 %ptr1 = getelementptr inbounds i32, i32* %alloca1, i32 %b
40 %select = select i1 undef, i32* %ptr0, i32* %ptr1
41 store i32 0, i32* %select, align 4
42 ret void
43 }
44
45 ; TODO: Maybe this should be canonicalized to select on the constant and GEP after.
46 ; CHECK-LABEL: @lds_promote_alloca_select_two_derived_constant_pointers(
47 ; CHECK: [[ARRAYGEP:%[0-9]+]] = getelementptr inbounds [256 x [16 x i32]], [256 x [16 x i32]] addrspace(3)* @lds_promote_alloca_select_two_derived_constant_pointers.alloca, i32 0, i32 %{{[0-9]+}}
48 ; CHECK: %ptr0 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* [[ARRAYGEP]], i32 0, i32 1
49 ; CHECK: %ptr1 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* [[ARRAYGEP]], i32 0, i32 3
50 ; CHECK: %select = select i1 undef, i32 addrspace(3)* %ptr0, i32 addrspace(3)* %ptr1
51 ; CHECK: store i32 0, i32 addrspace(3)* %select, align 4
52 define void @lds_promote_alloca_select_two_derived_constant_pointers() #0 {
53 %alloca = alloca [16 x i32], align 4
54 %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 1
55 %ptr1 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 3
56 %select = select i1 undef, i32* %ptr0, i32* %ptr1
57 store i32 0, i32* %select, align 4
58 ret void
59 }
60
61 ; CHECK-LABEL: @lds_promoted_alloca_select_input_select(
62 ; CHECK: getelementptr inbounds [256 x [16 x i32]], [256 x [16 x i32]] addrspace(3)* @lds_promoted_alloca_select_input_select.alloca, i32 0, i32 %{{[0-9]+}}
63 ; CHECK: %ptr0 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* %{{[0-9]+}}, i32 0, i32 %a
64 ; CHECK: %ptr1 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* %{{[0-9]+}}, i32 0, i32 %b
65 ; CHECK: %ptr2 = getelementptr inbounds [16 x i32], [16 x i32] addrspace(3)* %{{[0-9]+}}, i32 0, i32 %c
66 ; CHECK: %select0 = select i1 undef, i32 addrspace(3)* %ptr0, i32 addrspace(3)* %ptr1
67 ; CHECK: %select1 = select i1 undef, i32 addrspace(3)* %select0, i32 addrspace(3)* %ptr2
68 ; CHECK: store i32 0, i32 addrspace(3)* %select1, align 4
69 define void @lds_promoted_alloca_select_input_select(i32 %a, i32 %b, i32 %c) #0 {
70 %alloca = alloca [16 x i32], align 4
71 %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %a
72 %ptr1 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %b
73 %ptr2 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %c
74 %select0 = select i1 undef, i32* %ptr0, i32* %ptr1
75 %select1 = select i1 undef, i32* %select0, i32* %ptr2
76 store i32 0, i32* %select1, align 4
77 ret void
78 }
79
80 define void @lds_promoted_alloca_select_input_phi(i32 %a, i32 %b, i32 %c) #0 {
81 entry:
82 %alloca = alloca [16 x i32], align 4
83 %ptr0 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %a
84 %ptr1 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %b
85 store i32 0, i32* %ptr0
86 br i1 undef, label %bb1, label %bb2
87
88 bb1:
89 %ptr2 = getelementptr inbounds [16 x i32], [16 x i32]* %alloca, i32 0, i32 %c
90 %select0 = select i1 undef, i32* undef, i32* %ptr2
91 store i32 0, i32* %ptr1
92 br label %bb2
93
94 bb2:
95 %phi.ptr = phi i32* [ %ptr0, %entry ], [ %select0, %bb1 ]
96 %select1 = select i1 undef, i32* %phi.ptr, i32* %ptr1
97 store i32 0, i32* %select1, align 4
98 ret void
99 }
100
101 attributes #0 = { norecurse nounwind }