diff options
| author | Pekka Enberg <penberg@kernel.org> | 2011-08-23 17:11:44 +0300 |
|---|---|---|
| committer | Pekka Enberg <penberg@kernel.org> | 2011-08-23 17:40:41 +0300 |
| commit | 45a6fbff825047582979c93ca363d8483122c3d5 (patch) | |
| tree | 278f064f2ba6b30991841ddab15c6596da0fb57b | |
| parent | cfcf8b5d5c1075c27ebb751946d1f19cdc77fe17 (diff) | |
| download | sparse-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-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 18 | ||||
| -rw-r--r-- | sparse-llvm.c | 185 | ||||
| -rwxr-xr-x | sparsec | 31 |
4 files changed, 234 insertions, 1 deletions
@@ -23,6 +23,7 @@ example test-unssa ctags c2xml +sparse-llvm # tags tags @@ -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 |
