mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +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