Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] View of /sml/trunk/src/compiler/CodeGen/x86/x86CG.sml
ViewVC logotype

View of /sml/trunk/src/compiler/CodeGen/x86/x86CG.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1003 - (download) (annotate)
Fri Dec 7 02:45:32 2001 UTC (18 years, 1 month ago) by george
File size: 7031 byte(s)
Changed the representation of instructions from being fully abstract
to being partially concrete. That is to say:

  from
	type instruction

  to
	type instr				(* machine instruction *)

	datatype instruction =
	    LIVE of {regs: C.cellset, spilled: C.cellset}
          | KILL of {regs: C.cellset, spilled: C.cellset}
          | COPYXXX of {k: CB.cellkind, dst: CB.cell list, src: CB.cell list}
          | ANNOTATION of {i: instruction, a: Annotations.annotation}
          | INSTR of instr

This makes the handling of certain special instructions that appear on
all architectures easier and uniform.

LIVE and KILL say that a list of registers are live or killed at the
program point where they appear. No spill code is generated when an
element of the 'regs' field is spilled, but the register is moved to
the 'spilled' (which is present, more for debugging than anything else).

LIVE replaces the (now deprecated) DEFFREG instruction on the alpha.
We used to generate:

	DEFFREG f1
	f1 := f2 + f3
        trapb

but now generate:

	f1 := f2 + f3
	trapb
	LIVE {regs=[f1,f2,f3], spilled=[]}

Furthermore, the DEFFREG (hack) required that all floating point instruction
use all registers mentioned in the instruction. Therefore f1 := f2 + f3,
defines f1 and uses [f1,f2,f3]! This hack is no longer required resulting
in a cleaner alpha implementation. (Hopefully, intel will not get rid of
this architecture).

COPYXXX is intended to replace the parallel COPY and FCOPY  available on
all the architectures. This will result in further simplification of the
register allocator that must be aware of them for coalescing purposes, and
will also simplify certain aspects of the machine description that provides
callbacks related to parallel copies.

ANNOTATION should be obvious, and now INSTR represents the honest to God
machine instruction set!

The <arch>/instructions/<arch>Instr.sml files define certain utility
functions for making porting easier -- essentially converting upper case
to lower case. All machine instructions (of type instr) are in upper case,
and the lower case form generates an MLRISC instruction. For example on
the alpha we have:

  datatype instr =
     LDA of {r:cell, b:cell, d:operand}
   | ...

  val lda : {r:cell, b:cell, d:operand} -> instruction
    ...

where lda is just (INSTR o LDA), etc.
(*
 * X86 specific backend.  This one uses the new RA8 scheme.
 *)
structure X86CG = 
  MachineGen
  ( structure I          = X86Instr
    structure C          = I.C
    structure F          = X86CFG
    structure R          = X86CpsRegs
    structure CG         = Control.CG

    structure MachSpec   = X86Spec
    structure ClientPseudoOps = X86ClientPseudoOps
    structure PseudoOps  = X86PseudoOps
    structure Ext        = X86_SMLNJMLTreeExt(* x86-specific *)
    structure CpsRegs    = X86CpsRegs
    structure InsnProps  = X86Props
    structure Asm        = X86AsmEmitter
    structure Shuffle    = X86Shuffle

    val fast_floating_point = MLRiscControl.getFlag "x86-fast-fp"

    structure CCalls     = 
      IA32SVID_CCalls (structure T = X86MLTree  fun ix x = x
                       val fast_floating_point = fast_floating_point)

    structure OmitFramePtr = 
      X86OmitFramePointer(structure I=X86Instr  
			  structure MemRegs=X86MemRegs
			  structure CFG=X86CFG
			  val memRegBase = SOME(X86CpsRegs.vfp))

    val spill = CPSRegions.spill 
    val stack = CPSRegions.stack 

    fun error msg = MLRiscErrorMsg.error("X86CG",msg)

    fun base() = (* XXXX *)
      if !ClusterAnnotation.useVfp then X86CpsRegs.vfp else I.C.esp 


    structure MLTreeComp=
       X86(structure X86Instr=X86Instr
	   structure MLTreeUtils = MLTreeUtils
               (structure T = X86MLTree
                fun hashSext  _ _ = 0w0 
                fun hashRext  _ _ = 0w0
                fun hashFext  _ _ = 0w0 
                fun hashCCext _ _ = 0w0
             
                (* Equality extensions *)
                fun eqSext  _ _ = false
                fun eqRext  _ _ = false
                fun eqFext  _ _ = false
                fun eqCCext _ _ = false
             
                (* Pretty printing extensions *)
                fun showSext  _ _ = ""
                fun showRext  _ _ = ""
                fun showFext  _ _ = ""
                fun showCCext _ _ = ""
               )
           structure ExtensionComp = X86MLTreeExtComp
               (structure I = X86Instr
                structure T = X86MLTree
		structure CFG = X86CFG
		structure TS = X86MLTreeStream
               ) 
	   structure MLTreeStream = X86MLTreeStream
           datatype arch = Pentium | PentiumPro | PentiumII | PentiumIII
           val arch = ref Pentium (* Lowest common denominator *)
           fun cvti2f{src,ty,an} = let (* ty is always 32 for SML/NJ *)
	     val tempMem = I.Displace{base=base(), disp=I.Immed 304, mem=stack}
           in
               {instrs  = [I.move{mvOp=I.MOVL, src=src, dst=tempMem}],
                tempMem = tempMem,
                cleanup = []
               }
           end
           val fast_floating_point = fast_floating_point
          )

    structure Jumps = 
       X86Jumps(structure Instr=X86Instr
                structure AsmEmitter=X86AsmEmitter
		structure Eval=X86MLTreeEval 
                structure Shuffle=X86Shuffle
                structure MCEmitter=X86MCEmitter)
   
    structure BackPatch = 
       BackPatch(structure Jumps=Jumps
                 structure Emitter=X86MCEmitter
                 structure Props=InsnProps
		 structure Placement=DefaultBlockPlacement(X86CFG)
		 structure CFG = X86CFG
                 structure Asm=X86AsmEmitter
                 structure CodeString=CodeString)


    structure RA = 
      X86RA
      (structure I         = X86Instr
       structure CB	   = CellsBasis
       structure InsnProps = InsnProps
       structure Asm       = X86AsmEmitter
       structure CFG       = X86CFG
       structure SpillHeur = ChowHennessySpillHeur
       structure Spill     = RASpill
                             (structure Asm = X86AsmEmitter
                              structure InsnProps = InsnProps
                             )

       type spill_info = unit

       fun beforeRA _ = X86StackSpills.init()
       val fast_floating_point = fast_floating_point

       val toInt32 = Int32.fromInt
       fun cacheOffset r = I.Immed(toInt32(X86Runtime.vregStart + 
                                Word.toIntX(Word.<<(Word.fromInt(r-8),0w2))))
       fun cacheFPOffset f = I.Immed(toInt32(X86Runtime.vFpStart + 
                                Word.toIntX(Word.<<(Word.fromInt(f-40),0w3))))

       datatype raPhase = SPILL_PROPAGATION | SPILL_COLORING
       datatype spillOperandKind = SPILL_LOC | CONST_VAL

       structure Int =  
       struct
          val avail     = R.availR
          val dedicated = R.dedicatedR
          val memRegs   = C.Regs CB.GP {from=8,to=31,step=1}
          val phases    = [SPILL_PROPAGATION,SPILL_COLORING]

          (* We try to make unused memregs available for spilling 
           * This is necessary because of the stupid SML code generator
           * doesn't keep track of which are being used.
           *)
          fun spillInit(RAGraph.GRAPH{nodes, ...}) = 
          let val lookup = IntHashTable.lookup nodes
              fun find(r, free) =
                  if r >= 10 then (* note, %8 and %9 are reserved! *)
                     let val free = 
                             case lookup r of
                               RAGraph.NODE{uses=ref [], defs=ref [], ...} => 
                                  cacheOffset r::free
                             | _ => free
                     in  find(r-1, free) end
                  else 
                     free
              val free = find(31 (* X86Runtime.numVregs+8-1 *), [])
          in  X86StackSpills.setAvailableOffsets free
          end 
 
          val getRegLoc' = X86StackSpills.getRegLoc
 
          fun spillLoc{info, an, cell, id} = 
              {opnd=I.Displace{base=base(), disp=getRegLoc' id, mem=spill},
               kind=SPILL_LOC
              }
 
       end

       structure Float =
       struct
          val avail     = R.availF
          val dedicated = R.dedicatedF
          val memRegs   = []
          val phases    = [SPILL_PROPAGATION]

          fun spillInit(RAGraph.GRAPH{nodes, ...}) = 
              if !fast_floating_point then
              let val lookup = IntHashTable.lookup nodes
                 fun find(r, free) =
                     if r >= 32+8 then 
                        let val free = 
                                case lookup r of
                                  RAGraph.NODE{uses=ref [], defs=ref [],...} =>
                                     cacheFPOffset r::free
                                | _ => free
                        in  find(r-1, free) end
                     else 
                        free
                 val free = find(63, [])
              in X86StackSpills.setAvailableFPOffsets free
              end 
              else ()

          fun spillLoc(S, an, loc) =
            I.Displace{base=base(), disp=X86StackSpills.getFregLoc loc, mem=spill}

          val fastMemRegs = C.Regs CB.FP {from=8, to=31, step=1}
          val fastPhases  = [SPILL_PROPAGATION,SPILL_COLORING]
      end
    ) (* X86RA *)
  ) 


root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0