Creating LIR for Fun and Profit
Tuesday, May 5, 2009 at 11:36PM // load var a. lhs = left hand side
LIns* lhs = loadAtomRep(sp-1);
<---- Data Bits here ----------> <Type>
aaaaaaaa bbbbbbbb cccccccc ddddd zzzEg the number 10 as an integer: // 6 represents an integer
00000000 00000000 00000000 01010 101
// Same thing but top of stack
LIns* rhs = loadAtomRep(sp);// TopLevel contains a bunch of helper functions that are too complex for x86
LIns* toplevel = loadToplevel();
// Call the function TopLevel::add2 with parameters lhs and rhs
LIns* out = callIns(FUNCTIONID(add2), 3, toplevel, lhs, rhs);
// store the result in memory
localSet(sp-1, atomToNativeRep(result, out), result);
The add2() method returns an Atom. atomToNativeRep() converts Atoms to their known types if they have been assigned one. The LocalSet function creates the necessary instructions to store the resulting atom to memory. The final sequence of instructions actually used by Tamarin to add two numbers is:
CodegenLIR.cpp
LIns* lhs = loadAtomRep(sp-1);
LIns* rhs = loadAtomRep(sp);
LIns* toplevel = loadToplevel();
LIns* out = callIns(FUNCTIONID(add2), 3, toplevel, lhs, rhs);
localSet(sp-1, atomToNativeRep(result, out), result)
Building Branches
It would be a shame if we couldn't branch, but generating LIR to branch is pretty easy! Let's go back to the add example and say build a piece of x86 code that does the following:
if (lhs == int && rhs == int) {
int add
jump to LABEL
}
else {
call add2()
}LABEL
Let's focus on building only the check to make sure lhs == int and creating the jump to LABEL. We can check that lhs is really an integer by reading the type tag of the bottom 3 bits. If (lhs & 6 == 6) is true, then the atom is an integer.
// Check that the lhs is an integer.
// InsConst(kIntegerType) creates a constant integer 6
// atom & 6 gives us if this is an int.
LIns *lhs_type = binaryIns(LIR_and, lhs, InsConst(kIntegerType));// check to see if it is equal to an integer
LIns *lhs_is_int = binaryIns(LIR_eq, lhs_type, InsConst(kIntegerType));
// if not, jump to the normal add2. Notice no label reference.
LIns *lhs_not_integer = branchIns(LIR_jf, lhs_is_int);
// Make sure rhs is an integer
// do an integer add
// jump somewhere else
// tell the lhs_not_inger branch instruction to jump to this location
// Create a LIR_label instruction and point previous branch instructions
// to use this label
LIns *genericAddLabel = Ins(LIR_label);
// Tell lhs_not_inger to point to this new address
lhs_not_integer->target(genericAddLabel);
// Generate the add2() method call
Tada, like magic!. The backend will find all the labels and generate the appropriate jump. You can just generate LIR, branch to wherever you want, and Tamarin figures out the rest. It's actually quite nice that the backend does all the register allocation and figures everything out for method calls and parameters.

Reader Comments