Index: code/qcommon/vm_local.h =================================================================== --- code/qcommon/vm_local.h (revision 1508) +++ code/qcommon/vm_local.h (working copy) @@ -138,6 +138,11 @@ intptr_t (QDECL *entryPoint)( int callNum, ... ); void (*destroy)(vm_t* self); +#if USE_LLVM + // for llvm modules + void *llvmModuleProvider; +#endif // USE_LLVM + // for interpreted modules qboolean currentlyInterpreting; Index: code/qcommon/vm_llvm.cpp =================================================================== --- code/qcommon/vm_llvm.cpp (revision 0) +++ code/qcommon/vm_llvm.cpp (revision 0) @@ -0,0 +1,104 @@ +#ifdef __cplusplus +extern "C" { +#endif +#include "vm_local.h" +#ifdef __cplusplus +} +#endif + +#include "vm_llvm.h" + +#define __STDC_CONSTANT_MACROS +#define __STDC_LIMIT_MACROS +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +#ifdef __cplusplus +extern "C" { +#endif + +static ExecutionEngine *engine = NULL; + +void *VM_LoadLLVM( vm_t *vm, intptr_t (*systemcalls)(intptr_t, ...) ) { + char name[MAX_QPATH]; + char filename[MAX_QPATH]; + int len; + char *bytes; + std::string error; + + COM_StripExtension( vm->name, name, sizeof(name) ); + Com_sprintf( filename, sizeof(filename), "%sllvm.bc", name ); + len = FS_ReadFile( filename, (void **)&bytes ); + + if ( !bytes ) { + Com_Printf( "Couldn't load llvm file: %s\n", filename ); + return NULL; + } + + MemoryBuffer *buffer = MemoryBuffer::getMemBuffer( bytes, bytes + len ); + Module *module = ParseBitcodeFile( buffer, &error ); + delete buffer; + FS_FreeFile( bytes ); + + if ( !module ) { + Com_Printf( "Couldn't parse llvm file: %s: %s\n", filename, error.c_str() ); + return NULL; + } + + PassManager p; + p.add( new TargetData( module ) ); + p.add( createFunctionInliningPass() ); + p.run( *module ); + + ExistingModuleProvider *mp = new ExistingModuleProvider( module ); + if ( !engine ) { + engine = ExecutionEngine::create( mp ); + } else { + engine->addModuleProvider( mp ); + } + + Function *func = module->getFunction( std::string("dllEntry") ); + void (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) ) = (void (*)(intptr_t (*syscallptr)(intptr_t, ...)))engine->getPointerToFunction( func ); + dllEntry( systemcalls ); + + func = module->getFunction( std::string("vmMain") ); + intptr_t(*fp)(int, ...) = (intptr_t(*)(int, ...))engine->getPointerToFunction( func ); + + vm->entryPoint = fp; + + if ( com_developer->integer ) { + Com_Printf("Loaded LLVM %s with mp==%p\n", name, mp); + } + + return mp; +} + +void VM_UnloadLLVM( void *llvmModuleProvider ) { + if ( !llvmModuleProvider ) { + Com_Printf( "VM_UnloadLLVM called with NULL pointer\n" ); + return; + } + + if ( com_developer->integer ) { + Com_Printf( "Unloading LLVM with mp==%p\n", llvmModuleProvider ); + } + + Module *module = engine->removeModuleProvider( (ExistingModuleProvider *)llvmModuleProvider ); + if ( !module ) { + Com_Printf( "Couldn't remove llvm\n" ); + return; + } + delete module; +} + +#ifdef __cplusplus +} +#endif Index: code/qcommon/vm_llvm.h =================================================================== --- code/qcommon/vm_llvm.h (revision 0) +++ code/qcommon/vm_llvm.h (revision 0) @@ -0,0 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif + +void *VM_LoadLLVM( vm_t *vm, intptr_t (*systemcalls)(intptr_t, ...) ); +void VM_UnloadLLVM( void *llvmModuleProvider ); + +#ifdef __cplusplus +} +#endif Index: code/qcommon/vm.c =================================================================== --- code/qcommon/vm.c (revision 1508) +++ code/qcommon/vm.c (working copy) @@ -35,6 +35,9 @@ #include "vm_local.h" +#if USE_LLVM +#include "vm_llvm.h" +#endif // USE_LLVM vm_t *currentVM = NULL; vm_t *lastVM = NULL; @@ -480,7 +483,11 @@ vmHeader_t *header; // DLL's can't be restarted in place - if ( vm->dllHandle ) { + if ( vm->dllHandle +#if USE_LLVM + || vm->llvmModuleProvider +#endif + ) { char name[MAX_QPATH]; intptr_t (*systemCall)( intptr_t *parms ); @@ -562,10 +569,25 @@ return vm; } +#if USE_LLVM + Com_Printf( "Failed to load dll, looking for llvm.\n" ); +#else Com_Printf( "Failed to load dll, looking for qvm.\n" ); +#endif // USE_LLVM interpret = VMI_COMPILED; } +#if USE_LLVM + // try to load the LLVM + Com_Printf( "Loading llvm file %s.\n", vm->name ); + vm->llvmModuleProvider = VM_LoadLLVM( vm, VM_DllSyscall ); + if ( vm->llvmModuleProvider ) { + return vm; + } + + Com_Printf( "Failed to load llvm, looking for qvm.\n" ); +#endif // USE_LLVM + // load the image if( !( header = VM_LoadQVM( vm, qtrue ) ) ) { return NULL; @@ -639,6 +661,14 @@ Sys_UnloadDll( vm->dllHandle ); Com_Memset( vm, 0, sizeof( *vm ) ); } + +#if USE_LLVM + if (vm->llvmModuleProvider ) { + VM_UnloadLLVM( vm->llvmModuleProvider ); + Com_Memset( vm, 0, sizeof( *vm ) ); + } +#endif + #if 0 // now automatically freed by hunk if ( vm->codeBase ) { Z_Free( vm->codeBase ); @@ -885,6 +915,12 @@ Com_Printf( "native\n" ); continue; } +#if USE_LLVM + if ( vm->llvmModuleProvider ) { + Com_Printf( "llvm\n" ); + continue; + } +#endif // USE_LLVM if ( vm->compiled ) { Com_Printf( "compiled on load\n" ); } else { Index: Makefile =================================================================== --- Makefile (revision 1508) +++ Makefile (working copy) @@ -143,6 +143,10 @@ USE_INTERNAL_SPEEX=1 endif +ifndef USE_LLVM +USE_LLVM=0 +endif + ifndef USE_LOCAL_HEADERS USE_LOCAL_HEADERS=1 endif @@ -208,6 +212,11 @@ endif endif +ifeq ($(USE_LLVM),1) +LD=$(CXX) +else +LD=$(CC) +endif ############################################################################# # SETUP AND BUILD -- LINUX @@ -258,6 +267,10 @@ BASE_CFLAGS += -DUSE_CODEC_VORBIS endif + ifeq ($(USE_LLVM),1) + BASE_CFLAGS += -DUSE_LLVM + endif + OPTIMIZE = -O3 -ffast-math -funroll-loops -fomit-frame-pointer ifeq ($(ARCH),x86_64) @@ -321,7 +334,11 @@ CLIENT_LIBS += -lrt endif -ifeq ($(USE_LOCAL_HEADERS),1) + ifeq ($(USE_LLVM),1) + LIBS += $(shell llvm-config --libs) -pthread + endif + + ifeq ($(USE_LOCAL_HEADERS),1) BASE_CFLAGS += -I$(SDLHDIR)/include endif @@ -764,6 +781,33 @@ else # ifeq sunos ############################################################################# +# SETUP AND BUILD -- LLVM +############################################################################# + +ifeq ($(PLATFORM),llvm) + + CC=llvm-gcc + LD=llvm-link + ARCH=llvm + + HAVE_VM_COMPILED=true + + BASE_CFLAGS += -emit-llvm + DEBUG_CFLAGS = $(BASE_CFLAGS) -O0 + RELEASE_CFLAGS = $(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE) + + LDFLAGS= + SHLIBEXT=bc + SHLIBLDFLAGS=$(LDFLAGS) + + BUILD_CLIENT = 0 + BUILD_CLIENT_SMP = 0 + BUILD_SERVER = 0 + BUILD_GAME_QVM = 0 + +else # ifeq llvm + +############################################################################# # SETUP AND BUILD -- GENERIC ############################################################################# BASE_CFLAGS=-DNO_VM_COMPILED @@ -782,6 +826,7 @@ endif #NetBSD endif #IRIX endif #SunOS +endif #LLVM TARGETS = @@ -870,6 +915,11 @@ $(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $< endef +define DO_CXX +$(echo_cmd) "CXX $<" +$(Q)$(CXX) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $< +endef + define DO_SMP_CC $(echo_cmd) "SMP_CC $<" $(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DSMP -o $@ -c $< @@ -942,6 +992,11 @@ $(Q)$(CC) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) -o $@ -c $< endef +define DO_DED_CXX +$(echo_cmd) "DED_CXX $<" +$(Q)$(CXX) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) -o $@ -c $< +endef + define DO_WINDRES $(echo_cmd) "WINDRES $<" $(Q)$(WINDRES) -i $< -o $@ @@ -974,6 +1029,8 @@ @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)" @echo " COMPILE_ARCH: $(COMPILE_ARCH)" @echo " CC: $(CC)" + @echo " CXX: $(CXX)" + @echo " LD: $(LD)" @echo "" @echo " CFLAGS:" -@for i in $(CFLAGS); \ @@ -1431,6 +1488,9 @@ endif endif +ifeq ($(USE_LLVM),1) + Q3OBJ += $(B)/client/vm_llvm.o +endif ifeq ($(HAVE_VM_COMPILED),true) ifeq ($(ARCH),i386) @@ -1475,13 +1535,13 @@ $(B)/ioquake3.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ + $(Q)$(LD) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ -o $@ $(Q3OBJ) $(Q3POBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS) $(B)/ioquake3-smp.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \ + $(Q)$(LD) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \ -o $@ $(Q3OBJ) $(Q3POBJ_SMP) \ $(THREAD_LIBS) $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS) @@ -1581,6 +1641,10 @@ $(B)/ded/matha.o endif +ifeq ($(USE_LLVM),1) + Q3DOBJ += $(B)/ded/vm_llvm.o +endif + ifeq ($(HAVE_VM_COMPILED),true) ifeq ($(ARCH),i386) Q3DOBJ += $(B)/ded/vm_x86.o @@ -1615,7 +1679,7 @@ $(B)/ioq3ded.$(ARCH)$(BINEXT): $(Q3DOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS) + $(Q)$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS) @@ -1655,7 +1719,7 @@ $(B)/baseq3/cgame$(ARCH).$(SHLIBEXT): $(Q3CGOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ) + $(Q)$(LD) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ) $(B)/baseq3/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM) $(echo_cmd) "Q3ASM $@" @@ -1699,7 +1763,7 @@ $(B)/missionpack/cgame$(ARCH).$(SHLIBEXT): $(MPCGOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ) + $(Q)$(LD) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ) $(B)/missionpack/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM) $(echo_cmd) "Q3ASM $@" @@ -1752,7 +1816,7 @@ $(B)/baseq3/qagame$(ARCH).$(SHLIBEXT): $(Q3GOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ) + $(Q)$(LD) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ) $(B)/baseq3/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM) $(echo_cmd) "Q3ASM $@" @@ -1803,7 +1867,7 @@ $(B)/missionpack/qagame$(ARCH).$(SHLIBEXT): $(MPGOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ) + $(Q)$(LD) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ) $(B)/missionpack/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM) $(echo_cmd) "Q3ASM $@" @@ -1866,7 +1930,7 @@ $(B)/baseq3/ui$(ARCH).$(SHLIBEXT): $(Q3UIOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ) + $(Q)$(LD) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ) $(B)/baseq3/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM) $(echo_cmd) "Q3ASM $@" @@ -1894,7 +1958,7 @@ $(B)/missionpack/ui$(ARCH).$(SHLIBEXT): $(MPUIOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPUIOBJ) + $(Q)$(LD) $(SHLIBLDFLAGS) -o $@ $(MPUIOBJ) $(B)/missionpack/vm/ui.qvm: $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM) $(echo_cmd) "Q3ASM $@" @@ -1942,7 +2006,10 @@ $(B)/client/%.o: $(SYSDIR)/%.rc $(DO_WINDRES) +$(B)/client/vm_llvm.o: $(CMDIR)/vm_llvm.cpp + $(DO_CXX) + $(B)/ded/%.o: $(ASMDIR)/%.s $(DO_AS) @@ -1964,6 +2031,9 @@ $(B)/ded/%.o: $(NDIR)/%.c $(DO_DED_CC) +$(B)/ded/vm_llvm.o: $(CMDIR)/vm_llvm.cpp + $(DO_DED_CXX) + # Extra dependencies to ensure the SVN version is incorporated ifeq ($(USE_SVN),1) $(B)/client/cl_console.o : .svn/entries @@ -1972,6 +2042,8 @@ endif +$(CMDIR)/vm_llvm.c: + ############################################################################# ## GAME MODULE RULES #############################################################################