【问题标题】:Exotic architectures the standards committees care about标准委员会关心的异乎寻常的架构
【发布时间】:2011-10-21 18:17:06
【问题描述】:

我知道 C 和 C++ 标准保留了语言实现的许多方面,只是因为如果存在具有其他特征的架构,那么为它编写符合标准的编译器将非常困难或不可能。

我知道 40 年前,任何计算机都有自己独特的规格。但是,我不知道今天使用的任何架构:

  • CHAR_BIT != 8
  • signed 不是二进制补码(我听说 Java 对此有问题)。
  • 浮点不符合 IEEE 754(编辑:我的意思是“不在 IEEE 754 二进制编码中”)。

我问的原因是,我经常向人们解释说,C++ 不强制要求任何其他低级方面(如固定大小的类型)是件好事。这很好,因为与“其他语言”不同,它使您的代码在正确使用时可移植(编辑:因为它可以移植到更多架构而无需模拟机器的低级方面,例如符号+幅度架构上的二进制补码算法) .但是我很难自己指出任何具体的架构。

所以问题是:哪些架构具有上述特性?

uint*_ts 是可选的。

【问题讨论】:

  • 我认为你有它倒退。如果 C++ 强制要求对有符号整数使用二进制补码,那么它将使 C++ 代码更便携而不是更少。为什么 C++ 标准委员会不强制要求这样做是另一回事。尤其是,尽管你说,为非标准架构编写编译器并不是不可能,你总是可以模拟 8 位字符或二进制补码算法,即使你的平台没有直接支持。
  • @john:那么这将是不切实际的,因此不符合标准的编译器将生成比符合标准的更快的代码。而且我仍然看不到它如何使您的代码更具可移植性。
  • 我确信标准如此的真正原因并不是因为它是一些理想的解决方案。但这是因为在编写标准时已经存在许多 C 和 C++ 编译器,标准委员会不想拒绝现有的编译器。
  • @john :我怀疑“让编译器编写者更容易”是创建 C++ 标准时的优先事项(如果是,他们会做得很糟糕,因为 C++ 是最难的之一要解析的语言,并且该语言的其他方面也不完全使编译器编写者变得容易)。不过,性能、广泛的平台支持和向后兼容性非常重要。如果将您提到的限制添加到标准中,所有这三个都会受到影响。
  • 不是编译器而是硬件。 C++ 保留了一些未指定的内容以允许直接使用硬件功能。无论如何,您的手机应用程序都不会在大型机上运行,​​因此无论代码是否一致,都没有可移植性。

标签: c++ c architecture


【解决方案1】:

看看这个

Unisys ClearPath Dorado Servers

为尚未迁移所有 Univac 软件的用户提供向后兼容性。

关键点:

  • 36 位字
  • CHAR_BIT == 9
  • 补码
  • 72 位非 IEEE 浮点数
  • 代码和数据的独立地址空间
  • 字地址
  • 没有专用的堆栈指针

虽然不知道他们是否提供 C++ 编译器,但他们可以


现在他们的 C 手册最新版本的链接已经浮出水面:

Unisys C Compiler Programming Reference Manual

第 4.5 节有一个包含 9、18、36 和 72 位的数据类型表。

【讨论】:

  • 我猜 void* 在那种架构中使用肯定是地狱般的。
  • @ybungalobill - 我相信char*void* 的大小必须相同,并且大到足以容纳任何其他指针。其余的取决于实施。
  • @ybungalobill:在旧的 Win16 编译器上,常规指针接近指针并且只包含 16 位偏移量,所以 sizeof(int*) == 2,但远指针也有一个 16 位选择器,所以 sizeof(void*) == 4 .
  • 有,或者曾经有,他们的 C++ 编译器的在线手册。还值得指出的是,这只是 Unisys 大型机架构中的一种:另一种是 48 位有符号幅度标记架构(我只找到了 C 手册,而不是 C++ 手册)。关于其余部分:我不认为sizeof(int*) != sizeof(char*) 在这里:两者都是 36 位。但是char* 中的字节选择器位于高位,在int* 中被忽略。 (不过,我使用过其他机器,其中 `sizeof(char*) > sizeof(int*)。)
  • @Adam Rosenfield 在 MS/DOS 16 位编译器上,您有不同的“模式”,并且数据指针的大小不一定与函数指针的大小相同。但至少在我使用的那些上,所有数据指针(包括void*)总是具有相同的大小。 (当然,你不能将函数指针转换为void*,因为void* 可能更小。但根据标准,你今天也不能这样做。)
【解决方案2】:

我在CHAR_BIT != 8 找到了this link listing some systems。它们包括

一些 TI DSP 有CHAR_BIT == 16

BlueCore-5 芯片(蓝牙 来自 Cambridge Silicon Radio 的芯片),它有CHAR_BIT == 16

当然还有一个关于 Stack Overflow 的问题:What platforms have something other than 8-bit char

关于非二进制补码系统, comp.lang.c++.moderated 上有一篇有趣的文章。总结:有些平台有一个的补码或符号和幅度表示。

【讨论】:

  • Analog Devices 32 位 SHARC DSP 有CHAR_BIT=32,而 TMS32F28xx 的德州仪器 DSP 有CHAR_BIT=16。 PDP-10 的 GCC 3.2 有 CHAR_BIT=9。我认为,S/360 也可能有一个非 8 位字符。
  • 我仍然想要一个“非二进制补码”架构的示例。特别是因为碰巧CHAR_BITS 是部分重复。
  • TI DSP 具有 16 位字符只是因为实施者选择了它(要使其正常工作需要做更多的工作,但 IIRC 并不难 - 可能只是一些“漏洞”底层编译器中的代码生成脚手架)。所以这不是一些深层的架构原因。 C 代码在抽象机器上工作。如果您只有 16 位 INT,请在每个 INT 中存储两个字符,并将读取-修改-写入合并添加到窥孔优化器(至少)。当然,这需要更多的工作,但只要看看每个人在他们永远不会出现的地方处理这些奇怪的类型还有多少工作量。糟糕。
【解决方案3】:

直到最近,IEEE 754 二进制表示在 GPU 上并不常见,请参阅 GPU Floating-Point Paranoia

编辑:在 cmets 中提出了一个问题,GPU 浮点是否与通常的计算机编程相关,与图形无关。当然好!今天工业计算的大多数高性能计算都是在 GPU 上完成的。该列表包括人工智能、数据挖掘、神经网络、物理模拟、天气预报等等。 cmets 中的一个链接说明了原因:GPU 的浮点优势数量级

我想补充的另一件事与 OP 问题更相关:10-15 年前,当 GPU 浮点不是 IEEE 并且没有诸如今天的 OpenCL 或 CUDA 之类的 API 时,人们做了什么?程序GPU?信不信由你,早期的 GPU 计算先驱们设法在没有 API 的情况下对 GPU 进行编程!我在公司遇到了其中一位。他是这样做的:他将需要计算的数据编码为图像,其中像素代表他正在处理的值,然后使用 OpenGL 执行他需要的操作(例如“高斯模糊”来表示具有正态分布的卷积等),并将生成的图像解码回结果数组。而且这仍然比使用 CPU 快!

类似的事情促使 NVidia 最终使其内部数据二进制与 IEEE 兼容,并引入了面向计算而不是图像处理的 API。

【讨论】:

  • @ybungalobill,将重复性工作卸载到 GPU 目前是large scale computations首选方法。事实上,我目前正在用 C++ 开发一个。幸运的是,我们只使用 NVidia CUDA GPU 具有 IEEE 754 兼容的浮点二进制表示。
  • @ybungalobill:有几个答案。首先,CUDA does support C, C++, and Fortran。查看相同的链接,了解 2048 线程 GPU 相对于典型 8 线程 CPU 的巨大性能优势。其次,确实,仅支持这些语言的子集(尽管很大),包括在 CUDA 5.0 之前缺乏对适合 CUDA 编程模型递归(称为“动态并行”)的支持。第三,递归通常可以用循环代替,这对于多线程性能来说是必需的。
【解决方案4】:

CHAR_BITS

根据gcc源码:

CHAR_BIT1750adsp16xx 架构的 16 位。
CHAR_BITdsp56k24 位> 架构。
CHAR_BITc4x 架构的 32 位。

您可以通过以下方式轻松找到更多信息:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

如果CHAR_TYPE_SIZE 被适当定义。

IEEE 754 合规性

如果目标架构不支持浮点指令,gcc 可能会生成软件回退,默认情况下不符合标准。不仅如此,还可以使用特殊选项(例如 -funsafe-math-optimizationswitch 也禁用零符号保留)。

【讨论】:

  • 赞成简单地指导 OP 查看流行编译器的源代码;这是RFTM在这种情况下的定义,所以它应该是人们首先看到的地方。
【解决方案5】:

您对大型机的假设都不成立。对于初学者,我不知道 使用 IEEE 754 的大型机:IBM 使用 base 16 浮点数,以及 两台 Unisys 大型机都使用 base 8。 Unisys 机器有点 其他许多方面的特殊之处:Bo 提到了 2200 架构, 但 MPS 架构更奇怪:48 位标记字。 (字是否为指针取决于字中的位。) 并且数字表示被设计成没有真实的 浮点数和积分算术的区别:浮点数 点是基数 8;它不需要规范化,并且不像每个 我见过的其他浮点数,它把小数点放在右边 尾数,而不是左边,并使用带符号的幅度 指数(除了尾数)。结果是 整数浮点值具有(或可以具有)完全相同的位 表示为有符号幅度整数。并且没有浮动 点算术指令:如果两个值的指数是 均为 0,指令执行积分运算,否则执行 浮点运算。 (标签哲学的延续 架构。)这意味着虽然int 可能占用 48 位,但 8 其中必须为 0,否则该值不会被视为整数。

【讨论】:

【解决方案6】:

我很确定 VAX 系统仍在使用中。它们不支持 IEEE 浮点;他们使用自己的格式。 Alpha 支持 VAX 和 IEEE 浮点格式。

Cray 向量机(如 T90)也有自己的浮点格式,但较新的 Cray 系统使用 IEEE。 (我用的T90几年前就退役了,不知道还有没有还在用。)

T90 也有/有一些有趣的指针和整数表示。本机地址只能指向 64 位字。 C 和 C++ 编译器有 CHAR_BIT==8(这是必要的,因为它运行 Unicos,一种 Unix 风格,并且必须与其他系统互操作),但本机地址只能指向 64 位字。所有字节级操作都由编译器合成,void*char* 在字的高 3 位中存储了一个字节偏移量。而且我认为一些整数类型有填充位。

IBM 大型机是另一个例子。

另一方面,这些特定系统不需要必然排除对语言标准的更改。 Cray 对将其 C 编译器升级到 C99 没有表现出任何特别的兴趣。大概同样的事情适用于 C++ 编译器。 可能收紧对托管实现的要求是合理的,例如要求 CHAR_BIT==8、IEEE 格式浮点(如果不是完整的语义)和 2 的补码,而没有填充位的有符号整数。旧系统可以继续支持早期的语言标准(C99 出现时 C90 并没有消亡),并且对于 DSP 等独立实现(嵌入式系统)的要求可能会更宽松。

另一方面,未来系统可能有充分的理由去做今天被认为是异国情调的事情。

【讨论】:

  • 最后的要点是关于过于严格的标准如何阻碍创新。当我们得到具有三态的量子(或有机)计算机时,unsigned 整数类型的模算术要求将是一个主要难题,而有符号算术将很好。
  • @BenVoigt 为什么无符号算术很痛苦?这些计算机中的模 3^n 加法器不是不可能吗?
  • @LưuVĩnhPhúc:这正是关键所在,硬件操作以 3**n 为模,提供 C++ 无符号类型的操作以 2**n 为模将是困难的。
  • 我知道一个 VAX 11/780 仍在用作交叉编译器的主机,该交叉编译器针对具有专有架构的专用嵌入式系统。为了维持这种特殊的 VAX,保管人一直在接近博物馆寻找备件。
  • @Keith - 从技术上讲,唯一的障碍是通过一个过程来提供满足监管要求的证据,因为目标嵌入式系统具有很高的关键性。然而,有许多非技术障碍(组织政治等),迄今为止是无法克服的。目前,安装一个案例来突袭博物馆比更新主机更容易。
【解决方案7】:

完全符合 IEEE 754 标准在浮点实现中很少见。在这方面削弱规范可以进行大量优化。

例如,子规范支持 x87​​ 和 SSE 之间的差异。

像融合乘法和加法这样的优化在源代码中是分开的,也会稍微改变结果,但在某些架构上是很好的优化。

或者在 x86 上,严格的 IEEE 合规性可能需要设置某些标志或浮点寄存器和普通内存之间的额外传输,以强制它使用指定的浮点类型而不是其内部 80 位浮点数。

有些平台根本没有硬件浮动,因此需要在软件中模拟它们。并且 IEEE 754 的某些要求在软件中实现可能会很昂贵。特别是舍入规则可能是个问题。

我的结论是,如果您并不总是想要保证严格的 IEEE 合规性,那么您不需要奇特的架构来应对这种情况。由于这个原因,很少有编程语言能保证严格遵守 IEEE。

【讨论】:

  • 另一组“奇特”硬件是 IBM 大型机,其中浮点格式早于 IEEE 标准。与 Java 不同,C++ 仍然可以使用现有的硬件。
  • GPU 不完全支持 IEEE 754。
  • 缺乏对 IEEE 754 的严格合规性对某些人来说是个麻烦,但我认为这不是 OP 真正关心的问题范围。
  • @Matthieu 因为这也被标记为“C”,所以我应该提到一个 C 分析器,它可以告诉你浮点程序在 80 位浮点寄存器溢出到内存时可能采用的所有值C 编译器的奇思妙想。 blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
  • @MatthieuM.: 太糟糕了 ISO/ANSI 不允许可变参数来指定浮点和整数参数的最小/最大大小;如果有的话,80 位的long double 可能是一种有用且寿命长的类型,因为它的一个真正问题是它与printf 配合不好。扩展双精度存储前导 1 显式加速了非 FPU 系统上的计算,并且还将消除在任何上下文中对非规范化进行特殊处理的需要,而不是与其他类型的转换。太糟糕了 C 的 printf 把一切都搞砸了。
猜你喜欢
  • 2012-11-01
  • 2013-04-15
  • 2019-12-28
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 2017-08-17
  • 2012-02-27
  • 1970-01-01
相关资源
最近更新 更多