-- --------------------------------------------------------------------------
-- Statements.
--

pprStmt :: CmmNode e x -> SDoc

pprStmt stmt =
    sdocWithDynFlags $ \dflags ->
    case stmt of
    CmmEntry{}   -> empty
    CmmComment _ -> empty -- (hang (ptext (sLit "/*")) 3 (ftext s)) $$ ptext (sLit "*/")
                          -- XXX if the string contains "*/", we need to fix it
                          -- XXX we probably want to emit these comments when
                          -- some debugging option is on.  They can get quite
                          -- large.

    CmmTick _ -> empty

    CmmAssign dest src -> pprAssign dflags dest src

    CmmStore  dest src
        | typeWidth rep == W64 && wordWidth dflags /= W64
        -> (if isFloatType rep then ptext (sLit "ASSIGN_DBL")
                               else ptext (sLit ("ASSIGN_Word64"))) <>
           parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi

        | otherwise
        -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ]
        where
          rep = cmmExprType dflags src

    CmmUnsafeForeignCall target@(ForeignTarget fn conv) results args ->
        fnCall
        where
        (res_hints, arg_hints) = foreignTargetHints target
        hresults = zip results res_hints
        hargs    = zip args arg_hints

        ForeignConvention cconv _ _ ret = conv

        cast_fn = parens (cCast (pprCFunType (char '*') cconv hresults hargs) fn)

        -- See wiki:Commentary/Compiler/Backends/PprC#Prototypes
        fnCall =
            case fn of
              CmmLit (CmmLabel lbl)
                | StdCallConv <- cconv ->
                    pprCall (ppr lbl) cconv hresults hargs
                        -- stdcall functions must be declared with
                        -- a function type, otherwise the C compiler
                        -- doesn't add the @n suffix to the label.  We
                        -- can't add the @n suffix ourselves, because
                        -- it isn't valid C.
                | CmmNeverReturns <- ret ->
                    pprCall cast_fn cconv hresults hargs <> semi
                | not (isMathFun lbl) ->
                    pprForeignCall (ppr lbl) cconv hresults hargs
              _ ->
                    pprCall cast_fn cconv hresults hargs <> semi
                        -- for a dynamic call, no declaration is necessary.

    CmmUnsafeForeignCall (PrimTarget MO_Touch) _results _args -> empty
    CmmUnsafeForeignCall (PrimTarget (MO_Prefetch_Data _)) _results _args -> empty

    CmmUnsafeForeignCall target@(PrimTarget op) results args ->
        fn_call
      where
        cconv = CCallConv
        fn = pprCallishMachOp_for_C op

        (res_hints, arg_hints) = foreignTargetHints target
        hresults = zip results res_hints
        hargs    = zip args arg_hints

        fn_call
          -- The mem primops carry an extra alignment arg.
          -- We could maybe emit an alignment directive using this info.
          -- We also need to cast mem primops to prevent conflicts with GCC
          -- builtins (see bug #5967).
          | Just _align <- machOpMemcpyishAlign op
          = (ptext (sLit ";EF_(") <> fn <> char ')' <> semi) $$
            pprForeignCall fn cconv hresults hargs
          | otherwise
          = pprCall fn cconv hresults hargs

    CmmBranch ident          -> pprBranch ident
    CmmCondBranch expr yes no _ -> pprCondBranch expr yes no
    CmmCall { cml_target = expr } -> mkJMP_ (pprExpr expr) <> semi
    CmmSwitch arg ids        -> sdocWithDynFlags $ \dflags ->
                                pprSwitch dflags arg ids

    _other -> pprPanic "PprC.pprStmt" (ppr stmt)
pprStmt :: CmmNode e x -> SDoc
pprStmt stmt =
    sdocWithDynFlags $ \dflags ->
    case stmt of
    CmmEntry{}   -> empty
    CmmComment _ -> empty -- (hang (ptext (sLit "/*")) 3 (ftext s)) $$ ptext (sLit "*/")
                          -- XXX if the string contains "*/", we need to fix it
                          -- XXX we probably want to emit these comments when
                          -- some debugging option is on.  They can get quite
                          -- large.

    CmmTick _ -> empty

    CmmAssign dest src -> pprAssign dflags dest src

    CmmStore  dest src
        | typeWidth rep == W64 && wordWidth dflags /= W64
        -> (if isFloatType rep then ptext (sLit "ASSIGN_DBL")
                               else ptext (sLit ("ASSIGN_Word64"))) <>
           parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi

        | otherwise
        -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ]
        where
          rep = cmmExprType dflags src

    CmmUnsafeForeignCall target@(ForeignTarget fn conv) results args ->
        fnCall
        where
        (res_hints, arg_hints) = foreignTargetHints target
        hresults = zip results res_hints
        hargs    = zip args arg_hints

        ForeignConvention cconv _ _ ret = conv

        cast_fn = parens (cCast (pprCFunType (char '*') cconv hresults hargs) fn)

        -- See wiki:Commentary/Compiler/Backends/PprC#Prototypes
        fnCall =
            case fn of
              CmmLit (CmmLabel lbl)
                | StdCallConv <- cconv ->
                    pprCall (ppr lbl) cconv hresults hargs
                        -- stdcall functions must be declared with
                        -- a function type, otherwise the C compiler
                        -- doesn't add the @n suffix to the label.  We
                        -- can't add the @n suffix ourselves, because
                        -- it isn't valid C.
                | CmmNeverReturns <- ret ->
                    pprCall cast_fn cconv hresults hargs <> semi
                | not (isMathFun lbl) ->
                    pprForeignCall (ppr lbl) cconv hresults hargs
              _ ->
                    pprCall cast_fn cconv hresults hargs <> semi
                        -- for a dynamic call, no declaration is necessary.

    CmmUnsafeForeignCall (PrimTarget MO_Touch) _results _args -> empty
    CmmUnsafeForeignCall (PrimTarget (MO_Prefetch_Data _)) _results _args -> empty

    CmmUnsafeForeignCall target@(PrimTarget op) results args ->
        fn_call
      where
        cconv = CCallConv
        fn = pprCallishMachOp_for_C op

        (res_hints, arg_hints) = foreignTargetHints target
        hresults = zip results res_hints
        hargs    = zip args arg_hints

        fn_call
          -- The mem primops carry an extra alignment arg.
          -- We could maybe emit an alignment directive using this info.
          -- We also need to cast mem primops to prevent conflicts with GCC
          -- builtins (see bug #5967).
          | Just _align <- machOpMemcpyishAlign op
          = (ptext (sLit ";EF_(") <> fn <> char ')' <> semi) $$
            pprForeignCall fn cconv hresults hargs
          | otherwise
          = pprCall fn cconv hresults hargs

    CmmBranch ident          -> pprBranch ident
    CmmCondBranch expr yes no _ -> pprCondBranch expr yes no
    CmmCall { cml_target = expr } -> mkJMP_ (pprExpr expr) <> semi
    CmmSwitch arg ids        -> sdocWithDynFlags $ \dflags ->
                                pprSwitch dflags arg ids

    _other -> pprPanic "PprC.pprStmt" (ppr stmt)
pprStmt stmt =
    sdocWithDynFlags $ \dflags ->
    case stmt of
    CmmEntry{}   -> empty
    CmmComment _ -> empty -- (hang (ptext (sLit "/*")) 3 (ftext s)) $$ ptext (sLit "*/")
                          -- XXX if the string contains "*/", we need to fix it
                          -- XXX we probably want to emit these comments when
                          -- some debugging option is on.  They can get quite
                          -- large.

    CmmTick _ -> empty

    CmmAssign dest src -> pprAssign dflags dest src

    CmmStore  dest src
        | typeWidth rep == W64 && wordWidth dflags /= W64
        -> (if isFloatType rep then ptext (sLit "ASSIGN_DBL")
                               else ptext (sLit ("ASSIGN_Word64"))) <>
           parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi

        | otherwise
        -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ]
        where
          rep = cmmExprType dflags src

    CmmUnsafeForeignCall target@(ForeignTarget fn conv) results args ->
        fnCall
        where
        (res_hints, arg_hints) = foreignTargetHints target
        hresults = zip results res_hints
        hargs    = zip args arg_hints

        ForeignConvention cconv _ _ ret = conv

        cast_fn = parens (cCast (pprCFunType (char '*') cconv hresults hargs) fn)

        -- See wiki:Commentary/Compiler/Backends/PprC#Prototypes
        fnCall =
            case fn of
              CmmLit (CmmLabel lbl)
                | StdCallConv <- cconv ->
                    pprCall (ppr lbl) cconv hresults hargs
                        -- stdcall functions must be declared with
                        -- a function type, otherwise the C compiler
                        -- doesn't add the @n suffix to the label.  We
                        -- can't add the @n suffix ourselves, because
                        -- it isn't valid C.
                | CmmNeverReturns <- ret ->
                    pprCall cast_fn cconv hresults hargs <> semi
                | not (isMathFun lbl) ->
                    pprForeignCall (ppr lbl) cconv hresults hargs
              _ ->
                    pprCall cast_fn cconv hresults hargs <> semi
                        -- for a dynamic call, no declaration is necessary.

    CmmUnsafeForeignCall (PrimTarget MO_Touch) _results _args -> empty
    CmmUnsafeForeignCall (PrimTarget (MO_Prefetch_Data _)) _results _args -> empty

    CmmUnsafeForeignCall target@(PrimTarget op) results args ->
        fn_call
      where
        cconv = CCallConv
        fn = pprCallishMachOp_for_C op

        (res_hints, arg_hints) = foreignTargetHints target
        hresults = zip results res_hints
        hargs    = zip args arg_hints

        fn_call
          -- The mem primops carry an extra alignment arg.
          -- We could maybe emit an alignment directive using this info.
          -- We also need to cast mem primops to prevent conflicts with GCC
          -- builtins (see bug #5967).
          | Just _align <- machOpMemcpyishAlign op
          = (ptext (sLit ";EF_(") <> fn <> char ')' <> semi) $$
            pprForeignCall fn cconv hresults hargs
          | otherwise
          = pprCall fn cconv hresults hargs

    CmmBranch ident          -> pprBranch ident
    CmmCondBranch expr yes no _ -> pprCondBranch expr yes no
    CmmCall { cml_target = expr } -> mkJMP_ (pprExpr expr) <> semi
    CmmSwitch arg ids        -> sdocWithDynFlags $ \dflags ->
                                pprSwitch dflags arg ids

    _other -> pprPanic "PprC.pprStmt" (ppr stmt)