llvm.org GIT mirror llvm / 1a699b6
bug fix for PR20020: anti-dependency-breaker causes miscompilation This patch sets the 'KeepReg' bit for any tied and live registers during the PrescanInstruction() phase of the dependency breaking algorithm. It then checks those 'KeepReg' bits during the ScanInstruction() phase to avoid changing any tied registers. For more details, please see comments in: http://llvm.org/bugs/show_bug.cgi?id=20020 I added two FIXME comments for code that I think can be removed by using register iterators that include self. I don't want to include those code changes with this patch, however, to keep things as small as possible. The test case is larger than I'd like, but I don't know how to reduce it further and still produce the failing asm. Differential Revision: http://reviews.llvm.org/D4351 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212275 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjay Patel 5 years ago
2 changed file(s) with 104 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
199199 if (Classes[Reg] != reinterpret_cast(-1))
200200 RegRefs.insert(std::make_pair(Reg, &MO));
201201
202 // If this reg is tied and live (Classes[Reg] is set to -1), we can't change
203 // it or any of its sub or super regs. We need to use KeepRegs to mark the
204 // reg because not all uses of the same reg within an instruction are
205 // necessarily tagged as tied.
206 // Example: an x86 "xor %eax, %eax" will have one source operand tied to the
207 // def register but not the second (see PR20020 for details).
208 // FIXME: can this check be relaxed to account for undef uses
209 // of a register? In the above 'xor' example, the uses of %eax are undef, so
210 // earlier instructions could still replace %eax even though the 'xor'
211 // itself can't be changed.
212 if (MI->isRegTiedToUseOperand(i) &&
213 Classes[Reg] == reinterpret_cast(-1)) {
214 for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/true);
215 SubRegs.isValid(); ++SubRegs) {
216 KeepRegs.set(*SubRegs);
217 }
218 for (MCSuperRegIterator SuperRegs(Reg, TRI);
219 SuperRegs.isValid(); ++SuperRegs) {
220 KeepRegs.set(*SuperRegs);
221 }
222 }
223
202224 if (MO.isUse() && Special) {
203225 if (!KeepRegs.test(Reg)) {
204226 for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/true);
235257 unsigned Reg = MO.getReg();
236258 if (Reg == 0) continue;
237259 if (!MO.isDef()) continue;
260
261 // If we've already marked this reg as unchangeable, carry on.
262 if (KeepRegs.test(Reg)) continue;
263
238264 // Ignore two-addr defs.
239265 if (MI->isRegTiedToUseOperand(i)) continue;
240266
267 // FIXME: we should use a SubRegIterator that includes self (as above), so
268 // we don't have to repeat all this code for the reg itself.
241269 DefIndices[Reg] = Count;
242270 KillIndices[Reg] = ~0u;
243271 assert(((KillIndices[Reg] == ~0u) !=
280308
281309 RegRefs.insert(std::make_pair(Reg, &MO));
282310
311 // FIXME: we should use an MCRegAliasIterator that includes self so we don't
312 // have to repeat all this code for the reg itself.
313
283314 // It wasn't previously live but now it is, this is a kill.
284315 if (KillIndices[Reg] == ~0u) {
285316 KillIndices[Reg] = Count;
0 ; RUN: llc < %s -mtriple=x86_64-apple-macosx -disable-lsr -post-RA-scheduler=1 -break-anti-dependencies=critical | FileCheck %s
1
2 ; In PR20020, the critical anti-dependency breaker algorithm mistakenly
3 ; changes the register operands of an 'xorl %eax, %eax' to 'xorl %ecx, %ecx'
4 ; and then immediately reloads %rcx with a value based on the wrong %rax
5
6 ; CHECK-NOT: xorl %ecx, %ecx
7 ; CHECK: leaq 1(%rax), %rcx
8
9
10 %struct.planet = type { double, double, double }
11
12 ; Function Attrs: nounwind ssp uwtable
13 define void @advance(i32 %nbodies, %struct.planet* nocapture %bodies) #0 {
14 entry:
15 %cmp4 = icmp sgt i32 %nbodies, 0
16 br i1 %cmp4, label %for.body.preheader, label %for.end38
17
18 for.body.preheader: ; preds = %entry
19 %gep = getelementptr %struct.planet* %bodies, i64 1, i32 1
20 %gep13 = bitcast double* %gep to %struct.planet*
21 %0 = add i32 %nbodies, -1
22 br label %for.body
23
24 for.body: ; preds = %for.body.preheader, %for.inc20
25 %iv19 = phi i32 [ %0, %for.body.preheader ], [ %iv.next, %for.inc20 ]
26 %iv = phi %struct.planet* [ %gep13, %for.body.preheader ], [ %gep14, %for.inc20 ]
27 %iv9 = phi i64 [ %iv.next10, %for.inc20 ], [ 0, %for.body.preheader ]
28 %iv.next10 = add nuw nsw i64 %iv9, 1
29 %1 = trunc i64 %iv.next10 to i32
30 %cmp22 = icmp slt i32 %1, %nbodies
31 br i1 %cmp22, label %for.body3.lr.ph, label %for.inc20
32
33 for.body3.lr.ph: ; preds = %for.body
34 %x = getelementptr inbounds %struct.planet* %bodies, i64 %iv9, i32 0
35 %y = getelementptr inbounds %struct.planet* %bodies, i64 %iv9, i32 1
36 %vx = getelementptr inbounds %struct.planet* %bodies, i64 %iv9, i32 2
37 br label %for.body3
38
39 for.body3: ; preds = %for.body3, %for.body3.lr.ph
40 %iv20 = phi i32 [ %iv.next21, %for.body3 ], [ %iv19, %for.body3.lr.ph ]
41 %iv15 = phi %struct.planet* [ %gep16, %for.body3 ], [ %iv, %for.body3.lr.ph ]
42 %iv1517 = bitcast %struct.planet* %iv15 to double*
43 %2 = load double* %x, align 8
44 %gep18 = getelementptr double* %iv1517, i64 -1
45 %3 = load double* %gep18, align 8
46 %sub = fsub double %2, %3
47 %4 = load double* %y, align 8
48 %5 = load double* %iv1517, align 8
49 %sub8 = fsub double %4, %5
50 %add10 = fadd double %sub, %sub8
51 %call = tail call double @sqrt(double %sub8) #2
52 store double %add10, double* %vx, align 8
53 %gep16 = getelementptr %struct.planet* %iv15, i64 1
54 %iv.next21 = add i32 %iv20, -1
55 %exitcond = icmp eq i32 %iv.next21, 0
56 br i1 %exitcond, label %for.inc20, label %for.body3
57
58 for.inc20: ; preds = %for.body3, %for.body
59 %lftr.wideiv11 = trunc i64 %iv.next10 to i32
60 %gep14 = getelementptr %struct.planet* %iv, i64 1
61 %iv.next = add i32 %iv19, -1
62 %exitcond12 = icmp eq i32 %lftr.wideiv11, %nbodies
63 br i1 %exitcond12, label %for.end38, label %for.body
64
65 for.end38: ; preds = %for.inc20, %entry
66 ret void
67 }
68
69 ; Function Attrs: nounwind
70 declare double @sqrt(double) #1
71
72 attributes #0 = { "no-frame-pointer-elim-non-leaf" }