AMDGPU: Whitelist handled intrinsics

We shouldn't crash on unhandled intrinsics.
Also simplify failure handling in loop.

llvm-svn: 259546
This commit is contained in:
Matt Arsenault 2016-02-02 19:18:53 +00:00
parent 853a1fc6d9
commit ad1348459f
2 changed files with 60 additions and 8 deletions

View File

@ -399,15 +399,37 @@ static bool tryPromoteAllocaToVector(AllocaInst *Alloca) {
return true; return true;
} }
static bool isCallPromotable(CallInst *CI) {
// TODO: We might be able to handle some cases where the callee is a
// constantexpr bitcast of a function.
if (!CI->getCalledFunction())
return false;
IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI);
if (!II)
return false;
switch (II->getIntrinsicID()) {
case Intrinsic::memcpy:
case Intrinsic::memset:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::invariant_start:
case Intrinsic::invariant_end:
case Intrinsic::invariant_group_barrier:
return true;
default:
return false;
}
}
static bool collectUsesWithPtrTypes(Value *Val, std::vector<Value*> &WorkList) { static bool collectUsesWithPtrTypes(Value *Val, std::vector<Value*> &WorkList) {
bool Success = true;
for (User *User : Val->users()) { for (User *User : Val->users()) {
if(std::find(WorkList.begin(), WorkList.end(), User) != WorkList.end()) if (std::find(WorkList.begin(), WorkList.end(), User) != WorkList.end())
continue; continue;
if (CallInst *CI = dyn_cast<CallInst>(User)) { if (CallInst *CI = dyn_cast<CallInst>(User)) {
// TODO: We might be able to handle some cases where the callee is a if (!isCallPromotable(CI))
// constantexpr bitcast of a function.
if (!CI->getCalledFunction())
return false; return false;
WorkList.push_back(User); WorkList.push_back(User);
@ -429,10 +451,11 @@ static bool collectUsesWithPtrTypes(Value *Val, std::vector<Value*> &WorkList) {
continue; continue;
WorkList.push_back(User); WorkList.push_back(User);
if (!collectUsesWithPtrTypes(User, WorkList))
Success &= collectUsesWithPtrTypes(User, WorkList); return false;
} }
return Success;
return true;
} }
void AMDGPUPromoteAlloca::visitAlloca(AllocaInst &I) { void AMDGPUPromoteAlloca::visitAlloca(AllocaInst &I) {
@ -521,6 +544,11 @@ void AMDGPUPromoteAlloca::visitAlloca(AllocaInst &I) {
IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Call); IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Call);
if (!Intr) { if (!Intr) {
// FIXME: What is this for? It doesn't make sense to promote arbitrary
// function calls. If the call is to a defined function that can also be
// promoted, we should be able to do this once that function is also
// rewritten.
std::vector<Type*> ArgTypes; std::vector<Type*> ArgTypes;
for (unsigned ArgIdx = 0, ArgEnd = Call->getNumArgOperands(); for (unsigned ArgIdx = 0, ArgEnd = Call->getNumArgOperands();
ArgIdx != ArgEnd; ++ArgIdx) { ArgIdx != ArgEnd; ++ArgIdx) {

View File

@ -0,0 +1,24 @@
; RUN: opt -S -mtriple=amdgcn-unknown-amdhsa < %s | FileCheck %s
; This is just an arbitrary intrinisic that shouldn't ever need to be
; handled to ensure it doesn't crash.
declare void @eh.sjlj.functioncontext(i8*) #2
; CHECK-LABEL: @try_promote_unhandled_intrinsic(
; CHECK: alloca
; CHECK: call void @eh.sjlj.functioncontext(i8* %tmp1)
define void @try_promote_unhandled_intrinsic(i32 addrspace(1)* %arg) #2 {
bb:
%tmp = alloca i32, align 4
%tmp1 = bitcast i32* %tmp to i8*
%tmp2 = getelementptr inbounds i32, i32 addrspace(1)* %arg, i64 1
%tmp3 = load i32, i32 addrspace(1)* %tmp2
store i32 %tmp3, i32* %tmp
call void @eh.sjlj.functioncontext(i8* %tmp1)
ret void
}
attributes #0 = { argmemonly nounwind }
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }