llvm.org GIT mirror llvm / f67baf0
Fix an issue with isGuaranteedToTransferExecutionToSuccessor I'm not sure if this was intentional, but today isGuaranteedToTransferExecutionToSuccessor returns true for readonly and argmemonly calls that may throw. This commit changes the function to not implicitly infer nounwind this way. Even if we eventually specify readonly calls as not throwing, isGuaranteedToTransferExecutionToSuccessor is not the best place to infer that. We should instead teach FunctionAttrs or some other such pass to tag readonly functions / calls as nounwind instead. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@290794 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjoy Das 2 years ago
2 changed file(s) with 71 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
36563656
36573657 // Calls can throw, or contain an infinite loop, or kill the process.
36583658 if (auto CS = ImmutableCallSite(I)) {
3659 // Calls which don't write to arbitrary memory are safe.
3660 // FIXME: Ignoring infinite loops without any side-effects is too
3661 // aggressive,
3662 // but it's consistent with other passes. See http://llvm.org/PR965 .
3663 // FIXME: This isn't aggressive enough; a call which only writes to a
3664 // global is guaranteed to return.
3659 // Call sites that throw have implicit non-local control flow.
3660 if (!CS.doesNotThrow())
3661 return false;
3662
3663 // Non-throwing call sites can loop infinitely, call exit/pthread_exit
3664 // etc. and thus not return. However, LLVM already assumes that
3665 //
3666 // - Thread exiting actions are modeled as writes to memory invisible to
3667 // the program.
3668 //
3669 // - Loops that don't have side effects (side effects are volatile/atomic
3670 // stores and IO) always terminate (see http://llvm.org/PR965).
3671 // Furthermore IO itself is also modeled as writes to memory invisible to
3672 // the program.
3673 //
3674 // We rely on those assumptions here, and use the memory effects of the call
3675 // target as a proxy for checking that it always returns.
3676
3677 // FIXME: This isn't aggressive enough; a call which only writes to a global
3678 // is guaranteed to return.
36653679 return CS.onlyReadsMemory() || CS.onlyAccessesArgMemory() ||
36663680 match(I, m_Intrinsic());
36673681 }
187187 // The cast types here aren't the same, so we cannot match an UMIN.
188188 expectPattern({SPF_UNKNOWN, SPNB_NA, false});
189189 }
190
191 TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {
192 StringRef Assembly =
193 "declare void @nounwind_readonly(i32*) nounwind readonly "
194 "declare void @nounwind_argmemonly(i32*) nounwind argmemonly "
195 "declare void @throws_but_readonly(i32*) readonly "
196 "declare void @throws_but_argmemonly(i32*) argmemonly "
197 " "
198 "declare void @unknown(i32*) "
199 " "
200 "define void @f(i32* %p) { "
201 " call void @nounwind_readonly(i32* %p) "
202 " call void @nounwind_argmemonly(i32* %p) "
203 " call void @throws_but_readonly(i32* %p) "
204 " call void @throws_but_argmemonly(i32* %p) "
205 " call void @unknown(i32* %p) nounwind readonly "
206 " call void @unknown(i32* %p) nounwind argmemonly "
207 " call void @unknown(i32* %p) readonly "
208 " call void @unknown(i32* %p) argmemonly "
209 " ret void "
210 "} ";
211
212 LLVMContext Context;
213 SMDiagnostic Error;
214 auto M = parseAssemblyString(Assembly, Error, Context);
215 assert(M && "Bad assembly?");
216
217 auto *F = M->getFunction("f");
218 assert(F && "Bad assembly?");
219
220 auto &BB = F->getEntryBlock();
221 ArrayRef ExpectedAnswers = {
222 true, // call void @nounwind_readonly(i32* %p)
223 true, // call void @nounwind_argmemonly(i32* %p)
224 false, // call void @throws_but_readonly(i32* %p)
225 false, // call void @throws_but_argmemonly(i32* %p)
226 true, // call void @unknown(i32* %p) nounwind readonly
227 true, // call void @unknown(i32* %p) nounwind argmemonly
228 false, // call void @unknown(i32* %p) readonly
229 false, // call void @unknown(i32* %p) argmemonly
230 false, // ret void
231 };
232
233 int Index = 0;
234 for (auto &I : BB) {
235 EXPECT_EQ(isGuaranteedToTransferExecutionToSuccessor(&I),
236 ExpectedAnswers[Index])
237 << "Incorrect answer at instruction " << Index << " = " << I;
238 Index++;
239 }
240 }