aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPekka Enberg <penberg@kernel.org>2011-11-18 17:30:59 +0200
committerPekka Enberg <penberg@kernel.org>2011-11-19 10:46:31 +0200
commit064c4adfb5fdf0403614cb0a5a1a6373e88866b8 (patch)
treef6158cfe7604b01aae143e196881002094f1a9f6
parent6329d02b495b415dcac9f51300f7209a65ba80eb (diff)
downloadsparse-064c4adfb5fdf0403614cb0a5a1a6373e88866b8.tar.gz
sparse, llvm: Function pointer code generation
This patch implements support for function pointer types and function pointer calls to the LLVM backend. Cc: Christopher Li <sparse@chrisli.org> Cc: Jeff Garzik <jgarzik@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Pekka Enberg <penberg@kernel.org>
-rw-r--r--sparse-llvm.c54
-rw-r--r--validation/backend/function-ptr.c11
2 files changed, 63 insertions, 2 deletions
diff --git a/sparse-llvm.c b/sparse-llvm.c
index 7f46c8a2..c037e026 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -34,6 +34,46 @@ static inline bool symbol_is_fp_type(struct symbol *sym)
static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym);
+static LLVMTypeRef func_return_type(LLVMModuleRef module, struct symbol *sym)
+{
+ return symbol_type(module, sym->ctype.base_type);
+}
+
+static LLVMTypeRef sym_func_type(LLVMModuleRef module, struct symbol *sym)
+{
+ LLVMTypeRef *arg_type;
+ LLVMTypeRef func_type;
+ LLVMTypeRef ret_type;
+ struct symbol *arg;
+ int n_arg = 0;
+
+ /* to avoid strangeness with varargs [for now], we build
+ * the function and type anew, for each call. This
+ * is probably wrong. We should look up the
+ * symbol declaration info.
+ */
+
+ ret_type = func_return_type(module, sym);
+
+ /* count args, build argument type information */
+ FOR_EACH_PTR(sym->arguments, arg) {
+ n_arg++;
+ } END_FOR_EACH_PTR(arg);
+
+ arg_type = calloc(n_arg, sizeof(LLVMTypeRef));
+
+ int idx = 0;
+ FOR_EACH_PTR(sym->arguments, arg) {
+ struct symbol *arg_sym = arg->ctype.base_type;
+
+ arg_type[idx++] = symbol_type(module, arg_sym);
+ } END_FOR_EACH_PTR(arg);
+ func_type = LLVMFunctionType(ret_type, arg_type, n_arg,
+ /* varargs? */ 0);
+
+ return func_type;
+}
+
static LLVMTypeRef sym_array_type(LLVMModuleRef module, struct symbol *sym)
{
LLVMTypeRef elem_type;
@@ -172,6 +212,9 @@ static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym)
case SYM_ARRAY:
ret = sym_array_type(module, sym);
break;
+ case SYM_FN:
+ ret = sym_func_type(module, sym);
+ break;
default:
assert(0);
}
@@ -638,7 +681,10 @@ static LLVMTypeRef get_func_type(struct function *fn, struct instruction *insn)
int n_arg = 0;
LLVMTypeRef *arg_type;
- sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name);
+ if (sym->ident)
+ sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name);
+ else
+ sprintf(buffer, "<anon sym %p>", sym);
/* VERIFY: is this correct, for functions? */
func_type = LLVMGetTypeByName(fn->module, buffer);
@@ -682,7 +728,11 @@ static LLVMValueRef get_function(struct function *fn, struct instruction *insn)
LLVMValueRef func;
struct llfunc *f;
- sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name);
+ if (sym->ident)
+ sprintf(buffer, "%.*s", sym->ident->len, sym->ident->name);
+ else
+ sprintf(buffer, "<anon sym %p>", sym);
+
/* search for pre-built function type definition */
FOR_EACH_PTR(mi.llfunc_list, f) {
diff --git a/validation/backend/function-ptr.c b/validation/backend/function-ptr.c
new file mode 100644
index 00000000..fc022b3c
--- /dev/null
+++ b/validation/backend/function-ptr.c
@@ -0,0 +1,11 @@
+typedef int (*fn_t)(int x, int y);
+
+static int run(fn_t fn, int x, int y)
+{
+ return fn(x, y);
+}
+
+/*
+ * check-name: Function pointer code generation
+ * check-command: ./sparsec -c $file -o tmp.o
+ */