PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/cmm/CmmParse.y

https://github.com/luite/ghc
Happy | 1295 lines | 1101 code | 194 blank | 0 comment | 0 complexity | 49d3add72ee94ddd6246cfe39107b899 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. -----------------------------------------------------------------------------
  2. --
  3. -- (c) The University of Glasgow, 2004-2012
  4. --
  5. -- Parser for concrete Cmm.
  6. --
  7. -----------------------------------------------------------------------------
  8. {- -----------------------------------------------------------------------------
  9. Note [Syntax of .cmm files]
  10. NOTE: You are very much on your own in .cmm. There is very little
  11. error checking at all:
  12. * Type errors are detected by the (optional) -dcmm-lint pass, if you
  13. don't turn this on then a type error will likely result in a panic
  14. from the native code generator.
  15. * Passing the wrong number of arguments or arguments of the wrong
  16. type is not detected.
  17. There are two ways to write .cmm code:
  18. (1) High-level Cmm code delegates the stack handling to GHC, and
  19. never explicitly mentions Sp or registers.
  20. (2) Low-level Cmm manages the stack itself, and must know about
  21. calling conventions.
  22. Whether you want high-level or low-level Cmm is indicated by the
  23. presence of an argument list on a procedure. For example:
  24. foo ( gcptr a, bits32 b )
  25. {
  26. // this is high-level cmm code
  27. if (b > 0) {
  28. // we can make tail calls passing arguments:
  29. jump stg_ap_0_fast(a);
  30. }
  31. push (stg_upd_frame_info, a) {
  32. // stack frames can be explicitly pushed
  33. (x,y) = call wibble(a,b,3,4);
  34. // calls pass arguments and return results using the native
  35. // Haskell calling convention. The code generator will automatically
  36. // construct a stack frame and an info table for the continuation.
  37. return (x,y);
  38. // we can return multiple values from the current proc
  39. }
  40. }
  41. bar
  42. {
  43. // this is low-level cmm code, indicated by the fact that we did not
  44. // put an argument list on bar.
  45. x = R1; // the calling convention is explicit: better be careful
  46. // that this works on all platforms!
  47. jump %ENTRY_CODE(Sp(0))
  48. }
  49. Here is a list of rules for high-level and low-level code. If you
  50. break the rules, you get a panic (for using a high-level construct in
  51. a low-level proc), or wrong code (when using low-level code in a
  52. high-level proc). This stuff isn't checked! (TODO!)
  53. High-level only:
  54. - tail-calls with arguments, e.g.
  55. jump stg_fun (arg1, arg2);
  56. - function calls:
  57. (ret1,ret2) = call stg_fun (arg1, arg2);
  58. This makes a call with the NativeNodeCall convention, and the
  59. values are returned to the following code using the NativeReturn
  60. convention.
  61. - returning:
  62. return (ret1, ret2)
  63. These use the NativeReturn convention to return zero or more
  64. results to the caller.
  65. - pushing stack frames:
  66. push (info_ptr, field1, ..., fieldN) { ... statements ... }
  67. Low-level only:
  68. - References to Sp, R1-R8, F1-F4 etc.
  69. NB. foreign calls may clobber the argument registers R1-R8, F1-F4
  70. etc., so ensure they are saved into variables around foreign
  71. calls.
  72. - SAVE_THREAD_STATE() and LOAD_THREAD_STATE(), which modify Sp
  73. directly.
  74. Both high-level and low-level code can use a raw tail-call:
  75. jump stg_fun [R1,R2]
  76. This always transfers control to a low-level Cmm function, but the
  77. call can be made from high-level code. Arguments must be passed
  78. explicitly in R/F/D/L registers.
  79. NB. you *must* specify the list of GlobalRegs that are passed via a
  80. jump, otherwise the register allocator will assume that all the
  81. GlobalRegs are dead at the jump.
  82. A stack frame is written like this:
  83. INFO_TABLE_RET ( label, FRAME_TYPE, info_ptr, field1, ..., fieldN )
  84. return ( arg1, ..., argM )
  85. {
  86. ... code ...
  87. }
  88. where field1 ... fieldN are the fields of the stack frame (with types)
  89. arg1...argN are the values returned to the stack frame (with types).
  90. The return values are assumed to be passed according to the
  91. NativeReturn convention.
  92. On entry to the code, the stack frame looks like:
  93. |----------|
  94. | fieldN |
  95. | ... |
  96. | field1 |
  97. |----------|
  98. | info_ptr |
  99. |----------|
  100. | argN |
  101. | ... | <- Sp
  102. and some of the args may be in registers.
  103. We prepend the code by a copyIn of the args, and assign all the stack
  104. frame fields to their formals. The initial "arg offset" for stack
  105. layout purposes consists of the whole stack frame plus any args that
  106. might be on the stack.
  107. A tail-call may pass a stack frame to the callee using the following
  108. syntax:
  109. jump f (info_ptr, field1,..,fieldN) (arg1,..,argN)
  110. where info_ptr and field1..fieldN describe the stack frame, and
  111. arg1..argN are the arguments passed to f using the NativeNodeCall
  112. convention.
  113. ----------------------------------------------------------------------------- -}
  114. {
  115. {-# LANGUAGE BangPatterns #-} -- required for versions of Happy before 1.18.6
  116. {-# OPTIONS -Wwarn -w #-}
  117. -- The above warning supression flag is a temporary kludge.
  118. -- While working on this module you are encouraged to remove it and fix
  119. -- any warnings in the module. See
  120. -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
  121. -- for details
  122. module CmmParse ( parseCmmFile ) where
  123. import StgCmmExtCode
  124. import CmmCallConv
  125. import StgCmmProf
  126. import StgCmmHeap
  127. import StgCmmMonad hiding ( getCode, getCodeR, emitLabel, emit, emitStore
  128. , emitAssign, emitOutOfLine, withUpdFrameOff
  129. , getUpdFrameOff )
  130. import qualified StgCmmMonad as F
  131. import StgCmmUtils
  132. import StgCmmForeign
  133. import StgCmmExpr
  134. import StgCmmClosure
  135. import StgCmmLayout hiding (ArgRep(..))
  136. import StgCmmTicky
  137. import StgCmmBind ( emitBlackHoleCode, emitUpdateFrame )
  138. import MkGraph
  139. import Cmm
  140. import CmmUtils
  141. import CmmInfo
  142. import BlockId
  143. import CmmLex
  144. import CLabel
  145. import SMRep
  146. import Lexer
  147. import CostCentre
  148. import ForeignCall
  149. import Module
  150. import Platform
  151. import Literal
  152. import Unique
  153. import UniqFM
  154. import SrcLoc
  155. import DynFlags
  156. import StaticFlags
  157. import ErrUtils
  158. import StringBuffer
  159. import FastString
  160. import Panic
  161. import Constants
  162. import Outputable
  163. import BasicTypes
  164. import Bag ( emptyBag, unitBag )
  165. import Var
  166. import Control.Monad
  167. import Data.Array
  168. import Data.Char ( ord )
  169. import System.Exit
  170. import Data.Maybe
  171. #include "HsVersions.h"
  172. }
  173. %expect 0
  174. %token
  175. ':' { L _ (CmmT_SpecChar ':') }
  176. ';' { L _ (CmmT_SpecChar ';') }
  177. '{' { L _ (CmmT_SpecChar '{') }
  178. '}' { L _ (CmmT_SpecChar '}') }
  179. '[' { L _ (CmmT_SpecChar '[') }
  180. ']' { L _ (CmmT_SpecChar ']') }
  181. '(' { L _ (CmmT_SpecChar '(') }
  182. ')' { L _ (CmmT_SpecChar ')') }
  183. '=' { L _ (CmmT_SpecChar '=') }
  184. '`' { L _ (CmmT_SpecChar '`') }
  185. '~' { L _ (CmmT_SpecChar '~') }
  186. '/' { L _ (CmmT_SpecChar '/') }
  187. '*' { L _ (CmmT_SpecChar '*') }
  188. '%' { L _ (CmmT_SpecChar '%') }
  189. '-' { L _ (CmmT_SpecChar '-') }
  190. '+' { L _ (CmmT_SpecChar '+') }
  191. '&' { L _ (CmmT_SpecChar '&') }
  192. '^' { L _ (CmmT_SpecChar '^') }
  193. '|' { L _ (CmmT_SpecChar '|') }
  194. '>' { L _ (CmmT_SpecChar '>') }
  195. '<' { L _ (CmmT_SpecChar '<') }
  196. ',' { L _ (CmmT_SpecChar ',') }
  197. '!' { L _ (CmmT_SpecChar '!') }
  198. '..' { L _ (CmmT_DotDot) }
  199. '::' { L _ (CmmT_DoubleColon) }
  200. '>>' { L _ (CmmT_Shr) }
  201. '<<' { L _ (CmmT_Shl) }
  202. '>=' { L _ (CmmT_Ge) }
  203. '<=' { L _ (CmmT_Le) }
  204. '==' { L _ (CmmT_Eq) }
  205. '!=' { L _ (CmmT_Ne) }
  206. '&&' { L _ (CmmT_BoolAnd) }
  207. '||' { L _ (CmmT_BoolOr) }
  208. 'CLOSURE' { L _ (CmmT_CLOSURE) }
  209. 'INFO_TABLE' { L _ (CmmT_INFO_TABLE) }
  210. 'INFO_TABLE_RET'{ L _ (CmmT_INFO_TABLE_RET) }
  211. 'INFO_TABLE_FUN'{ L _ (CmmT_INFO_TABLE_FUN) }
  212. 'INFO_TABLE_CONSTR'{ L _ (CmmT_INFO_TABLE_CONSTR) }
  213. 'INFO_TABLE_SELECTOR'{ L _ (CmmT_INFO_TABLE_SELECTOR) }
  214. 'else' { L _ (CmmT_else) }
  215. 'export' { L _ (CmmT_export) }
  216. 'section' { L _ (CmmT_section) }
  217. 'align' { L _ (CmmT_align) }
  218. 'goto' { L _ (CmmT_goto) }
  219. 'if' { L _ (CmmT_if) }
  220. 'call' { L _ (CmmT_call) }
  221. 'jump' { L _ (CmmT_jump) }
  222. 'foreign' { L _ (CmmT_foreign) }
  223. 'never' { L _ (CmmT_never) }
  224. 'prim' { L _ (CmmT_prim) }
  225. 'return' { L _ (CmmT_return) }
  226. 'returns' { L _ (CmmT_returns) }
  227. 'import' { L _ (CmmT_import) }
  228. 'switch' { L _ (CmmT_switch) }
  229. 'case' { L _ (CmmT_case) }
  230. 'default' { L _ (CmmT_default) }
  231. 'push' { L _ (CmmT_push) }
  232. 'bits8' { L _ (CmmT_bits8) }
  233. 'bits16' { L _ (CmmT_bits16) }
  234. 'bits32' { L _ (CmmT_bits32) }
  235. 'bits64' { L _ (CmmT_bits64) }
  236. 'bits128' { L _ (CmmT_bits128) }
  237. 'float32' { L _ (CmmT_float32) }
  238. 'float64' { L _ (CmmT_float64) }
  239. 'gcptr' { L _ (CmmT_gcptr) }
  240. GLOBALREG { L _ (CmmT_GlobalReg $$) }
  241. NAME { L _ (CmmT_Name $$) }
  242. STRING { L _ (CmmT_String $$) }
  243. INT { L _ (CmmT_Int $$) }
  244. FLOAT { L _ (CmmT_Float $$) }
  245. %monad { P } { >>= } { return }
  246. %lexer { cmmlex } { L _ CmmT_EOF }
  247. %name cmmParse cmm
  248. %tokentype { Located CmmToken }
  249. -- C-- operator precedences, taken from the C-- spec
  250. %right '||' -- non-std extension, called %disjoin in C--
  251. %right '&&' -- non-std extension, called %conjoin in C--
  252. %right '!'
  253. %nonassoc '>=' '>' '<=' '<' '!=' '=='
  254. %left '|'
  255. %left '^'
  256. %left '&'
  257. %left '>>' '<<'
  258. %left '-' '+'
  259. %left '/' '*' '%'
  260. %right '~'
  261. %%
  262. cmm :: { CmmParse () }
  263. : {- empty -} { return () }
  264. | cmmtop cmm { do $1; $2 }
  265. cmmtop :: { CmmParse () }
  266. : cmmproc { $1 }
  267. | cmmdata { $1 }
  268. | decl { $1 }
  269. | 'CLOSURE' '(' NAME ',' NAME lits ')' ';'
  270. {% withThisPackage $ \pkg ->
  271. do lits <- sequence $6;
  272. staticClosure pkg $3 $5 (map getLit lits) }
  273. -- The only static closures in the RTS are dummy closures like
  274. -- stg_END_TSO_QUEUE_closure and stg_dummy_ret. We don't need
  275. -- to provide the full generality of static closures here.
  276. -- In particular:
  277. -- * CCS can always be CCS_DONT_CARE
  278. -- * closure is always extern
  279. -- * payload is always empty
  280. -- * we can derive closure and info table labels from a single NAME
  281. cmmdata :: { CmmParse () }
  282. : 'section' STRING '{' data_label statics '}'
  283. { do lbl <- $4;
  284. ss <- sequence $5;
  285. code (emitDecl (CmmData (section $2) (Statics lbl $ concat ss))) }
  286. data_label :: { CmmParse CLabel }
  287. : NAME ':'
  288. {% withThisPackage $ \pkg ->
  289. return (mkCmmDataLabel pkg $1) }
  290. statics :: { [CmmParse [CmmStatic]] }
  291. : {- empty -} { [] }
  292. | static statics { $1 : $2 }
  293. -- Strings aren't used much in the RTS HC code, so it doesn't seem
  294. -- worth allowing inline strings. C-- doesn't allow them anyway.
  295. static :: { CmmParse [CmmStatic] }
  296. : type expr ';' { do e <- $2;
  297. return [CmmStaticLit (getLit e)] }
  298. | type ';' { return [CmmUninitialised
  299. (widthInBytes (typeWidth $1))] }
  300. | 'bits8' '[' ']' STRING ';' { return [mkString $4] }
  301. | 'bits8' '[' INT ']' ';' { return [CmmUninitialised
  302. (fromIntegral $3)] }
  303. | typenot8 '[' INT ']' ';' { return [CmmUninitialised
  304. (widthInBytes (typeWidth $1) *
  305. fromIntegral $3)] }
  306. | 'CLOSURE' '(' NAME lits ')'
  307. { do { lits <- sequence $4
  308. ; dflags <- getDynFlags
  309. ; return $ map CmmStaticLit $
  310. mkStaticClosure dflags (mkForeignLabel $3 Nothing ForeignLabelInExternalPackage IsData)
  311. -- mkForeignLabel because these are only used
  312. -- for CHARLIKE and INTLIKE closures in the RTS.
  313. dontCareCCS (map getLit lits) [] [] [] } }
  314. -- arrays of closures required for the CHARLIKE & INTLIKE arrays
  315. lits :: { [CmmParse CmmExpr] }
  316. : {- empty -} { [] }
  317. | ',' expr lits { $2 : $3 }
  318. cmmproc :: { CmmParse () }
  319. : info maybe_conv maybe_formals maybe_body
  320. { do ((entry_ret_label, info, stk_formals, formals), agraph) <-
  321. getCodeR $ loopDecls $ do {
  322. (entry_ret_label, info, stk_formals) <- $1;
  323. formals <- sequence (fromMaybe [] $3);
  324. $4;
  325. return (entry_ret_label, info, stk_formals, formals) }
  326. let do_layout = isJust $3
  327. code (emitProcWithStackFrame $2 info
  328. entry_ret_label stk_formals formals agraph
  329. do_layout ) }
  330. maybe_conv :: { Convention }
  331. : {- empty -} { NativeNodeCall }
  332. | 'return' { NativeReturn }
  333. maybe_body :: { CmmParse () }
  334. : ';' { return () }
  335. | '{' body '}' { $2 }
  336. info :: { CmmParse (CLabel, Maybe CmmInfoTable, [LocalReg]) }
  337. : NAME
  338. {% withThisPackage $ \pkg ->
  339. do newFunctionName $1 pkg
  340. return (mkCmmCodeLabel pkg $1, Nothing, []) }
  341. | 'INFO_TABLE' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
  342. -- ptrs, nptrs, closure type, description, type
  343. {% withThisPackage $ \pkg ->
  344. do dflags <- getDynFlags
  345. let prof = profilingInfo dflags $11 $13
  346. rep = mkRTSRep (fromIntegral $9) $
  347. mkHeapRep dflags False (fromIntegral $5)
  348. (fromIntegral $7) Thunk
  349. -- not really Thunk, but that makes the info table
  350. -- we want.
  351. return (mkCmmEntryLabel pkg $3,
  352. Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3
  353. , cit_rep = rep
  354. , cit_prof = prof, cit_srt = NoC_SRT },
  355. []) }
  356. | 'INFO_TABLE_FUN' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ',' INT ')'
  357. -- ptrs, nptrs, closure type, description, type, fun type
  358. {% withThisPackage $ \pkg ->
  359. do dflags <- getDynFlags
  360. let prof = profilingInfo dflags $11 $13
  361. ty = Fun 0 (ArgSpec (fromIntegral $15))
  362. -- Arity zero, arg_type $15
  363. rep = mkRTSRep (fromIntegral $9) $
  364. mkHeapRep dflags False (fromIntegral $5)
  365. (fromIntegral $7) ty
  366. return (mkCmmEntryLabel pkg $3,
  367. Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3
  368. , cit_rep = rep
  369. , cit_prof = prof, cit_srt = NoC_SRT },
  370. []) }
  371. -- we leave most of the fields zero here. This is only used
  372. -- to generate the BCO info table in the RTS at the moment.
  373. | 'INFO_TABLE_CONSTR' '(' NAME ',' INT ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
  374. -- ptrs, nptrs, tag, closure type, description, type
  375. {% withThisPackage $ \pkg ->
  376. do dflags <- getDynFlags
  377. let prof = profilingInfo dflags $13 $15
  378. ty = Constr (fromIntegral $9) -- Tag
  379. (stringToWord8s $13)
  380. rep = mkRTSRep (fromIntegral $11) $
  381. mkHeapRep dflags False (fromIntegral $5)
  382. (fromIntegral $7) ty
  383. return (mkCmmEntryLabel pkg $3,
  384. Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3
  385. , cit_rep = rep
  386. , cit_prof = prof, cit_srt = NoC_SRT },
  387. []) }
  388. -- If profiling is on, this string gets duplicated,
  389. -- but that's the way the old code did it we can fix it some other time.
  390. | 'INFO_TABLE_SELECTOR' '(' NAME ',' INT ',' INT ',' STRING ',' STRING ')'
  391. -- selector, closure type, description, type
  392. {% withThisPackage $ \pkg ->
  393. do dflags <- getDynFlags
  394. let prof = profilingInfo dflags $9 $11
  395. ty = ThunkSelector (fromIntegral $5)
  396. rep = mkRTSRep (fromIntegral $7) $
  397. mkHeapRep dflags False 0 0 ty
  398. return (mkCmmEntryLabel pkg $3,
  399. Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3
  400. , cit_rep = rep
  401. , cit_prof = prof, cit_srt = NoC_SRT },
  402. []) }
  403. | 'INFO_TABLE_RET' '(' NAME ',' INT ')'
  404. -- closure type (no live regs)
  405. {% withThisPackage $ \pkg ->
  406. do let prof = NoProfilingInfo
  407. rep = mkRTSRep (fromIntegral $5) $ mkStackRep []
  408. return (mkCmmRetLabel pkg $3,
  409. Just $ CmmInfoTable { cit_lbl = mkCmmRetInfoLabel pkg $3
  410. , cit_rep = rep
  411. , cit_prof = prof, cit_srt = NoC_SRT },
  412. []) }
  413. | 'INFO_TABLE_RET' '(' NAME ',' INT ',' formals0 ')'
  414. -- closure type, live regs
  415. {% withThisPackage $ \pkg ->
  416. do dflags <- getDynFlags
  417. live <- sequence $7
  418. let prof = NoProfilingInfo
  419. -- drop one for the info pointer
  420. bitmap = mkLiveness dflags (map Just (drop 1 live))
  421. rep = mkRTSRep (fromIntegral $5) $ mkStackRep bitmap
  422. return (mkCmmRetLabel pkg $3,
  423. Just $ CmmInfoTable { cit_lbl = mkCmmRetInfoLabel pkg $3
  424. , cit_rep = rep
  425. , cit_prof = prof, cit_srt = NoC_SRT },
  426. live) }
  427. body :: { CmmParse () }
  428. : {- empty -} { return () }
  429. | decl body { do $1; $2 }
  430. | stmt body { do $1; $2 }
  431. decl :: { CmmParse () }
  432. : type names ';' { mapM_ (newLocal $1) $2 }
  433. | 'import' importNames ';' { mapM_ newImport $2 }
  434. | 'export' names ';' { return () } -- ignore exports
  435. -- an imported function name, with optional packageId
  436. importNames
  437. :: { [(FastString, CLabel)] }
  438. : importName { [$1] }
  439. | importName ',' importNames { $1 : $3 }
  440. importName
  441. :: { (FastString, CLabel) }
  442. -- A label imported without an explicit packageId.
  443. -- These are taken to come frome some foreign, unnamed package.
  444. : NAME
  445. { ($1, mkForeignLabel $1 Nothing ForeignLabelInExternalPackage IsFunction) }
  446. -- A label imported with an explicit packageId.
  447. | STRING NAME
  448. { ($2, mkCmmCodeLabel (fsToPackageId (mkFastString $1)) $2) }
  449. names :: { [FastString] }
  450. : NAME { [$1] }
  451. | NAME ',' names { $1 : $3 }
  452. stmt :: { CmmParse () }
  453. : ';' { return () }
  454. | NAME ':'
  455. { do l <- newLabel $1; emitLabel l }
  456. | lreg '=' expr ';'
  457. { do reg <- $1; e <- $3; emitAssign reg e }
  458. | type '[' expr ']' '=' expr ';'
  459. { doStore $1 $3 $6 }
  460. -- Gah! We really want to say "foreign_results" but that causes
  461. -- a shift/reduce conflict with assignment. We either
  462. -- we expand out the no-result and single result cases or
  463. -- we tweak the syntax to avoid the conflict. The later
  464. -- option is taken here because the other way would require
  465. -- multiple levels of expanding and get unwieldy.
  466. | foreign_results 'foreign' STRING foreignLabel '(' cmm_hint_exprs0 ')' safety opt_never_returns ';'
  467. {% foreignCall $3 $1 $4 $6 $8 $9 }
  468. | foreign_results 'prim' '%' NAME '(' exprs0 ')' ';'
  469. {% primCall $1 $4 $6 }
  470. -- stmt-level macros, stealing syntax from ordinary C-- function calls.
  471. -- Perhaps we ought to use the %%-form?
  472. | NAME '(' exprs0 ')' ';'
  473. {% stmtMacro $1 $3 }
  474. | 'switch' maybe_range expr '{' arms default '}'
  475. { do as <- sequence $5; doSwitch $2 $3 as $6 }
  476. | 'goto' NAME ';'
  477. { do l <- lookupLabel $2; emit (mkBranch l) }
  478. | 'return' '(' exprs0 ')' ';'
  479. { doReturn $3 }
  480. | 'jump' expr vols ';'
  481. { doRawJump $2 $3 }
  482. | 'jump' expr '(' exprs0 ')' ';'
  483. { doJumpWithStack $2 [] $4 }
  484. | 'jump' expr '(' exprs0 ')' '(' exprs0 ')' ';'
  485. { doJumpWithStack $2 $4 $7 }
  486. | 'call' expr '(' exprs0 ')' ';'
  487. { doCall $2 [] $4 }
  488. | '(' formals ')' '=' 'call' expr '(' exprs0 ')' ';'
  489. { doCall $6 $2 $8 }
  490. | 'if' bool_expr 'goto' NAME
  491. { do l <- lookupLabel $4; cmmRawIf $2 l }
  492. | 'if' bool_expr '{' body '}' else
  493. { cmmIfThenElse $2 $4 $6 }
  494. | 'push' '(' exprs0 ')' maybe_body
  495. { pushStackFrame $3 $5 }
  496. foreignLabel :: { CmmParse CmmExpr }
  497. : NAME { return (CmmLit (CmmLabel (mkForeignLabel $1 Nothing ForeignLabelInExternalPackage IsFunction))) }
  498. opt_never_returns :: { CmmReturnInfo }
  499. : { CmmMayReturn }
  500. | 'never' 'returns' { CmmNeverReturns }
  501. bool_expr :: { CmmParse BoolExpr }
  502. : bool_op { $1 }
  503. | expr { do e <- $1; return (BoolTest e) }
  504. bool_op :: { CmmParse BoolExpr }
  505. : bool_expr '&&' bool_expr { do e1 <- $1; e2 <- $3;
  506. return (BoolAnd e1 e2) }
  507. | bool_expr '||' bool_expr { do e1 <- $1; e2 <- $3;
  508. return (BoolOr e1 e2) }
  509. | '!' bool_expr { do e <- $2; return (BoolNot e) }
  510. | '(' bool_op ')' { $2 }
  511. safety :: { Safety }
  512. : {- empty -} { PlayRisky }
  513. | STRING {% parseSafety $1 }
  514. vols :: { [GlobalReg] }
  515. : '[' ']' { [] }
  516. | '[' '*' ']' {% do df <- getDynFlags
  517. ; return (realArgRegsCover df) }
  518. -- All of them. See comment attached
  519. -- to realArgRegsCover
  520. | '[' globals ']' { $2 }
  521. globals :: { [GlobalReg] }
  522. : GLOBALREG { [$1] }
  523. | GLOBALREG ',' globals { $1 : $3 }
  524. maybe_range :: { Maybe (Int,Int) }
  525. : '[' INT '..' INT ']' { Just (fromIntegral $2, fromIntegral $4) }
  526. | {- empty -} { Nothing }
  527. arms :: { [CmmParse ([Int],Either BlockId (CmmParse ()))] }
  528. : {- empty -} { [] }
  529. | arm arms { $1 : $2 }
  530. arm :: { CmmParse ([Int],Either BlockId (CmmParse ())) }
  531. : 'case' ints ':' arm_body { do b <- $4; return ($2, b) }
  532. arm_body :: { CmmParse (Either BlockId (CmmParse ())) }
  533. : '{' body '}' { return (Right $2) }
  534. | 'goto' NAME ';' { do l <- lookupLabel $2; return (Left l) }
  535. ints :: { [Int] }
  536. : INT { [ fromIntegral $1 ] }
  537. | INT ',' ints { fromIntegral $1 : $3 }
  538. default :: { Maybe (CmmParse ()) }
  539. : 'default' ':' '{' body '}' { Just $4 }
  540. -- taking a few liberties with the C-- syntax here; C-- doesn't have
  541. -- 'default' branches
  542. | {- empty -} { Nothing }
  543. -- Note: OldCmm doesn't support a first class 'else' statement, though
  544. -- CmmNode does.
  545. else :: { CmmParse () }
  546. : {- empty -} { return () }
  547. | 'else' '{' body '}' { $3 }
  548. -- we have to write this out longhand so that Happy's precedence rules
  549. -- can kick in.
  550. expr :: { CmmParse CmmExpr }
  551. : expr '/' expr { mkMachOp MO_U_Quot [$1,$3] }
  552. | expr '*' expr { mkMachOp MO_Mul [$1,$3] }
  553. | expr '%' expr { mkMachOp MO_U_Rem [$1,$3] }
  554. | expr '-' expr { mkMachOp MO_Sub [$1,$3] }
  555. | expr '+' expr { mkMachOp MO_Add [$1,$3] }
  556. | expr '>>' expr { mkMachOp MO_U_Shr [$1,$3] }
  557. | expr '<<' expr { mkMachOp MO_Shl [$1,$3] }
  558. | expr '&' expr { mkMachOp MO_And [$1,$3] }
  559. | expr '^' expr { mkMachOp MO_Xor [$1,$3] }
  560. | expr '|' expr { mkMachOp MO_Or [$1,$3] }
  561. | expr '>=' expr { mkMachOp MO_U_Ge [$1,$3] }
  562. | expr '>' expr { mkMachOp MO_U_Gt [$1,$3] }
  563. | expr '<=' expr { mkMachOp MO_U_Le [$1,$3] }
  564. | expr '<' expr { mkMachOp MO_U_Lt [$1,$3] }
  565. | expr '!=' expr { mkMachOp MO_Ne [$1,$3] }
  566. | expr '==' expr { mkMachOp MO_Eq [$1,$3] }
  567. | '~' expr { mkMachOp MO_Not [$2] }
  568. | '-' expr { mkMachOp MO_S_Neg [$2] }
  569. | expr0 '`' NAME '`' expr0 {% do { mo <- nameToMachOp $3 ;
  570. return (mkMachOp mo [$1,$5]) } }
  571. | expr0 { $1 }
  572. expr0 :: { CmmParse CmmExpr }
  573. : INT maybe_ty { return (CmmLit (CmmInt $1 (typeWidth $2))) }
  574. | FLOAT maybe_ty { return (CmmLit (CmmFloat $1 (typeWidth $2))) }
  575. | STRING { do s <- code (newStringCLit $1);
  576. return (CmmLit s) }
  577. | reg { $1 }
  578. | type '[' expr ']' { do e <- $3; return (CmmLoad e $1) }
  579. | '%' NAME '(' exprs0 ')' {% exprOp $2 $4 }
  580. | '(' expr ')' { $2 }
  581. -- leaving out the type of a literal gives you the native word size in C--
  582. maybe_ty :: { CmmType }
  583. : {- empty -} {% do dflags <- getDynFlags; return $ bWord dflags }
  584. | '::' type { $2 }
  585. cmm_hint_exprs0 :: { [CmmParse (CmmExpr, ForeignHint)] }
  586. : {- empty -} { [] }
  587. | cmm_hint_exprs { $1 }
  588. cmm_hint_exprs :: { [CmmParse (CmmExpr, ForeignHint)] }
  589. : cmm_hint_expr { [$1] }
  590. | cmm_hint_expr ',' cmm_hint_exprs { $1 : $3 }
  591. cmm_hint_expr :: { CmmParse (CmmExpr, ForeignHint) }
  592. : expr { do e <- $1;
  593. return (e, inferCmmHint e) }
  594. | expr STRING {% do h <- parseCmmHint $2;
  595. return $ do
  596. e <- $1; return (e, h) }
  597. exprs0 :: { [CmmParse CmmExpr] }
  598. : {- empty -} { [] }
  599. | exprs { $1 }
  600. exprs :: { [CmmParse CmmExpr] }
  601. : expr { [ $1 ] }
  602. | expr ',' exprs { $1 : $3 }
  603. reg :: { CmmParse CmmExpr }
  604. : NAME { lookupName $1 }
  605. | GLOBALREG { return (CmmReg (CmmGlobal $1)) }
  606. foreign_results :: { [CmmParse (LocalReg, ForeignHint)] }
  607. : {- empty -} { [] }
  608. | '(' foreign_formals ')' '=' { $2 }
  609. foreign_formals :: { [CmmParse (LocalReg, ForeignHint)] }
  610. : foreign_formal { [$1] }
  611. | foreign_formal ',' { [$1] }
  612. | foreign_formal ',' foreign_formals { $1 : $3 }
  613. foreign_formal :: { CmmParse (LocalReg, ForeignHint) }
  614. : local_lreg { do e <- $1; return (e, (inferCmmHint (CmmReg (CmmLocal e)))) }
  615. | STRING local_lreg {% do h <- parseCmmHint $1;
  616. return $ do
  617. e <- $2; return (e,h) }
  618. local_lreg :: { CmmParse LocalReg }
  619. : NAME { do e <- lookupName $1;
  620. return $
  621. case e of
  622. CmmReg (CmmLocal r) -> r
  623. other -> pprPanic "CmmParse:" (ftext $1 <> text " not a local register") }
  624. lreg :: { CmmParse CmmReg }
  625. : NAME { do e <- lookupName $1;
  626. return $
  627. case e of
  628. CmmReg r -> r
  629. other -> pprPanic "CmmParse:" (ftext $1 <> text " not a register") }
  630. | GLOBALREG { return (CmmGlobal $1) }
  631. maybe_formals :: { Maybe [CmmParse LocalReg] }
  632. : {- empty -} { Nothing }
  633. | '(' formals0 ')' { Just $2 }
  634. formals0 :: { [CmmParse LocalReg] }
  635. : {- empty -} { [] }
  636. | formals { $1 }
  637. formals :: { [CmmParse LocalReg] }
  638. : formal ',' { [$1] }
  639. | formal { [$1] }
  640. | formal ',' formals { $1 : $3 }
  641. formal :: { CmmParse LocalReg }
  642. : type NAME { newLocal $1 $2 }
  643. type :: { CmmType }
  644. : 'bits8' { b8 }
  645. | typenot8 { $1 }
  646. typenot8 :: { CmmType }
  647. : 'bits16' { b16 }
  648. | 'bits32' { b32 }
  649. | 'bits64' { b64 }
  650. | 'bits128' { b128 }
  651. | 'float32' { f32 }
  652. | 'float64' { f64 }
  653. | 'gcptr' {% do dflags <- getDynFlags; return $ gcWord dflags }
  654. {
  655. section :: String -> Section
  656. section "text" = Text
  657. section "data" = Data
  658. section "rodata" = ReadOnlyData
  659. section "relrodata" = RelocatableReadOnlyData
  660. section "bss" = UninitialisedData
  661. section s = OtherSection s
  662. mkString :: String -> CmmStatic
  663. mkString s = CmmString (map (fromIntegral.ord) s)
  664. -- |
  665. -- Given an info table, decide what the entry convention for the proc
  666. -- is. That is, for an INFO_TABLE_RET we want the return convention,
  667. -- otherwise it is a NativeNodeCall.
  668. --
  669. infoConv :: Maybe CmmInfoTable -> Convention
  670. infoConv Nothing = NativeNodeCall
  671. infoConv (Just info)
  672. | isStackRep (cit_rep info) = NativeReturn
  673. | otherwise = NativeNodeCall
  674. -- mkMachOp infers the type of the MachOp from the type of its first
  675. -- argument. We assume that this is correct: for MachOps that don't have
  676. -- symmetrical args (e.g. shift ops), the first arg determines the type of
  677. -- the op.
  678. mkMachOp :: (Width -> MachOp) -> [CmmParse CmmExpr] -> CmmParse CmmExpr
  679. mkMachOp fn args = do
  680. dflags <- getDynFlags
  681. arg_exprs <- sequence args
  682. return (CmmMachOp (fn (typeWidth (cmmExprType dflags (head arg_exprs)))) arg_exprs)
  683. getLit :: CmmExpr -> CmmLit
  684. getLit (CmmLit l) = l
  685. getLit (CmmMachOp (MO_S_Neg _) [CmmLit (CmmInt i r)]) = CmmInt (negate i) r
  686. getLit _ = panic "invalid literal" -- TODO messy failure
  687. nameToMachOp :: FastString -> P (Width -> MachOp)
  688. nameToMachOp name =
  689. case lookupUFM machOps name of
  690. Nothing -> fail ("unknown primitive " ++ unpackFS name)
  691. Just m -> return m
  692. exprOp :: FastString -> [CmmParse CmmExpr] -> P (CmmParse CmmExpr)
  693. exprOp name args_code = do
  694. dflags <- getDynFlags
  695. case lookupUFM (exprMacros dflags) name of
  696. Just f -> return $ do
  697. args <- sequence args_code
  698. return (f args)
  699. Nothing -> do
  700. mo <- nameToMachOp name
  701. return $ mkMachOp mo args_code
  702. exprMacros :: DynFlags -> UniqFM ([CmmExpr] -> CmmExpr)
  703. exprMacros dflags = listToUFM [
  704. ( fsLit "ENTRY_CODE", \ [x] -> entryCode dflags x ),
  705. ( fsLit "INFO_PTR", \ [x] -> closureInfoPtr dflags x ),
  706. ( fsLit "STD_INFO", \ [x] -> infoTable dflags x ),
  707. ( fsLit "FUN_INFO", \ [x] -> funInfoTable dflags x ),
  708. ( fsLit "GET_ENTRY", \ [x] -> entryCode dflags (closureInfoPtr dflags x) ),
  709. ( fsLit "GET_STD_INFO", \ [x] -> infoTable dflags (closureInfoPtr dflags x) ),
  710. ( fsLit "GET_FUN_INFO", \ [x] -> funInfoTable dflags (closureInfoPtr dflags x) ),
  711. ( fsLit "INFO_TYPE", \ [x] -> infoTableClosureType dflags x ),
  712. ( fsLit "INFO_PTRS", \ [x] -> infoTablePtrs dflags x ),
  713. ( fsLit "INFO_NPTRS", \ [x] -> infoTableNonPtrs dflags x )
  714. ]
  715. -- we understand a subset of C-- primitives:
  716. machOps = listToUFM $
  717. map (\(x, y) -> (mkFastString x, y)) [
  718. ( "add", MO_Add ),
  719. ( "sub", MO_Sub ),
  720. ( "eq", MO_Eq ),
  721. ( "ne", MO_Ne ),
  722. ( "mul", MO_Mul ),
  723. ( "neg", MO_S_Neg ),
  724. ( "quot", MO_S_Quot ),
  725. ( "rem", MO_S_Rem ),
  726. ( "divu", MO_U_Quot ),
  727. ( "modu", MO_U_Rem ),
  728. ( "ge", MO_S_Ge ),
  729. ( "le", MO_S_Le ),
  730. ( "gt", MO_S_Gt ),
  731. ( "lt", MO_S_Lt ),
  732. ( "geu", MO_U_Ge ),
  733. ( "leu", MO_U_Le ),
  734. ( "gtu", MO_U_Gt ),
  735. ( "ltu", MO_U_Lt ),
  736. ( "and", MO_And ),
  737. ( "or", MO_Or ),
  738. ( "xor", MO_Xor ),
  739. ( "com", MO_Not ),
  740. ( "shl", MO_Shl ),
  741. ( "shrl", MO_U_Shr ),
  742. ( "shra", MO_S_Shr ),
  743. ( "fadd", MO_F_Add ),
  744. ( "fsub", MO_F_Sub ),
  745. ( "fneg", MO_F_Neg ),
  746. ( "fmul", MO_F_Mul ),
  747. ( "fquot", MO_F_Quot ),
  748. ( "feq", MO_F_Eq ),
  749. ( "fne", MO_F_Ne ),
  750. ( "fge", MO_F_Ge ),
  751. ( "fle", MO_F_Le ),
  752. ( "fgt", MO_F_Gt ),
  753. ( "flt", MO_F_Lt ),
  754. ( "lobits8", flip MO_UU_Conv W8 ),
  755. ( "lobits16", flip MO_UU_Conv W16 ),
  756. ( "lobits32", flip MO_UU_Conv W32 ),
  757. ( "lobits64", flip MO_UU_Conv W64 ),
  758. ( "zx16", flip MO_UU_Conv W16 ),
  759. ( "zx32", flip MO_UU_Conv W32 ),
  760. ( "zx64", flip MO_UU_Conv W64 ),
  761. ( "sx16", flip MO_SS_Conv W16 ),
  762. ( "sx32", flip MO_SS_Conv W32 ),
  763. ( "sx64", flip MO_SS_Conv W64 ),
  764. ( "f2f32", flip MO_FF_Conv W32 ), -- TODO; rounding mode
  765. ( "f2f64", flip MO_FF_Conv W64 ), -- TODO; rounding mode
  766. ( "f2i8", flip MO_FS_Conv W8 ),
  767. ( "f2i16", flip MO_FS_Conv W16 ),
  768. ( "f2i32", flip MO_FS_Conv W32 ),
  769. ( "f2i64", flip MO_FS_Conv W64 ),
  770. ( "i2f32", flip MO_SF_Conv W32 ),
  771. ( "i2f64", flip MO_SF_Conv W64 )
  772. ]
  773. callishMachOps = listToUFM $
  774. map (\(x, y) -> (mkFastString x, y)) [
  775. ( "write_barrier", MO_WriteBarrier ),
  776. ( "memcpy", MO_Memcpy ),
  777. ( "memset", MO_Memset ),
  778. ( "memmove", MO_Memmove )
  779. -- ToDo: the rest, maybe
  780. ]
  781. parseSafety :: String -> P Safety
  782. parseSafety "safe" = return PlaySafe
  783. parseSafety "unsafe" = return PlayRisky
  784. parseSafety "interruptible" = return PlayInterruptible
  785. parseSafety str = fail ("unrecognised safety: " ++ str)
  786. parseCmmHint :: String -> P ForeignHint
  787. parseCmmHint "ptr" = return AddrHint
  788. parseCmmHint "signed" = return SignedHint
  789. parseCmmHint str = fail ("unrecognised hint: " ++ str)
  790. -- labels are always pointers, so we might as well infer the hint
  791. inferCmmHint :: CmmExpr -> ForeignHint
  792. inferCmmHint (CmmLit (CmmLabel _)) = AddrHint
  793. inferCmmHint (CmmReg (CmmGlobal g)) | isPtrGlobalReg g = AddrHint
  794. inferCmmHint _ = NoHint
  795. isPtrGlobalReg Sp = True
  796. isPtrGlobalReg SpLim = True
  797. isPtrGlobalReg Hp = True
  798. isPtrGlobalReg HpLim = True
  799. isPtrGlobalReg CCCS = True
  800. isPtrGlobalReg CurrentTSO = True
  801. isPtrGlobalReg CurrentNursery = True
  802. isPtrGlobalReg (VanillaReg _ VGcPtr) = True
  803. isPtrGlobalReg _ = False
  804. happyError :: P a
  805. happyError = srcParseFail
  806. -- -----------------------------------------------------------------------------
  807. -- Statement-level macros
  808. stmtMacro :: FastString -> [CmmParse CmmExpr] -> P (CmmParse ())
  809. stmtMacro fun args_code = do
  810. case lookupUFM stmtMacros fun of
  811. Nothing -> fail ("unknown macro: " ++ unpackFS fun)
  812. Just fcode -> return $ do
  813. args <- sequence args_code
  814. code (fcode args)
  815. stmtMacros :: UniqFM ([CmmExpr] -> FCode ())
  816. stmtMacros = listToUFM [
  817. ( fsLit "CCS_ALLOC", \[words,ccs] -> profAlloc words ccs ),
  818. ( fsLit "ENTER_CCS_THUNK", \[e] -> enterCostCentreThunk e ),
  819. ( fsLit "CLOSE_NURSERY", \[] -> emitCloseNursery ),
  820. ( fsLit "OPEN_NURSERY", \[] -> emitOpenNursery ),
  821. -- completely generic heap and stack checks, for use in high-level cmm.
  822. ( fsLit "HP_CHK_GEN", \[bytes] ->
  823. heapStackCheckGen Nothing (Just bytes) ),
  824. ( fsLit "STK_CHK_GEN", \[] ->
  825. heapStackCheckGen (Just (CmmLit CmmHighStackMark)) Nothing ),
  826. -- A stack check for a fixed amount of stack. Sounds a bit strange, but
  827. -- we use the stack for a bit of temporary storage in a couple of primops
  828. ( fsLit "STK_CHK_GEN_N", \[bytes] ->
  829. heapStackCheckGen (Just bytes) Nothing ),
  830. -- A stack check on entry to a thunk, where the argument is the thunk pointer.
  831. ( fsLit "STK_CHK_NP" , \[node] -> entryHeapCheck' False node 0 [] (return ())),
  832. ( fsLit "LOAD_THREAD_STATE", \[] -> emitLoadThreadState ),
  833. ( fsLit "SAVE_THREAD_STATE", \[] -> emitSaveThreadState ),
  834. ( fsLit "LDV_ENTER", \[e] -> ldvEnter e ),
  835. ( fsLit "LDV_RECORD_CREATE", \[e] -> ldvRecordCreate e ),
  836. ( fsLit "PUSH_UPD_FRAME", \[sp,e] -> emitPushUpdateFrame sp e ),
  837. ( fsLit "SET_HDR", \[ptr,info,ccs] ->
  838. emitSetDynHdr ptr info ccs ),
  839. ( fsLit "TICK_ALLOC_PRIM", \[hdr,goods,slop] ->
  840. tickyAllocPrim hdr goods slop ),
  841. ( fsLit "TICK_ALLOC_PAP", \[goods,slop] ->
  842. tickyAllocPAP goods slop ),
  843. ( fsLit "TICK_ALLOC_UP_THK", \[goods,slop] ->
  844. tickyAllocThunk goods slop ),
  845. ( fsLit "UPD_BH_UPDATABLE", \[reg] -> emitBlackHoleCode False reg ),
  846. ( fsLit "UPD_BH_SINGLE_ENTRY", \[reg] -> emitBlackHoleCode True reg )
  847. ]
  848. emitPushUpdateFrame :: CmmExpr -> CmmExpr -> FCode ()
  849. emitPushUpdateFrame sp e = do
  850. dflags <- getDynFlags
  851. emitUpdateFrame dflags sp mkUpdInfoLabel e
  852. pushStackFrame :: [CmmParse CmmExpr] -> CmmParse () -> CmmParse ()
  853. pushStackFrame fields body = do
  854. dflags <- getDynFlags
  855. exprs <- sequence fields
  856. updfr_off <- getUpdFrameOff
  857. let (new_updfr_off, _, g) = copyOutOflow dflags NativeReturn Ret Old
  858. [] updfr_off exprs
  859. emit g
  860. withUpdFrameOff new_updfr_off body
  861. profilingInfo dflags desc_str ty_str
  862. = if not (gopt Opt_SccProfilingOn dflags)
  863. then NoProfilingInfo
  864. else ProfilingInfo (stringToWord8s desc_str)
  865. (stringToWord8s ty_str)
  866. staticClosure :: PackageId -> FastString -> FastString -> [CmmLit] -> CmmParse ()
  867. staticClosure pkg cl_label info payload
  868. = do dflags <- getDynFlags
  869. let lits = mkStaticClosure dflags (mkCmmInfoLabel pkg info) dontCareCCS payload [] [] []
  870. code $ emitDataLits (mkCmmDataLabel pkg cl_label) lits
  871. foreignCall
  872. :: String
  873. -> [CmmParse (LocalReg, ForeignHint)]
  874. -> CmmParse CmmExpr
  875. -> [CmmParse (CmmExpr, ForeignHint)]
  876. -> Safety
  877. -> CmmReturnInfo
  878. -> P (CmmParse ())
  879. foreignCall conv_string results_code expr_code args_code safety ret
  880. = do conv <- case conv_string of
  881. "C" -> return CCallConv
  882. "stdcall" -> return StdCallConv
  883. _ -> fail ("unknown calling convention: " ++ conv_string)
  884. return $ do
  885. dflags <- getDynFlags
  886. results <- sequence results_code
  887. expr <- expr_code
  888. args <- sequence args_code
  889. let
  890. expr' = adjCallTarget dflags conv expr args
  891. (arg_exprs, arg_hints) = unzip args
  892. (res_regs, res_hints) = unzip results
  893. fc = ForeignConvention conv arg_hints res_hints ret
  894. target = ForeignTarget expr' fc
  895. _ <- code $ emitForeignCall safety res_regs target arg_exprs
  896. return ()
  897. doReturn :: [CmmParse CmmExpr] -> CmmParse ()
  898. doReturn exprs_code = do
  899. dflags <- getDynFlags
  900. exprs <- sequence exprs_code
  901. updfr_off <- getUpdFrameOff
  902. emit (mkReturnSimple dflags exprs updfr_off)
  903. mkReturnSimple :: DynFlags -> [CmmActual] -> UpdFrameOffset -> CmmAGraph
  904. mkReturnSimple dflags actuals updfr_off =
  905. mkReturn dflags e actuals updfr_off
  906. where e = entryCode dflags (CmmLoad (CmmStackSlot Old updfr_off)
  907. (gcWord dflags))
  908. doRawJump :: CmmParse CmmExpr -> [GlobalReg] -> CmmParse ()
  909. doRawJump expr_code vols = do
  910. dflags <- getDynFlags
  911. expr <- expr_code
  912. updfr_off <- getUpdFrameOff
  913. emit (mkRawJump dflags expr updfr_off vols)
  914. doJumpWithStack :: CmmParse CmmExpr -> [CmmParse CmmExpr]
  915. -> [CmmParse CmmExpr] -> CmmParse ()
  916. doJumpWithStack expr_code stk_code args_code = do
  917. dflags <- getDynFlags
  918. expr <- expr_code
  919. stk_args <- sequence stk_code
  920. args <- sequence args_code
  921. updfr_off <- getUpdFrameOff
  922. emit (mkJumpExtra dflags NativeNodeCall expr args updfr_off stk_args)
  923. doCall :: CmmParse CmmExpr -> [CmmParse LocalReg] -> [CmmParse CmmExpr]
  924. -> CmmParse ()
  925. doCall expr_code res_code args_code = do
  926. dflags <- getDynFlags
  927. expr <- expr_code
  928. args <- sequence args_code
  929. ress <- sequence res_code
  930. updfr_off <- getUpdFrameOff
  931. c <- code $ mkCall expr (NativeNodeCall,NativeReturn) ress args updfr_off []
  932. emit c
  933. adjCallTarget :: DynFlags -> CCallConv -> CmmExpr -> [(CmmExpr, ForeignHint) ]
  934. -> CmmExpr
  935. -- On Windows, we have to add the '@N' suffix to the label when making
  936. -- a call with the stdcall calling convention.
  937. adjCallTarget dflags StdCallConv (CmmLit (CmmLabel lbl)) args
  938. | platformOS (targetPlatform dflags) == OSMinGW32
  939. = CmmLit (CmmLabel (addLabelSize lbl (sum (map size args))))
  940. where size (e, _) = max (wORD_SIZE dflags) (widthInBytes (typeWidth (cmmExprType dflags e)))
  941. -- c.f. CgForeignCall.emitForeignCall
  942. adjCallTarget _ _ expr _
  943. = expr
  944. primCall
  945. :: [CmmParse (CmmFormal, ForeignHint)]
  946. -> FastString
  947. -> [CmmParse CmmExpr]
  948. -> P (CmmParse ())
  949. primCall results_code name args_code
  950. = case lookupUFM callishMachOps name of
  951. Nothing -> fail ("unknown primitive " ++ unpackFS name)
  952. Just p -> return $ do
  953. results <- sequence results_code
  954. args <- sequence args_code
  955. code (emitPrimCall (map fst results) p args)
  956. doStore :: CmmType -> CmmParse CmmExpr -> CmmParse CmmExpr -> CmmParse ()
  957. doStore rep addr_code val_code
  958. = do dflags <- getDynFlags
  959. addr <- addr_code
  960. val <- val_code
  961. -- if the specified store type does not match the type of the expr
  962. -- on the rhs, then we insert a coercion that will cause the type
  963. -- mismatch to be flagged by cmm-lint. If we don't do this, then
  964. -- the store will happen at the wrong type, and the error will not
  965. -- be noticed.
  966. let val_width = typeWidth (cmmExprType dflags val)
  967. rep_width = typeWidth rep
  968. let coerce_val
  969. | val_width /= rep_width = CmmMachOp (MO_UU_Conv val_width rep_width) [val]
  970. | otherwise = val
  971. emitStore addr coerce_val
  972. -- -----------------------------------------------------------------------------
  973. -- If-then-else and boolean expressions
  974. data BoolExpr
  975. = BoolExpr `BoolAnd` BoolExpr
  976. | BoolExpr `BoolOr` BoolExpr
  977. | BoolNot BoolExpr
  978. | BoolTest CmmExpr
  979. -- ToDo: smart constructors which simplify the boolean expression.
  980. cmmIfThenElse cond then_part else_part = do
  981. then_id <- newBlockId
  982. join_id <- newBlockId
  983. c <- cond
  984. emitCond c then_id
  985. else_part
  986. emit (mkBranch join_id)
  987. emitLabel then_id
  988. then_part
  989. -- fall through to join
  990. emitLabel join_id
  991. cmmRawIf cond then_id = do
  992. c <- cond
  993. emitCond c then_id
  994. -- 'emitCond cond true_id' emits code to test whether the cond is true,
  995. -- branching to true_id if so, and falling through otherwise.
  996. emitCond (BoolTest e) then_id = do
  997. else_id <- newBlockId
  998. emit (mkCbranch e then_id else_id)
  999. emitLabel else_id
  1000. emitCond (BoolNot (BoolTest (CmmMachOp op args))) then_id
  1001. | Just op' <- maybeInvertComparison op
  1002. = emitCond (BoolTest (CmmMachOp op' args)) then_id
  1003. emitCond (BoolNot e) then_id = do
  1004. else_id <- newBlockId
  1005. emitCond e else_id
  1006. emit (mkBranch then_id)
  1007. emitLabel else_id
  1008. emitCond (e1 `BoolOr` e2) then_id = do
  1009. emitCond e1 then_id
  1010. emitCond e2 then_id
  1011. emitCond (e1 `BoolAnd` e2) then_id = do
  1012. -- we'd like to invert one of the conditionals here to avoid an
  1013. -- extra branch instruction, but we can't use maybeInvertComparison
  1014. -- here because we can't look too closely at the expression since
  1015. -- we're in a loop.
  1016. and_id <- newBlockId
  1017. else_id <- newBlockId
  1018. emitCond e1 and_id
  1019. emit (mkBranch else_id)
  1020. emitLabel and_id
  1021. emitCond e2 then_id
  1022. emitLabel else_id
  1023. -- -----------------------------------------------------------------------------
  1024. -- Table jumps
  1025. -- We use a simplified form of C-- switch statements for now. A
  1026. -- switch statement always compiles to a table jump. Each arm can
  1027. -- specify a list of values (not ranges), and there can be a single
  1028. -- default branch. The range of the table is given either by the
  1029. -- optional range on the switch (eg. switch [0..7] {...}), or by
  1030. -- the minimum/maximum values from the branches.
  1031. doSwitch :: Maybe (Int,Int) -> CmmParse CmmExpr -> [([Int],Either BlockId (CmmParse ()))]
  1032. -> Maybe (CmmParse ()) -> CmmParse ()
  1033. doSwitch mb_range scrut arms deflt
  1034. = do
  1035. -- Compile code for the default branch
  1036. dflt_entry <-
  1037. case deflt of
  1038. Nothing -> return Nothing
  1039. Just e -> do b <- forkLabelledCode e; return (Just b)
  1040. -- Compile each case branch
  1041. table_entries <- mapM emitArm arms
  1042. -- Construct the table
  1043. let
  1044. all_entries = concat table_entries
  1045. ixs = map fst all_entries
  1046. (min,max)
  1047. | Just (l,u) <- mb_range = (l,u)
  1048. | otherwise = (minimum ixs, maximum ixs)
  1049. entries = elems (accumArray (\_ a -> Just a) dflt_entry (min,max)
  1050. all_entries)
  1051. expr <- scrut
  1052. -- ToDo: check for out of range and jump to default if necessary
  1053. emit (mkSwitch expr entries)
  1054. where
  1055. emitArm :: ([Int],Either BlockId (CmmParse ())) -> CmmParse [(Int,BlockId)]
  1056. emitArm (ints,Left blockid) = return [ (i,blockid) | i <- ints ]
  1057. emitArm (ints,Right code) = do
  1058. blockid <- forkLabelledCode code
  1059. return [ (i,blockid) | i <- ints ]
  1060. forkLabelledCode :: CmmParse () -> CmmParse BlockId
  1061. forkLabelledCode p = do
  1062. ag <- getCode p
  1063. l <- newBlockId
  1064. emitOutOfLine l ag
  1065. return l
  1066. -- -----------------------------------------------------------------------------
  1067. -- Putting it all together
  1068. -- The initial environment: we define some constants that the compiler
  1069. -- knows about here.
  1070. initEnv :: DynFlags -> Env
  1071. initEnv dflags = listToUFM [
  1072. ( fsLit "SIZEOF_StgHeader",
  1073. VarN (CmmLit (CmmInt (fromIntegral (fixedHdrSize dflags * wORD_SIZE dflags)) (wordWidth dflags)) )),
  1074. ( fsLit "SIZEOF_StgInfoTable",
  1075. VarN (CmmLit (CmmInt (fromIntegral (stdInfoTableSizeB dflags)) (wordWidth dflags)) ))
  1076. ]
  1077. parseCmmFile :: DynFlags -> FilePath -> IO (Messages, Maybe CmmGroup)
  1078. parseCmmFile dflags filename = do
  1079. showPass dflags "ParseCmm"
  1080. buf <- hGetStringBuffer filename
  1081. let
  1082. init_loc = mkRealSrcLoc (mkFastString filename) 1 1
  1083. init_state = (mkPState dflags buf init_loc) { lex_state = [0] }

Large files files are truncated, but you can click here to view the full file