<div dir="ltr"><div dir="ltr">Alright, let me expand a bit. I've been looking at aarch64 NCG for ghc. The Linux side of things is looking really good,<div>so I've moved onto the macOS side (I'm afraid I don't have any Windows aarch64 hardware, nor much windows knowledge</div><div>to even attempt a Windows version yet).</div><div><br></div><div>When calling C functions, the usual approach is to pass the first few arguments in registers, and then arguments that exceed</div><div>the argument passing slots on the stack. The Arm AArch64 Procedure Call Standard (aapcs) for C does this by assigning 8byte</div><div>slots to each overflow argument on the stack. A company I won't name, has decided to implement a slightly different variation of</div><div>the Procedure Call Standard, often referred to as darwinpcs. This deviates from the aapcs for vargs, as well as for handling of</div><div>spilled arguments on the stack.</div><div><br></div><div>The aapcs allows us to generate calls to C functions without knowing the actual prototype of the function, as all arguments are</div><div>simply spilled into 8byte slots on the stack. The darwinpcs however requires us to know the size of the arguments, so we can</div><div>properly pack them onto the stack. Ints have 4 bytes, so we need to pack them into 4byte slots.</div><div><br></div><div>In the process library we have this rather fun foreign import:</div><div>foreign import ccall unsafe "runInteractiveProcess"<br><font face="monospace"> c_runInteractiveProcess<br> :: Ptr CString<br> -> CString<br> -> Ptr CString<br> -> FD<br> -> FD<br> -> FD<br> -> Ptr FD<br> -> Ptr FD<br> -> Ptr FD<br> -> Ptr CGid<br> -> Ptr CUid<br> -> CInt -- reset child's SIGINT & SIGQUIT handlers<br> -> CInt -- flags<br> -> Ptr CString<br> -> IO PHANDLE</font><br></div><div><br></div><div>with the corresponding C declaration:<br><br></div><div><font face="monospace">extern ProcHandle runInteractiveProcess( char *const args[],<br> char *workingDirectory,<br> char **environment,<br> int fdStdIn,<br> int fdStdOut,<br> int fdStdErr,<br> int *pfdStdInput,<br> int *pfdStdOutput,<br> int *pfdStdError,<br> gid_t *childGroup,<br> uid_t *childUser,<br> int reset_int_quit_handlers,<br> int flags,<br> char **failed_doing);<br></font></div><div>This function thus takes 14 arguments. We pass only the first 8 arguments in registers, and the others on the stack.</div><div>Argument 12 and 13 are of type int. On linux using the aapcs, we can pass those in 8byte slots on the stack. That is</div><div>both of them are effectively 64bits wide when passed. However for darwinpcs, it is expected that these adhere to their</div><div>size and are packed as such. Therefore Argument 12 and 13 need to be passed as 4byte slots each on the stack.</div><div><br></div><div>This yields a moderate 8byte saving on the stack for the same function call on darwinpcs compared to aapcs.</div><div><br></div><div>Now onto GHC. When we generate function calls for foreign C functions, we deal with something like:<br><br></div><div><font face="monospace">genCCall<br> :: ForeignTarget -- function to call<br> -> [CmmFormal] -- where to put the result<br> -> [CmmActual] -- arguments (of mixed type)<br> -> BlockId -- The block we are in<br> -> NatM (InstrBlock, Maybe BlockId)</font><br></div><div><br></div><div>based on Cmm Nodes of the form <font face="monospace">CmmUnsafeForeignCall target result_regs args</font></div></div><br><div class="gmail_quote"><div class="gmail_attr">The <font face="monospace">CmmActual</font> in the care of runInteractiveProcess hold the arguments for the function, however contrary to the function</div><div class="gmail_attr">declaration, it contains I64 slots for Argument 12 and 13. Thus computing the space needed for them based on their Cmm</div><div class="gmail_attr">Representations yields 8bytes, when they should really be 32bit and consume only 4 byte.</div><div class="gmail_attr"><br></div><div class="gmail_attr">To illustrate this a bit better: here is what we see in the pretty printed cmm:</div><div class="gmail_attr"><br></div><div class="gmail_attr"><font face="monospace">(_s6w3::I64) = call "ccall" arg hints: [PtrHint, PtrHint, PtrHint, signed, signed, signed, PtrHint, PtrHint, PtrHint, PtrHint, PtrHint, signed, signed, PtrHint] result hints: [signed] _runInteractiveProcess(I64[Sp + 96], I64[Sp + 88], I64[Sp + 104], I64[Sp + 112], I64[Sp + 120], I64[Sp + 56], I64[Sp + 64], I64[Sp + 72], I64[Sp + 24], 0, 0, I64[Sp + 8], I64[Sp + 40] | I64[Sp + 48] | I64[Sp + 80] | 3, I64[R1 + 7]);</font></div><div dir="ltr" class="gmail_attr"><br></div><div class="gmail_attr">I've added size information to the ForeignHints (NoHint, AddrHint, SignedHint) we have, and computed both, which yields:<br><br></div><div class="gmail_attr"><font face="monospace">[(CmmReg (CmmLocal (LocalReg s6Gi (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gk (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gm (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Go (CmmType BitsCat W64))),SignedHint W32)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gq (CmmType BitsCat W64))),SignedHint W32)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gs (CmmType BitsCat W64))),SignedHint W32)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gu (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gw (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Gy (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6Cp (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6FU (CmmType BitsCat W64))),AddrHint)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6GA (CmmType BitsCat W64))),SignedHint W32)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6GR (CmmType BitsCat W64))),SignedHint W32)</font></div><div class="gmail_attr"><font face="monospace">,(CmmReg (CmmLocal (LocalReg s6GM (CmmType BitsCat W64))),AddrHint)]</font></div><div dir="ltr" class="gmail_attr"><br></div><div class="gmail_attr">Thus, while we *do* know the right size from STG (which is what the Hints are computed from), we loose this information when lowering</div><div class="gmail_attr">into Cmm, where we represent them with W64. This is what I was alluding to in the previous email. In primRepCmmType, and mkIntCLit, we set their type to 64bit for Ints; which on this platform does not hold.</div><div class="gmail_attr"><br></div><div class="gmail_attr">Now I've gone ahead and effectively assume Cmm is lying to me when generating Foreign Function Calls, and rely on the (new) sized</div><div class="gmail_attr">hints to produce the appropriate argument packing on the stack. However I believe the correct way would be for GHC not to conflate Ints</div><div class="gmail_attr">and Words in Cmm; implicitly assuming they are the same width. Sadly it's not as simple as having primRepCmmType and mkIntCLit produce 32bit types. I fear GHC internally assumes "Int" means 64bit Integer, and then just happens to make the Int ~ CInt assumption.</div><div dir="ltr" class="gmail_attr"><br></div><div class="gmail_attr">Cheers,</div><div class="gmail_attr"> Moritz</div><div class="gmail_attr"><br></div><div dir="ltr" class="gmail_attr">On Tue, Oct 20, 2020 at 3:33 PM Simon Peyton Jones <<a href="mailto:simonpj@microsoft.com">simonpj@microsoft.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div lang="EN-GB" style="overflow-wrap: break-word;">
<div class="gmail-m_-8448329107995274415WordSection1">
<p class="MsoNormal"><span>Moritz<u></u><u></u></span></p>
<p class="MsoNormal"><span><u></u> <u></u></span></p>
<p class="MsoNormal"><span>I’m afraid I don’t understand any of this. Not your fault, but I just don’t have enough context to know what you mean.<u></u><u></u></span></p>
<p class="MsoNormal"><span><u></u> <u></u></span></p>
<p class="MsoNormal"><span>Is there a current bug? If so, can you demonstrate it? If not, what is the problem you want to solve? Examples are always helpful.<u></u><u></u></span></p>
<p class="MsoNormal"><span><u></u> <u></u></span></p>
<p class="MsoNormal"><span>Maybe it’s worth opening a ticket too?<u></u><u></u></span></p>
<p class="MsoNormal"><span><u></u> <u></u></span></p>
<p class="MsoNormal"><span>Thanks!<u></u><u></u></span></p>
<p class="MsoNormal"><span><u></u> <u></u></span></p>
<p class="MsoNormal"><span>Simon<u></u><u></u></span></p>
<p class="MsoNormal"><span><u></u> <u></u></span></p>
<div style="border-top:none;border-right:none;border-bottom:none;border-left:1.5pt solid blue;padding:0cm 0cm 0cm 4pt">
<div>
<div style="border-right:none;border-bottom:none;border-left:none;border-top:1pt solid rgb(225,225,225);padding:3pt 0cm 0cm">
<p class="MsoNormal"><b><span lang="EN-US">From:</span></b><span lang="EN-US"> ghc-devs <<a href="mailto:ghc-devs-bounces@haskell.org" target="_blank">ghc-devs-bounces@haskell.org</a>>
<b>On Behalf Of </b>Moritz Angermann<br>
<b>Sent:</b> 20 October 2020 02:51<br>
<b>To:</b> ghc-devs <<a href="mailto:ghc-devs@haskell.org" target="_blank">ghc-devs@haskell.org</a>><br>
<b>Subject:</b> GHC's internal confusion about Ints and Words<u></u><u></u></span></p>
</div>
</div>
<p class="MsoNormal"><u></u> <u></u></p>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
Hi there!<u></u><u></u></p>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
So there is a procedure calling convention that for reasons I did not fully understand, but seem to be historically grown, uses packed arguments for those that are spilled onto the stack. On top of that, CInt is 32bit, Word is 64bits. This provides the following
spectacle:<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
While we know in STG that the CInt is 32bits wide, when lowered into Cmm, it's represented as I64 in the arguments to the C function. Thus packing based on the format of the Cmm type would yield 8 bytes. And now, all further packed arguments have the wrong
offset (by four).<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
Specifically in GHC.Cmm.Utils we find:<br>
<br>
<span style="font-family:"Courier New"">primRepCmmType :: Platform -> PrimRep -> CmmType</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<span style="font-family:"Courier New"">primRepCmmType platform IntRep = bWord platform</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<span style="font-family:"Courier New"">mkIntCLit :: Platform -> Int -> CmmLit<br>
mkIntCLit platform i = CmmInt (toInteger i) (wordWidth platform)</span><u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
The naive idea to just fix this and make them return cIntWidth instead, seemingly produces the correct Cmm expressions at a local level, but produces a broken compiler.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
A second approach could be to extend the Hints into providing sizes, and using those during the foreign call generation to pack spilled arguments. This however appears to be more of a patching up of some fundamental underlying issue, instead of rectifying
it properly.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
Maybe I'll have to go down the Hint path, it does however break current Eq assumptions, as they are sized now, and what was equal before, is only equal now if they represent the same size.<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
>From a cursory glance at the issues with naively fixing the width for Int, it seems that GHC internally assumes sizeof(Int) = sizeof(Word). Maybe there is a whole level of HsInt vs CInt discrimination missing?<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
<u></u> <u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
Cheers,<u></u><u></u></p>
</div>
<div>
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:6pt;margin-left:0cm">
Moritz<u></u><u></u></p>
</div>
</div>
</div>
</div>
</div>
</blockquote></div></div>