aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorPekka Enberg <penberg@kernel.org>2011-08-23 17:11:44 +0300
committerPekka Enberg <penberg@kernel.org>2011-08-23 17:40:41 +0300
commit45a6fbff825047582979c93ca363d8483122c3d5 (patch)
tree278f064f2ba6b30991841ddab15c6596da0fb57b
parentcfcf8b5d5c1075c27ebb751946d1f19cdc77fe17 (diff)
downloadsparse-dev-45a6fbff825047582979c93ca363d8483122c3d5.tar.gz
sparse, llvm: Initial commit
This is the first commit to implementing a LLVM backend for sparse using the LLVM C bindings. Signed-off-by: Pekka Enberg <penberg@kernel.org>
-rw-r--r--.gitignore1
-rw-r--r--Makefile18
-rw-r--r--sparse-llvm.c185
-rwxr-xr-xsparsec31
4 files changed, 234 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index caee412c..bb33508a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ example
test-unssa
ctags
c2xml
+sparse-llvm
# tags
tags
diff --git a/Makefile b/Makefile
index ad86014a..31d8faa6 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ CC = gcc
CFLAGS = -O2 -finline-functions -fno-strict-aliasing -g
CFLAGS += -Wall -Wwrite-strings
LDFLAGS += -g
+LD = gcc
AR = ar
ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS)
@@ -21,6 +22,7 @@ HAVE_GCC_DEP:=$(shell touch .gcc-test.c && \
$(CC) -c -Wp,-MD,.gcc-test.d .gcc-test.c 2>/dev/null && \
echo 'yes'; rm -f .gcc-test.d .gcc-test.o .gcc-test.c)
HAVE_GTK2:=$(shell pkg-config --exists gtk+-2.0 2>/dev/null && echo 'yes')
+HAVE_LLVM:=$(shell llvm-config --version >/dev/null 2>&1 && echo 'yes')
GCC_BASE = $(shell $(CC) --print-file-name=)
BASIC_CFLAGS = -DGCC_BASE=\"$(GCC_BASE)\"
@@ -63,6 +65,20 @@ else
$(warning Your system does not have libgtk2, disabling test-inspect)
endif
+ifeq ($(HAVE_LLVM),yes)
+LD = g++
+LDFLAGS += $(shell llvm-config --ldflags)
+LLVM_CFLAGS := $(shell llvm-config --cflags)
+LLVM_LIBS := $(shell llvm-config --libs)
+PROGRAMS += sparse-llvm
+INST_PROGRAMS += sparse-llvm
+sparse-llvm_EXTRA_DEPS := sparse-llvm.o
+sparse-llvm.o $(sparse-llvm_EXTRA_DEPS): BASIC_CFLAGS += $(LLVM_CFLAGS)
+sparse-llvm_EXTRA_OBJS := $(LLVM_LIBS)
+else
+$(warning Your system does not have llvm, disabling sparse-llvm)
+endif
+
LIB_H= token.h parse.h lib.h symbol.h scope.h expression.h target.h \
linearize.h bitmap.h ident-list.h compat.h flow.h allocate.h \
storage.h ptrlist.h dissect.h
@@ -141,7 +157,7 @@ compile_EXTRA_DEPS = compile-i386.o
$(foreach p,$(PROGRAMS),$(eval $(p): $($(p)_EXTRA_DEPS) $(LIBS)))
$(PROGRAMS): % : %.o
- $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $^ $($@_EXTRA_OBJS)
+ $(QUIET_LINK)$(LD) $(LDFLAGS) -o $@ $^ $($@_EXTRA_OBJS)
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(AR) rcs $@ $(LIB_OBJS)
diff --git a/sparse-llvm.c b/sparse-llvm.c
new file mode 100644
index 00000000..792f8253
--- /dev/null
+++ b/sparse-llvm.c
@@ -0,0 +1,185 @@
+/*
+ * Example usage:
+ * ./sparse-llvm hello.c | llc | as -o hello.o
+ */
+
+#include <llvm-c/Core.h>
+#include <llvm-c/BitWriter.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "symbol.h"
+#include "expression.h"
+#include "linearize.h"
+#include "flow.h"
+
+static LLVMTypeRef symbol_type(struct symbol *sym)
+{
+ LLVMTypeRef ret = NULL;
+
+ switch (sym->bit_size) {
+ case -1:
+ ret = LLVMVoidType();
+ break;
+ case 8:
+ ret = LLVMInt8Type();
+ break;
+ case 16:
+ ret = LLVMInt16Type();
+ break;
+ case 32:
+ ret = LLVMInt32Type();
+ break;
+ case 64:
+ ret = LLVMInt64Type();
+ break;
+ default:
+ die("invalid bit size %d for type %d", sym->bit_size, sym->type);
+ break;
+ };
+
+ return ret;
+}
+
+static LLVMLinkage data_linkage(struct symbol *sym)
+{
+ if (sym->ctype.modifiers & MOD_STATIC)
+ return LLVMPrivateLinkage;
+
+ return LLVMCommonLinkage;
+}
+
+static LLVMLinkage function_linkage(struct symbol *sym)
+{
+ if (sym->ctype.modifiers & MOD_STATIC)
+ return LLVMInternalLinkage;
+
+ return LLVMExternalLinkage;
+}
+
+static void output_insn(struct instruction *insn)
+{
+}
+
+static void output_bb(struct basic_block *bb, unsigned long generation)
+{
+ struct instruction *insn;
+
+ bb->generation = generation;
+
+ FOR_EACH_PTR(bb->insns, insn) {
+ if (!insn->bb)
+ continue;
+
+ output_insn(insn);
+ }
+ END_FOR_EACH_PTR(insn);
+}
+
+#define MAX_ARGS 64
+
+static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
+{
+ unsigned long generation = ++bb_generation;
+ struct symbol *sym = ep->name;
+ struct symbol *base_type = sym->ctype.base_type;
+ struct symbol *ret_type = sym->ctype.base_type->ctype.base_type;
+ LLVMTypeRef arg_types[MAX_ARGS];
+ struct basic_block *bb;
+ LLVMValueRef function;
+ struct symbol *arg;
+ const char *name;
+ int nr_args = 0;
+
+ FOR_EACH_PTR(base_type->arguments, arg) {
+ struct symbol *arg_base_type = arg->ctype.base_type;
+
+ arg_types[nr_args++] = symbol_type(arg_base_type);
+ } END_FOR_EACH_PTR(arg);
+
+ name = show_ident(sym->ident);
+
+ function = LLVMAddFunction(module, name, LLVMFunctionType(symbol_type(ret_type), arg_types, nr_args, 0));
+
+ LLVMSetLinkage(function, function_linkage(sym));
+
+ unssa(ep);
+
+ FOR_EACH_PTR(ep->bbs, bb) {
+ if (bb->generation == generation)
+ continue;
+ output_bb(bb, generation);
+ }
+ END_FOR_EACH_PTR(bb);
+
+ LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
+
+ LLVMBuilderRef builder = LLVMCreateBuilder();
+
+ LLVMPositionBuilderAtEnd(builder, entry);
+
+ if (ret_type == &void_ctype)
+ LLVMBuildRetVoid(builder);
+ else
+ LLVMBuildRet(builder, LLVMConstInt(symbol_type(ret_type), 0, 1));
+}
+
+static int output_data(LLVMModuleRef module, struct symbol *sym)
+{
+ LLVMValueRef data;
+ const char *name;
+
+ name = show_ident(sym->ident);
+
+ data = LLVMAddGlobal(module, symbol_type(sym->ctype.base_type), name);
+
+ LLVMSetLinkage(data, data_linkage(sym));
+
+ LLVMSetInitializer(data, LLVMConstInt(symbol_type(sym), 0, 1));
+
+ return 0;
+}
+
+static int compile(LLVMModuleRef module, struct symbol_list *list)
+{
+ struct symbol *sym;
+
+ FOR_EACH_PTR(list, sym) {
+ struct entrypoint *ep;
+ expand_symbol(sym);
+ ep = linearize_symbol(sym);
+ if (ep)
+ output_fn(module, ep);
+ else
+ output_data(module, sym);
+ }
+ END_FOR_EACH_PTR(sym);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct string_list * filelist = NULL;
+ char *file;
+
+ LLVMModuleRef module = LLVMModuleCreateWithName("sparse");
+
+ compile(module, sparse_initialize(argc, argv, &filelist));
+
+ FOR_EACH_PTR_NOTAG(filelist, file) {
+ compile(module, sparse(file));
+ } END_FOR_EACH_PTR_NOTAG(file);
+
+#if 1
+ LLVMWriteBitcodeToFD(module, STDOUT_FILENO, 0, 0);
+#else
+ LLVMDumpModule(module);
+#endif
+
+ LLVMDisposeModule(module);
+
+ return 0;
+}
diff --git a/sparsec b/sparsec
new file mode 100755
index 00000000..5ae4bb8d
--- /dev/null
+++ b/sparsec
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# GCC compatible C compiler based on Sparse LLVM
+
+SPARSEOPTS=""
+ASOPTS=""
+DIRNAME=`dirname $0`
+
+use_gcc=1
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ '-o')
+ ASOPTS=$ASOPTS"-o "$2" "
+ shift
+ ;;
+ '-c')
+ use_gcc=0
+ ;;
+ *)
+ SPARSEOPTS="$SPARSEOPTS $1 " ;;
+ esac
+ shift
+done
+
+if [ $use_gcc -eq 1 ]; then
+ gcc $ASOPTS $SPARSEOPTS
+
+else
+ sparse-llvm $SPARSEOPTS | llc | as $ASOPTS
+fi