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 Operand Operand -- 1st operand must be an Imm or CL
507 | SAR Size Operand Operand -- 1st operand must be an Imm or CL
508 | SHR Size Operand Operand -- 1st operand must be an Imm or CL
511 -- Float Arithmetic. -- ToDo for 386
513 -- Note that we cheat by treating G{ABS,MOV,NEG} of doubles as single instructions
514 -- right up until we spit them out.
516 -- all the 3-operand fake fp insns are src1 src2 dst
517 -- and furthermore are constrained to be fp regs only.
518 -- IMPORTANT: keep is_G_insn up to date with any changes here
519 | GMOV Reg Reg -- src(fpreg), dst(fpreg)
520 | GLD Size MachRegsAddr Reg -- src, dst(fpreg)
521 | GST Size Reg MachRegsAddr -- src(fpreg), dst
523 | GFTOD Reg Reg -- src(fpreg), dst(fpreg)
524 | GFTOI Reg Reg -- src(fpreg), dst(intreg)
526 | GDTOF Reg Reg -- src(fpreg), dst(fpreg)
527 | GDTOI Reg Reg -- src(fpreg), dst(intreg)
529 | GITOF Reg Reg -- src(intreg), dst(fpreg)
530 | GITOD Reg Reg -- src(intreg), dst(fpreg)
532 | GADD Size Reg Reg Reg -- src1, src2, dst
533 | GDIV Size Reg Reg Reg -- src1, src2, dst
534 | GSUB Size Reg Reg Reg -- src1, src2, dst
535 | GMUL Size Reg Reg Reg -- src1, src2, dst
537 | GCMP Size Reg Reg -- src1, src2
539 | GABS Size Reg Reg -- src, dst
540 | GNEG Size Reg Reg -- src, dst
541 | GSQRT Size Reg Reg -- src, dst
543 | GFREE -- do ffree on all x86 regs; an ugly hack
546 | TEST Size Operand Operand
547 | CMP Size Operand Operand
559 | JMP Operand -- target
560 | JXX Cond CLabel -- target
565 | CLTD -- sign extend %eax into %edx:%eax
568 = OpReg Reg -- register
569 | OpImm Imm -- immediate value
570 | OpAddr MachRegsAddr -- memory reference
573 i386_insert_ffrees :: [Instr] -> [Instr]
574 i386_insert_ffrees insns
575 | any is_G_instr insns
576 = concatMap ffree_before_nonlocal_transfers insns
580 ffree_before_nonlocal_transfers insn
582 CALL _ -> [GFREE, insn]
583 JMP (OpImm (ImmCLbl clbl)) | isAsmTemp clbl -> [insn]
584 JMP _ -> [GFREE, insn]
588 -- if you ever add a new FP insn to the fake x86 FP insn set,
589 -- you must update this too
590 is_G_instr :: Instr -> Bool
593 GMOV _ _ -> True; GLD _ _ _ -> True; GST _ _ _ -> True;
594 GFTOD _ _ -> True; GFTOI _ _ -> True;
595 GDTOF _ _ -> True; GDTOI _ _ -> True;
596 GITOF _ _ -> True; GITOD _ _ -> True;
597 GADD _ _ _ _ -> True; GDIV _ _ _ _ -> True
598 GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
599 GCMP _ _ _ -> True; GABS _ _ _ -> True
600 GNEG _ _ _ -> True; GSQRT _ _ _ -> True
601 GFREE -> panic "is_G_instr: GFREE (!)"
604 #endif {- i386_TARGET_ARCH -}
608 #if sparc_TARGET_ARCH
610 -- data Instr continues...
614 | LD Size MachRegsAddr Reg -- size, src, dst
615 | ST Size Reg MachRegsAddr -- size, src, dst
619 | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
620 | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
622 -- Simple bit-twiddling.
624 | AND Bool Reg RI Reg -- cc?, src1, src2, dst
625 | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst
626 | OR Bool Reg RI Reg -- cc?, src1, src2, dst
627 | ORN Bool Reg RI Reg -- cc?, src1, src2, dst
628 | XOR Bool Reg RI Reg -- cc?, src1, src2, dst
629 | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst
630 | SLL Reg RI Reg -- src1, src2, dst
631 | SRL Reg RI Reg -- src1, src2, dst
632 | SRA Reg RI Reg -- src1, src2, dst
633 | SETHI Imm Reg -- src, dst
634 | NOP -- Really SETHI 0, %g0, but worth an alias
638 -- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
639 -- right up until we spit them out.
641 | FABS Size Reg Reg -- src dst
642 | FADD Size Reg Reg Reg -- src1, src2, dst
643 | FCMP Bool Size Reg Reg -- exception?, src1, src2, dst
644 | FDIV Size Reg Reg Reg -- src1, src2, dst
645 | FMOV Size Reg Reg -- src, dst
646 | FMUL Size Reg Reg Reg -- src1, src2, dst
647 | FNEG Size Reg Reg -- src, dst
648 | FSQRT Size Reg Reg -- src, dst
649 | FSUB Size Reg Reg Reg -- src1, src2, dst
650 | FxTOy Size Size Reg Reg -- src, dst
654 | BI Cond Bool Imm -- cond, annul?, target
655 | BF Cond Bool Imm -- cond, annul?, target
657 | JMP MachRegsAddr -- target
658 | CALL Imm Int Bool -- target, args, terminal
665 riZero (RIImm (ImmInt 0)) = True
666 riZero (RIImm (ImmInteger 0)) = True
667 riZero (RIReg (FixedReg ILIT(0))) = True
670 #endif {- sparc_TARGET_ARCH -}