mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-26 05:25:47 +00:00
Get the verifier to check attributes on calls as well
as on functions. Make it verify invokes and not just ordinary calls. As a (desired) side-effect, it is no longer legal to have call attributes on arguments that are being passed to the varargs part of a varargs function (llvm-as drops them on the floor anyway). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45286 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -53,6 +53,7 @@
|
|||||||
#include "llvm/PassManager.h"
|
#include "llvm/PassManager.h"
|
||||||
#include "llvm/Analysis/Dominators.h"
|
#include "llvm/Analysis/Dominators.h"
|
||||||
#include "llvm/CodeGen/ValueTypes.h"
|
#include "llvm/CodeGen/ValueTypes.h"
|
||||||
|
#include "llvm/Support/CallSite.h"
|
||||||
#include "llvm/Support/CFG.h"
|
#include "llvm/Support/CFG.h"
|
||||||
#include "llvm/Support/InstVisitor.h"
|
#include "llvm/Support/InstVisitor.h"
|
||||||
#include "llvm/Support/Streams.h"
|
#include "llvm/Support/Streams.h"
|
||||||
@@ -243,6 +244,7 @@ namespace { // Anonymous namespace for class
|
|||||||
void visitShuffleVectorInst(ShuffleVectorInst &EI);
|
void visitShuffleVectorInst(ShuffleVectorInst &EI);
|
||||||
void visitVAArgInst(VAArgInst &VAA) { visitInstruction(VAA); }
|
void visitVAArgInst(VAArgInst &VAA) { visitInstruction(VAA); }
|
||||||
void visitCallInst(CallInst &CI);
|
void visitCallInst(CallInst &CI);
|
||||||
|
void visitInvokeInst(InvokeInst &II);
|
||||||
void visitGetElementPtrInst(GetElementPtrInst &GEP);
|
void visitGetElementPtrInst(GetElementPtrInst &GEP);
|
||||||
void visitLoadInst(LoadInst &LI);
|
void visitLoadInst(LoadInst &LI);
|
||||||
void visitStoreInst(StoreInst &SI);
|
void visitStoreInst(StoreInst &SI);
|
||||||
@@ -256,8 +258,11 @@ namespace { // Anonymous namespace for class
|
|||||||
void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI);
|
void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI);
|
||||||
void visitAllocationInst(AllocationInst &AI);
|
void visitAllocationInst(AllocationInst &AI);
|
||||||
|
|
||||||
|
void VerifyCallSite(CallSite CS);
|
||||||
void VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F,
|
void VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F,
|
||||||
unsigned Count, ...);
|
unsigned Count, ...);
|
||||||
|
void VerifyParamAttrs(const FunctionType *FT, const ParamAttrsList *Attrs,
|
||||||
|
const Value *V);
|
||||||
|
|
||||||
void WriteValue(const Value *V) {
|
void WriteValue(const Value *V) {
|
||||||
if (!V) return;
|
if (!V) return;
|
||||||
@@ -377,6 +382,70 @@ void Verifier::visitGlobalAlias(GlobalAlias &GA) {
|
|||||||
void Verifier::verifyTypeSymbolTable(TypeSymbolTable &ST) {
|
void Verifier::verifyTypeSymbolTable(TypeSymbolTable &ST) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyParamAttrs - Check parameter attributes against a function type.
|
||||||
|
// The value V is printed in error messages.
|
||||||
|
void Verifier::VerifyParamAttrs(const FunctionType *FT,
|
||||||
|
const ParamAttrsList *Attrs,
|
||||||
|
const Value *V) {
|
||||||
|
if (!Attrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Note that when calling a varargs function, the following test disallows
|
||||||
|
// parameter attributes for the arguments corresponding to the varargs part.
|
||||||
|
Assert1(Attrs->size() &&
|
||||||
|
Attrs->getParamIndex(Attrs->size()-1) <= FT->getNumParams(),
|
||||||
|
"Attributes after end of type!", V);
|
||||||
|
|
||||||
|
bool SawNest = false;
|
||||||
|
|
||||||
|
for (unsigned Idx = 0; Idx <= FT->getNumParams(); ++Idx) {
|
||||||
|
uint16_t Attr = Attrs->getParamAttrs(Idx);
|
||||||
|
|
||||||
|
if (!Idx) {
|
||||||
|
uint16_t RetI = Attr & ParamAttr::ParameterOnly;
|
||||||
|
Assert1(!RetI, "Attribute " + Attrs->getParamAttrsText(RetI) +
|
||||||
|
"does not apply to return values!", V);
|
||||||
|
} else {
|
||||||
|
uint16_t ParmI = Attr & ParamAttr::ReturnOnly;
|
||||||
|
Assert1(!ParmI, "Attribute " + Attrs->getParamAttrsText(ParmI) +
|
||||||
|
"only applies to return values!", V);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0;
|
||||||
|
i < array_lengthof(ParamAttr::MutuallyIncompatible); ++i) {
|
||||||
|
uint16_t MutI = Attr & ParamAttr::MutuallyIncompatible[i];
|
||||||
|
Assert1(!(MutI & (MutI - 1)), "Attributes " +
|
||||||
|
Attrs->getParamAttrsText(MutI) + "are incompatible!", V);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t IType = Attr & ParamAttr::IntegerTypeOnly;
|
||||||
|
Assert1(!IType || FT->getParamType(Idx-1)->isInteger(),
|
||||||
|
"Attribute " + Attrs->getParamAttrsText(IType) +
|
||||||
|
"should only apply to Integer type!", V);
|
||||||
|
|
||||||
|
uint16_t PType = Attr & ParamAttr::PointerTypeOnly;
|
||||||
|
Assert1(!PType || isa<PointerType>(FT->getParamType(Idx-1)),
|
||||||
|
"Attribute " + Attrs->getParamAttrsText(PType) +
|
||||||
|
"should only apply to Pointer type!", V);
|
||||||
|
|
||||||
|
if (Attr & ParamAttr::ByVal) {
|
||||||
|
const PointerType *Ty =
|
||||||
|
dyn_cast<PointerType>(FT->getParamType(Idx-1));
|
||||||
|
Assert1(!Ty || isa<StructType>(Ty->getElementType()),
|
||||||
|
"Attribute byval should only apply to pointer to structs!", V);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attr & ParamAttr::Nest) {
|
||||||
|
Assert1(!SawNest, "More than one parameter has attribute nest!", V);
|
||||||
|
SawNest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attr & ParamAttr::StructRet) {
|
||||||
|
Assert1(Idx == 1, "Attribute sret not on first parameter!", V);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// visitFunction - Verify that a function is ok.
|
// visitFunction - Verify that a function is ok.
|
||||||
//
|
//
|
||||||
void Verifier::visitFunction(Function &F) {
|
void Verifier::visitFunction(Function &F) {
|
||||||
@@ -394,67 +463,8 @@ void Verifier::visitFunction(Function &F) {
|
|||||||
Assert1(!F.isStructReturn() || FT->getReturnType() == Type::VoidTy,
|
Assert1(!F.isStructReturn() || FT->getReturnType() == Type::VoidTy,
|
||||||
"Invalid struct-return function!", &F);
|
"Invalid struct-return function!", &F);
|
||||||
|
|
||||||
bool SawSRet = false;
|
// Check function attributes.
|
||||||
|
VerifyParamAttrs(FT, F.getParamAttrs(), &F);
|
||||||
if (const ParamAttrsList *Attrs = F.getParamAttrs()) {
|
|
||||||
Assert1(Attrs->size() &&
|
|
||||||
Attrs->getParamIndex(Attrs->size()-1) <= FT->getNumParams(),
|
|
||||||
"Function has excess attributes!", &F);
|
|
||||||
|
|
||||||
bool SawNest = false;
|
|
||||||
|
|
||||||
for (unsigned Idx = 0; Idx <= FT->getNumParams(); ++Idx) {
|
|
||||||
uint16_t Attr = Attrs->getParamAttrs(Idx);
|
|
||||||
|
|
||||||
if (!Idx) {
|
|
||||||
uint16_t RetI = Attr & ParamAttr::ParameterOnly;
|
|
||||||
Assert1(!RetI, "Attribute " + Attrs->getParamAttrsText(RetI) +
|
|
||||||
"should not apply to functions!", &F);
|
|
||||||
} else {
|
|
||||||
uint16_t ParmI = Attr & ParamAttr::ReturnOnly;
|
|
||||||
Assert1(!ParmI, "Attribute " + Attrs->getParamAttrsText(ParmI) +
|
|
||||||
"should only be applied to function!", &F);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0;
|
|
||||||
i < array_lengthof(ParamAttr::MutuallyIncompatible); ++i) {
|
|
||||||
uint16_t MutI = Attr & ParamAttr::MutuallyIncompatible[i];
|
|
||||||
Assert1(!(MutI & (MutI - 1)), "Attributes " +
|
|
||||||
Attrs->getParamAttrsText(MutI) + "are incompatible!", &F);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t IType = Attr & ParamAttr::IntegerTypeOnly;
|
|
||||||
Assert1(!IType || FT->getParamType(Idx-1)->isInteger(),
|
|
||||||
"Attribute " + Attrs->getParamAttrsText(IType) +
|
|
||||||
"should only apply to Integer type!", &F);
|
|
||||||
|
|
||||||
uint16_t PType = Attr & ParamAttr::PointerTypeOnly;
|
|
||||||
Assert1(!PType || isa<PointerType>(FT->getParamType(Idx-1)),
|
|
||||||
"Attribute " + Attrs->getParamAttrsText(PType) +
|
|
||||||
"should only apply to Pointer type!", &F);
|
|
||||||
|
|
||||||
if (Attr & ParamAttr::ByVal) {
|
|
||||||
const PointerType *Ty =
|
|
||||||
dyn_cast<PointerType>(FT->getParamType(Idx-1));
|
|
||||||
Assert1(!Ty || isa<StructType>(Ty->getElementType()),
|
|
||||||
"Attribute byval should only apply to pointer to structs!", &F);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attr & ParamAttr::Nest) {
|
|
||||||
Assert1(!SawNest, "More than one parameter has attribute nest!", &F);
|
|
||||||
SawNest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attr & ParamAttr::StructRet) {
|
|
||||||
SawSRet = true;
|
|
||||||
Assert1(Idx == 1, "Attribute sret not on first parameter!", &F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert1(SawSRet == F.isStructReturn(),
|
|
||||||
"StructReturn function with no sret attribute!", &F);
|
|
||||||
|
|
||||||
// Check that this function meets the restrictions on this calling convention.
|
// Check that this function meets the restrictions on this calling convention.
|
||||||
switch (F.getCallingConv()) {
|
switch (F.getCallingConv()) {
|
||||||
@@ -825,35 +835,48 @@ void Verifier::visitPHINode(PHINode &PN) {
|
|||||||
visitInstruction(PN);
|
visitInstruction(PN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verifier::visitCallInst(CallInst &CI) {
|
void Verifier::VerifyCallSite(CallSite CS) {
|
||||||
Assert1(isa<PointerType>(CI.getOperand(0)->getType()),
|
Instruction *I = CS.getInstruction();
|
||||||
"Called function must be a pointer!", &CI);
|
|
||||||
const PointerType *FPTy = cast<PointerType>(CI.getOperand(0)->getType());
|
Assert1(isa<PointerType>(CS.getCalledValue()->getType()),
|
||||||
|
"Called function must be a pointer!", I);
|
||||||
|
const PointerType *FPTy = cast<PointerType>(CS.getCalledValue()->getType());
|
||||||
Assert1(isa<FunctionType>(FPTy->getElementType()),
|
Assert1(isa<FunctionType>(FPTy->getElementType()),
|
||||||
"Called function is not pointer to function type!", &CI);
|
"Called function is not pointer to function type!", I);
|
||||||
|
|
||||||
const FunctionType *FTy = cast<FunctionType>(FPTy->getElementType());
|
const FunctionType *FTy = cast<FunctionType>(FPTy->getElementType());
|
||||||
|
|
||||||
// Verify that the correct number of arguments are being passed
|
// Verify that the correct number of arguments are being passed
|
||||||
if (FTy->isVarArg())
|
if (FTy->isVarArg())
|
||||||
Assert1(CI.getNumOperands()-1 >= FTy->getNumParams(),
|
Assert1(CS.arg_size() >= FTy->getNumParams(),
|
||||||
"Called function requires more parameters than were provided!",&CI);
|
"Called function requires more parameters than were provided!",I);
|
||||||
else
|
else
|
||||||
Assert1(CI.getNumOperands()-1 == FTy->getNumParams(),
|
Assert1(CS.arg_size() == FTy->getNumParams(),
|
||||||
"Incorrect number of arguments passed to called function!", &CI);
|
"Incorrect number of arguments passed to called function!", I);
|
||||||
|
|
||||||
// Verify that all arguments to the call match the function type...
|
// Verify that all arguments to the call match the function type...
|
||||||
for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i)
|
for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i)
|
||||||
Assert3(CI.getOperand(i+1)->getType() == FTy->getParamType(i),
|
Assert3(CS.getArgument(i)->getType() == FTy->getParamType(i),
|
||||||
"Call parameter type does not match function signature!",
|
"Call parameter type does not match function signature!",
|
||||||
CI.getOperand(i+1), FTy->getParamType(i), &CI);
|
CS.getArgument(i), FTy->getParamType(i), I);
|
||||||
|
|
||||||
|
// Verify call attributes.
|
||||||
|
VerifyParamAttrs(FTy, CS.getParamAttrs(), I);
|
||||||
|
|
||||||
|
visitInstruction(*I);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Verifier::visitCallInst(CallInst &CI) {
|
||||||
|
VerifyCallSite(&CI);
|
||||||
|
|
||||||
if (Function *F = CI.getCalledFunction()) {
|
if (Function *F = CI.getCalledFunction()) {
|
||||||
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
|
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
|
||||||
visitIntrinsicFunctionCall(ID, CI);
|
visitIntrinsicFunctionCall(ID, CI);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
visitInstruction(CI);
|
void Verifier::visitInvokeInst(InvokeInst &II) {
|
||||||
|
VerifyCallSite(&II);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// visitBinaryOperator - Check that both arguments to the binary operator are
|
/// visitBinaryOperator - Check that both arguments to the binary operator are
|
||||||
|
10
test/Verifier/2007-12-21-InvokeParamAttrs.ll
Normal file
10
test/Verifier/2007-12-21-InvokeParamAttrs.ll
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
; RUN: not llvm-as < %s
|
||||||
|
|
||||||
|
declare void @foo(i8*)
|
||||||
|
|
||||||
|
define void @bar() {
|
||||||
|
invoke void @foo(i8* signext null)
|
||||||
|
to label %r unwind label %r
|
||||||
|
r:
|
||||||
|
ret void
|
||||||
|
}
|
Reference in New Issue
Block a user