mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
[Verifier] Verify invokes of intrinsics
We support invoking a subset of llvm's intrinsics, but the verifier didn't account for this. We had previously added a special case to verify invokes of statepoints. By generalizing the code in terms of CallSite, we can verify invokes of other intrinsics as well. Interestingly, this found one test case which was invalid. Note: I'm deliberately leaving the naming change from CI to CS to a follow up change. That will happen shortly, I just wanted to reduce the diff to make it clear what was happening with this one. Differential Revision: http://reviews.llvm.org/D10118 llvm-svn: 240836
This commit is contained in:
parent
ca220f5971
commit
4f4ed9b17b
@ -38,6 +38,7 @@ class CallInst;
|
||||
class InvokeInst;
|
||||
|
||||
template <typename FunTy = const Function,
|
||||
typename BBTy = const BasicBlock,
|
||||
typename ValTy = const Value,
|
||||
typename UserTy = const User,
|
||||
typename InstrTy = const Instruction,
|
||||
@ -82,6 +83,9 @@ public:
|
||||
InstrTy *operator->() const { return I.getPointer(); }
|
||||
explicit operator bool() const { return I.getPointer(); }
|
||||
|
||||
/// Get the basic block containing the call site
|
||||
BBTy* getParent() const { return getInstruction()->getParent(); }
|
||||
|
||||
/// getCalledValue - Return the pointer to function that is being called.
|
||||
///
|
||||
ValTy *getCalledValue() const {
|
||||
@ -189,6 +193,20 @@ public:
|
||||
else \
|
||||
cast<InvokeInst>(II)->METHOD
|
||||
|
||||
unsigned getNumArgOperands() const {
|
||||
CALLSITE_DELEGATE_GETTER(getNumArgOperands());
|
||||
}
|
||||
|
||||
Value *getArgOperand(unsigned i) const {
|
||||
CALLSITE_DELEGATE_GETTER(getArgOperand(i));
|
||||
}
|
||||
|
||||
bool isInlineAsm() const {
|
||||
if (isCall())
|
||||
return cast<CallInst>(getInstruction())->isInlineAsm();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getCallingConv/setCallingConv - get or set the calling convention of the
|
||||
/// call.
|
||||
CallingConv::ID getCallingConv() const {
|
||||
@ -366,8 +384,9 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class CallSite : public CallSiteBase<Function, Value, User, Instruction,
|
||||
CallInst, InvokeInst, User::op_iterator> {
|
||||
class CallSite : public CallSiteBase<Function, BasicBlock, Value, User,
|
||||
Instruction, CallInst, InvokeInst,
|
||||
User::op_iterator> {
|
||||
public:
|
||||
CallSite() {}
|
||||
CallSite(CallSiteBase B) : CallSiteBase(B) {}
|
||||
|
@ -102,6 +102,11 @@ private:
|
||||
OS << '\n';
|
||||
}
|
||||
}
|
||||
void Write(const CallSite *CS) {
|
||||
if (!CS)
|
||||
return;
|
||||
Write(CS->getInstruction());
|
||||
}
|
||||
|
||||
void Write(const Metadata *MD) {
|
||||
if (!MD)
|
||||
@ -367,7 +372,7 @@ private:
|
||||
void visitSelectInst(SelectInst &SI);
|
||||
void visitUserOp1(Instruction &I);
|
||||
void visitUserOp2(Instruction &I) { visitUserOp1(I); }
|
||||
void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI);
|
||||
void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallSite CS);
|
||||
template <class DbgIntrinsicTy>
|
||||
void visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII);
|
||||
void visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI);
|
||||
@ -2289,6 +2294,10 @@ void Verifier::VerifyCallSite(CallSite CS) {
|
||||
"Function has metadata parameter but isn't an intrinsic", I);
|
||||
}
|
||||
|
||||
if (Function *F = CS.getCalledFunction())
|
||||
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
|
||||
visitIntrinsicFunctionCall(ID, CS);
|
||||
|
||||
visitInstruction(*I);
|
||||
}
|
||||
|
||||
@ -2384,10 +2393,6 @@ void Verifier::visitCallInst(CallInst &CI) {
|
||||
|
||||
if (CI.isMustTailCall())
|
||||
verifyMustTailCall(CI);
|
||||
|
||||
if (Function *F = CI.getCalledFunction())
|
||||
if (Intrinsic::ID ID = F->getIntrinsicID())
|
||||
visitIntrinsicFunctionCall(ID, CI);
|
||||
}
|
||||
|
||||
void Verifier::visitInvokeInst(InvokeInst &II) {
|
||||
@ -2398,13 +2403,6 @@ void Verifier::visitInvokeInst(InvokeInst &II) {
|
||||
Assert(II.getUnwindDest()->isLandingPad(),
|
||||
"The unwind destination does not have a landingpad instruction!", &II);
|
||||
|
||||
if (Function *F = II.getCalledFunction())
|
||||
// TODO: Ideally we should use visitIntrinsicFunction here. But it uses
|
||||
// CallInst as an input parameter. It not woth updating this whole
|
||||
// function only to support statepoint verification.
|
||||
if (F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint)
|
||||
VerifyStatepoint(ImmutableCallSite(&II));
|
||||
|
||||
visitTerminatorInst(II);
|
||||
}
|
||||
|
||||
@ -3146,7 +3144,7 @@ Verifier::VerifyIntrinsicIsVarArg(bool isVarArg,
|
||||
|
||||
/// visitIntrinsicFunction - Allow intrinsics to be verified in different ways.
|
||||
///
|
||||
void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallSite CI) {
|
||||
Function *IF = CI.getCalledFunction();
|
||||
Assert(IF->isDeclaration(), "Intrinsic functions should never be defined!",
|
||||
IF);
|
||||
@ -3208,10 +3206,10 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
case Intrinsic::dbg_declare: // llvm.dbg.declare
|
||||
Assert(isa<MetadataAsValue>(CI.getArgOperand(0)),
|
||||
"invalid llvm.dbg.declare intrinsic call 1", &CI);
|
||||
visitDbgIntrinsic("declare", cast<DbgDeclareInst>(CI));
|
||||
visitDbgIntrinsic("declare", cast<DbgDeclareInst>(*CI.getInstruction()));
|
||||
break;
|
||||
case Intrinsic::dbg_value: // llvm.dbg.value
|
||||
visitDbgIntrinsic("value", cast<DbgValueInst>(CI));
|
||||
visitDbgIntrinsic("value", cast<DbgValueInst>(*CI.getInstruction()));
|
||||
break;
|
||||
case Intrinsic::memcpy:
|
||||
case Intrinsic::memmove:
|
||||
@ -3282,7 +3280,7 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
"llvm.frameescape used outside of entry block", &CI);
|
||||
Assert(!SawFrameEscape,
|
||||
"multiple calls to llvm.frameescape in one function", &CI);
|
||||
for (Value *Arg : CI.arg_operands()) {
|
||||
for (Value *Arg : CI.args()) {
|
||||
if (isa<ConstantPointerNull>(Arg))
|
||||
continue; // Null values are allowed as placeholders.
|
||||
auto *AI = dyn_cast<AllocaInst>(Arg->stripPointerCasts());
|
||||
@ -3315,7 +3313,7 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
Assert(CI.getParent()->getParent()->hasGC(),
|
||||
"Enclosing function does not use GC.", &CI);
|
||||
|
||||
VerifyStatepoint(ImmutableCallSite(&CI));
|
||||
VerifyStatepoint(ImmutableCallSite(CI));
|
||||
break;
|
||||
case Intrinsic::experimental_gc_result_int:
|
||||
case Intrinsic::experimental_gc_result_float:
|
||||
@ -3377,7 +3375,7 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
|
||||
// Verify rest of the relocate arguments
|
||||
|
||||
GCRelocateOperands Ops(&CI);
|
||||
GCRelocateOperands Ops(CI);
|
||||
ImmutableCallSite StatepointCS(Ops.getStatepoint());
|
||||
|
||||
// Both the base and derived must be piped through the safepoint
|
||||
@ -3433,7 +3431,7 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
|
||||
// Relocated value must be a pointer type, but gc_relocate does not need to return the
|
||||
// same pointer type as the relocated pointer. It can be casted to the correct type later
|
||||
// if it's desired. However, they must have the same address space.
|
||||
GCRelocateOperands Operands(&CI);
|
||||
GCRelocateOperands Operands(CI);
|
||||
Assert(Operands.getDerivedPtr()->getType()->isPointerTy(),
|
||||
"gc.relocate: relocated value must be a gc pointer", &CI);
|
||||
|
||||
|
@ -61,7 +61,7 @@ entry:
|
||||
%.i8 = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?f@@YAXXZ" to i8*), i8* %1, i32 1)
|
||||
%2 = bitcast i8* %.i8 to double*
|
||||
%3 = bitcast double* %2 to i8*
|
||||
invoke void (...) @llvm.donothing()
|
||||
invoke void () @llvm.donothing()
|
||||
to label %done unwind label %lpad
|
||||
|
||||
done:
|
||||
@ -201,7 +201,7 @@ declare void @llvm.frameescape(...) #3
|
||||
; Function Attrs: nounwind readnone
|
||||
declare i8* @llvm.framerecover(i8*, i8*, i32) #2
|
||||
|
||||
declare void @llvm.donothing(...)
|
||||
declare void @llvm.donothing()
|
||||
|
||||
attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?f@@YAXXZ" }
|
||||
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
|
Loading…
Reference in New Issue
Block a user