/* example specifications file */ // put inside any statement you want to see at the top of the generated .h // file for the class extern { // this structure represents all the registers our imaginary platform has struct registers { int accumulator; }; } // the functions generated from this will require a register* argument ImaginaryPlatformRecompiler = (registers* regs) { // it will be possible to generate code for an ADD instruction by calling // this method add = (int number) { regs->accumulator += number; } sub = (int number) { regs->accumulator -= number; } } /* example generated code */ // see? that's from the 'extern' block from above struct registers { int accumulator; }; // you get a new class... class ImaginaryPlatformRecompiler { // ... that has a function and a builder Function* function; IRBuilder<> builder; public: ImaginaryPlatformRecompiler() : builder(...) { function = ...;// create the function // the function expects one registers* argument, because that's what the // specifications file said } void add(int number) { // arguments are replaced by constants in the generated code Value* constant = builder.getInt32(number); // get accumulator from regs Value* accu = builder.CreateLoad(...); Value* added = builder.CreateAdd(accu, constant); builder.CreateStore(...); } void sub(int number) { Value* constant = builder.getInt32(number); Value* accu = builder.CreateLoad(...); Value* subbed = builder.CreateSub(accu, constant); builder.CreateStore(...); } Function* getFunction() { return function; } }; /* example usage */ // instructions on our imaginary platforms are as follows: instructions are all // 32 bits, if the MSB is not set it's an addition, otherwise it's a subtraction // and all the other bits represent the unsigned operand. // this code is actually written by humans (or at least, not written by my tool) Function* recompileImaginaryPlatformInstructions(unsigned* begin, unsigned* end) { const unsigned mostSignificantBitMask = 0x80000000; ImaginaryPlatformRecompiler recompiler; for (unsigned* current = begin; current < end; current++) { unsigned instruction = *current; unsigned operand = instruction & ~mostSignificantBitMask; // for more complex cases, we could obviously have a method table for // easier dispatch, but this simple if-else does it perfectly if ((instruction & mostSignificantBitMask) == mostSignificantBitMask) { recompiler.sub(operand); } else { recompiler.add(operand); } } return recompiler.getFunction(); }