Index: code/server/sv_client.c =================================================================== --- code/server/sv_client.c (revision 1508) +++ code/server/sv_client.c (working copy) @@ -1170,11 +1170,6 @@ if ( sv_pure->integer != 0 ) { bGood = qtrue; - nChkSum1 = nChkSum2 = 0; - // we run the game, so determine which cgame and ui the client "should" be running - bGood = (FS_FileIsInPAK("vm/cgame.qvm", &nChkSum1) == 1); - if (bGood) - bGood = (FS_FileIsInPAK("vm/ui.qvm", &nChkSum2) == 1); nClientPaks = Cmd_Argc(); @@ -1206,18 +1201,39 @@ bGood = qfalse; break; } + // verify first to be the cgame checksum pArg = Cmd_Argv(nCurArg++); - if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum1 ) { + if (!pArg || *pArg == '@') { bGood = qfalse; break; } + // we run the game, so determine which cgame the client "should" be running + nChkSum1 = atoi(pArg); + if (FS_FileIsInPAK("vm/cgame.qvm", &nChkSum2) != 1 || nChkSum2 != nChkSum1) { + // LLVM - if the client is not running QVM, it might still be running llvm. + if (FS_FileIsInPAK("cgamellvm.bc", &nChkSum2) != 1 || nChkSum2 != nChkSum1) { + bGood = qfalse; + break; + } + } + // verify the second to be the ui checksum pArg = Cmd_Argv(nCurArg++); - if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum2 ) { + if (!pArg || *pArg == '@') { bGood = qfalse; break; } + // we run the game, so determine which ui the client "should" be running + nChkSum1 = atoi(pArg); + if (FS_FileIsInPAK("vm/ui.qvm", &nChkSum2) != 1 || nChkSum2 != nChkSum1) { + // LLVM - if the client is not running QVM, it might still be running llvm. + if (FS_FileIsInPAK("uillvm.bc", &nChkSum2) != 1 || nChkSum2 != nChkSum1) { + bGood = qfalse; + break; + } + } + // should be sitting at the delimeter now pArg = Cmd_Argv(nCurArg++); if (*pArg != '@') { Index: code/server/sv_init.c =================================================================== --- code/server/sv_init.c (revision 1508) +++ code/server/sv_init.c (working copy) @@ -378,18 +378,22 @@ ================ SV_TouchCGame - touch the cgame.vm so that a pure client can load it if it's in a seperate pk3 + touch cgame so that a pure client can load it if it's in a seperate pk3 ================ */ void SV_TouchCGame(void) { fileHandle_t f; - char filename[MAX_QPATH]; - Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", "cgame" ); - FS_FOpenFileRead( filename, &f, qfalse ); + FS_FOpenFileRead( "vm/cgame.qvm", &f, qfalse ); if ( f ) { FS_FCloseFile( f ); } + + // LLVM - even if the server doesn't use llvm itself, it should still add the references. + FS_FOpenFileRead( "cgamellvm.bc", &f, qfalse ); + if ( f ) { + FS_FCloseFile( f ); + } } /* 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/files.c =================================================================== --- code/qcommon/files.c (revision 1508) +++ code/qcommon/files.c (working copy) @@ -1117,6 +1117,18 @@ pak->referenced |= FS_UI_REF; } + // LLVM - if we were asked to open an llvm, reference that. + // this assumes that we don't reference both, qvm AND llvm! + if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "qagamellvm.bc")) { + pak->referenced |= FS_QAGAME_REF; + } + if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgamellvm.bc")) { + pak->referenced |= FS_CGAME_REF; + } + if (!(pak->referenced & FS_UI_REF) && strstr(filename, "uillvm.bc")) { + pak->referenced |= FS_UI_REF; + } + if ( uniqueFILE ) { // open a new file on the pakfile fsh[*file].handleFiles.file.z = unzReOpen (pak->pakFilename, pak->handle); Index: code/qcommon/qcommon.h =================================================================== --- code/qcommon/qcommon.h (revision 1508) +++ code/qcommon/qcommon.h (working copy) @@ -338,7 +338,7 @@ void VM_Init( void ); vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret ); -// module should be bare: "cgame", not "cgame.dll" or "vm/cgame.qvm" +// module should be bare: "cgame", not "cgame.dll", "vm/cgame.qvm" or "cgamellvm.bc" void VM_Free( vm_t *vm ); void VM_Clear(void); 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,12 @@ vmHeader_t *header; // DLL's can't be restarted in place - if ( vm->dllHandle ) { + if ( vm->dllHandle +#if USE_LLVM + // llvm's neither, at least not for now + || vm->llvmModuleProvider +#endif + ) { char name[MAX_QPATH]; intptr_t (*systemCall)( intptr_t *parms ); @@ -562,10 +570,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 +662,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 +916,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 #############################################################################