对 C99 可变长度数组 (VLA) 使用限制限定符

2024-01-08

我正在探索 C99 中简单循环的不同实现如何根据函数签名自动矢量化。

这是我的代码:

/* #define PRAGMA_SIMD _Pragma("simd") */
#define PRAGMA_SIMD

#ifdef __INTEL_COMPILER
#define ASSUME_ALIGNED(a) __assume_aligned(a,64)
#else
#define ASSUME_ALIGNED(a)
#endif

#ifndef ARRAY_RESTRICT
#define ARRAY_RESTRICT
#endif

void foo1(double * restrict a, const double * restrict b, const double * restrict c) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i) {
        if (c[i] > 0) {
            a[i] = b[i];
        } else {
            a[i] = 0.0;
        } 
    }
}

void foo2(double * restrict a, const double * restrict b, const double * restrict c) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i) {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

/* Undetermined size version */

void foo3(int n, double * restrict a, const double * restrict b, const double * restrict c) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i) {
        if (c[i] > 0) {
            a[i] = b[i];
        } else {
            a[i] = 0.0;
        } 
    }
}

void foo4(int n, double * restrict a, const double * restrict b, const double * restrict c) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i) {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

/* Static array versions */

void foo5(double ARRAY_RESTRICT a[2048], const double ARRAY_RESTRICT b[2048], const double ARRAY_RESTRICT c[2048]) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i) {
        if (c[i] > 0) {
            a[i] = b[i];
        } else {
            a[i] = 0.0;
        } 
    }
}

void foo6(double ARRAY_RESTRICT a[2048], const double ARRAY_RESTRICT b[2048], const double ARRAY_RESTRICT c[2048]) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i) {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

/* VLA versions */

void foo7(int n, double ARRAY_RESTRICT a[n], const double ARRAY_RESTRICT b[n], const double ARRAY_RESTRICT c[n]) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i) {
        if (c[i] > 0) {
            a[i] = b[i];
        } else {
            a[i] = 0.0;
        } 
    }
}

void foo8(int n, double ARRAY_RESTRICT a[n], const double ARRAY_RESTRICT b[n], const double ARRAY_RESTRICT c[n]) 
{ 
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i) {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

当我编译时

$ icc -O3 -std=c99 -opt-report5 -mavx -S foo.c 
icc: remark #10397: optimization reports are generated in *.optrpt files in the output location

我看到 VLA 案例没有自动矢量化,但是当我添加标志来断言没有混叠时-fno-alias, 他们是。因此,我得出的结论是,我应该在源代码中规定这一点,因此我尝试通过编译来做到这一点

$ icc -O3 -std=c99 -opt-report5 -mavx -DARRAY_RESTRICT=restrict -S foo.c 
icc: remark #10397: optimization reports are generated in *.optrpt files in the output location

编译器错误输出包括

foo.c(98): error: "restrict" is not allowed
void foo7(int n, double ARRAY_RESTRICT a[n], const double ARRAY_RESTRICT b[n], 
const double ARRAY_RESTRICT c[n]) 

             ^

但正如您所看到的,我的 VLA 参数不允许限制。

所以我的问题是:有没有办法断言 ISO C 中 VLA 没有别名?

请注意,我可以使用编译指示在源代码中断言没有别名 - 例如simd, omp simd, ivdep等等 - 并获得我想要的自动矢量化,但这些不是 ISO C。

在这种情况下,ISO C 表示 C 的最新版本,当然在撰写本文时是 C11。


您的原始代码对我来说很失败,并显示以下消息:

 void foo7(int n, double ARRAY_RESTRICT a[n], const double ARRAY_RESTRICT b[n], const double ARRAY_RESTRICT c[n])
 ^
restrict.c:126:1: error: invalid use of ‘restrict’
restrict.c:126:1: error: invalid use of ‘restrict’
restrict.c:145:1: error: invalid use of ‘restrict’

Transferring selected parts of the comments

§6.7.6.3函数声明符(包括原型)示例 5 表明以下函数原型声明符是等效的:

void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);

这是标准中唯一出现与数组类型直接关联的限制的地方。 §6.7.6 通常用于声明符,而 §6.7.6.2 则用于数组声明符,在我看来,限制必须出现在数组维度的第一个组件内。根据您的情况,它应该是:

void foo7(int n, double a[ARRAY_RESTRICT n],
           const double b[ARRAY_RESTRICT n],
           const double c[ARRAY_RESTRICT n])

如果没有看到标准中的示例并且您提出问题,我不会相信这种符号!请注意,这适用于数组和 VLA。

根据注释修改后的代码在相同的编译选项下可以干净地编译:

gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition -Wold-style-declaration -Werror -c new.restrict.c

编译选项要求事先声明非静态函数,因此声明位于文件顶部。我也强行#define ARRAY_RESTRICT restrict在源代码中,而不是将其保留为编译选项。

编译器是在 Ubuntu 14.04 衍生版本上运行的 GCC 4.9.2。

File new.restrict.c:

/* #define PRAGMA_SIMD _Pragma("simd") */
#define PRAGMA_SIMD

#ifdef __INTEL_COMPILER
#define ASSUME_ALIGNED(a) __assume_aligned(a, 64)
#else
#define ASSUME_ALIGNED(a)
#endif

#define ARRAY_RESTRICT restrict

#ifndef ARRAY_RESTRICT
#define ARRAY_RESTRICT
#endif

void foo1(double *restrict a, const double *restrict b, const double *restrict c);
void foo2(double *restrict a, const double *restrict b, const double *restrict c);
void foo3(int n, double *restrict a, const double *restrict b, const double *restrict c);
void foo4(int n, double *restrict a, const double *restrict b, const double *restrict c);
void foo5(double a[ARRAY_RESTRICT 2048], const double b[ARRAY_RESTRICT 2048], const double c[ARRAY_RESTRICT 2048]);
void foo6(double a[ARRAY_RESTRICT 2048], const double b[ARRAY_RESTRICT 2048], const double c[ARRAY_RESTRICT 2048]);
void foo7(int n, double a[ARRAY_RESTRICT n], const double b[ARRAY_RESTRICT n], const double c[ARRAY_RESTRICT n]);
void foo8(int n, double a[ARRAY_RESTRICT n], const double b[ARRAY_RESTRICT n], const double c[ARRAY_RESTRICT n]);

void foo1(double *restrict a, const double *restrict b, const double *restrict c)
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i)
    {
        if (c[i] > 0)
        {
            a[i] = b[i];
        }
        else
        {
            a[i] = 0.0;
        }
    }
}

void foo2(double *restrict a, const double *restrict b, const double *restrict c)
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i)
    {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

/* Undetermined size version */

void foo3(int n, double *restrict a, const double *restrict b, const double *restrict c)
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i)
    {
        if (c[i] > 0)
        {
            a[i] = b[i];
        }
        else
        {
            a[i] = 0.0;
        }
    }
}

void foo4(int n, double *restrict a, const double *restrict b, const double *restrict c)
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i)
    {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

/* Static array versions */

void foo5(double a[ARRAY_RESTRICT 2048], const double b[ARRAY_RESTRICT 2048], const double c[ARRAY_RESTRICT 2048])
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i)
    {
        if (c[i] > 0)
        {
            a[i] = b[i];
        }
        else
        {
            a[i] = 0.0;
        }
    }
}

void foo6(double a[ARRAY_RESTRICT 2048], const double b[ARRAY_RESTRICT 2048], const double c[ARRAY_RESTRICT 2048])
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < 2048; ++i)
    {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}

/* VLA versions */

void foo7(int n, double a[ARRAY_RESTRICT n], const double b[ARRAY_RESTRICT n], const double c[ARRAY_RESTRICT n])
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i)
    {
        if (c[i] > 0)
        {
            a[i] = b[i];
        }
        else
        {
            a[i] = 0.0;
        }
    }
}

void foo8(int n, double a[ARRAY_RESTRICT n], const double b[ARRAY_RESTRICT n], const double c[ARRAY_RESTRICT n])
{
    ASSUME_ALIGNED(a);
    ASSUME_ALIGNED(b);
    ASSUME_ALIGNED(c);
    PRAGMA_SIMD
    for (int i = 0; i < n; ++i)
    {
        a[i] = ((c[i] > 0) ? b[i] : 0.0);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对 C99 可变长度数组 (VLA) 使用限制限定符 的相关文章

随机推荐

  • JavaScript for 循环问题

    for循环可以重复一个数字3次吗 例如 for i 0 i lt 5 i 创建 1 2 3 4 5 我想创建一个执行此操作的循环 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 那可能吗 for i 1 i lt 5 i for
  • 获取 MethodBase 对象的最快方法是什么?

    我有一个 Type 对象和一个方法名称 Type type string methodName 我需要一个方法 methodName 的 MethodBase 对象 位于堆栈中的某个位置 这有效 MethodBase nemo StackT
  • Detours - 挂钩类成员函数 - 设置目标函数偏移量的语法?

    对于非类函数 我可以简单地声明要绕行的函数的偏移量 如下所示 typedef int cdecl SomeFunc char pBuffer int size SomeFunc Real SomeFunc SomeFunc 0xCAFEBA
  • 在android中添加水印图像

    我有代码可以在图像中添加水印 如下所示 public static Bitmap mark Bitmap src String watermark Point location Color color int alpha int size
  • 为什么 Edge 主体滚动条与 Firefox 主体滚动条不同?

    我正在创建一个聊天列表 它在 Firefox 上运行良好 但在 Microsoft Edge 上却不起作用 根的CSS div class chatting chatting position fixed bottom 5px right
  • 将客户端证书传递给 Web 服务,而无需设置系统范围的属性

    我正在尝试使用 JAX RPC 实现将客户端证书传递给 Web 服务 Web 服务采用 rpc 编码风格 到目前为止 我可以通过设置系统属性来做到这一点 System setProperty javax net ssl keyStore c
  • 当用户尚未登录时,FB.ui() 在 Safari 中通过异步请求给出错误

    我正在尝试让用户能够在我的外部网站上的 Facebook 墙上发布内容 我在 Safari 中遇到问题 如果用户未登录 即他们尚未完成调用 FB login 的流程 则在调用 FB ui 时会收到以下 JS 错误 类型错误 未定义 不是对象
  • ServiceLoader.next 导致 NoClassDefFoundError

    我这么问是因为我完全not我确信我做了正确的事 我正在使用 Eclipse 进行 Web 项目 我们在包中将其称为 WebProject 废话 com web project 我希望 WebProject 在运行时加载 JAR 插件 所以我
  • 上下文、AsyncTask 和轮换更改

    这是一个很好的做法吗getApplicationContext 使用 AsyncTask 以便不必附加和分离 Activity以避免内存泄漏when发生旋转变化并且活动被破坏 我认为它应该是正确的 因为我实际上需要一个依赖于洞应用程序的上下
  • 使用 Gmail 凭据登录

    有没有一种方法可以使用 Google 凭据来获取基本用户信息 例如 电子邮件 姓名 性别 并在我的应用程序中使用它们 这就像允许用户使用 Gmail 登录我的应用程序一样 我也问了同样的问题here https stackoverflow
  • ggplot2 二维密度权重

    我正在尝试使用 R 中的 ggplot2 用二维密度轮廓绘制一些数据 我得到一个有点奇怪的结果 首先 我设置了 ggplot 对象 p lt ggplot data aes x Distance y Rate colour Company
  • 如何让 gVim 的 vimdiff 忽略大小写?

    我正在尝试比较两个程序集文件 其中一个文件全部大写 另一个文件全部小写 许多行在大小写和空格方面都是相同的 我尝试了以下操作 同时两个缓冲区处于差异模式 set diffopt icase set diffopt iwhite diffup
  • List.Add 似乎是重复的条目。怎么了?

    我有一堂这样的课 public class myClass public List
  • 计划任务的限制(或者任务持久化是如何实现的)?

    我开始阅读 Hangfire 文档 但没有发现任何有关任务限制的信息 正如声明的那样 任务 或作业 存储在某个地方 由于它们只是代表 据我所知 唯一可以存储的东西是代表 主体 IL 但是可能存在闭包 它为任务提供了一些上下文 例如一些外部服
  • 如何在Python中对二进制文件进行base64编码/解码?

    我正在尝试使用 python 使用以下简单代码对同一图像文件进行编码和解码 但每次输出文件都大于输入文件并且无法打开 这段代码有什么问题 import base64 with open img jpeg rb as image file e
  • 多线程异常和Dispose。为什么 Dispose 没有调用?

    using 语句保证该对象将被调用 Dispose 方法 在此示例中 这种情况没有发生 并且终结器方法也没有调用 为什么这一切 当其他线程发生异常时 如何更改代码以保证处理我的对象 class Program static void Mai
  • JavaScript 中的动态方法调用

    我知道我可以这样做 var myClass my class definition var methodName myMethod myClass methodName p1 p2 pN 但如果有这样的情况我该怎么办 if data som
  • 在 tkinter 画布上绘制 png 图像 python

    我正在尝试使用创建一个简单的游戏tkinter in python 3 5使用画布小部件 对于这个游戏 我需要能够使用透明 png 图像 这是我的代码 from PIL import ImageTk from tkinter import
  • 我可以使用 PHP 读取 .TXT 文件吗?

    当我开始使用 PHP 和 MySQL 编写站点时 我编写的第一个 PHP 脚本之一是初始化数据库的脚本 删除 创建数据库 删除 创建每个表 然后从脚本中的文字加载表 一切正常 呼呼 但我更喜欢从文件中读取数据 而不是在 PHP 脚本中对它们
  • 对 C99 可变长度数组 (VLA) 使用限制限定符

    我正在探索 C99 中简单循环的不同实现如何根据函数签名自动矢量化 这是我的代码 define PRAGMA SIMD Pragma simd define PRAGMA SIMD ifdef INTEL COMPILER define A