824a8595fc6c4fdd20c9221db18d3f8d965d7560
[ghc.git] / compiler / llvmGen / LlvmCodeGen / Base.hs
1 {-# LANGUAGE CPP #-}
2
3 -- ----------------------------------------------------------------------------
4 -- | Base LLVM Code Generation module
5 --
6 -- Contains functions useful through out the code generator.
7 --
8
9 module LlvmCodeGen.Base (
10
11 LlvmCmmDecl, LlvmBasicBlock,
12 LiveGlobalRegs,
13 LlvmUnresData, LlvmData, UnresLabel, UnresStatic,
14
15 LlvmVersion, supportedLlvmVersion, llvmVersionStr,
16
17 LlvmM,
18 runLlvm, liftStream, withClearVars, varLookup, varInsert,
19 markStackReg, checkStackReg,
20 funLookup, funInsert, getLlvmVer, getDynFlags, getDynFlag, getLlvmPlatform,
21 dumpIfSetLlvm, renderLlvm, markUsedVar, getUsedVars,
22 ghcInternalFunctions,
23
24 getMetaUniqueId,
25 setUniqMeta, getUniqMeta,
26
27 cmmToLlvmType, widthToLlvmFloat, widthToLlvmInt, llvmFunTy,
28 llvmFunSig, llvmFunArgs, llvmStdFunAttrs, llvmFunAlign, llvmInfAlign,
29 llvmPtrBits, tysToParams, llvmFunSection,
30
31 strCLabel_llvm, strDisplayName_llvm, strProcedureName_llvm,
32 getGlobalPtr, generateExternDecls,
33
34 aliasify,
35 ) where
36
37 #include "HsVersions.h"
38 #include "ghcautoconf.h"
39
40 import Llvm
41 import LlvmCodeGen.Regs
42
43 import CLabel
44 import CodeGen.Platform ( activeStgRegs )
45 import DynFlags
46 import FastString
47 import Cmm hiding ( succ )
48 import Outputable as Outp
49 import qualified Pretty as Prt
50 import Platform
51 import UniqFM
52 import Unique
53 import BufWrite ( BufHandle )
54 import UniqSet
55 import UniqSupply
56 import ErrUtils
57 import qualified Stream
58
59 import Control.Monad (ap)
60
61 -- ----------------------------------------------------------------------------
62 -- * Some Data Types
63 --
64
65 type LlvmCmmDecl = GenCmmDecl [LlvmData] (Maybe CmmStatics) (ListGraph LlvmStatement)
66 type LlvmBasicBlock = GenBasicBlock LlvmStatement
67
68 -- | Global registers live on proc entry
69 type LiveGlobalRegs = [GlobalReg]
70
71 -- | Unresolved code.
72 -- Of the form: (data label, data type, unresolved data)
73 type LlvmUnresData = (CLabel, Section, LlvmType, [UnresStatic])
74
75 -- | Top level LLVM Data (globals and type aliases)
76 type LlvmData = ([LMGlobal], [LlvmType])
77
78 -- | An unresolved Label.
79 --
80 -- Labels are unresolved when we haven't yet determined if they are defined in
81 -- the module we are currently compiling, or an external one.
82 type UnresLabel = CmmLit
83 type UnresStatic = Either UnresLabel LlvmStatic
84
85 -- ----------------------------------------------------------------------------
86 -- * Type translations
87 --
88
89 -- | Translate a basic CmmType to an LlvmType.
90 cmmToLlvmType :: CmmType -> LlvmType
91 cmmToLlvmType ty | isVecType ty = LMVector (vecLength ty) (cmmToLlvmType (vecElemType ty))
92 | isFloatType ty = widthToLlvmFloat $ typeWidth ty
93 | otherwise = widthToLlvmInt $ typeWidth ty
94
95 -- | Translate a Cmm Float Width to a LlvmType.
96 widthToLlvmFloat :: Width -> LlvmType
97 widthToLlvmFloat W32 = LMFloat
98 widthToLlvmFloat W64 = LMDouble
99 widthToLlvmFloat W80 = LMFloat80
100 widthToLlvmFloat W128 = LMFloat128
101 widthToLlvmFloat w = panic $ "widthToLlvmFloat: Bad float size: " ++ show w
102
103 -- | Translate a Cmm Bit Width to a LlvmType.
104 widthToLlvmInt :: Width -> LlvmType
105 widthToLlvmInt w = LMInt $ widthInBits w
106
107 -- | GHC Call Convention for LLVM
108 llvmGhcCC :: DynFlags -> LlvmCallConvention
109 llvmGhcCC dflags
110 | platformUnregisterised (targetPlatform dflags) = CC_Ccc
111 | otherwise = CC_Ghc
112
113 -- | Llvm Function type for Cmm function
114 llvmFunTy :: LiveGlobalRegs -> LlvmM LlvmType
115 llvmFunTy live = return . LMFunction =<< llvmFunSig' live (fsLit "a") ExternallyVisible
116
117 -- | Llvm Function signature
118 llvmFunSig :: LiveGlobalRegs -> CLabel -> LlvmLinkageType -> LlvmM LlvmFunctionDecl
119 llvmFunSig live lbl link = do
120 lbl' <- strCLabel_llvm lbl
121 llvmFunSig' live lbl' link
122
123 llvmFunSig' :: LiveGlobalRegs -> LMString -> LlvmLinkageType -> LlvmM LlvmFunctionDecl
124 llvmFunSig' live lbl link
125 = do let toParams x | isPointer x = (x, [NoAlias, NoCapture])
126 | otherwise = (x, [])
127 dflags <- getDynFlags
128 return $ LlvmFunctionDecl lbl link (llvmGhcCC dflags) LMVoid FixedArgs
129 (map (toParams . getVarType) (llvmFunArgs dflags live))
130 (llvmFunAlign dflags)
131
132 -- | Alignment to use for functions
133 llvmFunAlign :: DynFlags -> LMAlign
134 llvmFunAlign dflags = Just (wORD_SIZE dflags)
135
136 -- | Alignment to use for into tables
137 llvmInfAlign :: DynFlags -> LMAlign
138 llvmInfAlign dflags = Just (wORD_SIZE dflags)
139
140 -- | Section to use for a function
141 llvmFunSection :: DynFlags -> LMString -> LMSection
142 llvmFunSection dflags lbl
143 | gopt Opt_SplitSections dflags = Just (concatFS [fsLit ".text.", lbl])
144 | otherwise = Nothing
145
146 -- | A Function's arguments
147 llvmFunArgs :: DynFlags -> LiveGlobalRegs -> [LlvmVar]
148 llvmFunArgs dflags live =
149 map (lmGlobalRegArg dflags) (filter isPassed (activeStgRegs platform))
150 where platform = targetPlatform dflags
151 isLive r = not (isSSE r) || r `elem` alwaysLive || r `elem` live
152 isPassed r = not (isSSE r) || isLive r
153 isSSE (FloatReg _) = True
154 isSSE (DoubleReg _) = True
155 isSSE (XmmReg _) = True
156 isSSE (YmmReg _) = True
157 isSSE (ZmmReg _) = True
158 isSSE _ = False
159
160 -- | Llvm standard fun attributes
161 llvmStdFunAttrs :: [LlvmFuncAttr]
162 llvmStdFunAttrs = [NoUnwind]
163
164 -- | Convert a list of types to a list of function parameters
165 -- (each with no parameter attributes)
166 tysToParams :: [LlvmType] -> [LlvmParameter]
167 tysToParams = map (\ty -> (ty, []))
168
169 -- | Pointer width
170 llvmPtrBits :: DynFlags -> Int
171 llvmPtrBits dflags = widthInBits $ typeWidth $ gcWord dflags
172
173 -- ----------------------------------------------------------------------------
174 -- * Llvm Version
175 --
176
177 -- | LLVM Version Number
178 type LlvmVersion = (Int, Int)
179
180 -- | The LLVM Version that is currently supported.
181 supportedLlvmVersion :: LlvmVersion
182 supportedLlvmVersion = sUPPORTED_LLVM_VERSION
183
184 llvmVersionStr :: LlvmVersion -> String
185 llvmVersionStr (major, minor) = show major ++ "." ++ show minor
186
187 -- ----------------------------------------------------------------------------
188 -- * Environment Handling
189 --
190
191 data LlvmEnv = LlvmEnv
192 { envVersion :: LlvmVersion -- ^ LLVM version
193 , envDynFlags :: DynFlags -- ^ Dynamic flags
194 , envOutput :: BufHandle -- ^ Output buffer
195 , envUniq :: UniqSupply -- ^ Supply of unique values
196 , envFreshMeta :: MetaId -- ^ Supply of fresh metadata IDs
197 , envUniqMeta :: UniqFM MetaId -- ^ Global metadata nodes
198 , envFunMap :: LlvmEnvMap -- ^ Global functions so far, with type
199 , envAliases :: UniqSet LMString -- ^ Globals that we had to alias, see [Llvm Forward References]
200 , envUsedVars :: [LlvmVar] -- ^ Pointers to be added to llvm.used (see @cmmUsedLlvmGens@)
201
202 -- the following get cleared for every function (see @withClearVars@)
203 , envVarMap :: LlvmEnvMap -- ^ Local variables so far, with type
204 , envStackRegs :: [GlobalReg] -- ^ Non-constant registers (alloca'd in the function prelude)
205 }
206
207 type LlvmEnvMap = UniqFM LlvmType
208
209 -- | The Llvm monad. Wraps @LlvmEnv@ state as well as the @IO@ monad
210 newtype LlvmM a = LlvmM { runLlvmM :: LlvmEnv -> IO (a, LlvmEnv) }
211
212 instance Functor LlvmM where
213 fmap f m = LlvmM $ \env -> do (x, env') <- runLlvmM m env
214 return (f x, env')
215
216 instance Applicative LlvmM where
217 pure x = LlvmM $ \env -> return (x, env)
218 (<*>) = ap
219
220 instance Monad LlvmM where
221 m >>= f = LlvmM $ \env -> do (x, env') <- runLlvmM m env
222 runLlvmM (f x) env'
223
224 instance HasDynFlags LlvmM where
225 getDynFlags = LlvmM $ \env -> return (envDynFlags env, env)
226
227 instance MonadUnique LlvmM where
228 getUniqueSupplyM = do
229 us <- getEnv envUniq
230 let (us1, us2) = splitUniqSupply us
231 modifyEnv (\s -> s { envUniq = us2 })
232 return us1
233
234 getUniqueM = do
235 us <- getEnv envUniq
236 let (u,us') = takeUniqFromSupply us
237 modifyEnv (\s -> s { envUniq = us' })
238 return u
239
240 -- | Lifting of IO actions. Not exported, as we want to encapsulate IO.
241 liftIO :: IO a -> LlvmM a
242 liftIO m = LlvmM $ \env -> do x <- m
243 return (x, env)
244
245 -- | Get initial Llvm environment.
246 runLlvm :: DynFlags -> LlvmVersion -> BufHandle -> UniqSupply -> LlvmM () -> IO ()
247 runLlvm dflags ver out us m = do
248 _ <- runLlvmM m env
249 return ()
250 where env = LlvmEnv { envFunMap = emptyUFM
251 , envVarMap = emptyUFM
252 , envStackRegs = []
253 , envUsedVars = []
254 , envAliases = emptyUniqSet
255 , envVersion = ver
256 , envDynFlags = dflags
257 , envOutput = out
258 , envUniq = us
259 , envFreshMeta = MetaId 0
260 , envUniqMeta = emptyUFM
261 }
262
263 -- | Get environment (internal)
264 getEnv :: (LlvmEnv -> a) -> LlvmM a
265 getEnv f = LlvmM (\env -> return (f env, env))
266
267 -- | Modify environment (internal)
268 modifyEnv :: (LlvmEnv -> LlvmEnv) -> LlvmM ()
269 modifyEnv f = LlvmM (\env -> return ((), f env))
270
271 -- | Lift a stream into the LlvmM monad
272 liftStream :: Stream.Stream IO a x -> Stream.Stream LlvmM a x
273 liftStream s = Stream.Stream $ do
274 r <- liftIO $ Stream.runStream s
275 case r of
276 Left b -> return (Left b)
277 Right (a, r2) -> return (Right (a, liftStream r2))
278
279 -- | Clear variables from the environment for a subcomputation
280 withClearVars :: LlvmM a -> LlvmM a
281 withClearVars m = LlvmM $ \env -> do
282 (x, env') <- runLlvmM m env { envVarMap = emptyUFM, envStackRegs = [] }
283 return (x, env' { envVarMap = emptyUFM, envStackRegs = [] })
284
285 -- | Insert variables or functions into the environment.
286 varInsert, funInsert :: Uniquable key => key -> LlvmType -> LlvmM ()
287 varInsert s t = modifyEnv $ \env -> env { envVarMap = addToUFM (envVarMap env) s t }
288 funInsert s t = modifyEnv $ \env -> env { envFunMap = addToUFM (envFunMap env) s t }
289
290 -- | Lookup variables or functions in the environment.
291 varLookup, funLookup :: Uniquable key => key -> LlvmM (Maybe LlvmType)
292 varLookup s = getEnv (flip lookupUFM s . envVarMap)
293 funLookup s = getEnv (flip lookupUFM s . envFunMap)
294
295 -- | Set a register as allocated on the stack
296 markStackReg :: GlobalReg -> LlvmM ()
297 markStackReg r = modifyEnv $ \env -> env { envStackRegs = r : envStackRegs env }
298
299 -- | Check whether a register is allocated on the stack
300 checkStackReg :: GlobalReg -> LlvmM Bool
301 checkStackReg r = getEnv ((elem r) . envStackRegs)
302
303 -- | Allocate a new global unnamed metadata identifier
304 getMetaUniqueId :: LlvmM MetaId
305 getMetaUniqueId = LlvmM $ \env ->
306 return (envFreshMeta env, env { envFreshMeta = succ $ envFreshMeta env })
307
308 -- | Get the LLVM version we are generating code for
309 getLlvmVer :: LlvmM LlvmVersion
310 getLlvmVer = getEnv envVersion
311
312 -- | Get the platform we are generating code for
313 getDynFlag :: (DynFlags -> a) -> LlvmM a
314 getDynFlag f = getEnv (f . envDynFlags)
315
316 -- | Get the platform we are generating code for
317 getLlvmPlatform :: LlvmM Platform
318 getLlvmPlatform = getDynFlag targetPlatform
319
320 -- | Dumps the document if the corresponding flag has been set by the user
321 dumpIfSetLlvm :: DumpFlag -> String -> Outp.SDoc -> LlvmM ()
322 dumpIfSetLlvm flag hdr doc = do
323 dflags <- getDynFlags
324 liftIO $ dumpIfSet_dyn dflags flag hdr doc
325
326 -- | Prints the given contents to the output handle
327 renderLlvm :: Outp.SDoc -> LlvmM ()
328 renderLlvm sdoc = do
329
330 -- Write to output
331 dflags <- getDynFlags
332 out <- getEnv envOutput
333 let doc = Outp.withPprStyleDoc dflags (Outp.mkCodeStyle Outp.CStyle) sdoc
334 liftIO $ Prt.bufLeftRender out doc
335
336 -- Dump, if requested
337 dumpIfSetLlvm Opt_D_dump_llvm "LLVM Code" sdoc
338 return ()
339
340 -- | Marks a variable as "used"
341 markUsedVar :: LlvmVar -> LlvmM ()
342 markUsedVar v = modifyEnv $ \env -> env { envUsedVars = v : envUsedVars env }
343
344 -- | Return all variables marked as "used" so far
345 getUsedVars :: LlvmM [LlvmVar]
346 getUsedVars = getEnv envUsedVars
347
348 -- | Saves that at some point we didn't know the type of the label and
349 -- generated a reference to a type variable instead
350 saveAlias :: LMString -> LlvmM ()
351 saveAlias lbl = modifyEnv $ \env -> env { envAliases = addOneToUniqSet (envAliases env) lbl }
352
353 -- | Sets metadata node for a given unique
354 setUniqMeta :: Unique -> MetaId -> LlvmM ()
355 setUniqMeta f m = modifyEnv $ \env -> env { envUniqMeta = addToUFM (envUniqMeta env) f m }
356
357 -- | Gets metadata node for given unique
358 getUniqMeta :: Unique -> LlvmM (Maybe MetaId)
359 getUniqMeta s = getEnv (flip lookupUFM s . envUniqMeta)
360
361 -- ----------------------------------------------------------------------------
362 -- * Internal functions
363 --
364
365 -- | Here we pre-initialise some functions that are used internally by GHC
366 -- so as to make sure they have the most general type in the case that
367 -- user code also uses these functions but with a different type than GHC
368 -- internally. (Main offender is treating return type as 'void' instead of
369 -- 'void *'). Fixes trac #5486.
370 ghcInternalFunctions :: LlvmM ()
371 ghcInternalFunctions = do
372 dflags <- getDynFlags
373 mk "memcpy" i8Ptr [i8Ptr, i8Ptr, llvmWord dflags]
374 mk "memmove" i8Ptr [i8Ptr, i8Ptr, llvmWord dflags]
375 mk "memset" i8Ptr [i8Ptr, llvmWord dflags, llvmWord dflags]
376 mk "newSpark" (llvmWord dflags) [i8Ptr, i8Ptr]
377 where
378 mk n ret args = do
379 let n' = fsLit n `appendFS` fsLit "$def"
380 decl = LlvmFunctionDecl n' ExternallyVisible CC_Ccc ret
381 FixedArgs (tysToParams args) Nothing
382 renderLlvm $ ppLlvmFunctionDecl decl
383 funInsert n' (LMFunction decl)
384
385 -- ----------------------------------------------------------------------------
386 -- * Label handling
387 --
388
389 -- | Pretty print a 'CLabel'.
390 strCLabel_llvm :: CLabel -> LlvmM LMString
391 strCLabel_llvm lbl = do
392 platform <- getLlvmPlatform
393 dflags <- getDynFlags
394 let sdoc = pprCLabel platform lbl
395 str = Outp.renderWithStyle dflags sdoc (Outp.mkCodeStyle Outp.CStyle)
396 return (fsLit str)
397
398 strDisplayName_llvm :: CLabel -> LlvmM LMString
399 strDisplayName_llvm lbl = do
400 platform <- getLlvmPlatform
401 dflags <- getDynFlags
402 let sdoc = pprCLabel platform lbl
403 depth = Outp.PartWay 1
404 style = Outp.mkUserStyle Outp.reallyAlwaysQualify depth
405 str = Outp.renderWithStyle dflags sdoc style
406 return (fsLit (dropInfoSuffix str))
407
408 dropInfoSuffix :: String -> String
409 dropInfoSuffix = go
410 where go "_info" = []
411 go "_static_info" = []
412 go "_con_info" = []
413 go (x:xs) = x:go xs
414 go [] = []
415
416 strProcedureName_llvm :: CLabel -> LlvmM LMString
417 strProcedureName_llvm lbl = do
418 platform <- getLlvmPlatform
419 dflags <- getDynFlags
420 let sdoc = pprCLabel platform lbl
421 depth = Outp.PartWay 1
422 style = Outp.mkUserStyle Outp.neverQualify depth
423 str = Outp.renderWithStyle dflags sdoc style
424 return (fsLit str)
425
426 -- ----------------------------------------------------------------------------
427 -- * Global variables / forward references
428 --
429
430 -- | Create/get a pointer to a global value. Might return an alias if
431 -- the value in question hasn't been defined yet. We especially make
432 -- no guarantees on the type of the returned pointer.
433 getGlobalPtr :: LMString -> LlvmM LlvmVar
434 getGlobalPtr llvmLbl = do
435 m_ty <- funLookup llvmLbl
436 let mkGlbVar lbl ty = LMGlobalVar lbl (LMPointer ty) Private Nothing Nothing
437 case m_ty of
438 -- Directly reference if we have seen it already
439 Just ty -> return $ mkGlbVar (llvmLbl `appendFS` fsLit "$def") ty Global
440 -- Otherwise use a forward alias of it
441 Nothing -> do
442 saveAlias llvmLbl
443 return $ mkGlbVar llvmLbl i8 Alias
444
445 -- | Generate definitions for aliases forward-referenced by @getGlobalPtr@.
446 --
447 -- Must be called at a point where we are sure that no new global definitions
448 -- will be generated anymore!
449 generateExternDecls :: LlvmM ([LMGlobal], [LlvmType])
450 generateExternDecls = do
451 delayed <- fmap nonDetEltsUFM $ getEnv envAliases
452 -- This is non-deterministic but we do not
453 -- currently support deterministic code-generation.
454 -- See Note [Unique Determinism and code generation]
455 defss <- flip mapM delayed $ \lbl -> do
456 m_ty <- funLookup lbl
457 case m_ty of
458 -- If we have a definition we've already emitted the proper aliases
459 -- when the symbol itself was emitted by @aliasify@
460 Just _ -> return []
461
462 -- If we don't have a definition this is an external symbol and we
463 -- need to emit a declaration
464 Nothing ->
465 let var = LMGlobalVar lbl i8Ptr External Nothing Nothing Global
466 in return [LMGlobal var Nothing]
467
468 -- Reset forward list
469 modifyEnv $ \env -> env { envAliases = emptyUniqSet }
470 return (concat defss, [])
471
472 -- | Here we take a global variable definition, rename it with a
473 -- @$def@ suffix, and generate the appropriate alias.
474 aliasify :: LMGlobal -> LlvmM [LMGlobal]
475 aliasify (LMGlobal var val) = do
476 let i8Ptr = LMPointer (LMInt 8)
477 LMGlobalVar lbl ty link sect align const = var
478
479 defLbl = lbl `appendFS` fsLit "$def"
480 defVar = LMGlobalVar defLbl ty Internal sect align const
481
482 defPtrVar = LMGlobalVar defLbl (LMPointer ty) link Nothing Nothing const
483 aliasVar = LMGlobalVar lbl (LMPointer i8Ptr) link Nothing Nothing Alias
484 aliasVal = LMBitc (LMStaticPointer defPtrVar) i8Ptr
485
486 -- we need to mark the $def symbols as used so LLVM doesn't forget which
487 -- section they need to go in. This will vanish once we switch away from
488 -- mangling sections for TNTC.
489 markUsedVar defVar
490
491 return [ LMGlobal defVar val
492 , LMGlobal aliasVar (Just aliasVal)
493 ]
494
495 -- Note [Llvm Forward References]
496 --
497 -- The issue here is that LLVM insists on being strongly typed at
498 -- every corner, so the first time we mention something, we have to
499 -- settle what type we assign to it. That makes things awkward, as Cmm
500 -- will often reference things before their definition, and we have no
501 -- idea what (LLVM) type it is going to be before that point.
502 --
503 -- Our work-around is to define "aliases" of a standard type (i8 *) in
504 -- these kind of situations, which we later tell LLVM to be either
505 -- references to their actual local definitions (involving a cast) or
506 -- an external reference. This obviously only works for pointers.
507 --
508 -- In particular when we encounter a reference to a symbol in a chunk of
509 -- C-- there are three possible scenarios,
510 --
511 -- 1. We have already seen a definition for the referenced symbol. This
512 -- means we already know its type.
513 --
514 -- 2. We have not yet seen a definition but we will find one later in this
515 -- compilation unit. Since we want to be a good consumer of the
516 -- C-- streamed to us from upstream, we don't know the type of the
517 -- symbol at the time when we must emit the reference.
518 --
519 -- 3. We have not yet seen a definition nor will we find one in this
520 -- compilation unit. In this case the reference refers to an
521 -- external symbol for which we do not know the type.
522 --
523 -- Let's consider case (2) for a moment: say we see a reference to
524 -- the symbol @fooBar@ for which we have not seen a definition. As we
525 -- do not know the symbol's type, we assume it is of type @i8*@ and emit
526 -- the appropriate casts in @getSymbolPtr@. Later on, when we
527 -- encounter the definition of @fooBar@ we emit it but with a modified
528 -- name, @fooBar$def@ (which we'll call the definition symbol), to
529 -- since we have already had to assume that the symbol @fooBar@
530 -- is of type @i8*@. We then emit @fooBar@ itself as an alias
531 -- of @fooBar$def@ with appropriate casts. This all happens in
532 -- @aliasify@.
533 --
534 -- Case (3) is quite similar to (2): References are emitted assuming
535 -- the referenced symbol is of type @i8*@. When we arrive at the end of
536 -- the compilation unit and realize that the symbol is external, we emit
537 -- an LLVM @external global@ declaration for the symbol @fooBar@
538 -- (handled in @generateExternDecls@). This takes advantage of the
539 -- fact that the aliases produced by @aliasify@ for exported symbols
540 -- have external linkage and can therefore be used as normal symbols.
541 --
542 -- Historical note: As of release 3.5 LLVM does not allow aliases to
543 -- refer to declarations. This the reason why aliases are produced at the
544 -- point of definition instead of the point of usage, as was previously
545 -- done. See #9142 for details.
546 --
547 -- Finally, case (1) is trival. As we already have a definition for
548 -- and therefore know the type of the referenced symbol, we can do
549 -- away with casting the alias to the desired type in @getSymbolPtr@
550 -- and instead just emit a reference to the definition symbol directly.
551 -- This is the @Just@ case in @getSymbolPtr@.