ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
How to implement a just in time compiler for ETISS

ETISS comes with two implementations of the etiss::JIT just in time compiler interface.

Please refer to the GCC based implementation in JITImpl/GCC/ for a simple example.

Implementing etiss::JIT can be very simple. The just in timer compilation relies on two steps. The first one is to compile a passed string of code and return some sort of pointer to identify the compilation result and the second one is to get a function pointer from the compiled code pointer.

For simplification the implementation name in this guide will be referred to as X.

Step 1: Create a workfolder and necessary files

First of all a directory should be created. It is recommended to create a folder in JITImpl with the name of the implementation (analogue to JITImpl/GCC/: JITImpl/X/)

For the following steps a header and source file for the etiss::JIT implementation and a source file containing an interface for etiss are needed. The following empty files should be created in your JITImpl/X/ folder:

		XJIT.h
		XJIT.cpp
		XJITLib.cpp
		Makefile
	

Step2 : Implement etiss::JIT

To allow compilation of C code etiss::JIT needs to be implemented.

The implementation should be done in XJIT.h/.cpp.

XJIT.h:

#include "etiss/JIT.h"
class XJIT : public etiss::JIT {
public :
XJIT();
virtual void * translate(std::string code,std::set<std::string> headerpaths,std::set<std::string> librarypaths,std::set<std::string> libraries,std::string & error,bool debug= false);
virtual void * getFunction(void * handle,std::string name,std::string & error);
virtual void free(void * handle);
};
JIT compiler interface definition.
compiler interface for just in time compilation of generated C code
Definition: JIT.h:67
virtual void * translate(std::string code, std::set< std::string > headerpaths, std::set< std::string > librarypaths, std::set< std::string > libraries, std::string &error, bool debug=true)=0
translate C code to executable code and return a handle/pointer that identifies the compilation resul...
virtual void * getFunction(void *handle, std::string name, std::string &error)=0
returns a function pointer to a compiled function from the handle returned by etiss::JIT::translate
virtual void free(void *handle)=0
clean up handled returned by etiss::JIT::translate

XJIT.cpp:

#include "XJIT.h"
XJIT::XJIT() : JIT("X"){}
void * XJIT::translate(std::string code,std::set<std::string> headerpaths,std::set<std::string> librarypaths,std::set<std::string> libraries,std::string & error,bool debug){
//TODO
// compile code
// return some kind of handle
// EXAMPLE:
//write code to file
//compile file as dynamic library using headerpaths and librarypaths for dependencies
//if (compilation successfull){
//open and return compiled library
//return (void*) dlopen("COMPILED DYNAMIC LIBRARY",0);
//} else {
//error = "FAILED";
//return 0;
//}
}
void * XJIT::getFunction(void * handle,std::string name,std::string & error){
//TODO
// extract a function from the passed handle
// return function pointer
// in case of a handle from above example the handle can be used by dlsym
// EXAMPLE:
//return dlsym(handle,name.c_str());
}
void XJIT::free(void * handle){
//TODO
// cleanup resources associated with the handle from the translate(...) function
// in case of a handle from above example
// EXAMPLE:
//dlclose(handle);
}
PUGI__FN void translate(char_t *buffer, const char_t *from, const char_t *to)
Definition: pugixml.cpp:7504

Step 3: Implement the loading interface

ETISS preferably loads a compiler as a dynamic library at runtime. To do this it is necessary to implement some functions to find the JIT implementation(s).

XJITLib.cpp:

// define a name for this library. this will be used to avoid name clashes with other libraries. in this example the library is named "X".
// IMPORTANT this name MUST match the library name: e.g. X -> libX.so
#define ETISS_LIBNAME X
#include "etiss/helper/JITLibrary.h" // defines the following functions
#include "etiss/Version.h"
#include "XJIT.h"
extern "C"{
unsigned X_etissversion(){
return ETISS_LIBRARYIF_VERSION;
}
unsigned X_countJIT(){
//TODO
return 1; // number of implementations provided
}
const char * X_nameJIT(unsigned index){
//TODO
switch (index){
case 0:
return "X";
default:
return "";
}
}
etiss::JIT * X_createJIT(unsigned index,std::map<std::string,std::string> options){
//TODO
switch (index){
case 0:
// parse arguments?
return new XJIT();
default:
return 0;
}
}
void X_deleteJIT(etiss::JIT* arch){
delete arch;
}
}
ETISS_PLUGIN_EXPORT etiss::CPUArch std::map< std::string, std::string > options
create new instance of the CPUArch type at index
defines the functions needed for a library that provides etiss::JIT implementations

Step 4: Build and run the Library

Finally a makefile is needed to build the new library with the X compiler implementation as a dynamic library

Makefile

DEBUG?=1
CC=gcc
ifeq ($(DEBUG),0)
DBGPARAM =
OPTLEVEL?=-O3
else
DBGPARAM =-g
OPTLEVEL?=
endif
ETISS_FOLDER=../..
CFLAGS=-std=c++0x -c -MMD -Wall -Werror -fPIC $(OPTLEVEL) $(DBGPARAM) -DDEBUG=$(DEBUG) -I$(ETISS_FOLDER)/include -I$(ETISS_FOLDER)/include_c
all : libX.so
XJIT.o : XJIT.cpp
$(CC) $(CFLAGS) XJIT.cpp
XJITLib.o: XJITLib.cpp
$(CC) $(CFLAGS) XJITLib.cpp
-include ./*.d
libX.so : XJIT.o XJITLib.o
$(CC) -std=c++0x -shared -g -L$(ETISS_FOLDER) -dl -o libX.so XJIT.o XJITLib.o
clean :
rm -f *o
rm -f libX.so
__device__ __2f16 float c
uint32_t I
Definition: Instruction.h:80
int __ovld __cnfn all(char x)
Returns 1 if the most significant bit in all components of x is set; otherwise returns 0.

Once the dynamic library was build it is available in ETISS by default if placed in JITImpl/X/ or can be loaded with void etiss::loadLibrary(std::string path,std::string name). Use etiss::listLibraries() and etiss::listCPUArchs() to view the status of loaded libraries.

Refer to Removing symbols from a shared library once the api of the new library is out of it's testing state or runtime linkage errors arise.