2 % (c) The AQUA Project, Glasgow University, 1993-1998
4 \section[MachMisc]{Description of various machine-specific things}
7 #include "nativeGen/NCG.h"
11 sizeOf, primRepToSize,
15 volatileSaves, volatileRestores,
17 targetMaxDouble, targetMaxInt, targetMinDouble, targetMinInt,
23 stixFor_stdout, stixFor_stderr, stixFor_stdin,
25 Instr(..), IF_ARCH_i386(Operand(..) COMMA,)
28 IF_ARCH_i386(i386_insert_ffrees COMMA,)
40 #include "HsVersions.h"
41 -- #include "config.h"
43 import AbsCSyn ( MagicId(..) )
44 import AbsCUtils ( magicIdPrimRep )
45 import CLabel ( CLabel, isAsmTemp )
46 import Const ( mkMachInt, Literal(..) )
47 import MachRegs ( stgReg, callerSaves, RegLoc(..),
51 import PrimRep ( PrimRep(..) )
52 import SMRep ( SMRep(..) )
53 import Stix ( StixTree(..), StixReg(..), CodeSegment )
54 import Panic ( panic )
55 import Char ( isDigit )
56 import GlaExts ( word2Int#, int2Word#, shiftRL#, and#, (/=#) )
57 import Outputable ( text )
61 underscorePrefix :: Bool -- leading underscore on assembler labels?
63 #ifdef LEADING_UNDERSCORE
64 underscorePrefix = True
66 underscorePrefix = False
69 ---------------------------
70 fmtAsmLbl :: String -> String -- for formatting labels
74 {- The alpha assembler likes temporary labels to look like $L123
75 instead of L123. (Don't toss the L, because then Lf28
83 ---------------------------
84 stixFor_stdout, stixFor_stderr, stixFor_stdin :: StixTree
86 -- Linux glibc 2 / libc6
87 stixFor_stdout = StInd PtrRep (StLitLbl (text "stdout"))
88 stixFor_stderr = StInd PtrRep (StLitLbl (text "stderr"))
89 stixFor_stdin = StInd PtrRep (StLitLbl (text "stdin"))
93 stixFor_stdout = error "stixFor_stdout: not implemented for Alpha"
94 stixFor_stderr = error "stixFor_stderr: not implemented for Alpha"
95 stixFor_stdin = error "stixFor_stdin: not implemented for Alpha"
99 stixFor_stdout = error "stixFor_stdout: not implemented for Sparc"
100 stixFor_stderr = error "stixFor_stderr: not implemented for Sparc"
101 stixFor_stdin = error "stixFor_stdin: not implemented for Sparc"
105 Here's some old stuff from which it shouldn't be too hard to
106 implement the above for Alpha/Sparc.
108 cvtLitLit :: String -> String
111 -- Rather than relying on guessing, use FILE_SIZE to compute the
114 cvtLitLit "stdin" = IF_ARCH_alpha("_iob+0" {-probably OK...-}
115 ,IF_ARCH_i386("stdin"
116 ,IF_ARCH_sparc("__iob+0x0"{-probably OK...-}
119 cvtLitLit "stdout" = IF_ARCH_alpha("_iob+"++show (``FILE_SIZE''::Int)
120 ,IF_ARCH_i386("stdout"
121 ,IF_ARCH_sparc("__iob+"++show (``FILE_SIZE''::Int)
123 cvtLitLit "stderr" = IF_ARCH_alpha("_iob+"++show (2*(``FILE_SIZE''::Int))
124 ,IF_ARCH_i386("stderr"
125 ,IF_ARCH_sparc("__iob+"++show (2*(``FILE_SIZE''::Int))
131 % ----------------------------------------------------------------
133 We (allegedly) put the first six C-call arguments in registers;
134 where do we start putting the rest of them?
136 eXTRA_STK_ARGS_HERE :: Int
138 = IF_ARCH_alpha(0, IF_ARCH_i386(23{-6x4bytes-}, IF_ARCH_sparc(23,???)))
141 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143 Size of a @PrimRep@, in bytes.
146 sizeOf :: PrimRep -> Integer{-in bytes-}
147 -- the result is an Integer only because it's more convenient
149 sizeOf pr = case (primRepToSize pr) of
150 IF_ARCH_alpha({B -> 1; BU -> 1; {-W -> 2; WU -> 2; L -> 4; SF -> 4;-} _ -> 8},)
151 IF_ARCH_sparc({B -> 1; BU -> 1; {-HW -> 2; HWU -> 2;-} W -> 4; {-D -> 8;-} F -> 4; DF -> 8},)
152 IF_ARCH_i386( {B -> 1; {-S -> 2;-} L -> 4; F -> 4; DF -> 8 },)
155 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
157 Now the volatile saves and restores. We add the basic guys to the
158 list of ``user'' registers provided. Note that there are more basic
159 registers on the restore list, because some are reloaded from
162 (@volatileRestores@ used only for wrapper-hungry PrimOps.)
165 volatileSaves, volatileRestores :: [MagicId] -> [StixTree]
167 save_cands = [BaseReg,Sp,Su,SpLim,Hp,HpLim]
168 restore_cands = save_cands
171 = map save ((filter callerSaves) (save_cands ++ vols))
173 save x = StAssign (magicIdPrimRep x) loc reg
175 reg = StReg (StixMagicId x)
176 loc = case stgReg x of
178 Always _ -> panic "volatileSaves"
180 volatileRestores vols
181 = map restore ((filter callerSaves) (restore_cands ++ vols))
183 restore x = StAssign (magicIdPrimRep x) reg loc
185 reg = StReg (StixMagicId x)
186 loc = case stgReg x of
188 Always _ -> panic "volatileRestores"
191 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
193 Obviously slightly weedy
194 (Note that the floating point values aren't terribly important.)
197 targetMinDouble = MachDouble (-1.7976931348623157e+308)
198 targetMaxDouble = MachDouble (1.7976931348623157e+308)
199 targetMinInt = mkMachInt (-2147483648)
200 targetMaxInt = mkMachInt 2147483647
203 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
205 This algorithm for determining the $\log_2$ of exact powers of 2 comes
206 from GCC. It requires bit manipulation primitives, and we use GHC
213 exactLog2 :: Integer -> Maybe Integer
215 = if (x <= 0 || x >= 2147483648) then
218 case (fromInteger x) of { I# x# ->
219 if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
222 Just (toInteger (I# (pow2 x#)))
225 shiftr x y = shiftRL# x y
227 pow2 x# | x# ==# 1# = 0#
228 | otherwise = 1# +# pow2 (w2i (i2w x# `shiftr` 1#))
231 % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
235 #if alpha_TARGET_ARCH
236 = ALWAYS -- For BI (same as BR)
237 | EQQ -- For CMP and BI (NB: "EQ" is a 1.3 Prelude name)
239 | GTT -- For BI only (NB: "GT" is a 1.3 Prelude name)
240 | LE -- For CMP and BI
241 | LTT -- For CMP and BI (NB: "LT" is a 1.3 Prelude name)
243 | NEVER -- For BI (null instruction)
244 | ULE -- For CMP only
245 | ULT -- For CMP only
248 = ALWAYS -- What's really used? ToDo
262 #if sparc_TARGET_ARCH
263 = ALWAYS -- What's really used? ToDo
284 #if alpha_TARGET_ARCH
287 -- | W -- word (2 bytes): UNUSED
289 -- | L -- longword (4 bytes): UNUSED
290 | Q -- quadword (8 bytes)
291 -- | FF -- VAX F-style floating pt: UNUSED
292 -- | GF -- VAX G-style floating pt: UNUSED
293 -- | DF -- VAX D-style floating pt: UNUSED
294 -- | SF -- IEEE single-precision floating pt: UNUSED
295 | TF -- IEEE double-precision floating pt
299 -- | HB -- higher byte **UNUSED**
302 | F -- IEEE single-precision floating pt
303 | DF -- IEEE single-precision floating pt
305 #if sparc_TARGET_ARCH
307 | BU -- byte (unsigned)
308 -- | HW -- halfword, 2 bytes (signed): UNUSED
309 -- | HWU -- halfword, 2 bytes (unsigned): UNUSED
311 -- | D -- doubleword, 8 bytes: UNUSED
312 | F -- IEEE single-precision floating pt
313 | DF -- IEEE single-precision floating pt
316 primRepToSize :: PrimRep -> Size
318 primRepToSize PtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
319 primRepToSize CodePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
320 primRepToSize DataPtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
321 primRepToSize RetRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
322 primRepToSize CostCentreRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
323 primRepToSize CharRep = IF_ARCH_alpha( BU, IF_ARCH_i386( B, IF_ARCH_sparc( BU,)))
324 primRepToSize IntRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
325 primRepToSize WordRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
326 primRepToSize AddrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
327 primRepToSize FloatRep = IF_ARCH_alpha( TF, IF_ARCH_i386( F, IF_ARCH_sparc( F ,)))
328 primRepToSize DoubleRep = IF_ARCH_alpha( TF, IF_ARCH_i386( DF,IF_ARCH_sparc( DF,)))
329 primRepToSize ArrayRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
330 primRepToSize ByteArrayRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
331 primRepToSize WeakPtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
332 primRepToSize ForeignObjRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
333 primRepToSize StablePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
336 %************************************************************************
338 \subsection{Machine's assembly language}
340 %************************************************************************
342 We have a few common ``instructions'' (nearly all the pseudo-ops) but
343 mostly all of @Instr@ is machine-specific.
347 = COMMENT FAST_STRING -- comment pseudo-op
348 | SEGMENT CodeSegment -- {data,text} segment pseudo-op
349 | LABEL CLabel -- global label pseudo-op
350 | ASCII Bool -- True <=> needs backslash conversion
351 String -- the literal string
357 #if alpha_TARGET_ARCH
359 -- data Instr continues...
363 | LD Size Reg MachRegsAddr -- size, dst, src
364 | LDA Reg MachRegsAddr -- dst, src
365 | LDAH Reg MachRegsAddr -- dst, src
366 | LDGP Reg MachRegsAddr -- dst, src
367 | LDI Size Reg Imm -- size, dst, src
368 | ST Size Reg MachRegsAddr -- size, src, dst
373 | ABS Size RI Reg -- size, src, dst
374 | NEG Size Bool RI Reg -- size, overflow, src, dst
375 | ADD Size Bool Reg RI Reg -- size, overflow, src, src, dst
376 | SADD Size Size Reg RI Reg -- size, scale, src, src, dst
377 | SUB Size Bool Reg RI Reg -- size, overflow, src, src, dst
378 | SSUB Size Size Reg RI Reg -- size, scale, src, src, dst
379 | MUL Size Bool Reg RI Reg -- size, overflow, src, src, dst
380 | DIV Size Bool Reg RI Reg -- size, unsigned, src, src, dst
381 | REM Size Bool Reg RI Reg -- size, unsigned, src, src, dst
383 -- Simple bit-twiddling.
403 | CMP Cond Reg RI Reg
410 | FADD Size Reg Reg Reg
411 | FDIV Size Reg Reg Reg
412 | FMUL Size Reg Reg Reg
413 | FSUB Size Reg Reg Reg
414 | CVTxy Size Size Reg Reg
415 | FCMP Size Cond Reg Reg Reg
423 | JMP Reg MachRegsAddr Int
425 | JSR Reg MachRegsAddr Int
427 -- Alpha-specific pseudo-ops.
436 #endif {- alpha_TARGET_ARCH -}
439 Intel, in their infinite wisdom, selected a stack model for floating
440 point registers on x86. That might have made sense back in 1979 --
441 nowadays we can see it for the nonsense it really is. A stack model
442 fits poorly with the existing nativeGen infrastructure, which assumes
443 flat integer and FP register sets. Prior to this commit, nativeGen
444 could not generate correct x86 FP code -- to do so would have meant
445 somehow working the register-stack paradigm into the register
446 allocator and spiller, which sounds very difficult.
448 We have decided to cheat, and go for a simple fix which requires no
449 infrastructure modifications, at the expense of generating ropey but
450 correct FP code. All notions of the x86 FP stack and its insns have
451 been removed. Instead, we pretend (to the instruction selector and
452 register allocator) that x86 has six floating point registers, %fake0
453 .. %fake5, which can be used in the usual flat manner. We further
454 claim that x86 has floating point instructions very similar to SPARC
455 and Alpha, that is, a simple 3-operand register-register arrangement.
456 Code generation and register allocation proceed on this basis.
458 When we come to print out the final assembly, our convenient fiction
459 is converted to dismal reality. Each fake instruction is
460 independently converted to a series of real x86 instructions.
461 %fake0 .. %fake5 are mapped to %st(0) .. %st(5). To do reg-reg
462 arithmetic operations, the two operands are pushed onto the top of the
463 FP stack, the operation done, and the result copied back into the
464 relevant register. There are only six %fake registers because 2 are
465 needed for the translation, and x86 has 8 in total.
467 The translation is inefficient but is simple and it works. A cleverer
468 translation would handle a sequence of insns, simulating the FP stack
469 contents, would not impose a fixed mapping from %fake to %st regs, and
470 hopefully could avoid most of the redundant reg-reg moves of the
476 -- data Instr continues...
480 | MOV Size Operand Operand
481 | MOVZxL Size Operand Operand -- size is the size of operand 1
482 | MOVSxL Size Operand Operand -- size is the size of operand 1
484 -- Load effective address (also a very useful three-operand add instruction :-)
486 | LEA Size Operand Operand
490 | ADD Size Operand Operand
491 | SUB Size Operand Operand
493 -- Multiplication (signed and unsigned), Division (signed and unsigned),
494 -- result in %eax, %edx.
496 | IMUL Size Operand Operand
499 -- Simple bit-twiddling.
501 | AND Size Operand Operand
502 | OR Size Operand Operand
503 | XOR Size Operand Operand
505 | NEGI Size Operand -- NEG instruction (name clash with Cond)
506 | SHL Size Imm Operand -- Only immediate shifts allowed
507 | SAR Size Imm Operand -- Only immediate shifts allowed
508 | SHR Size Imm Operand -- Only immediate shifts allowed
509 | BT Size Imm Operand
512 -- Float Arithmetic. -- ToDo for 386
514 -- Note that we cheat by treating G{ABS,MOV,NEG} of doubles as single instructions
515 -- right up until we spit them out.
517 -- all the 3-operand fake fp insns are src1 src2 dst
518 -- and furthermore are constrained to be fp regs only.
519 -- IMPORTANT: keep is_G_insn up to date with any changes here
520 | GMOV Reg Reg -- src(fpreg), dst(fpreg)
521 | GLD Size MachRegsAddr Reg -- src, dst(fpreg)
522 | GST Size Reg MachRegsAddr -- src(fpreg), dst
524 | GFTOD Reg Reg -- src(fpreg), dst(fpreg)
525 | GFTOI Reg Reg -- src(fpreg), dst(intreg)
527 | GDTOF Reg Reg -- src(fpreg), dst(fpreg)
528 | GDTOI Reg Reg -- src(fpreg), dst(intreg)
530 | GITOF Reg Reg -- src(intreg), dst(fpreg)
531 | GITOD Reg Reg -- src(intreg), dst(fpreg)
533 | GADD Size Reg Reg Reg -- src1, src2, dst
534 | GDIV Size Reg Reg Reg -- src1, src2, dst
535 | GSUB Size Reg Reg Reg -- src1, src2, dst
536 | GMUL Size Reg Reg Reg -- src1, src2, dst
538 | GCMP Size Reg Reg -- src1, src2
540 | GABS Size Reg Reg -- src, dst
541 | GNEG Size Reg Reg -- src, dst
542 | GSQRT Size Reg Reg -- src, dst
543 | GSIN Size Reg Reg -- src, dst
544 | GCOS Size Reg Reg -- src, dst
545 | GTAN Size Reg Reg -- src, dst
547 | GFREE -- do ffree on all x86 regs; an ugly hack
550 | TEST Size Operand Operand
551 | CMP Size Operand Operand
563 | JMP Operand -- target
564 | JXX Cond CLabel -- target
569 | CLTD -- sign extend %eax into %edx:%eax
572 = OpReg Reg -- register
573 | OpImm Imm -- immediate value
574 | OpAddr MachRegsAddr -- memory reference
577 i386_insert_ffrees :: [Instr] -> [Instr]
578 i386_insert_ffrees insns
579 | any is_G_instr insns
580 = concatMap ffree_before_nonlocal_transfers insns
584 ffree_before_nonlocal_transfers insn
586 CALL _ -> [GFREE, insn]
587 JMP (OpImm (ImmCLbl clbl)) | isAsmTemp clbl -> [insn]
588 JMP _ -> [GFREE, insn]
592 -- if you ever add a new FP insn to the fake x86 FP insn set,
593 -- you must update this too
594 is_G_instr :: Instr -> Bool
597 GMOV _ _ -> True; GLD _ _ _ -> True; GST _ _ _ -> True;
598 GFTOD _ _ -> True; GFTOI _ _ -> True;
599 GDTOF _ _ -> True; GDTOI _ _ -> True;
600 GITOF _ _ -> True; GITOD _ _ -> True;
601 GADD _ _ _ _ -> True; GDIV _ _ _ _ -> True
602 GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
603 GCMP _ _ _ -> True; GABS _ _ _ -> True
604 GNEG _ _ _ -> True; GSQRT _ _ _ -> True
605 GSIN _ _ _ -> True; GCOS _ _ _ -> True; GTAN _ _ _ -> True;
606 GFREE -> panic "is_G_instr: GFREE (!)"
609 #endif {- i386_TARGET_ARCH -}
613 #if sparc_TARGET_ARCH
615 -- data Instr continues...
619 | LD Size MachRegsAddr Reg -- size, src, dst
620 | ST Size Reg MachRegsAddr -- size, src, dst
624 | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
625 | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
627 -- Simple bit-twiddling.
629 | AND Bool Reg RI Reg -- cc?, src1, src2, dst
630 | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst
631 | OR Bool Reg RI Reg -- cc?, src1, src2, dst
632 | ORN Bool Reg RI Reg -- cc?, src1, src2, dst
633 | XOR Bool Reg RI Reg -- cc?, src1, src2, dst
634 | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst
635 | SLL Reg RI Reg -- src1, src2, dst
636 | SRL Reg RI Reg -- src1, src2, dst
637 | SRA Reg RI Reg -- src1, src2, dst
638 | SETHI Imm Reg -- src, dst
639 | NOP -- Really SETHI 0, %g0, but worth an alias
643 -- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
644 -- right up until we spit them out.
646 | FABS Size Reg Reg -- src dst
647 | FADD Size Reg Reg Reg -- src1, src2, dst
648 | FCMP Bool Size Reg Reg -- exception?, src1, src2, dst
649 | FDIV Size Reg Reg Reg -- src1, src2, dst
650 | FMOV Size Reg Reg -- src, dst
651 | FMUL Size Reg Reg Reg -- src1, src2, dst
652 | FNEG Size Reg Reg -- src, dst
653 | FSQRT Size Reg Reg -- src, dst
654 | FSUB Size Reg Reg Reg -- src1, src2, dst
655 | FxTOy Size Size Reg Reg -- src, dst
659 | BI Cond Bool Imm -- cond, annul?, target
660 | BF Cond Bool Imm -- cond, annul?, target
662 | JMP MachRegsAddr -- target
663 | CALL Imm Int Bool -- target, args, terminal
670 riZero (RIImm (ImmInt 0)) = True
671 riZero (RIImm (ImmInteger 0)) = True
672 riZero (RIReg (FixedReg ILIT(0))) = True
675 #endif {- sparc_TARGET_ARCH -}