Annotation of researchv10no/cmd/sml/src/mips/mips.nw, revision 1.1

1.1     ! root        1: \section{Using [[MIPSCODER]] to implement a [[CMACHINE]]}
        !             2: 
        !             3: <<*>>=
        !             4: functor MipsCM(MipsC : MIPSCODER) : CMACHINE = struct
        !             5: 
        !             6:     open MipsC System.Tags
        !             7: 
        !             8:     <<utility functions>>
        !             9: 
        !            10:     <<immediate and register functions>>
        !            11: 
        !            12:     <<register definitions>>
        !            13: 
        !            14:     <<move>>
        !            15:     <<alignment, marks, and constants>>
        !            16:     <<labels>>
        !            17:     <<record manipulation>>
        !            18:     <<indexed fetch and store (byte)>>
        !            19:     <<indexed fetch and store (word)>>
        !            20:     <<arithmetic>>
        !            21:     <<shifts>>
        !            22:     <<arithmetic and shifts with overflow detection>>
        !            23:     <<bitwise operations>>
        !            24:     <<branches>>
        !            25: 
        !            26:     <<floating point>>
        !            27: 
        !            28:     <<memory check>>
        !            29: 
        !            30:     <<omitted functions>>
        !            31: 
        !            32:     val comment = M.comment
        !            33: 
        !            34: (* +DEBUG *)
        !            35:     <<DEBUG code>>
        !            36: (* -DEBUG *)
        !            37: 
        !            38: end (* MipsCM *)
        !            39: 
        !            40: @ The debugging code replaces possibly offensive functions with functions
        !            41: that diagnose their own exceptions.
        !            42: <<DEBUG code>>=
        !            43: fun diag (s : string) f x =
        !            44:        f x handle e =>
        !            45:                (print "?exception "; print (System.exn_name e);
        !            46:                 print " in mips."; print s; print "\n";
        !            47:                 raise e)
        !            48: 
        !            49: <<immediate and register functions>>=
        !            50: val immed = Immed
        !            51: fun isimmed(Immed i) = SOME i
        !            52:   | isimmed _ = NONE
        !            53: 
        !            54: fun isreg(Direct(Reg i)) = SOME i | isreg _ = NONE
        !            55: fun eqreg (a: EA) b = a=b
        !            56: 
        !            57: 
        !            58: @ Here's what our register conventions are:
        !            59: \input regs
        !            60: <<register definitions>>=
        !            61: val standardarg = Direct(Reg 2)
        !            62: val standardcont = Direct(Reg 3)
        !            63: val standardclosure = Direct(Reg 4)
        !            64: val miscregs = map (Direct o Reg) [5,6,7,8,9,10,11,12,13,14,
        !            65:                                    15,16,17,18,19]
        !            66: val storeptr as Direct storeptr' = Direct(Reg 22)
        !            67: val dataptr  as Direct dataptr'  = Direct(Reg 23)
        !            68: val exnptr = Direct(Reg 30)
        !            69: 
        !            70:   (* internal use only *)
        !            71: val my_arithtemp as Direct my_arithtemp'= Direct(Reg 20) 
        !            72: val my_ptrtemp as Direct my_ptrtemp' = Direct(Reg 21)
        !            73: 
        !            74:   (* exported for external use *)
        !            75: val arithtemp as Direct arithtemp' = Direct(Reg 24) 
        !            76: val arithtemp2 as Direct arithtemp2'= Direct(Reg 25)
        !            77: 
        !            78: <<move>>=
        !            79: fun move (src,Direct dest) = M.move(src, dest)
        !            80:   | move _ = ErrorMsg.impossible "destination of move not register in mips"
        !            81: <<alignment, marks, and constants>>=
        !            82: val align = M.align
        !            83: val mark = M.mark
        !            84: 
        !            85: val emitlong = M.emitlong
        !            86: val realconst = M.realconst
        !            87: val emitstring = M.emitstring
        !            88: 
        !            89: <<labels>>=
        !            90: fun emitlab(i,Immedlab lab) = M.emitlab(i,lab)
        !            91:   | emitlab _ = ErrorMsg.impossible "bad emitlab arg in mips"
        !            92: fun newlabel() = Immedlab(M.newlabel())
        !            93: fun define (Immedlab lab) = M.define lab
        !            94:   | define _ = ErrorMsg.impossible "bad define arg in mips"
        !            95: <<DEBUG code>>=
        !            96: val emitlab = diag "emitlab" emitlab
        !            97: val define = diag "define" define
        !            98: 
        !            99: 
        !           100: @ We only ever put the address of a newly created record into a register.
        !           101: If I make this out correctly, the first word on the list of
        !           102: values [[vl]] is actually a descriptor.
        !           103: BUGS: The original routine put the address of the descriptor
        !           104: into [[z]].  
        !           105: What needs to go into [[z]] is the address of the first word in the record.
        !           106: We can get this by adding 4 to the [[dataptr']].
        !           107: <<record manipulation>>=
        !           108: fun record(vl, Direct z) =
        !           109:     let open CPS
        !           110:         val len = List.length vl
        !           111:         fun f(i,nil) = ()
        !           112:           | f(i,(r, SELp(j,p))::rest) = (* follow ptrs to get the item *)
        !           113:                 (M.lw(my_ptrtemp', r, j*4); f(i,(my_ptrtemp,p)::rest))
        !           114:           | f(i,(Direct r,OFFp 0)::rest) =  (* simple store, last first *) 
        !           115:                 (M.sw(r, dataptr, i*4); f(i-1,rest))
        !           116:           | f(i,(Direct r, OFFp j)::rest) = 
        !           117:                 (M.add(r, Immed(4*j), my_ptrtemp'); 
        !           118:                                 f(i,(my_ptrtemp,OFFp 0)::rest))
        !           119:           | f(i,(ea,p)::rest) = (* convert to register-based *)
        !           120:                 (M.move(ea, my_ptrtemp'); f(i,(my_ptrtemp,p)::rest))
        !           121:       in f(len - 1, rev vl); (* store first word in [[0(dataptr')]] *)
        !           122:          M.add(dataptr', Immed 4, z);
        !           123:          M.add(dataptr', Immed(4*len), dataptr')
        !           124:      end
        !           125:    | record _ = ErrorMsg.impossible "result of record not register in mips"
        !           126: 
        !           127: fun select(i, r, Direct s) = M.lw(s, r, i*4)
        !           128:   | select _ = ErrorMsg.impossible "result of select not register in mips"
        !           129: 
        !           130: fun offset(i, Direct r, Direct s) = M.add(r,Immed(i*4), s)
        !           131:   | offset _ = ErrorMsg.impossible "nonregister arg to offset in mips"
        !           132: <<DEBUG code>>=
        !           133: val record = diag "record" record
        !           134: val select = diag "select" select
        !           135: val offset = diag "offset" offset
        !           136: 
        !           137: @ For the indexed fetch and store, arithtemp is {\em not} tagged---the
        !           138: tags are removed at a higher level (in {\tt generic.sml}).
        !           139: These could be made faster for the case when they're called with immediate
        !           140: constants as [[x]].
        !           141: <<indexed fetch and store (byte)>>=
        !           142: (* fetchindexb(x,y) fetches a byte: y <- mem[x+arithtemp]
        !           143:         y cannot be arithtemp *)
        !           144: fun fetchindexb(x,Direct y) =
        !           145:     (M.add(arithtemp',x,my_arithtemp');    
        !           146:      M.lbu(y,my_arithtemp,0))
        !           147:   | fetchindexb _ = ErrorMsg.impossible "fetchb result not register in mips"
        !           148: 
        !           149: (* storeindexb(x,y) stores a byte: mem[y+arithtemp] <- x; *)
        !           150: fun storeindexb(Direct x,y) =
        !           151:     (M.add(arithtemp',y,my_arithtemp');
        !           152:      M.sb(x,my_arithtemp,0))
        !           153:   | storeindexb _ = ErrorMsg.impossible "storeb arg not register in mips"
        !           154: 
        !           155: (* jmpindexb(x)    pc <- (x+arithtemp) *)
        !           156: fun jmpindexb x = (M.add(arithtemp',x,my_arithtemp');
        !           157:                      M.jump(my_arithtemp'))
        !           158: 
        !           159: <<DEBUG code>>=
        !           160: val fetchindexb = diag "fetchindexb" fetchindexb
        !           161: val storeindexb = diag "storeindexb" storeindexb
        !           162: val jmpindexb = diag "jmpindexb" jmpindexb
        !           163: 
        !           164: 
        !           165: @ Here it looks like [[z]] is a tagged integer number of words,
        !           166: so that [[2*(z-1)]] converts to the appropriate byte offset.
        !           167: But I'm just guessing.
        !           168: In any case, it saves an instruction to compute [[2*z]] (actually [[z+z]])
        !           169: and 
        !           170: load (or store) with offset [[~2]].
        !           171: 
        !           172: Anything stored with [[storeindexl]] is being put into an array, so it
        !           173: is safe to treat it as a pointer. 
        !           174: <<indexed fetch and store (word)>>=
        !           175:    (* fetchindexl(x,y,z) fetches a word:   y <- mem[x+2*(z-1)] *)
        !           176:    (* storeindexl(x,y,z) stores a word:    mem[y+2*(z-1)] <- x *)
        !           177: 
        !           178: fun fetchindexl(x,Direct y, Direct z) = 
        !           179:       (M.sll(Immed 1,z,my_arithtemp');
        !           180:        M.add(my_arithtemp',x,my_arithtemp');
        !           181:        M.lw(y, my_arithtemp,~2))
        !           182:   | fetchindexl(x,Direct y, Immed z) = M.lw(y, x, z+z-2)
        !           183:   | fetchindexl _ = ErrorMsg.impossible "fetchl result not register in mips"
        !           184: 
        !           185: fun storeindexl(Direct x,y, Immed 1) = M.sw(x,y,0)
        !           186:   | storeindexl(Direct x,y,Direct z) = 
        !           187:     (M.sll(Immed 1,z,my_arithtemp');
        !           188:      M.add(my_arithtemp',y,my_arithtemp');
        !           189:      M.sw(x, my_arithtemp,~2))
        !           190:   | storeindexl(Direct x,y,Immed z) = M.sw(x,y,z+z-2)
        !           191: 
        !           192:   | storeindexl(Direct _,_,Immedlab _) =
        !           193:        ErrorMsg.impossible "storeindexl(Direct _,_,Immedlab _) in mips"
        !           194: 
        !           195:   | storeindexl(Immedlab label,y,z) =
        !           196:     (M.move(Immedlab label,my_ptrtemp');
        !           197:      storeindexl(my_ptrtemp,y,z))
        !           198: 
        !           199:   | storeindexl(Immed constant,y,offset) =
        !           200:        (M.move(Immed constant,my_ptrtemp');
        !           201:         storeindexl(my_ptrtemp,y,offset))
        !           202: 
        !           203: <<DEBUG code>>=
        !           204: val fetchindexl = diag "fetchindexl" fetchindexl
        !           205: val storeindexl = diag "storeindexl" storeindexl
        !           206: 
        !           207: 
        !           208: @ The function [[three]] makes commutative three-operand
        !           209: instructions easier to call.
        !           210: All three operands become [[EA]]s, and it is enough if either of the
        !           211: first two operands is a register.
        !           212: <<utility functions>>=
        !           213: fun three f (Direct x, ea, Direct y) = f(x,ea,y)
        !           214:   | three f (ea, Direct x, Direct y) = f(x,ea,y)
        !           215:   | three f _ =ErrorMsg.impossible "neither arg to three f is register in mips"
        !           216: 
        !           217: @ I assume that shifts are only ever done on arithmetic quantities,
        !           218: not pointers, so that I am justified in using [[my_arithtemp']] to
        !           219: store intermediate values.  This is consistent with being unwilling
        !           220: to shift things matching [[Immedlab _]].
        !           221: Appel agrees that pointers aren't shifted, as far as he can remember.
        !           222: <<shifts>>=
        !           223: fun ashr(shamt, Direct op1, Direct result) = M.sra(shamt,op1,result)
        !           224:   | ashr(shamt, Immed op1, Direct result) = 
        !           225:        (M.move(Immed op1,my_arithtemp'); M.sra(shamt,my_arithtemp',result))
        !           226:   | ashr _ = ErrorMsg.impossible "ashr args don't match in mips"
        !           227: fun ashl(shamt, Direct op1, Direct result) = M.sll(shamt,op1,result)
        !           228:   | ashl(shamt, Immed op1, Direct result) = 
        !           229:        (M.move(Immed op1,my_arithtemp'); M.sll(shamt,my_arithtemp',result))
        !           230:   | ashl _ = ErrorMsg.impossible "ashl args don't match in mips"
        !           231: <<DEBUG code>>=
        !           232: val ashr = diag "ashr" ashr
        !           233: val ashl = diag "ashl" ashl
        !           234: 
        !           235: <<bitwise operations>>=
        !           236: val orb = three M.or
        !           237: val andb = three M.and'
        !           238: fun notb (a,b) = subl3(a, Immed ~1, b) (* ~1 - a == one's complement *)
        !           239: val xorb = three M.xor
        !           240: <<DEBUG code>>=
        !           241: val orb = diag "orb" orb
        !           242: val andb = diag "andb" andb
        !           243: val notb = diag "notb" notb
        !           244: val xorb = diag "xorb" xorb
        !           245: 
        !           246: 
        !           247: @ Subtraction may appear a bit odd.
        !           248: The MIPS machine instruction and  [[MIPSCODER.sub]] both subtract
        !           249: their second operand from their first operand.
        !           250: The VAX machine instruction and [[CMACHINE.subl3]] both subtract
        !           251: their first operand from their second operand.
        !           252: This will certainly lead to endless confusion.
        !           253: <<arithmetic>>=
        !           254: val addl3 = three M.add
        !           255: 
        !           256: fun subl3(Immed k, x, y) = addl3(x, Immed(~k), y)
        !           257:   | subl3(Direct x, Direct y, Direct z) = M.sub(y,x,z)
        !           258:   | subl3(x, Immed k, dest) = 
        !           259:             (M.move(Immed k, my_arithtemp');
        !           260:              subl3(x, my_arithtemp, dest))
        !           261:   | subl3 _ = ErrorMsg.impossible "subl3 args don't match in mips"
        !           262: 
        !           263: @ We assume that any quantities being multiplied are arithmetic
        !           264: quantities, not pointers.
        !           265: <<arithmetic>>=
        !           266: fun mull2(Direct x, Direct y) = M.mult(y,x,y)
        !           267:   | mull2(Immed x, Direct y) = (M.move(Immed x,my_arithtemp');
        !           268:                                M.mult(y,my_arithtemp',y))
        !           269:   | mull2 _ = ErrorMsg.impossible "mull2 args don't match in mips"
        !           270: fun divl2(Direct x, Direct y) = M.div(y,x,y)
        !           271:   | divl2(Immed x, Direct y) = (M.move(Immed x,my_arithtemp');
        !           272:                                M.div(y,my_arithtemp',y))
        !           273:   | divl2 _ = ErrorMsg.impossible "divl2 args don't match in mips"
        !           274: 
        !           275: <<DEBUG code>>=
        !           276: val addl3 = diag "addl3" addl3
        !           277: val subl3 = diag "subl3" subl3
        !           278: val mull2 = diag "mull2" mull2
        !           279: val divl2 = diag "divl2" divl2
        !           280: 
        !           281: 
        !           282: @ The Mips hardware detects two's complement integer overflow on 
        !           283: add and subtract instructions only.  
        !           284: The exception is not maskable (see the Mips book, page 5-18).
        !           285: At the moment we don't implement any overflow detection for multiplications
        !           286: or for left shifts.
        !           287: This has consequences only for coping with real constants and for
        !           288: compiling user programs.  
        !           289: <<arithmetic and shifts with overflow detection>>=
        !           290: val addl3t = addl3
        !           291: val subl3t = subl3
        !           292: @ The Mips multiplies two 32-bit quantities to get a 64-bit result.
        !           293: That result fits in 32 bits if and only if the high-order word is zero or
        !           294: negative one, and it has the same sign as the low order word.
        !           295: Thus, we can add the sign bit of the low order word to the high order
        !           296: word, and we have overflow if and only if the result is nonzero.
        !           297: <<arithmetic and shifts with overflow detection>>=
        !           298: fun mull2t(x,y as Direct y') = 
        !           299:     let val ok = M.newlabel()
        !           300:     in  mull2(x,y);
        !           301:        M.mfhi(my_arithtemp');
        !           302:        M.slt(y',Direct (Reg 0),my_ptrtemp'); (* 0 or 1 OK in pointer *)
        !           303:        M.add(my_arithtemp',my_ptrtemp,my_arithtemp');
        !           304:        M.beq(true,my_arithtemp',Reg 0,ok);    (* OK if not overflow *)
        !           305:        M.lui(my_arithtemp',32767);
        !           306:        M.add(my_arithtemp',my_arithtemp,my_arithtemp');  (* overflows *)
        !           307:        M.define(ok)
        !           308:     end
        !           309:   | mull2t _ = ErrorMsg.impossible "result of mull2t not register in mips"
        !           310: 
        !           311: <<DEBUG code>>=
        !           312: val addl3t = diag "addl3t" addl3t
        !           313: val subl3t = diag "subl3t" subl3t
        !           314: val mull2t = diag "mull2t" mull2t
        !           315: val ashlt = diag "ashlt" ashlt
        !           316: 
        !           317: 
        !           318: @ We hack [[ibranch]] to make sure it will only reverse once.
        !           319: It's easier than thinking.
        !           320: <<branches>>=
        !           321: datatype condition = NEQ | EQL | LEQ | GEQ | LSS | GTR
        !           322: local 
        !           323: fun makeibranch reverse = 
        !           324: let
        !           325: fun ibranch (cond, Immed a, Immed b, Immedlab label) =
        !           326:             if (case cond of EQL => a=b | NEQ => a<>b | LSS => a<b |
        !           327:                              LEQ => a<=b | GTR => a>b | GEQ => a>=b)
        !           328:                 then M.beq(true,Reg 0, Reg 0, label) else ()
        !           329:   | ibranch (NEQ, Direct r, Direct s, Immedlab label) =
        !           330:                     M.beq(false, r, s, label)
        !           331:   | ibranch (NEQ, Direct r, x, Immedlab label) =
        !           332:                     (M.move(x, my_arithtemp');
        !           333:                      M.beq(false, r, my_arithtemp', label))
        !           334:   | ibranch (EQL, Direct r, Direct s, Immedlab label) =
        !           335:                     M.beq(true, r, s, label)
        !           336:   | ibranch (EQL, Direct r, x, Immedlab label) =
        !           337:                     (M.move(x, my_arithtemp');
        !           338:                      M.beq(true, r, my_arithtemp', label))
        !           339:   | ibranch (LSS, Direct r, x, Immedlab lab) =
        !           340:                 (M.slt(r,x,my_arithtemp');
        !           341:                  M.beq(false,Reg 0, my_arithtemp',lab))
        !           342:   | ibranch (GEQ, Direct r, x, Immedlab lab) =
        !           343:                 (M.slt(r,x,my_arithtemp'); 
        !           344:                  M.beq(true,Reg 0, my_arithtemp',lab))
        !           345:   | ibranch (GTR, x, Direct r, Immedlab lab) =
        !           346:                 (M.slt(r,x,my_arithtemp'); 
        !           347:                  M.beq(false,Reg 0, my_arithtemp',lab))
        !           348:   | ibranch (LEQ, x, Direct r, Immedlab lab) =
        !           349:                 (M.slt(r,x,my_arithtemp'); 
        !           350:                  M.beq(true,Reg 0, my_arithtemp',lab))
        !           351: (* These two cases added to prevent infinite reversal *)
        !           352:   | ibranch (GTR, Direct r, x, Immedlab lab) =
        !           353:                (M.move(x, my_arithtemp');
        !           354:                 M.slt(my_arithtemp',Direct r,my_arithtemp');
        !           355:                 M.beq(false,Reg 0,my_arithtemp',lab))
        !           356:   | ibranch (LEQ, Direct r, x, Immedlab lab) =
        !           357:                (M.move(x, my_arithtemp');
        !           358:                 M.slt(my_arithtemp',Direct r,my_arithtemp');
        !           359:                 M.beq(true,Reg 0,my_arithtemp',lab))
        !           360:   | ibranch (_, Immedlab _, Immedlab _, _) = 
        !           361:                 ErrorMsg.impossible "bad ibranch args 1 in mips"
        !           362:   | ibranch (_, Immedlab _, _, _) = 
        !           363:                 ErrorMsg.impossible "bad ibranch args 1a in mips"
        !           364:   | ibranch (_, _, Immedlab _, _) = 
        !           365:                 ErrorMsg.impossible "bad ibranch args 1b in mips"
        !           366:   | ibranch (_, _, _, Direct _) = 
        !           367:                 ErrorMsg.impossible "bad ibranch args 2 in mips"
        !           368:   | ibranch (_, _, _, Immed _) = 
        !           369:                 ErrorMsg.impossible "bad ibranch args 3 in mips"
        !           370:   | ibranch (cond, x, y, l) = 
        !           371:         let fun rev LEQ = GEQ
        !           372:               | rev GEQ = LEQ
        !           373:               | rev LSS = GTR
        !           374:               | rev GTR = LSS
        !           375:               | rev NEQ = NEQ
        !           376:               | rev EQL = EQL
        !           377:         in  if reverse then (makeibranch false) (rev cond, y,x,l) 
        !           378:            else ErrorMsg.impossible "infinite ibranch reversal in mips"
        !           379:        
        !           380:         end
        !           381: in ibranch
        !           382: end
        !           383: in
        !           384: val ibranch = makeibranch true
        !           385: end
        !           386:     
        !           387: <<branches>>=
        !           388: fun jmp (Direct r) = M.jump(r)
        !           389:   | jmp (Immedlab lab) = M.beq(true,Reg 0,Reg 0,lab)
        !           390:   | jmp (Immed i) = ErrorMsg.impossible "jmp (Immed i) in mips"
        !           391: 
        !           392: 
        !           393:         (* branch on bit set *)
        !           394: fun bbs (Immed k, Direct y, Immedlab label) =
        !           395:         (M.and'(y,Immed (Bits.lshift(1,k)),my_arithtemp');
        !           396:          M.beq(false,my_arithtemp',Reg 0,label))
        !           397:   | bbs _ = ErrorMsg.impossible "bbs args don't match in mips"
        !           398: 
        !           399: <<DEBUG code>>=
        !           400: val ibranch = diag "ibranch" ibranch
        !           401: val jmp = diag "jmp" jmp
        !           402: val bbs = diag "bbs" bbs
        !           403: 
        !           404: @ We decided not to include floating point registers in our galaxy of
        !           405: effective addresses.
        !           406: This means that floating point registers are used only at this level, and
        !           407: only to contain intermediate results.
        !           408: All operands and final results will be stored in memory, in the usual
        !           409: ML format (i.e. as 8-byte strings).
        !           410: 
        !           411: In fact, we can be much more strict than that, and claim that
        !           412: all floating point operands will live in FPR0 and FPR2, and that all 
        !           413: results will appear in FPR0.
        !           414: 
        !           415: We don't make a distinction between general-purpose and floating point
        !           416: registers; it's up to the instructions to know the difference.
        !           417: <<floating point>>=
        !           418: val floatop1 = Reg 0
        !           419: val floatop2 = Reg 2
        !           420: val floatresult = Reg 0
        !           421: 
        !           422: @ One very common operation is to take the result of a floating point
        !           423: operation and put it into a fresh record, newly allocated on the heap.
        !           424: This operation is traditionally called [[finish_real]], and it takes one
        !           425: argument, the destination register for the new value.
        !           426: All real values on the heap are labelled as 8-byte strings.
        !           427: To store a floating point, we store the least significant
        !           428: word in the lower address, but we store the most significant word
        !           429: first, in case that triggers a garbage collection.
        !           430: <<floating point>>=
        !           431: val real_tag = Immed(8*System.Tags.power_tags + System.Tags.tag_string)
        !           432: 
        !           433: fun store_float(Reg n,ea,offset) = 
        !           434:     if n mod 2 <> 0 then ErrorMsg.impossible "bad float reg in mips"
        !           435:     else (M.swc1(Reg (n+1),ea,offset+4);M.swc1(Reg n,ea,offset))
        !           436: 
        !           437: fun finish_real (Direct result) = (
        !           438:     store_float(floatresult,dataptr,4);
        !           439:     M.move(real_tag,my_arithtemp');
        !           440:     M.sw(my_arithtemp',dataptr,0);
        !           441:     M.add(dataptr',Immed 4,result);
        !           442:     M.add(dataptr',Immed 12,dataptr'))
        !           443:   | finish_real _ = 
        !           444:      ErrorMsg.impossible "ptr to result of real operation not register in mips"
        !           445: 
        !           446: @ Loading a floating point quantity is analogous.
        !           447: <<floating point>>=
        !           448: fun load_float(Reg dest,src,offset) =
        !           449:     if dest mod 2 <> 0 then ErrorMsg.impossible "bad float reg in mips"
        !           450:     else (M.lwc1(Reg dest,src,offset); M.lwc1(Reg (dest+1),src,offset+4))
        !           451: 
        !           452: @ Now we can do a general two- and three-operand floating point operationa.
        !           453: The only parameter is the function in [[MipsCoder]] that
        !           454: emits the floating point register operation.
        !           455: <<floating point>>=
        !           456: fun two_float instruction (op1,result) = (
        !           457:     load_float(floatop1,op1,0);
        !           458:     instruction(floatop1,floatresult);
        !           459:     finish_real(result))
        !           460: 
        !           461: fun three_float instruction (op1,op2,result) = (
        !           462:     load_float(floatop1,op1,0);
        !           463:     load_float(floatop2,op2,0);
        !           464:     instruction(floatop1,floatop2,floatresult);
        !           465:     finish_real(result))
        !           466: 
        !           467: @ That takes care of everything except branch
        !           468: <<floating point>>=
        !           469: val mnegg = two_float M.neg_double
        !           470: val mulg3 = three_float M.mul_double
        !           471: val divg3 = three_float M.div_double
        !           472: val addg3 = three_float M.add_double
        !           473: val subg3 = three_float M.sub_double
        !           474: 
        !           475: 
        !           476: @ The Mips doesn't provide all six comparisons in hardware, so the
        !           477: next function does the comparison using only less than and equal.
        !           478: The result tells [[bcop1]] whether to branch on condition true
        !           479: or condition false.
        !           480: <<floating point compare>>=
        !           481: fun compare(LSS,op1,op2) = (M.slt_double(op1,op2); true)
        !           482:   | compare(GEQ,op1,op2) = (M.slt_double(op1,op2); false)
        !           483:   | compare(EQL,op1,op2) = (M.seq_double(op1,op2); true)
        !           484:   | compare(NEQ,op1,op2) = (M.seq_double(op1,op2); false)
        !           485:   | compare(LEQ,op1,op2) = compare(GEQ,op2,op1)
        !           486:   | compare(GTR,op1,op2) = compare(LSS,op2,op1)
        !           487: <<floating point>>=
        !           488: local
        !           489:     <<floating point compare>>
        !           490: in
        !           491:     fun gbranch (cond, op1, op2, Immedlab label) = (
        !           492:             load_float(floatop1,op1,0);
        !           493:             load_float(floatop2,op2,0);
        !           494:             M.bcop1(compare(cond,floatop1,floatop2),label))
        !           495:       | gbranch _ = ErrorMsg.impossible "insane gbranch target in mips.nw"
        !           496: end
        !           497:        
        !           498: 
        !           499: @ When a function begins execution, it checks to make sure there is sufficient
        !           500: memory available that it can do all its allocation.
        !           501: generic does this by calling [[checkLimit : int -> unit]].
        !           502: At the moment, we implement this check by doing a store,
        !           503: taking advantage of the virtual memory hardware, which will cause an exception
        !           504: if there's not enough memory.
        !           505: Later we will replace this store with a check against a limit register,
        !           506: which will avoid virtual memory hacking and which will have advantages
        !           507: for concurrency.
        !           508: <<memory check>>=
        !           509: fun checkLimit max_allocation = M.sw(Reg 0, dataptr, max_allocation-4)
        !           510:                              (* store zero in last location to be used *)
        !           511: 
        !           512: @ These two functions have null implementations.
        !           513: [[beginStdFn]] is necessary only on the SPARC, since that machine needs to get 
        !           514: its program counter, and it is awkward to do so in the middle of a function.
        !           515: 
        !           516: [[profile]] is a mysterious relic.
        !           517: <<omitted functions>>=
        !           518: fun beginStdFn _ = ()           (* do nothing, just like the Vax *)
        !           519: 
        !           520: fun profile(i,incr) = ()
        !           521: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.