diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -548,6 +548,9 @@ /// Verify the llvm.experimental.noalias.scope.decl declarations void verifyNoAliasScopeDecl(); + + /// Verify operand bundles. + void verifyOperandBundles(CallBase& Call); }; } // end anonymous namespace @@ -2995,7 +2998,6 @@ "AddrSpaceCast vector pointer number of elements mismatch", &I); visitInstruction(I); } - /// visitPHINode - Ensure that a PHI node is well formed. /// void Verifier::visitPHINode(PHINode &PN) { @@ -3022,6 +3024,68 @@ visitInstruction(PN); } +void Verifier::verifyOperandBundles(CallBase& Call) { + bool FoundOpBundle[LLVMContext::OB_clang_arc_attachedcall + 1] = {}; + // Verify that a callsite has at most one of the given tag. + auto CheckAtMostOne = [this, &Call, &FoundOpBundle](uint32_t Tag, const char* Name) { + bool& Found = FoundOpBundle[Tag]; + Assert(!Found, Twine("Multiple ").concat(Name).concat(" operand bundles"), Call); + Found = true; + }; + + for (unsigned i = 0, e = Call.getNumOperandBundles(); i < e; ++i) { + OperandBundleUse BU = Call.getOperandBundleAt(i); + uint32_t Tag = BU.getTagID(); + switch (Tag) { + case LLVMContext::OB_deopt: + CheckAtMostOne(Tag, "deopt"); + break; + case LLVMContext::OB_gc_transition: + CheckAtMostOne(Tag, "gc-transition"); + break; + case LLVMContext::OB_funclet: + CheckAtMostOne(Tag, "funclet"); + Assert(BU.Inputs.size() == 1, + "Expected exactly one funclet bundle operand", Call); + Assert(isa(BU.Inputs.front()), + "Funclet bundle operands should correspond to a FuncletPadInst", + Call); + break; + case LLVMContext::OB_cfguardtarget: + CheckAtMostOne(Tag, "CFGuardTarget"); + Assert(BU.Inputs.size() == 1, + "Expected exactly one cfguardtarget bundle operand", Call); + break; + case LLVMContext::OB_preallocated: { + CheckAtMostOne(Tag, "preallocated"); + Assert(BU.Inputs.size() == 1, + "Expected exactly one preallocated bundle operand", Call); + auto Input = dyn_cast(BU.Inputs.front()); + Assert(Input && + Input->getIntrinsicID() == Intrinsic::call_preallocated_setup, + "\"preallocated\" argument must be a token from " + "llvm.call.preallocated.setup", + Call); + break; + } + case LLVMContext::OB_gc_live: + CheckAtMostOne(Tag, "gc-live"); + break; + case LLVMContext::OB_clang_arc_attachedcall: + CheckAtMostOne(Tag, "\"clang.arc.attachedcall\""); + break; + default: + break; + } + } + + if (FoundOpBundle[LLVMContext::OB_clang_arc_attachedcall]) + Assert(Call.getFunctionType()->getReturnType()->isPointerTy(), + "a call with operand bundle \"clang.arc.attachedcall\" must call a " + "function returning a pointer", + Call); +} + void Verifier::visitCallBase(CallBase &Call) { Assert(Call.getCalledOperand()->getType()->isPointerTy(), "Called function must be a pointer!", Call); @@ -3201,65 +3265,7 @@ if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) visitIntrinsicCall(ID, Call); - // Verify that a callsite has at most one "deopt", at most one "funclet", at - // most one "gc-transition", at most one "cfguardtarget", - // and at most one "preallocated" operand bundle. - bool FoundDeoptBundle = false, FoundFuncletBundle = false, - FoundGCTransitionBundle = false, FoundCFGuardTargetBundle = false, - FoundPreallocatedBundle = false, FoundGCLiveBundle = false, - FoundAttachedCallBundle = false; - for (unsigned i = 0, e = Call.getNumOperandBundles(); i < e; ++i) { - OperandBundleUse BU = Call.getOperandBundleAt(i); - uint32_t Tag = BU.getTagID(); - if (Tag == LLVMContext::OB_deopt) { - Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", Call); - FoundDeoptBundle = true; - } else if (Tag == LLVMContext::OB_gc_transition) { - Assert(!FoundGCTransitionBundle, "Multiple gc-transition operand bundles", - Call); - FoundGCTransitionBundle = true; - } else if (Tag == LLVMContext::OB_funclet) { - Assert(!FoundFuncletBundle, "Multiple funclet operand bundles", Call); - FoundFuncletBundle = true; - Assert(BU.Inputs.size() == 1, - "Expected exactly one funclet bundle operand", Call); - Assert(isa(BU.Inputs.front()), - "Funclet bundle operands should correspond to a FuncletPadInst", - Call); - } else if (Tag == LLVMContext::OB_cfguardtarget) { - Assert(!FoundCFGuardTargetBundle, - "Multiple CFGuardTarget operand bundles", Call); - FoundCFGuardTargetBundle = true; - Assert(BU.Inputs.size() == 1, - "Expected exactly one cfguardtarget bundle operand", Call); - } else if (Tag == LLVMContext::OB_preallocated) { - Assert(!FoundPreallocatedBundle, "Multiple preallocated operand bundles", - Call); - FoundPreallocatedBundle = true; - Assert(BU.Inputs.size() == 1, - "Expected exactly one preallocated bundle operand", Call); - auto Input = dyn_cast(BU.Inputs.front()); - Assert(Input && - Input->getIntrinsicID() == Intrinsic::call_preallocated_setup, - "\"preallocated\" argument must be a token from " - "llvm.call.preallocated.setup", - Call); - } else if (Tag == LLVMContext::OB_gc_live) { - Assert(!FoundGCLiveBundle, "Multiple gc-live operand bundles", - Call); - FoundGCLiveBundle = true; - } else if (Tag == LLVMContext::OB_clang_arc_attachedcall) { - Assert(!FoundAttachedCallBundle, - "Multiple \"clang.arc.attachedcall\" operand bundles", Call); - FoundAttachedCallBundle = true; - } - } - - if (FoundAttachedCallBundle) - Assert(FTy->getReturnType()->isPointerTy(), - "a call with operand bundle \"clang.arc.attachedcall\" must call a " - "function returning a pointer", - Call); + verifyOperandBundles(Call); // Verify that each inlinable callsite of a debug-info-bearing function in a // debug-info-bearing function has a debug location attached to it. Failure to