Instruction selection

The instruction selection phase takes care of scheduling and instruction selection. The output of this phase is a one frame per function with a flat list of abstract machine instructions.

To select instruction, a tree rewrite system is used. This is also called bottom up rewrite generator (BURG). See pyburg.

Instruction selector.

This part of the compiler takes in a DAG (directed acyclic graph) of instructions and selects the proper target instructions.

Selecting instructions from a DAG is a NP-complete problem. The simplest strategy is to split the DAG into a forest of trees and match these trees.

Another solution may be: PBQP (Partitioned Boolean Quadratic Programming)

The selection process creates operations in a selection DAG. The possible operations are listed in the below table:

operation types description
ADD(c0,c1) I,U Add its operands
SUB(c0,c1) I,U Substracts c1 from c0
MUL(c0,c1) I,U Multiplies c0 by c1
DIV(c0,c1) I,U Divides c0 by c1
OR(c0,c1) I,U Bitwise or
AND(c0,c1) I,U Bitwise and
XOR(c0,c1) I,U Bitwise exclusive or
LDR(c0) I,U Load from memory
STR(c0,c1) I,U Store value c1 at memory address c0
FPREL U Frame pointer relative location
CONST I,U Constant value
REG I,U Value in a specific register
JMP I,U Jump to a label
CJMP I,U Conditional jump to a label

Memory move operations:

  • STRI64(REGI32[rax], CONSTI32[1])
  • MOVB()
class ppci.codegen.instructionselector.InstructionContext(frame, arch)

Usable to patterns when emitting code

emit(instruction)

Abstract instruction emitter proxy

move(dst, src)

Generate move

new_label()

Generate a new unique label

new_reg(cls)

Generate a new temporary of a given class

class ppci.codegen.instructionselector.InstructionSelector1(arch, sgraph_builder, weights=(1, 1, 1))

Instruction selector which takes in a DAG and puts instructions into a frame.

This one does selection and scheduling combined.

gen_tree(context, tree)

Generate code from a tree

inline_asm(context, tree)

Run assembler on inline assembly code.

memcp()

Invoke memcpy arch function

munch_trees(context, trees)

Consume a dag and match it using the matcher to the frame. DAG matching is NP-complete.

The simplest strategy is to split the dag into a forest of trees. Then, the DAG is reduced to only trees, which can be matched.

A different approach is use 0-1 programming, like the NOLTIS algo.

TODO: implement different strategies.

select(ir_function: ppci.ir.SubRoutine, frame, reporter)

Select instructions of function into a frame

class ppci.codegen.instructionselector.TreeSelector(sys)

Tree matcher that can match a tree and generate instructions

apply_rules(context, tree, goal)

Apply all selected instructions to the tree

burm_label(tree)

Label all nodes in the tree bottom up

gen(context, tree)

Generate code for a given tree. The tree will be tiled with patterns and the corresponding code will be emitted

kids(tree, rule)

Determine the kid trees for a rule

nts(rule)

Get the open ends of this rules pattern