On 2010-09-22, at 4:24 PM, chevalma@iro.umontreal.ca wrote:
I made some small changes to the IR and renamed the gte, lte and neq instructions as suggested today. If you do a checkout of my latest commit, doing a make run will show the updated mnemonics.
However, if I may, I would have a suggestion for the code generation. Instead of using mnemonics, we should probably "install" code generation functions on the instruction classes. For example:
AddInstr.prototype.genCode = function (...) { ... }
This will avoid relying on mnemonic names, and having redundant code for many variants of the same instruction. The code generation code can then find out the type of the operands by using this.uses[i].type, which refers to an IRType object. It can also find its own expected output type by using this.type.
Also, following todays discussion, I'm pondering whether or not I should have completely distinct HIR/MIR instructions. Right now, the add on boxed values, for example, has the semantic of a call to the add() primitive function (a JavaScript add), whereas the same add instruction on i64 values represents the machine word add instruction. The icast instructions are then needed if we want to directly perform a machine add on boxed values without doing any shifting, to indicate that we want to perform an integer add.
It would be possible to, instead, have HIRAdd and MIRAdd instructions. The HIRAdd instructions would then be translated either into a call or into an MIRAdd which would represent the machine instruction add, depending on the types of the input arguments supplied. This would make it possible to eliminate the cast instructions in this case, and directly perform an MIRAdd on boxed values. It would have the disadvantage that arithmetic, bitwise and comparison instruction classes would be duplicated for the two possible semantics, however.
This sounds like an interesting idea. It is in line with my position about having more abstract operations (which for example abstract the data representation). I'm not sure you have to call them HIRAdd and MIRAdd... it might be appropriate to mix both types of adds at the same IR level. I prefer to have families of related "add" operation that operate on different data representations. The families would differ on the *semantics* of the operation (i.e. what is the relation between the input and output). So
Add 2 JavaScript numbers to yield a JavaScript number:
add_js: (boxed,boxed) -> boxed
Add 2 integers with wraparound (operations that are useful if no overflow is possible, by design or program analysis):
iadd_wrap: (fixnum,fixnum) -> fixnum iadd_wrap: (int32,int32) -> int32 iadd_wrap: (int64,int64) -> int64
Add 2 integers with overflow detection (operations useful to implement add_js):
iadd_ovf: (fixnum,fixnum) -> fixnum normal: lbl1 overflow: lbl2 iadd_ovf: (int32,int32) -> int32 normal: lbl1 overflow: lbl2 iadd_ovf: (int64,int64) -> int64 normal: lbl1 overflow: lbl2
Add 2 floating point numbers (operations useful to implement add_js):
fadd: (flonum,flonum) -> flonum fadd: (float64,float64) -> float64
Marc