GHC 严格字段打包与显式使用未装箱类型相同吗?

问题描述 投票:0回答:1

我相信如果我制作一个像这样的构造函数:

data MyThing = MyThing 
  Word8# 
  Word8# 
  Word8# 
  Word8#

GHC(打开优化)现在会将未装箱的单词打包在一个单词中,而不是让它们每个占用 8 个字节。

如果我这样做怎么办:

data MyThing = MyThing 
  {-# UNPACK #-} !Word8 
  {-# UNPACK #-} !Word8 
  {-# UNPACK #-} !Word8 
  {-# UNPACK #-} !Word8

有同样的包装发生吗?

haskell ghc
1个回答
0
投票

是的,两个版本的

MyThing
具有相同的内存布局。 您可以通过编译以下程序来观察这一点:

ghc -O -ddump-cmm -ddump-asm -fforce-recomp -dsuppress-all Thing8.hs 

并研究生成的坐标测量机或装配体。 有了这个程序:

{-# LANGUAGE MagicHash #-}

module Thing8 where

import Data.Word
import GHC.Base
import GHC.Word

data MyThing1 = MyThing1
  Word8#
  Word8#
  Word8#
  Word8#

data MyThing2 = MyThing2
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8

foo :: MyThing1 -> MyThing2
foo (MyThing1 a b c d) = MyThing2 (W8# a) (W8# b) (W8# c) (W8# d)

foo
的核心CMM代码是:

 cJG:
     _sID::I8 = I8[R1 + 7];
     _sIE::I8 = I8[R1 + 8];
     _sIF::I8 = I8[R1 + 9];
     _sIG::I8 = I8[R1 + 10];
     I64[Hp - 8] = MyThing2_con_info;
     I8[Hp] = _sID::I8;
     I8[Hp + 1] = _sIE::I8;
     I8[Hp + 2] = _sIF::I8;
     I8[Hp + 3] = _sIG::I8;
     R1 = Hp - 7;
     Sp = Sp + 8;
     call (P64[Sp])(R1) args: 8, res: 0, upd: 8;

在这里您可以看到,连续 4 个字节从源对象复制到新创建的堆对象中。

在这种情况下,本机代码生成器不够聪明,无法将其重写为单个字大小的移动,并将其保留为四个字节大小的移动(请参阅汇编),即使使用

-O2
进行编译,但 LLVM 后端将如果您使用
-fllvm
进行编译,则可以正确优化它。

© www.soinside.com 2019 - 2024. All rights reserved.