From 043459646ccc1bb4e9bfd414c0e01cae2b88fd82 Mon Sep 17 00:00:00 2001
From: Stefan Schulze Frielinghaus <stefansf@linux.ibm.com>
Date: Wed, 21 Jul 2021 13:31:47 +0200
Subject: [PATCH] CmmToLlvm: Sign/Zero extend parameters for foreign calls

For some architectures the C calling convention is that any integer
shorter than 64 bits is replaced by its 64 bits representation using
sign or zero extension.

This is basically a backport of 0ac5860ea4d45587771869970beecdd4da0cb105
but adjusted for the 8.10 branch.

Fixes #20120
---
 compiler/llvmGen/Llvm/PpLlvm.hs         | 13 ++++++++-----
 compiler/llvmGen/Llvm/Types.hs          | 16 ++++++++++++----
 compiler/llvmGen/LlvmCodeGen/CodeGen.hs | 17 ++++++++++++++++-
 3 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/compiler/llvmGen/Llvm/PpLlvm.hs b/compiler/llvmGen/Llvm/PpLlvm.hs
index b534276f08ea..eb9508c9721d 100644
--- a/compiler/llvmGen/Llvm/PpLlvm.hs
+++ b/compiler/llvmGen/Llvm/PpLlvm.hs
@@ -268,7 +268,7 @@ ppCall ct fptr args attrs = case fptr of
     where
         ppCall' (LlvmFunctionDecl _ _ cc ret argTy params _) =
             let tc = if ct == TailCall then text "tail " else empty
-                ppValues = hsep $ punctuate comma $ map ppCallMetaExpr args
+                ppValues = ppCallParams (map snd params) args
                 ppArgTy  = (ppCommaJoin $ map fst params) <>
                            (case argTy of
                                VarArgs   -> text ", ..."
@@ -279,10 +279,13 @@ ppCall ct fptr args attrs = case fptr of
                     <> fnty <+> ppName fptr <> lparen <+> ppValues
                     <+> rparen <+> attrDoc
 
-        -- Metadata needs to be marked as having the `metadata` type when used
-        -- in a call argument
-        ppCallMetaExpr (MetaVar v) = ppr v
-        ppCallMetaExpr v           = text "metadata" <+> ppr v
+        ppCallParams :: [[LlvmParamAttr]] -> [MetaExpr] -> SDoc
+        ppCallParams attrs args = hsep $ punctuate comma $ zipWith ppCallMetaExpr attrs args
+         where
+          -- Metadata needs to be marked as having the `metadata` type when used
+          -- in a call argument
+          ppCallMetaExpr attrs (MetaVar v) = ppVar' attrs v
+          ppCallMetaExpr _ v               = text "metadata" <+> ppr v
 
 ppMachOp :: LlvmMachOp -> LlvmVar -> LlvmVar -> SDoc
 ppMachOp op left right =
diff --git a/compiler/llvmGen/Llvm/Types.hs b/compiler/llvmGen/Llvm/Types.hs
index f477aa64edda..059f412fe3e4 100644
--- a/compiler/llvmGen/Llvm/Types.hs
+++ b/compiler/llvmGen/Llvm/Types.hs
@@ -114,8 +114,12 @@ data LlvmVar
   deriving (Eq)
 
 instance Outputable LlvmVar where
-  ppr (LMLitVar x)  = ppr x
-  ppr (x         )  = ppr (getVarType x) <+> ppName x
+  ppr = ppVar' []
+
+ppVar' :: [LlvmParamAttr] -> LlvmVar -> SDoc
+ppVar' attrs v = case v of
+  LMLitVar x -> ppTypeLit' attrs x
+  x          -> ppr (getVarType x) <+> ppSpaceJoin attrs <+> ppName x
 
 
 -- | Llvm Literal Data.
@@ -135,8 +139,12 @@ data LlvmLit
   deriving (Eq)
 
 instance Outputable LlvmLit where
-  ppr l@(LMVectorLit {}) = ppLit l
-  ppr l                  = ppr (getLitType l) <+> ppLit l
+  ppr = ppTypeLit' []
+
+ppTypeLit' :: [LlvmParamAttr] -> LlvmLit -> SDoc
+ppTypeLit' attrs l = case l of
+  l@(LMVectorLit {}) -> ppLit l
+  _                  -> ppr (getLitType l) <+> ppSpaceJoin attrs <+> ppLit l
 
 
 -- | Llvm Static Data.
diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
index 7c1c5832ed27..15a4bc7199d9 100644
--- a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
+++ b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
@@ -460,6 +460,12 @@ genCall target res args = runStmtsDecls $ do
         The native code generator only handles StdCall and CCallConv.
     -}
 
+    let arg_type (hint, expr) =
+          case expr of
+            ty@(LMInt n) | n < 64 && lmconv == CC_Ccc && platformCConvNeedsExtension platform
+               -> (ty, if hint == Signed then [SignExt] else [ZeroExt])
+            ty -> (ty, [])
+
     -- call attributes
     let fnAttrs | never_returns = NoReturn : llvmStdFunAttrs
                 | otherwise     = llvmStdFunAttrs
@@ -477,7 +483,7 @@ genCall target res args = runStmtsDecls $ do
 
     let retTyCmm = ret_type_cmm ress_hints
 
-    let argTy = tysToParams $ map (snd . primRepToLlvmTy) args_rep
+    let argTy = map arg_type $ map primRepToLlvmTy args_rep
     let retTy = snd $ primRepToLlvmTy ret_rep
     let funTy = \name -> LMFunction $ LlvmFunctionDecl name ExternallyVisible
                              lmconv retTy FixedArgs argTy (llvmFunAlign dflags)
@@ -524,6 +530,15 @@ genCall target res args = runStmtsDecls $ do
                     v2 <- doExprW ty $ Cast op v1 ty
                     statement $ Store v2 vreg
                     doReturn
+ where
+  -- | For some architectures the C calling convention is that any
+  -- integer shorter than 64 bits is replaced by its 64 bits
+  -- representation using sign or zero extension.
+  platformCConvNeedsExtension :: Platform -> Bool
+  platformCConvNeedsExtension platform = case platformArch platform of
+    ArchPPC_64 _ -> True
+    ArchS390X    -> True
+    _            -> False
 
 -- | Generate a call to an LLVM intrinsic that performs arithmetic operation
 -- with overflow bit (i.e., returns a struct containing the actual result of the
-- 
GitLab