[PATCH] Varargs support for intrinsics.

Chris Lattner clattner at apple.com
Sat Oct 26 17:31:39 PDT 2013


On Oct 21, 2013, at 8:09 PM, Andrew Trick <atrick at apple.com> wrote:

> Hi lhames, ributzka, echristo,
> 
> Enable variables arguments support for intrinsics.

LGTM.

-Chris

> 
> http://llvm-reviews.chandlerc.com/D1992
> 
> Files:
>  include/llvm/IR/Intrinsics.h
>  lib/IR/Function.cpp
>  lib/IR/Verifier.cpp
>  test/TableGen/intrinsic-varargs.td
>  utils/TableGen/IntrinsicEmitter.cpp
> 
> Index: include/llvm/IR/Intrinsics.h
> ===================================================================
> --- include/llvm/IR/Intrinsics.h
> +++ include/llvm/IR/Intrinsics.h
> @@ -77,7 +77,7 @@
>   /// getIntrinsicInfoTableEntries.
>   struct IITDescriptor {
>     enum IITDescriptorKind {
> -      Void, MMX, Metadata, Half, Float, Double,
> +      Void, VarArg, MMX, Metadata, Half, Float, Double,
>       Integer, Vector, Pointer, Struct,
>       Argument, ExtendVecArgument, TruncVecArgument
>     } Kind;
> Index: lib/IR/Function.cpp
> ===================================================================
> --- lib/IR/Function.cpp
> +++ lib/IR/Function.cpp
> @@ -454,7 +454,8 @@
>   IIT_EXTEND_VEC_ARG = 23,
>   IIT_TRUNC_VEC_ARG = 24,
>   IIT_ANYPTR = 25,
> -  IIT_V1   = 26
> +  IIT_V1   = 26,
> +  IIT_VARARG = 27
> };
> 
> 
> @@ -468,6 +469,9 @@
>   case IIT_Done:
>     OutputTable.push_back(IITDescriptor::get(IITDescriptor::Void, 0));
>     return;
> +  case IIT_VARARG:
> +    OutputTable.push_back(IITDescriptor::get(IITDescriptor::VarArg, 0));
> +    return;
>   case IIT_MMX:
>     OutputTable.push_back(IITDescriptor::get(IITDescriptor::MMX, 0));
>     return;
> @@ -613,6 +617,7 @@
> 
>   switch (D.Kind) {
>   case IITDescriptor::Void: return Type::getVoidTy(Context);
> +  case IITDescriptor::VarArg: return Type::getVoidTy(Context);
>   case IITDescriptor::MMX: return Type::getX86_MMXTy(Context);
>   case IITDescriptor::Metadata: return Type::getMetadataTy(Context);
>   case IITDescriptor::Half: return Type::getHalfTy(Context);
> Index: lib/IR/Verifier.cpp
> ===================================================================
> --- lib/IR/Verifier.cpp
> +++ lib/IR/Verifier.cpp
> @@ -321,6 +321,8 @@
>     bool VerifyIntrinsicType(Type *Ty,
>                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
>                              SmallVectorImpl<Type*> &ArgTys);
> +    bool VerifyIntrinsicIsVarArg(bool isVarArg,
> +                                 ArrayRef<Intrinsic::IITDescriptor> &Infos);
>     bool VerifyAttributeCount(AttributeSet Attrs, unsigned Params);
>     void VerifyAttributeTypes(AttributeSet Attrs, unsigned Idx,
>                               bool isFunction, const Value *V);
> @@ -2135,6 +2137,7 @@
> 
>   switch (D.Kind) {
>   case IITDescriptor::Void: return !Ty->isVoidTy();
> +  case IITDescriptor::VarArg: return true;
>   case IITDescriptor::MMX:  return !Ty->isX86_MMXTy();
>   case IITDescriptor::Metadata: return !Ty->isMetadataTy();
>   case IITDescriptor::Half: return !Ty->isHalfTy();
> @@ -2199,6 +2202,33 @@
>   llvm_unreachable("unhandled");
> }
> 
> +/// \brief Verify if the intrinsic has variable arguments.
> +/// This method is intended to be called after all the fixed arguments have been
> +/// verified first.
> +///
> +/// This method returns true on error and does not print an error message.
> +bool
> +Verifier::VerifyIntrinsicIsVarArg(bool isVarArg,
> +                                  ArrayRef<Intrinsic::IITDescriptor> &Infos) {
> +  using namespace Intrinsic;
> +
> +  // If there are no descriptors left, then it can't be a vararg.
> +  if (Infos.empty())
> +    return isVarArg ? true : false;
> +
> +  // There should be only one descriptor remaining at this point.
> +  if (Infos.size() != 1)
> +    return true;
> +
> +  // Check and verify the descriptor.
> +  IITDescriptor D = Infos.front();
> +  Infos = Infos.slice(1);
> +  if (D.Kind == IITDescriptor::VarArg)
> +    return isVarArg ? false : true;
> +
> +  return true;
> +}
> +
> /// visitIntrinsicFunction - Allow intrinsics to be verified in different ways.
> ///
> void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
> @@ -2209,7 +2239,7 @@
>   // Verify that the intrinsic prototype lines up with what the .td files
>   // describe.
>   FunctionType *IFTy = IF->getFunctionType();
> -  Assert1(!IFTy->isVarArg(), "Intrinsic prototypes are not varargs", IF);
> +  bool IsVarArg = IFTy->isVarArg();
> 
>   SmallVector<Intrinsic::IITDescriptor, 8> Table;
>   getIntrinsicInfoTableEntries(ID, Table);
> @@ -2221,6 +2251,16 @@
>   for (unsigned i = 0, e = IFTy->getNumParams(); i != e; ++i)
>     Assert1(!VerifyIntrinsicType(IFTy->getParamType(i), TableRef, ArgTys),
>             "Intrinsic has incorrect argument type!", IF);
> +
> +  // Verify if the intrinsic call matches the vararg property.
> +  if (IsVarArg)
> +    Assert1(!VerifyIntrinsicIsVarArg(IsVarArg, TableRef),
> +            "Intrinsic was not defined with variable arguments!", IF);
> +  else
> +    Assert1(!VerifyIntrinsicIsVarArg(IsVarArg, TableRef),
> +            "Callsite was not defined with variable arguments!", IF);
> +
> +  // All descriptors should be absorbed by now.
>   Assert1(TableRef.empty(), "Intrinsic has too few arguments!", IF);
> 
>   // Now that we have the intrinsic ID and the actual argument types (and we
> Index: test/TableGen/intrinsic-varargs.td
> ===================================================================
> --- /dev/null
> +++ test/TableGen/intrinsic-varargs.td
> @@ -0,0 +1,29 @@
> +// RUN: llvm-tblgen -gen-intrinsic %s | FileCheck %s
> +
> +class IntrinsicProperty;
> +
> +class ValueType<int size, int value> {
> +  string Namespace = "MVT";
> +  int Size = size;
> +  int Value = value;
> +}
> +
> +class LLVMType<ValueType vt> {
> +  ValueType VT = vt;
> +}
> +
> +class Intrinsic<string name, list<LLVMType> param_types = []> {
> +  string LLVMName = name;
> +  bit isTarget = 0;
> +  string TargetPrefix = "";
> +  list<LLVMType> RetTypes = [];
> +  list<LLVMType> ParamTypes = param_types;
> +  list<IntrinsicProperty> Properties = [];
> +}
> +
> +// isVoid needs to match the definition in ValueTypes.td
> +def isVoid : ValueType<0, 56>;   // Produces no value
> +def llvm_vararg_ty : LLVMType<isVoid>;   // this means vararg here
> +
> +// CHECK: /* 0 */ 0, 27, 0,
> +def int_foo : Intrinsic<"llvm.foo", [llvm_vararg_ty]>;
> Index: utils/TableGen/IntrinsicEmitter.cpp
> ===================================================================
> --- utils/TableGen/IntrinsicEmitter.cpp
> +++ utils/TableGen/IntrinsicEmitter.cpp
> @@ -261,7 +261,8 @@
>   IIT_EXTEND_VEC_ARG = 23,
>   IIT_TRUNC_VEC_ARG = 24,
>   IIT_ANYPTR = 25,
> -  IIT_V1   = 26
> +  IIT_V1   = 26,
> +  IIT_VARARG = 27
> };
> 
> 
> @@ -288,6 +289,8 @@
>   case MVT::x86mmx: return Sig.push_back(IIT_MMX);
>   // MVT::OtherVT is used to mean the empty struct type here.
>   case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT);
> +  // MVT::isVoid is used to represent varargs here.
> +  case MVT::isVoid: return Sig.push_back(IIT_VARARG);
>   }
> }
> <D1992.1.patch>_______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list