"""

Power PC Backend

"""

import sys
from machinedefn import MachineDefinition, FunctionInfo
from machinedefn import Prefilter, GeneratedCode
import instrsdefn
from instrs import CallInstruction
import linker
from util import PyntoException, Enumeration
from lowir import argflags, regbits, tartypes, Operation
from lowir import ConstArgument, MemArgument, TempArgument
from lowir import RegArgument as Reg
from emittable import EmitTable
import chelpers

# PowerPC systems run on a number of different operating systems which use
# different ABIs.
abis = Enumeration ('OSX32', 'LINUX')
abifinfos = {}                        # maps abi constant -> FunctionInfo class
prefilters = {}                       # maps abi constant -> Prefilter class

class Definition (MachineDefinition):

    def __init__ (self, comp):

        MachineDefinition.__init__ (self, comp, -(1<<15))

        RV = regbits.RETVAL     # where return value is stored
        A = regbits.ARG         # where arguments go when calling a function
        V = regbits.CALLERSAVE  # Volatile registers are saved by caller
        NV = regbits.CALLEESAVE # Nonvolatile registers are saved in prol/epil
        P = regbits.PRIVATE     # Not accessible to register allocator
        SP = (regbits.SP |      # stack pointer/frame pointer (always same reg)
              regbits.FP)

        # Temporarily mark all argument registers private:
        A |= P
        
        self.regs = []

        # Currently use OSX as default ABI
        self.abi = abis.OSX32

        # Initialize registers appropriately depending on which ABI we 
        # have selected
        if self.abi == abis.OSX32:
            # These are for the Mac OS X, Mach-O ABI, with a 32 bit processor:
            #
            #   See PowerPC Runtime Architecture Guide on Apple's website
            #   for more information.
            self.regs.append (Reg ('GPR0', 0, P))
            self.regs.append (Reg ('GPR1', 1, NV|P|SP))
            self.regs.append (Reg ('GPR2', 2, V))
            self.regs.append (Reg ('GPR3', 3, RV|A)) 
            self.regs.append (Reg ('GPR4', 4, A)) 
            self.regs.append (Reg ('GPR5', 5, A))
            self.regs.append (Reg ('GPR6', 6, A))
            self.regs.append (Reg ('GPR7', 7, A))
            self.regs.append (Reg ('GPR8', 8, A))
            self.regs.append (Reg ('GPR9', 9, A))
            self.regs.append (Reg ('GPR10', 10, A))
            self.regs.append (Reg ('GPR11', 11, V))
            self.regs.append (Reg ('GPR12', 12, V))
            self.regs.append (Reg ('GPR13', 13, NV))
            self.regs.append (Reg ('GPR14', 14, NV))
            self.regs.append (Reg ('GPR15', 15, NV))
            self.regs.append (Reg ('GPR16', 16, NV))
            self.regs.append (Reg ('GPR17', 17, NV))
            self.regs.append (Reg ('GPR18', 18, NV))
            self.regs.append (Reg ('GPR19', 19, NV))
            self.regs.append (Reg ('GPR20', 20, NV))
            self.regs.append (Reg ('GPR21', 21, NV))
            self.regs.append (Reg ('GPR22', 22, NV))
            self.regs.append (Reg ('GPR23', 23, NV))
            self.regs.append (Reg ('GPR24', 24, NV))
            self.regs.append (Reg ('GPR25', 25, NV))
            self.regs.append (Reg ('GPR26', 26, NV))
            self.regs.append (Reg ('GPR27', 27, NV))
            self.regs.append (Reg ('GPR28', 28, NV))
            self.regs.append (Reg ('GPR29', 29, NV))
            self.regs.append (Reg ('GPR30', 30, NV))
            self.regs.append (Reg ('GPR31', 31, NV))
            pass

        M = argflags.MEM|argflags.SOFTSTACK
        R = argflags.REG|argflags.SOFTREG|argflags.TEMP
        C = argflags.CONST
        LC = argflags.LARGECONST
        
        # This table defines the legal low-level operations and how to create
        # them in terms of PPC assembly:

        def prefix (func, *preargs):
            return lambda *args: apply (func, preargs + args)
        
        self.emit_table = EmitTable (comp.log, {

            'PROLOGUE':( ( (), (),     emit_prologue ), ),

            'EPILOGUE':( ( (), (),     emit_epilogue ), ),

            'BR':      ( ( (), (),     prefix(emit_br, 0) ), ),
            
            'BEQ':     ( ( (), (R, R), prefix(emit_bc_rr, True, 2) ),
                         ( (), (R, C), prefix(emit_bc_rc, True, 2) ),
                         ( (), (C, R), prefix(emit_bc_cr, True, 2) ) ),
            
            'BNE':     ( ( (), (R, R), prefix(emit_bc_rr, False, 2) ), 
                         ( (), (R, C), prefix(emit_bc_rc, False, 2) ),
                         ( (), (C, R), prefix(emit_bc_cr, False, 2) ) ),

            # CALL and CALLPTR instructions make function calls.  The
            # return value handling is done separately, so the only argument
            # required is the address to call in the case of CALLPTR.
            'CALL':    ( ( (),
                           (),
                           prefix (emit_br, 1) ), ),
            
            'CALLPTR': ( ( (),
                           (R,),
                           emit_callptr ), ),
            
            'ADD':     ( ( (R,), (R, R), emit_add_rr ),
                         ( (R,), (R, C), emit_add_rc ),
                         ( (R,), (C, R), emit_add_cr ) ),
            
            'SUB':     ( ( (R,), (R, R), emit_sub_rr ),
                         ( (R,), (R, C), emit_sub_rc ) ),

            # NOOPs are mainly used when we need a label to point at
            # but there is no instruction we want to execute in that
            # slot.  
            'NOOP':    ( ( (), (), emit_noop ), ),

            'LOADLINK':( ( (R,), (), emit_load_large_constant ), ),

            'MOVE':    ( ( (M,), (R,), emit_store ),
                         ( (R,), (M,), emit_load ),
                         ( (R,), (R,), emit_reg_move ),
                         ( (R,), (C,), emit_load_constant ),
                         ( (R,), (LC,), emit_load_large_constant )
                         ),
            })

        self.prefilter = prefilters [self.abi] (self, self.log)
        
        pass

    def create_function_info (self):
        return abifinfos [self.abi] (self)

    pass

class OSX32Prefilter (Prefilter):

    """ Prefilter for the OS X 32 Bit ABI """

    def _arg_regs (self):
        return 

    def CALL (self, emitter, oper):

        """ Applies the Mach-O calling convention """

        self.log.mid ('CALL Operation intercepted w/ target %s',
                      oper.target)

        finfo = emitter.finfo
        md = finfo.md
        srcops = oper.sources
        ttype = oper.tartype
        tarinfo = oper.target
        argregs = list (finfo.argregs)
        ptrsize = finfo.pointer_size

        if ttype == tartypes.GEN:
            # When calling other generated code, we create a tuple
            # structure on the stack, and then pass in GPR3 a pointer
            # to that structure [ordinarily GPR3 would hold the second
            # argument]
            ptrreg = argregs[1]
            idx = 0

            # Start the structure at the position where the 4th argument
            # would go
            baseoffs = finfo.linkage_space + 16

            # So the stack grows downward, but structures are layed out
            # normally.
            numargs = len (srcops)
            structsize = chelpers.tuple_ob_items () + (numargs * ptrsize)
            finfo.remember_parameter_offset (structsize+baseoffs)

            # Write the size of the tuple
            argoffs = chelpers.tuple_ob_size ()
            argloc = MemArgument (finfo.spreg, argoffs+baseoffs)
            emitter._emit (Operation (
                'MOVE',
                dests=(argloc,),
                sources=(md.get_integer_constant(numargs),),
                comment='Place size in tuple'))

            # Write each item of the tuple
            argoffs = chelpers.tuple_ob_items ()
            for srcop in srcops:
                argloc = MemArgument (finfo.spreg, argoffs+baseoffs)
                emitter._emit (Operation ('MOVE',
                                          dests=(argloc,),
                                          sources=(srcop,),
                                          comment='Place in tuple'))
                argoffs += 4
                pass

            emitter._emit (Operation (
                'ADD',
                dests=(ptrreg,),
                sources=(finfo.spreg,md.get_integer_constant(baseoffs)),
                comment='Compute pointer'))
            
            pass
        else:
            idx = 0
            for srcop in srcops:
                
                # On PPC, we first store arguments into registers until we
                # run out of registers.
                if argregs:
                    # Emit a move of the operand into the frontmost register
                    # and pop it from the list.
                    self.log.low ('Loading argument #%d into register %s'
                                  % (idx, argregs[0]))
                    emitter._emit (Operation ('MOVE',
                                              dests=(argregs[0],),
                                              sources=(srcop,),
                                              comment='Load arg'))
                    argregs = argregs[1:]
                else:
                    # Calculate location on stack.  
                    offset = finfo.callee_parameter_offset (idx)
                    self.log.low ('Loading argument #%d onto stack at offset %d'
                                  % (idx, offset))
                    argloc = MemArgument (finfo.spreg, offset)
                    emitter._emit (Operation ('MOVE',
                                              dests=(argloc,),
                                              sources=(srcop,),
                                              comment='Load arg'))
                    assert offset < emitter.paramspace
                    pass
                
                idx += 1
                pass
            pass

        # Create the call instruction.  Note that on Mach-O, we never
        # end up calling by pointer, always to statically linked
        # functions.  In other words, we don't generate Position
        # Independent Code.  Also note that we *still* need to load
        # the address we're branching to into a register and jump to
        # that register!  This is because the address is a full 32
        # bits and we can't guarantee that the 16 bit offset for a
        # branch instruction will be enough to get us there.

        addrtemp = TempArgument ()

        # Load the address into a register.  Note that we use a
        # dummy constant; the real value comes from the target which is
        # set at link time.
        emitter._emit (Operation (
            'LOADLINK',
            dests=[addrtemp],
            target=(ttype, oper.target)))

        comment = None
        if ttype == tartypes.LIB: comment = oper.target.fname

        # Now emit a CALLPTR
        clobbers = finfo.argregs + finfo.volregs
        emitter._emit (Operation ('CALLPTR',
                                  sources=[addrtemp],
                                  clobber=clobbers,
                                  comment=comment))
    
        # Obtain the return value if anybody cares.
        dstops = oper.dests
        if dstops:
            assert len (dstops) == 1
            self.log.low ('Obtaining return value')
            emitter._emit (Operation ('MOVE',
                                      dests=dstops,
                                      sources=finfo.retvalregs,
                                      comment='Obtain Return Value'))
            pass
                
        return

    def LOADPARAM (self, emitter, oper):
        
        # Because the basic blocks are generated in reverse post
        # order, by the time we're generating LoadParam instructions
        # we'll have already processed all the data.  This will be
        # good because we will need it to calculate the offset of the
        # parameters if they are passed on the stack.
        #
        # At the moment, however, we always expect two parameters just
        # like a Python extension function written in C:
        #   (PyObject *self, PyObject *args)
        #
        # Note that the args come wrapped up in a tuple, so the code we
        # generate is:
        #
        #  mov resultreg, (argreg1+offsetof(PyTupleObject, items[idx]))
        #
        # where argreg1 is the register which the 'args' argument is
        # in, and 'idx' is the index we are loading from.

        idx = oper.sources[0]
        assert isinstance (idx, ConstArgument)
        idx = idx.value

        argsreg = emitter.finfo.argregs[1]
        itemoffset = idx * emitter.finfo.pointer_size + \
                     chelpers.tuple_ob_items()
        memarg = MemArgument (argsreg, itemoffset)
        moveoper = Operation ('MOVE', dests=oper.dests, sources=[memarg])
        emitter._emit (moveoper)
        return

    def RET (self, emitter, oper):

        # Stash result into return value register.
        emitter._emit (Operation ('MOVE',
                                  dests=emitter.finfo.retvalregs,
                                  sources=oper.sources))

        # TODO --- needs branch
        
        return
    
    pass
prefilters[abis.OSX32] = OSX32Prefilter

class PPCFunctionInfo (FunctionInfo):

    """ PPC Function Info object: This is the base class for all PPC
    function info implementations.  It tracks the state required for a
    single generated function.  Note that each supported API has a
    specific subclass, which are mapped in the global hashtable "apifinfos".

    Overall Stack Layout
    --------------------

    This base class also handles the PPC stack frames, which are
    mercifully similar between ABIs.  Here is a high level layout
    (from Mac OS X Runtime Architecture Guide, page 15, or IBM PPC
    Compiler Writer's Guide, page 162):

    Higher addresses ----> | ...
                           | [Arguments from caller: Parameter Area]
    SP on entry ---------> | [Space to save linkage pointer etc: Linkage Area]
                           | [Callee-save registers]
                           | [Local variables]
                           | [Parameter Area for called functions]
    SP during execution -> | [Linkage Area for called functions]
    Lower addresses -----> | ...

    Note that our stack frame is the space between SP on entry and
    SP during execution.

    The space of each of those sections is calculated like so:

    Local Variables: this is calculated during register allocation through
    calls to new_stack_slot().

    Saved Registers: this is calculated during register assignment.
    When a register object is used, it's DIRTY flag is set.  We can
    later scan through the list of registers objects for this function
    (note that we have a private set; see machinedefn.FunctionInfo) to
    determine which need to be saved.

    Arguments to callee functions: this is calculated during low level IR
    generation by calls to callee_parameter_offset() from the prefilter.

    Linkage Area: this varies depending on ABI, but is known in
    advance, and is set in the field self.linkage_space.  In practice
    for 32 bit architectures there is only one layout, and it is
    described below.

    Note that this means that until register allocation the offsets of
    local variables and our own arguments are unknown.  The offsets of
    arguments to functions we call *can* be computer, however.

    Linkage Area for 32 Bit PPC
    ---------------------------
    
    Let's examine the linkage area in more detail.  It is 24 bytes large,
    and is laid out like so [expressed in offsets from the incoming SP]:
    
    +20(incoming SP) --> | [Saved TOC]
    +16(incoming SP) --> | [Reserved]
    +12(incoming SP) --> | [Reserved]
    +8 (incoming SP) --> | [LR saved]
    +4 (incoming SP) --> | [CR saved]
    +0 (incoming SP) --> | [SP saved by caller]

    Note that of this space, the entry at offset 0 from the SP is
    stored by the calling routine during its prolog.  It is equal to
    the incoming SP for any called routines, or the frame pointer for
    the calling routine.
    """
    
    def __init__ (self, md):
        FunctionInfo.__init__ (self, md, md.regs, True)
        self.paramspace = 0
        self.localvars = 0
        self.dirty_regs = {}
        
        # Subclasses must fill in these parameters:
        self.linkage_space = None   # space to reserve for linkage
        self.pointer_size = None    # size of a pointer (4 or 8 bytes)
        
        # Precalculate certain sets of registers
        # used by prefilter:
        self.retvalregs = [ reg for reg in self.registers
                            if reg.check_flag (regbits.RETVAL) ]
        self.argregs = [ reg for reg in self.registers
                         if reg.check_flag (regbits.ARG) ]
        self.volregs = [ reg for reg in self.registers
                         if reg.check_flag (regbits.CALLERSAVE) ]
        self.nonvolregs = [ reg for reg in self.registers
                            if reg.check_flag (regbits.CALLEESAVE) ]
        pass

    def callee_parameter_offset (self, idx):

        """ Computes the offset from the stack pointer where parameter
        #idx must be placed when calling another function.  Note that
        in the stack layout parameters being passed to callee
        functions are closest to the stack pointer, and therefore
        lowest in the address space (since the stack grows down).
        This function also takes the opportunity to record how much
        space we will need for this parameter space so that later we
        can compute the final stack frame size.

        This function assumes that the arguments are all pointers, as
        no typing information is provided.

        Returns an integer that is the offset from SP during
        execution. """

        offset = self.linkage_space + idx * self.pointer_size
        if self.paramspace < offset: self.paramspace = offset
        return offset

    def remember_parameter_offset (self, offs):

        """ When calling other generated code, the prefilter creates a
        tuple structure on the stack in addition to the normal
        arguments.  This function lets it report back how large that
        tuple structure was so that this can be taken into account when
        computing the size of the stack frame. """
        
        if self.paramspace < offs: self.paramspace = offs
        return
        
    def next_stack_offset (self):

        """ Called to compute the stack offsets for local variables.
        By the time this routine has called, the amount of space
        needed for the parameter will have been computed; therefore we
        can dole out the actual offsets of each local variable here,
        no fixup will be required.  Each call generates a new slot, so the
        register allocator tries to reuse the values returned.

        Returns an integer that is the offset from SP during
        execution. """

        res = self.linkage_space   # linkage pointer
        res += self.paramspace     # parameters we'll pass
        res += self.localvars      # local vars we've given out so far
        self.localvars += 4        # reserve this one

        self.log.low ('next_stack_offset: localvars=%d res=%d',
                      self.localvars, res)
        
        return res
    
    def get_generated_code (self):

        """ Called when the entire function has been generated, epilogue
        and all.  Returns a GeneratedCode object to wrap this buffer. """

        self.buffer.set_method_entry_point ()

        return GeneratedCode (self.buffer.callable_object (),
                              self.buffer,
                              self.buffer.ppc_disasm,
                              self.get_constant_list ())

    pass

# ABI Specific Function Info Objects

class OSX32FunctionInfo (PPCFunctionInfo):

    def __init__ (self, md):
        PPCFunctionInfo.__init__ (self, md)
        self.linkage_space = 24
        self.pointer_size = 4
        pass

    def emit_prologue (self):

        prol = self.log.indent ('emit_prologue')

        # Determine which registers we'll need to save
        saveregs = [reg for reg in self.nonvolregs if reg.is_dirty()]

        # Compute the raw size of the stack.  
        stacksize = (self.linkage_space + self.paramspace + self.localvars +
                     len (saveregs) * self.pointer_size)

        # Align it on 16 byte boundaries as is recommended
        stacksize = (stacksize+15)&-16
        
        self.log.mid ('stacksize=%d [linkage=%d paramspace=%d '+
                      'localvars=%d len(saveregs)=%d]',
                      stacksize, self.linkage_space, self.paramspace,
                      self.localvars, len (saveregs))        

        # EPILOGUE
        # --------

        # Locate first byte of epilogue --- these are the bytes we
        # reserved in .emit_epilogue ().  Currently self.epistart is
        # stored as the size of the buffer at that time, convert it to
        # offsets from the front of the buffer at this time.
        self.epistart = self.buffer.size() - self.epistart

        # Start by emitting code to restore dirty registers
        bufpos = self.epistart
        stackoffs = self.paramspace + self.localvars
        for reg in saveregs:
            self.log.low ('LOADI of reg %d from stkoff 0x%x at offset 0x%x',
                          reg.id, stackoffs, bufpos)
            emit_const_op (self.buffer,
                           LOADI, reg.id, self.spreg.id, stackoffs,
                           offs=bufpos)
            bufpos += 4
            stackoffs += 4
            pass

        # Load old SP from the stack
        self.log.low ('Load old SP at offset 0x%x', bufpos)
        emit_const_op (self.buffer, LOADI,
                       self.spreg.id, self.spreg.id, 0,
                       offs=bufpos)
        bufpos += 4

        # Emit code to load old link pointer into r0
        self.log.low ('LOADI of link ptr at offset 0x%x', bufpos)
        emit_const_op (self.buffer, LOADI, 0, self.spreg.id, 8,
                       offs=bufpos)
        bufpos += 4

        # Load from r0 into the link register.  Just hardcode the
        # relevant bytes.
        self.log.low ('MTLR R0 at offset 0x%x', bufpos)
        self.buffer.set32 (bufpos, 0x7c0803a6) # "mtlr r0" or "mtspr lr,r0"
        bufpos += 4

        # Branch to the linkage register.  Just hardcode the relevant
        # bytes.
        self.log.low ('BLR at offset 0x%x', bufpos)
        self.buffer.set32 (bufpos, 0x4e800020) # "blr"
        bufpos += 4

        # PROLOGUE
        # --------

        # Grow the buffer by how many instructions we will be adding
        self.buffer.grow (4 * (len (saveregs) + 3))

        # Extract return address and save it
        self.log.low ('MFLR,STW at offset 0, 4')
        self.buffer.set32 (0, 0x7c0802a6L) # "mflr r0" or "mfspr r0,lr"
        self.buffer.set32 (4, 0x90010008L) # "stw r0,8(SP)"

        # Grow the size of the stack
        self.log.low ('ADDI SP at offset 8')
        emit_const_op (self.buffer,
                       STWU, self.spreg.id, self.spreg.id, -stacksize,
                       offs=8)

        # Save the relevant registers
        bufpos = 12
        stackoffs = self.paramspace + self.localvars
        for reg in saveregs:
            self.log.low ('STOREI of reg %d to stkoff 0x%x offset 0x%x',
                          reg.id, stackoffs, bufpos)
            emit_const_op (self.buffer,
                           STOREI, reg.id, self.spreg.id, stackoffs,
                           offs=bufpos)
            stackoffs += 4
            bufpos += 4
            pass

        del prol

        return 

    def emit_epilogue (self):
        
        """ Called when we just begin generating the function.
        At this point, we don't know which registers will be dirty
        etc, so we just leave some blank space in the buffer.  Later
        we'll patch it up. """

        # Every instruction is 4 bytes.  The epilogue looks like:
        #
        # [Restore volatile registers]
        # lwz r0,stacksize+8(SP)
        # mtlr r0
        # addi SP,SP,stacksize
        # blr

        numinstructions = len (self.nonvolregs) + 4
        self.buffer.grow (numinstructions*4)
        self.epistart = self.buffer.size ()

        self.log.low ('emit_epilogue numinstrs=%d epistart=%d',
                      numinstructions, self.epistart)                

        return 

    pass
abifinfos[abis.OSX32] = OSX32FunctionInfo

# Address Patch
#
# When we have calls to library functions, or to other generated code,
# we embed the address to call directly into the generated code.
# However, in some cases (generated code in particular) we may not
# know the address until later.  In this case, we create a MOVE
# operation with a target that is set to the generated code and thus
# use the same patching mechanism that branches use.  An object is returned
# by the emit function which will allow the final value to be patched in.
#
# However, because the final value is a 32 bit constant, this patching
# object is a bit specialized, and is defined below.

class LargeConstantPatcher:

    def __init__ (self, buffer, dstregid):
        self.out = buffer
        self.savedsize = self.out.size ()
        self.dstregid = dstregid
        pass

    def patch (self, srcval):

        offset = self.out.size() - self.savedsize

        # Convert srcval to its value
        srcval = long (srcval)

        # Convert from signed/unsigned 32 bit number to two 16 bit words.
        # Note use of long to prevent Python from getting confused.
        hiword = (srcval & 0xFFFF0000L) >> 16
        loword = (srcval & 0x0000FFFFL)
        
        # if the first ADDI will do sign extension, that will make the
        # hiword 0xFFFF, or -1 when considered independently, so we must
        # add one 1 the highword value to account for it
        if loword & 0x8000L: hiword += 1

        # Emit instruction
        # ADDI <reg 0> + <loword> -> <destid>
        emit_const_op (self.out, ADDI, self.dstregid, 0, loword,
                       offs=offset)

        # Emit instruction
        # ADDIS <destid> + <hiword> -> <destid>
        emit_const_op (self.out, ADDIS, self.dstregid, self.dstregid, hiword,
                       offs=offset+4)

        pass

    pass

# Binary Emitters

def emit_prologue (finfo, op):

    return finfo.emit_prologue ()

def emit_epilogue (finfo, op):

    return finfo.emit_epilogue ()

def emit_callptr (finfo, op):

    out = finfo.buffer

    srcreg = op.sources[0].assignment
    assert srcreg.is_type (argflags.REG)

    # on powerpc we implement call to a pointer by first loading the
    # count register then branching to its value

    # bctrl instruction
    wrd = 19 << 26       # Bits 0-5 must be 19
    wrd += 0x14 << 21    # BO == always branch (0b1z1zz)
    # B1 == 0
    wrd += 528 << 1      # magic constant
    wrd += 1
    out.grow (4)
    out.set32 (0, wrd)

    # mtcrf instruction 
    wrd = 31 << 26           # Bits 0-5: must be 31
    wrd += srcreg.id << 21   # Bits 6-10: source register (RS)
    wrd += 0x120 << 11       # bits 11-20: spr == CTR
    wrd += 467 << 1          # magic constant
    out.grow (4)
    out.set32 (0, wrd)

    return

def emit_br (link,                # from table above
             finfo, op):          # from machinedefn.py

    out = finfo.buffer
    
    # Bits 0-5: 18
    # Bits 6-29: 'LL' or destination
    # Bits 30: Absolute Address -- we always use zero
    # Bits 31: Link -- passed in by parameter.  True only for CALL.

    # We don't necessarily know the offset to where we are branching
    # yet, so we just set up a link object and return it.  We still
    # reserve the space where the instruction will go when it is
    # ready.
    
    framing = 18L << 26 + link
    out.grow (4)
    return linker.OffsetLinkPos (out, 0, 32, 0, framing, 4)

def emit_bc_rr (condtrue, condbit,
                finfo, op):

    out = finfo.buffer

    # Load the two registers we will be comparing
    source1 = op.sources[0].assignment
    source2 = op.sources[1].assignment
    assert source1.is_type (argflags.REG) and \
           source2.is_type (argflags.REG)

    # Now emit a conditional branch:
    linkpos = _emit_bc (condtrue, condbit, finfo, op)
        
    # Now emit a compare instruction to set the conditional
    # flags (note that it will come first in the final result)
    
    # Bits 0-5:   31
    # Bits 6-8:   crfD (which condition register to use; we use 0)
    # Bits 9:     /
    # Bits 10:    L
    # Bits 11-15: RA
    # Bits 16-20: RB
    # Bits 21-30: 0
    # Bits 31:    /

    word = 0x7C000000
    word |= source1.id << 16L
    word |= source2.id << 11L
    out.grow (4)
    out.set32 (0, word)
    return linkpos

def emit_bc_cr (condtrue, condbit,
                finfo, op):

    srcval = op.sources[0].assignment
    srcreg = op.sources[1].assignment
    assert srcval.is_type (argflags.CONST) and \
           srcreg.is_type (argflags.REG)

    return _emit_bc_const (condtrue, condbit, finfo, op, srcval, srcreg)

def emit_bc_rc (condtrue, condbit,
                finfo, op): 

    srcreg = op.sources[0].assignment
    srcval = op.sources[1].assignment
    assert srcval.is_type (argflags.CONST) and \
           srcreg.is_type (argflags.REG)

    return _emit_bc_const (condtrue, condbit, finfo, op, srcval, srcreg)

def _emit_bc_const (condtrue, condbit, finfo, op, srcval, srcreg):

    out = finfo.buffer
    
    # Emit the branch parameterized as requested:    
    linkpos = _emit_bc (condtrue, condbit, finfo, op)

    # Now emit a cmpi instruction (note that it will come first)
    # Bits 0-5:   11
    # Bits 6-8:   crfD (we use 0)
    # Bits 9:     /
    # Bits 10:    L   (always zero)
    # Bits 11-15: RA
    # Bits 16-31: C

    word = 0x2c000000
    word |= srcreg.id << 16L
    word |= srcval.value 
    out.grow (4)
    out.set32 (0, word)
    return linkpos

def _emit_bc (condtrue, condbit, finfo, op):

    """ Emits a conditional branch.

    condtrue should be true if we want to branch if the conditon is
    true.

    condbit should be 0 for LT, 1 for GT, 2 for EQ """

    out = finfo.buffer

    # Bits 0-5:   16
    # Bits 6-10:  BO (00100 if cond is true, 01100 if cond is false)
    # Bits 11-15: BI
    # Bits 16-29: BD
    # Bits 30:    Absolute Address -- we always use zero
    # Bits 31:    Link -- we always use zero

    framing = 16L << 26
    
    if condtrue: framing |= 12 << 21
    else: framing |= 4 << 21

    framing |= condbit << 16

    # We don't know the offset of our target, so reserve space for
    # the instruction and return a link pos for the caller to update:
    out.grow (4)
    return linker.OffsetLinkPos (out, 0, 32, 0, framing, 4)

def emit_noop (finfo, op):
    return

def emit_add_rr (finfo, op):

    # Load the source and destination registers.
    srcreg1 = op.sources[0].assignment
    srcreg2 = op.sources[1].assignment
    dstreg = op.dests[0].assignment
    assert srcreg1.is_type (argflags.REG) and \
           srcreg2.is_type (argflags.REG) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # ADD <srcreg1> <srcreg2> -> destid
    return emit_reg_op (finfo.buffer, ADD, dstreg.id, srcreg1.id, srcreg2.id)

def emit_add_rc (finfo, op):

    # Load the source and destination.
    srcreg = op.sources[0].assignment
    srcval = op.sources[1].assignment
    dstreg = op.dests[0].assignment
    assert srcreg.is_type (argflags.REG) and \
           srcval.is_type (argflags.CONST) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # ADDI <srcreg> <srcval> -> destid
    return emit_const_op (finfo.buffer, ADDI,
                          dstreg.id, srcreg.id, srcval.value)

def emit_add_cr (finfo, op):

    # Load the source and destination.
    srcval = op.sources[0].assignment
    srcreg = op.sources[1].assignment
    dstreg = op.dests[0].assignment
    assert srcreg.is_type (argflags.REG) and \
           srcval.is_type (argflags.CONST) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # ADDI <srcreg> <srcval> -> destid
    return emit_const_op (finfo.buffer, ADDI,
                          dstreg.id, srcreg.id, srcval.value)

def emit_sub_rr (finfo, op):

    # Load the source and destination registers.
    srcreg1 = op.sources[0].assignment
    srcreg2 = op.sources[1].assignment
    dstreg = op.dests[0].assignment
    assert srcreg1.is_type (argflags.REG) and \
           srcreg2.is_type (argflags.REG) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # SUB <srcreg1> - <srcreg2> -> destid
    return emit_reg_op (finfo.buffer, SUB,
                        dstreg.id, srcreg1.id, srcreg2.id)

def emit_sub_rc (finfo, op):

    # Load the source and destination.
    srcreg = op.sources[0].assignment
    srcval = op.sources[1].assignment
    dstreg = op.dests[0].assignment
    assert srcreg.is_type (argflags.REG) and \
           srcval.is_type (argflags.CONST) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # SUBI <srcreg> - <srcval> -> destid
    return emit_const_op (finfo.buffer, SUBI,
                          dstreg.id, srcreg.id, srcval.value)

def emit_reg_move (finfo, op):

    # Load the source and destination registers.
    srcreg = op.sources[0].assignment
    dstreg = op.dests[0].assignment
    assert srcreg.is_type (argflags.REG) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # OR <srcreg> | <srcreg> -> <dstreg>
    return emit_reg_op (finfo.buffer, OR, dstreg.id, srcreg.id, srcreg.id)

def emit_load_constant (finfo, op):

    # Load the source and destination.
    srcval = op.sources[0].assignment
    dstreg = op.dests[0].assignment
    assert srcval.is_type (argflags.CONST) and \
           dstreg.is_type (argflags.REG)

    # Emit instruction
    # ADDI <reg 0> + <srcval> -> <dstreg>
    return emit_const_op (finfo.buffer, ADDI, dstreg.id, 0, srcval.value)

def emit_load_large_constant (finfo, op):

    out = finfo.buffer

    out.grow (8)

    # Load the source and destination .
    dstreg = op.dests[0].assignment
    assert dstreg.is_type (argflags.REG)

    # Sometimes the large constant is not known at code generation time;
    # therefore we create a patching object which we can return and use to
    # set the value when it is known.  In this case, there is no source
    # argument.
    patch = LargeConstantPatcher (out, dstreg.id)

    # but if there is no target, then srcval *is* the correct value to use
    # so just patch it now and return None [in this case the opcode is MOVE]
    if not op.target:
        srcval = op.sources[0].assignment
        assert srcval.is_type (argflags.LARGECONST)
        patch.patch (long (srcval.value))
    else:
        # otherwise, if there is a target, return patch and let the caller
        # provide the real value when it is known [in this case the opcode
        # is LOADLINK]
        return patch
    return

def emit_load (finfo, op):

    # Load the source and destination.
    srcmem = op.sources[0].assignment
    dstreg = op.dests[0].assignment
    assert srcmem.is_type (argflags.MEM) and \
           dstreg.is_type (argflags.REG)

    return emit_mem_op (finfo, LOADI, srcmem, dstreg)

def emit_store (finfo, op):

    # Load the source and destination.
    srcreg = op.sources[0].assignment
    dstmem = op.dests[0].assignment
    assert srcreg.is_type (argflags.REG) and \
           dstmem.is_type (argflags.MEM)

    return emit_mem_op (finfo, STOREI, dstmem, srcreg)

def emit_mem_op (finfo, opcode, mem, reg):

    membase = mem.base.assignment
    assert membase.is_type (argflags.REG)

    return emit_const_op (finfo.buffer,
                          opcode,
                          reg.id,
                          membase.id,
                          mem.offset)

# ---------------------------------------------------------------------
# These routines capture the underlying patterns of the PPC
# instruction set.  They do not reference any lowir structures.  They
# are used by the emit_XXX routines above, as well as by emit_prologue
# and emit_epilogue.  The 'acode' and 'opcode' parameters refer to
# the constants defined alongside the function.

ADD = 0x214
SUB = 0x50
OR = 0x378

def emit_reg_op (out, acode, destid, srcid1, srcid2, offs=-1):

    """ Most reg X reg -> reg style operations (where X represents
    some sort of operator) share the same style.  I am calling
    these arith ops.  This function emits one of them; the parameter
    'acode' indicates which operator is in use. """
    
    wrd = 0x7c000000L
    wrd += (srcid1 << 21)
    wrd += (destid << 16)
    wrd += (srcid2 << 11)
    wrd += acode
    if offs < 0:
        out.grow (4)
        out.set32 (0, wrd)
    else:
        out.set32 (offs, wrd)
        pass
    return

LOADI = 32
STOREI = 36
ADDI = 14
SUBI = 8
ADDIS = 15
STWU = 37

def emit_const_op (out, opcode, rt, ra, immediate, offs=-1):

    """ Most reg X reg -> reg style operations (where X represents
    some sort of operator) share the same style.  I am calling
    these arith ops.  This function emits one of them; the parameter
    'acode' indicates which operator is in use. """

    wrd = immediate & 0xFFFF # prevent sign extension from affecting the rest
    wrd |= (opcode << 26L)
    wrd |= (rt << 21L)
    wrd |= (ra << 16L)
    if offs < 0:
        out.grow (4)
        out.set32 (0, wrd)
    else:
        out.set32 (offs, wrd)
        pass
    return

