[LLVMdev] automatically generating intrinsic declarations
Dan Gohman
djg at cray.com
Tue Feb 6 06:41:28 PST 2007
On Mon, Feb 05, 2007 at 12:28:56PM -0800, Chris Lattner wrote:
> On Mon, 5 Feb 2007, Dan Gohman wrote:
>
> > LLVM knows what all the types of the intrinsic functions are; I thought,
> > why are users (including llvm-gcc...) required to duplicate all this
> > information in order to use them? I mean in order to call
> > getOrInsertFunction to get declarations for them.
>
> That is an excellent question! :) In the bad old days, we used to allow
> intrinsics with slightly different types (e.g. http://llvm.org/PR1093).
> Because of this, we didn't know what type to create them as.
>
> Fortunately however, this misguided past is all behind us now, and there
> is no longer a reason to not have this facility.
It appears there is at least one more. The llvm.gcroot intrinsic is documented
as having generic argument types.
> > So I wrote this patch, which allows all this code to be generated
> > automatically. Is this a good approach?
>
> This looks great, but appears to be missing the API that wraps the
> generated piece of Intrinsics.gen. If you send it as well, I'd be happy
> to commit it for you. Is there also a piece that switches llvm-gcc over
> to use this? :)
Attached is a patch that includes the API bits.
I also noticed that my earlier patch didn't handle pointer types, so I fixed
that, and in doing so I noticed that the types for va_start, va_end, va_copy,
and dbg.declare were apparently wrong, so I fixed those too.
However, gcroot does currently come out as void @llvm.gcroot(i8**, i8*).
Dan
--
Dan Gohman, Cray Inc. <djg at cray.com>
-------------- next part --------------
Index: include/llvm/Intrinsics.h
===================================================================
RCS file: /var/cvs/llvm/llvm/include/llvm/Intrinsics.h,v
retrieving revision 1.40
diff -u -r1.40 Intrinsics.h
--- include/llvm/Intrinsics.h
+++ include/llvm/Intrinsics.h
@@ -18,6 +18,9 @@
namespace llvm {
+class Constant;
+class Module;
+
/// Intrinsic Namespace - This namespace contains an enum with a value for
/// every intrinsic/builtin function known by LLVM. These enum values are
/// returned by Function::getIntrinsicID().
@@ -36,6 +39,10 @@
/// Intrinsic::getName(ID) - Return the LLVM name for an intrinsic, such as
/// "llvm.ppc.altivec.lvx".
const char *getName(ID id);
+
+ /// Intrinsic::getDeclaration(M, ID) - Create or insert an LLVM Function
+ /// declaration for an intrinsic, and return it.
+ Constant *getDeclaration(Module *M, ID id);
} // End Intrinsic namespace
} // End llvm namespace
Index: include/llvm/Intrinsics.td
===================================================================
RCS file: /var/cvs/llvm/llvm/include/llvm/Intrinsics.td,v
retrieving revision 1.41
diff -u -r1.41 Intrinsics.td
--- include/llvm/Intrinsics.td
+++ include/llvm/Intrinsics.td
@@ -68,6 +68,15 @@
LLVMType ElTy = elty;
}
+class LLVMPointerType<LLVMType elty>
+ : LLVMType<iPTR, "Type::PointerTyID">{
+ LLVMType ElTy = elty;
+}
+
+class LLVMEmptyStructType
+ : LLVMType<OtherVT, "Type::StructTyID">{
+}
+
def llvm_void_ty : LLVMType<isVoid, "Type::VoidTyID">;
def llvm_bool_ty : LLVMIntegerType<i1, 1>;
def llvm_i8_ty : LLVMIntegerType<i8 , 8>;
@@ -76,9 +85,10 @@
def llvm_i64_ty : LLVMIntegerType<i64, 64>;
def llvm_float_ty : LLVMType<f32, "Type::FloatTyID">;
def llvm_double_ty : LLVMType<f64, "Type::DoubleTyID">;
-def llvm_ptr_ty : LLVMType<iPTR, "Type::PointerTyID">; // i8*
-def llvm_ptrptr_ty : LLVMType<iPTR, "Type::PointerTyID">; // i8**
-def llvm_descriptor_ty : LLVMType<iPTR, "Type::PointerTyID">; // global*
+def llvm_ptr_ty : LLVMPointerType<llvm_i8_ty>; // i8*
+def llvm_ptrptr_ty : LLVMPointerType<llvm_ptr_ty>; // i8**
+def llvm_empty_ty : LLVMEmptyStructType; // { }
+def llvm_descriptor_ty : LLVMPointerType<llvm_empty_ty>; // { }*
def llvm_v16i8_ty : LLVMPackedType<v16i8,16, llvm_i8_ty>; // 16 x i8
def llvm_v8i16_ty : LLVMPackedType<v8i16, 8, llvm_i16_ty>; // 8 x i16
@@ -121,10 +131,10 @@
//===--------------- Variable Argument Handling Intrinsics ----------------===//
//
-def int_vastart : Intrinsic<[llvm_void_ty, llvm_ptrptr_ty], [], "llvm.va_start">;
-def int_vacopy : Intrinsic<[llvm_void_ty, llvm_ptrptr_ty, llvm_ptrptr_ty], [],
+def int_vastart : Intrinsic<[llvm_void_ty, llvm_ptr_ty], [], "llvm.va_start">;
+def int_vacopy : Intrinsic<[llvm_void_ty, llvm_ptr_ty, llvm_ptr_ty], [],
"llvm.va_copy">;
-def int_vaend : Intrinsic<[llvm_void_ty, llvm_ptrptr_ty], [], "llvm.va_end">;
+def int_vaend : Intrinsic<[llvm_void_ty, llvm_ptr_ty], [], "llvm.va_end">;
//===------------------- Garbage Collection Intrinsics --------------------===//
//
@@ -214,7 +224,7 @@
def int_dbg_region_start : Intrinsic<[llvm_void_ty, llvm_descriptor_ty]>;
def int_dbg_region_end : Intrinsic<[llvm_void_ty, llvm_descriptor_ty]>;
def int_dbg_func_start : Intrinsic<[llvm_void_ty, llvm_descriptor_ty]>;
-def int_dbg_declare : Intrinsic<[llvm_void_ty, llvm_ptr_ty,
+def int_dbg_declare : Intrinsic<[llvm_void_ty, llvm_descriptor_ty,
llvm_descriptor_ty]>;
//===----------------------------------------------------------------------===//
Index: lib/VMCore/Function.cpp
===================================================================
RCS file: /var/cvs/llvm/llvm/lib/VMCore/Function.cpp,v
retrieving revision 1.111
diff -u -r1.111 Function.cpp
--- lib/VMCore/Function.cpp
+++ lib/VMCore/Function.cpp
@@ -183,6 +183,12 @@
return Table[id];
}
+Constant *Intrinsic::getDeclaration(Module *M, ID id) {
+#define GET_INTRINSIC_GENERATOR
+#include "llvm/Intrinsics.gen"
+#undef GET_INTRINSIC_GENERATOR
+}
+
Value *IntrinsicInst::StripPointerCasts(Value *Ptr) {
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr)) {
if (CE->getOpcode() == Instruction::BitCast) {
Index: utils/TableGen/IntrinsicEmitter.cpp
===================================================================
RCS file: /var/cvs/llvm/llvm/utils/TableGen/IntrinsicEmitter.cpp,v
retrieving revision 1.22
diff -u -r1.22 IntrinsicEmitter.cpp
--- utils/TableGen/IntrinsicEmitter.cpp
+++ utils/TableGen/IntrinsicEmitter.cpp
@@ -38,6 +38,9 @@
// Emit the intrinsic verifier.
EmitVerifier(Ints, OS);
+ // Emit the intrinsic declaration generator.
+ EmitGenerator(Ints, OS);
+
// Emit mod/ref info for each function.
EmitModRefInfo(Ints, OS);
@@ -121,6 +124,25 @@
}
}
+static void EmitTypeGenerate(std::ostream &OS, Record *ArgType) {
+ if (ArgType->isSubClassOf("LLVMIntegerType")) {
+ OS << "IntegerType::get(" << ArgType->getValueAsInt("Width") << ")";
+ } else if (ArgType->isSubClassOf("LLVMPackedType")) {
+ OS << "PackedType::get(";
+ EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"));
+ OS << ", " << ArgType->getValueAsInt("NumElts") << ")";
+ } else if (ArgType->isSubClassOf("LLVMPointerType")) {
+ OS << "PointerType::get(";
+ EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"));
+ OS << ")";
+ } else if (ArgType->isSubClassOf("LLVMEmptyStructType")) {
+ OS << "StructType::get(std::vector<const Type *>())";
+ } else {
+ OS << "Type::getPrimitiveType(";
+ OS << ArgType->getValueAsString("TypeVal") << ")";
+ }
+}
+
/// RecordListComparator - Provide a determinstic comparator for lists of
/// records.
namespace {
@@ -176,6 +198,43 @@
OS << "#endif\n\n";
}
+void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS) {
+ OS << "// Code for generating Intrinsic function declarations.\n";
+ OS << "#ifdef GET_INTRINSIC_GENERATOR\n";
+ OS << " switch (id) {\n";
+ OS << " default: assert(0 && \"Invalid intrinsic!\");\n";
+
+ // Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical
+ // types.
+ typedef std::map<std::vector<Record*>, std::vector<unsigned>,
+ RecordListComparator> MapTy;
+ MapTy UniqueArgInfos;
+
+ // Compute the unique argument type info.
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i)
+ UniqueArgInfos[Ints[i].ArgTypeDefs].push_back(i);
+
+ // Loop through the array, emitting one generator for each batch.
+ for (MapTy::iterator I = UniqueArgInfos.begin(),
+ E = UniqueArgInfos.end(); I != E; ++I) {
+ for (unsigned i = 0, e = I->second.size(); i != e; ++i) {
+ OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// "
+ << Ints[I->second[i]].Name << "\n";
+ }
+
+ const std::vector<Record*> &ArgTypes = I->first;
+ OS << " return M->getOrInsertFunction(Intrinsic::getName(id), ";
+ for (unsigned j = 0; j != ArgTypes.size(); ++j) {
+ EmitTypeGenerate(OS, ArgTypes[j]);
+ OS << ", ";
+ }
+ OS << "NULL);\n";
+ }
+ OS << " }\n";
+ OS << "#endif\n\n";
+}
+
void IntrinsicEmitter::EmitModRefInfo(const std::vector<CodeGenIntrinsic> &Ints,
std::ostream &OS) {
OS << "// BasicAliasAnalysis code.\n";
Index: utils/TableGen/IntrinsicEmitter.h
===================================================================
RCS file: /var/cvs/llvm/llvm/utils/TableGen/IntrinsicEmitter.h,v
retrieving revision 1.9
diff -u -r1.9 IntrinsicEmitter.h
--- utils/TableGen/IntrinsicEmitter.h
+++ utils/TableGen/IntrinsicEmitter.h
@@ -35,6 +35,8 @@
std::ostream &OS);
void EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
std::ostream &OS);
+ void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+ std::ostream &OS);
void EmitModRefInfo(const std::vector<CodeGenIntrinsic> &Ints,
std::ostream &OS);
void EmitNoMemoryInfo(const std::vector<CodeGenIntrinsic> &Ints,
More information about the llvm-dev
mailing list