2 % (c) The AQUA Project, Glasgow University, 1993-1996
4 \section[MachMisc]{Description of various machine-specific things}
7 #include "nativeGen/NCG.h"
11 fixedHdrSizeInWords, varHdrSizeInWords,
12 charLikeSize, intLikeSize, mutHS, dataHS, fixedHS, foHS,
13 sizeOf, primRepToSize,
17 volatileSaves, volatileRestores,
19 storageMgrInfo, smCAFlist, smOldLim, smOldMutables,
22 targetMaxDouble, targetMaxInt, targetMinDouble, targetMinInt,
29 Instr(..), IF_ARCH_i386(Operand(..) COMMA,)
43 #include "HsVersions.h"
45 import AbsCSyn ( MagicId(..) )
46 import AbsCUtils ( magicIdPrimRep )
47 import CLabel ( CLabel )
48 import CmdLineOpts ( opt_SccProfilingOn )
49 import Literal ( mkMachInt, Literal(..) )
50 import MachRegs ( stgReg, callerSaves, RegLoc(..),
54 import OrdList ( OrdList )
55 import PrimRep ( PrimRep(..) )
56 import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
57 import Stix ( StixTree(..), StixReg(..), sStLitLbl,
61 import Char ( isDigit )
62 import GlaExts ( word2Int#, int2Word#, shiftRA#, and#, (/=#) )
66 underscorePrefix :: Bool -- leading underscore on assembler labels?
70 ,{-else-} IF_ARCH_i386(
75 , {-otherwise-} False)))
77 ,{-else-}IF_ARCH_sparc(
78 IF_OS_sunos4(True, {-otherwise-} False)
81 ---------------------------
82 fmtAsmLbl :: String -> String -- for formatting labels
86 {- The alpha assembler likes temporary labels to look like $L123
87 instead of L123. (Don't toss the L, because then Lf28
95 ---------------------------
96 cvtLitLit :: String -> String
99 -- Rather than relying on guessing, use FILE_SIZE to compute the
102 cvtLitLit "stdin" = IF_ARCH_alpha("_iob+0" {-probably OK...-}
103 ,IF_ARCH_i386("_IO_stdin_"
104 ,IF_ARCH_sparc("__iob+0x0"{-probably OK...-}
107 cvtLitLit "stdout" = IF_ARCH_alpha("_iob+"++show (``FILE_SIZE''::Int)
108 ,IF_ARCH_i386("_IO_stdout_"
109 ,IF_ARCH_sparc("__iob+"++show (``FILE_SIZE''::Int)
111 cvtLitLit "stderr" = IF_ARCH_alpha("_iob+"++show (2*(``FILE_SIZE''::Int))
112 ,IF_ARCH_i386("_IO_stderr_"
113 ,IF_ARCH_sparc("__iob+"++show (2*(``FILE_SIZE''::Int))
116 cvtLitLit "stdout" = IF_ARCH_alpha("_iob+56"{-dodgy *at best*...-}
117 ,IF_ARCH_i386("_IO_stdout_"
118 ,IF_ARCH_sparc("__iob+0x10"{-dodgy *at best*...-}
120 cvtLitLit "stderr" = IF_ARCH_alpha("_iob+112"{-dodgy *at best*...-}
121 ,IF_ARCH_i386("_IO_stderr_"
122 ,IF_ARCH_sparc("__iob+0x20"{-dodgy *at best*...-}
127 | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
129 isHex ('0':'x':xs) = all isHexDigit xs
131 -- Now, where have I seen this before?
132 isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
135 % ----------------------------------------------------------------
137 We (allegedly) put the first six C-call arguments in registers;
138 where do we start putting the rest of them?
140 eXTRA_STK_ARGS_HERE :: Int
142 = IF_ARCH_alpha(0, IF_ARCH_i386(23{-6x4bytes-}, IF_ARCH_sparc(23,???)))
145 % ----------------------------------------------------------------
147 @fixedHdrSizeInWords@ and @varHdrSizeInWords@: these are not dependent
148 on target architecture.
150 fixedHdrSizeInWords :: Int
153 = 1{-info ptr-} + profFHS + parFHS + tickyFHS
154 -- obviously, we aren't taking non-sequential too seriously yet
156 profFHS = if opt_SccProfilingOn then 1 else 0
157 parFHS = {-if PAR or GRAN then 1 else-} 0
158 tickyFHS = {-if ticky ... then 1 else-} 0
160 varHdrSizeInWords :: SMRep -> Int{-in words-}
165 SpecialisedRep _ _ _ _ -> 0
166 GenericRep _ _ _ -> 0
168 MuTupleRep _ -> 2 {- (1 + GC_MUT_RESERVED_WORDS) -}
172 PhantomRep -> panic "MachMisc.varHdrSizeInWords:phantom"
175 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
177 Static closure sizes:
179 charLikeSize, intLikeSize :: Int
181 charLikeSize = blahLikeSize CharLikeRep
182 intLikeSize = blahLikeSize IntLikeRep
185 = fromInteger (sizeOf PtrRep)
186 * (fixedHdrSizeInWords + varHdrSizeInWords blahLikeRep + 1)
188 blahLikeRep = SpecialisedRep blah 0 1 SMNormalForm
191 mutHS, dataHS, fixedHS, foHS :: StixTree
193 mutHS = blah_hs (MuTupleRep 0)
194 dataHS = blah_hs (DataRep 0)
195 fixedHS = StInt (toInteger fixedHdrSizeInWords)
197 {- Semi-hack: to avoid introducing ForeignObjRep,
198 we hard-code the VHS for ForeignObj here.
201 = StInt (toInteger words)
203 words = fixedHdrSizeInWords + 1{-FOREIGN_VHS-}
206 = StInt (toInteger words)
208 words = fixedHdrSizeInWords + varHdrSizeInWords blah
211 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
213 Size of a @PrimRep@, in bytes.
216 sizeOf :: PrimRep -> Integer{-in bytes-}
217 -- the result is an Integer only because it's more convenient
219 sizeOf pr = case (primRepToSize pr) of
220 IF_ARCH_alpha({B -> 1; BU -> 1; {-W -> 2; WU -> 2; L -> 4; SF -> 4;-} _ -> 8},)
221 IF_ARCH_sparc({B -> 1; BU -> 1; {-HW -> 2; HWU -> 2;-} W -> 4; {-D -> 8;-} F -> 4; DF -> 8},)
222 IF_ARCH_i386( {B -> 1; {-S -> 2;-} L -> 4; F -> 4; DF -> 8 },)
225 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
227 Now the volatile saves and restores. We add the basic guys to the
228 list of ``user'' registers provided. Note that there are more basic
229 registers on the restore list, because some are reloaded from
232 (@volatileRestores@ used only for wrapper-hungry PrimOps.)
235 volatileSaves, volatileRestores :: [MagicId] -> [StixTree]
237 save_cands = [BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg]
238 restore_cands = save_cands ++ [StkStubReg,StdUpdRetVecReg]
241 = map save ((filter callerSaves) (save_cands ++ vols))
243 save x = StAssign (magicIdPrimRep x) loc reg
245 reg = StReg (StixMagicId x)
246 loc = case stgReg x of
248 Always _ -> panic "volatileSaves"
250 volatileRestores vols
251 = map restore ((filter callerSaves) (restore_cands ++ vols))
253 restore x = StAssign (magicIdPrimRep x) reg loc
255 reg = StReg (StixMagicId x)
256 loc = case stgReg x of
258 Always _ -> panic "volatileRestores"
261 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
263 Obviously slightly weedy
264 (Note that the floating point values aren't terribly important.)
267 targetMinDouble = MachDouble (-1.7976931348623157e+308)
268 targetMaxDouble = MachDouble (1.7976931348623157e+308)
269 targetMinInt = mkMachInt (-2147483647)
270 targetMaxInt = mkMachInt 2147483647
273 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
275 Storage manager nonsense. Note that the indices are dependent on
276 the definition of the smInfo structure in SMinterface.lh
279 storageMgrInfo, smCAFlist, smOldMutables, smOldLim :: StixTree
281 storageMgrInfo = sStLitLbl SLIT("StorageMgrInfo")
282 smCAFlist = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_CAFLIST))
283 smOldMutables = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_OLDMUTABLES))
284 smOldLim = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_OLDLIM))
285 smStablePtrTable = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_STABLEPOINTERTABLE))
288 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
290 This algorithm for determining the $\log_2$ of exact powers of 2 comes
291 from GCC. It requires bit manipulation primitives, and we use GHC
299 exactLog2 :: Integer -> Maybe Integer
301 = if (x <= 0 || x >= 2147483648) then
304 case (fromInteger x) of { I# x# ->
305 if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
308 Just (toInteger (I# (pow2 x#)))
311 shiftr x y = shiftRA# x y
313 pow2 x# | x# ==# 1# = 0#
314 | otherwise = 1# +# pow2 (w2i (i2w x# `shiftr` i2w_s 1#))
317 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
321 #if alpha_TARGET_ARCH
322 = ALWAYS -- For BI (same as BR)
323 | EQQ -- For CMP and BI (NB: "EQ" is a 1.3 Prelude name)
325 | GTT -- For BI only (NB: "GT" is a 1.3 Prelude name)
326 | LE -- For CMP and BI
327 | LTT -- For CMP and BI (NB: "LT" is a 1.3 Prelude name)
329 | NEVER -- For BI (null instruction)
330 | ULE -- For CMP only
331 | ULT -- For CMP only
334 = ALWAYS -- What's really used? ToDo
348 #if sparc_TARGET_ARCH
349 = ALWAYS -- What's really used? ToDo
370 #if alpha_TARGET_ARCH
373 -- | W -- word (2 bytes): UNUSED
375 -- | L -- longword (4 bytes): UNUSED
376 | Q -- quadword (8 bytes)
377 -- | FF -- VAX F-style floating pt: UNUSED
378 -- | GF -- VAX G-style floating pt: UNUSED
379 -- | DF -- VAX D-style floating pt: UNUSED
380 -- | SF -- IEEE single-precision floating pt: UNUSED
381 | TF -- IEEE double-precision floating pt
385 -- | HB -- higher byte **UNUSED**
388 | F -- IEEE single-precision floating pt
389 | DF -- IEEE single-precision floating pt
391 #if sparc_TARGET_ARCH
393 | BU -- byte (unsigned)
394 -- | HW -- halfword, 2 bytes (signed): UNUSED
395 -- | HWU -- halfword, 2 bytes (unsigned): UNUSED
397 -- | D -- doubleword, 8 bytes: UNUSED
398 | F -- IEEE single-precision floating pt
399 | DF -- IEEE single-precision floating pt
402 primRepToSize :: PrimRep -> Size
404 primRepToSize PtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
405 primRepToSize CodePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
406 primRepToSize DataPtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
407 primRepToSize RetRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
408 primRepToSize CostCentreRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
409 primRepToSize CharRep = IF_ARCH_alpha( BU, IF_ARCH_i386( L, IF_ARCH_sparc( BU,)))
410 primRepToSize IntRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
411 primRepToSize WordRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
412 primRepToSize AddrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
413 primRepToSize FloatRep = IF_ARCH_alpha( TF, IF_ARCH_i386( F, IF_ARCH_sparc( F ,)))
414 primRepToSize DoubleRep = IF_ARCH_alpha( TF, IF_ARCH_i386( DF,IF_ARCH_sparc( DF,)))
415 primRepToSize ArrayRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
416 primRepToSize ByteArrayRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
417 primRepToSize StablePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
418 primRepToSize ForeignObjRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
421 %************************************************************************
423 \subsection{Machine's assembly language}
425 %************************************************************************
427 We have a few common ``instructions'' (nearly all the pseudo-ops) but
428 mostly all of @Instr@ is machine-specific.
432 = COMMENT FAST_STRING -- comment pseudo-op
433 | SEGMENT CodeSegment -- {data,text} segment pseudo-op
434 | LABEL CLabel -- global label pseudo-op
435 | ASCII Bool -- True <=> needs backslash conversion
436 String -- the literal string
442 #if alpha_TARGET_ARCH
444 -- data Instr continues...
448 | LD Size Reg MachRegsAddr -- size, dst, src
449 | LDA Reg MachRegsAddr -- dst, src
450 | LDAH Reg MachRegsAddr -- dst, src
451 | LDGP Reg MachRegsAddr -- dst, src
452 | LDI Size Reg Imm -- size, dst, src
453 | ST Size Reg MachRegsAddr -- size, src, dst
458 | ABS Size RI Reg -- size, src, dst
459 | NEG Size Bool RI Reg -- size, overflow, src, dst
460 | ADD Size Bool Reg RI Reg -- size, overflow, src, src, dst
461 | SADD Size Size Reg RI Reg -- size, scale, src, src, dst
462 | SUB Size Bool Reg RI Reg -- size, overflow, src, src, dst
463 | SSUB Size Size Reg RI Reg -- size, scale, src, src, dst
464 | MUL Size Bool Reg RI Reg -- size, overflow, src, src, dst
465 | DIV Size Bool Reg RI Reg -- size, unsigned, src, src, dst
466 | REM Size Bool Reg RI Reg -- size, unsigned, src, src, dst
468 -- Simple bit-twiddling.
488 | CMP Cond Reg RI Reg
495 | FADD Size Reg Reg Reg
496 | FDIV Size Reg Reg Reg
497 | FMUL Size Reg Reg Reg
498 | FSUB Size Reg Reg Reg
499 | CVTxy Size Size Reg Reg
500 | FCMP Size Cond Reg Reg Reg
508 | JMP Reg MachRegsAddr Int
510 | JSR Reg MachRegsAddr Int
512 -- Alpha-specific pseudo-ops.
521 #endif {- alpha_TARGET_ARCH -}
527 -- data Instr continues...
531 | MOV Size Operand Operand
532 | MOVZX Size Operand Operand -- size is the size of operand 2
533 | MOVSX Size Operand Operand -- size is the size of operand 2
535 -- Load effective address (also a very useful three-operand add instruction :-)
537 | LEA Size Operand Operand
541 | ADD Size Operand Operand
542 | SUB Size Operand Operand
544 -- Multiplication (signed and unsigned), Division (signed and unsigned),
545 -- result in %eax, %edx.
547 | IMUL Size Operand Operand
550 -- Simple bit-twiddling.
552 | AND Size Operand Operand
553 | OR Size Operand Operand
554 | XOR Size Operand Operand
556 | NEGI Size Operand -- NEG instruction (name clash with Cond)
557 | SHL Size Operand Operand -- 1st operand must be an Imm or CL
558 | SAR Size Operand Operand -- 1st operand must be an Imm or CL
559 | SHR Size Operand Operand -- 1st operand must be an Imm or CL
562 -- Float Arithmetic. -- ToDo for 386
564 -- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
565 -- right up until we spit them out.
567 | SAHF -- stores ah into flags
569 | FADD Size Operand -- src
571 | FIADD Size MachRegsAddr -- src
573 | FCOM Size Operand -- src
575 | FDIV Size Operand -- src
577 | FIDIV Size MachRegsAddr -- src
578 | FDIVR Size Operand -- src
580 | FIDIVR Size MachRegsAddr -- src
581 | FICOM Size MachRegsAddr -- src
582 | FILD Size MachRegsAddr Reg -- src, dst
583 | FIST Size MachRegsAddr -- dst
584 | FLD Size Operand -- src
587 | FMUL Size Operand -- src
589 | FIMUL Size MachRegsAddr -- src
593 | FST Size Operand -- dst
594 | FSTP Size Operand -- dst
595 | FSUB Size Operand -- src
597 | FISUB Size MachRegsAddr -- src
598 | FSUBR Size Operand -- src
600 | FISUBR Size MachRegsAddr -- src
602 | FCOMP Size Operand -- src
610 | TEST Size Operand Operand
611 | CMP Size Operand Operand
621 | JMP Operand -- target
622 | JXX Cond CLabel -- target
627 | CLTD -- sign extend %eax into %edx:%eax
630 = OpReg Reg -- register
631 | OpImm Imm -- immediate value
632 | OpAddr MachRegsAddr -- memory reference
634 #endif {- i386_TARGET_ARCH -}
638 #if sparc_TARGET_ARCH
640 -- data Instr continues...
644 | LD Size MachRegsAddr Reg -- size, src, dst
645 | ST Size Reg MachRegsAddr -- size, src, dst
649 | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
650 | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
652 -- Simple bit-twiddling.
654 | AND Bool Reg RI Reg -- cc?, src1, src2, dst
655 | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst
656 | OR Bool Reg RI Reg -- cc?, src1, src2, dst
657 | ORN Bool Reg RI Reg -- cc?, src1, src2, dst
658 | XOR Bool Reg RI Reg -- cc?, src1, src2, dst
659 | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst
660 | SLL Reg RI Reg -- src1, src2, dst
661 | SRL Reg RI Reg -- src1, src2, dst
662 | SRA Reg RI Reg -- src1, src2, dst
663 | SETHI Imm Reg -- src, dst
664 | NOP -- Really SETHI 0, %g0, but worth an alias
668 -- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
669 -- right up until we spit them out.
671 | FABS Size Reg Reg -- src dst
672 | FADD Size Reg Reg Reg -- src1, src2, dst
673 | FCMP Bool Size Reg Reg -- exception?, src1, src2, dst
674 | FDIV Size Reg Reg Reg -- src1, src2, dst
675 | FMOV Size Reg Reg -- src, dst
676 | FMUL Size Reg Reg Reg -- src1, src2, dst
677 | FNEG Size Reg Reg -- src, dst
678 | FSQRT Size Reg Reg -- src, dst
679 | FSUB Size Reg Reg Reg -- src1, src2, dst
680 | FxTOy Size Size Reg Reg -- src, dst
684 | BI Cond Bool Imm -- cond, annul?, target
685 | BF Cond Bool Imm -- cond, annul?, target
687 | JMP MachRegsAddr -- target
688 | CALL Imm Int Bool -- target, args, terminal
695 riZero (RIImm (ImmInt 0)) = True
696 riZero (RIImm (ImmInteger 0)) = True
697 riZero (RIReg (FixedReg ILIT(0))) = True
700 #endif {- sparc_TARGET_ARCH -}