gcc 自动矢量化(未处理的数据引用)

2024-03-27

我不明白为什么这样的代码没有用 gcc 4.4.6 进行矢量化

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex)
{
  for (int i = 0; i < iSize; i++)
     pfResult[i] = pfResult[i] + pfTab[iIndex];
}

 note: not vectorized: unhandled data-ref

但是,如果我写下面的代码

   int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex)
{
  float fTab =  pfTab[iIndex];
  for (int i = 0; i < iSize; i++)
     pfResult[i] = pfResult[i] + fTab;
}

gcc 成功自动矢量化此循环

如果我添加 omp 指令

   int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex)
{
  float fTab =  pfTab[iIndex];
  #pragma omp parallel for
  for (int i = 0; i < iSize; i++)
     pfResult[i] = pfResult[i] + fTab;
}

我有以下错误未矢量化:未处理的数据引用

您能帮我解释一下为什么第一个代码和第三个代码没有自动矢量化吗?

第二个问题: 数学操作数似乎没有矢量化(exp、log等),例如这段代码

for (int i = 0; i < iSize; i++)
         pfResult[i] = exp(pfResult[i]);

没有矢量化。这是由于我的 gcc 版本所致?

Edit: 使用新版本的 gcc 4.8.1 和 openMP 2011 (echo |cpp -fopenmp -dM |grep -i open) 即使基本上,我对所有类型的循环都有以下错误

   for (iGID = 0; iGID < iSize; iGID++)
        {
             pfResult[iGID] = fValue;
        }


note: not consecutive access *_144 = 5.0e-1;
note: Failed to SLP the basic block.
note: not vectorized: failed to find SLP opportunities in basic block.

Edit2:

#include<stdio.h>
#include<sys/time.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <omp.h>

int main()
{
        int szGlobalWorkSize = 131072;
        int iGID = 0;
        int j = 0;
        omp_set_dynamic(0);
        // warmup
        #if WARMUP
        #pragma omp parallel
        {
        #pragma omp master
        {
        printf("%d threads\n", omp_get_num_threads());
        }
        }
        #endif
        printf("Pagesize=%d\n", getpagesize());
        float *pfResult = (float *)malloc(szGlobalWorkSize * 100* sizeof(float));
        float fValue = 0.5f;
        struct timeval tim;
        gettimeofday(&tim, NULL);
        double tLaunch1=tim.tv_sec+(tim.tv_usec/1000000.0);
        double time = omp_get_wtime();
        int iChunk = getpagesize();
        int iSize = ((int)szGlobalWorkSize * 100) / iChunk;
        //#pragma omp parallel for
        for (iGID = 0; iGID < iSize; iGID++)
        {
             pfResult[iGID] = fValue;
        }
        time = omp_get_wtime() - time;
        gettimeofday(&tim, NULL);
        double tLaunch2=tim.tv_sec+(tim.tv_usec/1000000.0);
        printf("%.6lf Time1\n", tLaunch2-tLaunch1);
        printf("%.6lf Time2\n", time);
}

结果与

#define _OPENMP 201107
gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15)

gcc -march=native -fopenmp -O3 -ftree-vectorizer-verbose=2 test.c -lm

lot of

note: Failed to SLP the basic block.
note: not vectorized: failed to find SLP opportunities in basic block.
and note: not consecutive access *_144 = 5.0e-1;

Thanks


GCC 无法矢量化循环的第一个版本,因为它无法证明pfTab[iIndex]不包含在内存跨越的某个地方pfResult[0] ... pfResult[iSize-1](指针别名)。确实,如果pfTab[iIndex]位于该内存中的某个位置,那么它的值必须被循环体中的赋值覆盖,并且新值必须在接下来的迭代中使用。您应该使用restrict关键字提示编译器这永远不会发生,然后它应该愉快地矢量化您的代码:

$ cat foo.c
int MyFunc(const float *restrict pfTab, float *restrict pfResult,
           int iSize, int iIndex)
{
   for (int i = 0; i < iSize; i++)
     pfResult[i] = pfResult[i] + pfTab[iIndex];
}
$ gcc -v
...
gcc version 4.6.1 (GCC)
$ gcc -std=c99 -O3 -march=native -ftree-vectorizer-verbose=2 -c foo.c
foo.c:3: note: LOOP VECTORIZED.
foo.c:1: note: vectorized 1 loops in function.

第二个版本进行矢量化,因为值被传输到具有自动存储持续时间的变量。这里的一般假设是pfResult不跨越堆栈内存,其中fTab已存储(粗略阅读 C99 语言规范并不能明确该假设是否较弱或标准中的某些内容允许)。

由于 OpenMP 在 GCC 中的实现方式,OpenMP 版本不会进行矢量化。它使用并行区域的代码大纲。

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex)
{
  float fTab =  pfTab[iIndex];
  #pragma omp parallel for
  for (int i = 0; i < iSize; i++)
     pfResult[i] = pfResult[i] + fTab;
}

实际上变成:

struct omp_data_s
{
  float *pfResult;
  int iSize;
  float *fTab;
};

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex)
{
  float fTab =  pfTab[iIndex];
  struct omp_data_s omp_data_o;

  omp_data_o.pfResult = pfResult;
  omp_data_o.iSize = iSize;
  omp_data_o.fTab = fTab;

  GOMP_parallel_start (MyFunc_omp_fn0, &omp_data_o, 0);
  MyFunc._omp_fn.0 (&omp_data_o);
  GOMP_parallel_end ();
  pfResult = omp_data_o.pfResult;
  iSize = omp_data_o.iSize;
  fTab = omp_data_o.fTab;
}

void MyFunc_omp_fn0 (struct omp_data_s *omp_data_i)
{
  int start = ...; // compute starting iteration for current thread
  int end = ...; // compute ending iteration for current thread

  for (int i = start; i < end; i++)
    omp_data_i->pfResult[i] = omp_data_i->pfResult[i] + omp_data_i->fTab;
}

MyFunc_omp_fn0包含概述的功能代码。编译器无法证明omp_data_i->pfResult不指向别名的内存omp_data_i特别是其成员fTab.

为了向量化该循环,你必须使fTab firstprivate。这将把它变成概述代码中的自动变量,这将相当于你的第二种情况:

$ cat foo.c
int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex)
{
   float fTab = pfTab[iIndex];
   #pragma omp parallel for firstprivate(fTab)
   for (int i = 0; i < iSize; i++)
     pfResult[i] = pfResult[i] + fTab;
}
$ gcc -std=c99 -fopenmp -O3 -march=native -ftree-vectorizer-verbose=2 -c foo.c
foo.c:6: note: LOOP VECTORIZED.
foo.c:4: note: vectorized 1 loops in function.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gcc 自动矢量化(未处理的数据引用) 的相关文章

随机推荐

  • C语言中的*和&有什么区别?

    我正在学习 C 但我仍然不确定我是否理解两者之间的区别 and yet 请允许我尝试解释一下 int a Declares a variable int b Declares a pointer int c Not possible a 1
  • JWT 令牌的最大大小是多少?

    我需要知道的最大长度 JSON Web 令牌 JWT 规格中没有相关信息 难道说 长度没有限制吗 我也一直在努力寻找这个 我会说 尝试并确保它是7kb 以下 虽然 JWT 在规范中没有定义上限 http www rfc editor org
  • Rmarkdown:在选项卡集下添加标题

    在 Rmarkdown 中我使用 tabset 将块拆分为选项卡 Tabset 1 tabset A Text under tab A B Text under tab B 我想在一些选项卡下添加一个大标题 Tabset 1 tabset
  • Java 中的 ArrayList 与 String

    我正在实现LZW算法 我已经成功地针对字符串和文本文件实现了它 并且当前正在修改我的代码以处理二进制文件 例如图像或可执行文件 因为我无法将这些文件作为字符串读取 我已经更换了String输入我的代码ArrayList
  • 如何在不使用 try-catch 的情况下检查路径是否有效?

    我想检查文件夹是否存在 如果不存在则创建它 但我不知道提供的路径是否有效 当路径无效时 会发生以下情况 string path this is an invalid path if Directory Exists path Directo
  • PayPal 的 Python 接口 - urllib.urlencode 非 ASCII 字符失败

    我正在尝试实现 PayPal IPN 功能 基本协议是这样的 客户从我的网站重定向到 PayPal 的网站以完成付款 他登录自己的帐户 授权付款 PayPal 调用我服务器上的一个页面 以 POST 形式传递详细信息 详细信息包括个人姓名
  • 上传的文件未保存到文件系统

    Context 我正在为我正在构建的 CMS 创建媒体库 基本功能包括上传文件并将其存储在文件系统中 但是 它会为保存的文件创建一个 id 目前我正在通过我构建的内容进行测试localhost db Files Add mediafile
  • Jira 插件自定义字段值如何在 .vm 模板中得到处理

    吉拉服务器 7 2 1 自定义字段插件 问题遵循此讨论 不明白 方法 getSingularObjectFromString 是做什么的 https stackoverflow com questions 17925377 cant und
  • Google表格公式中的数字增量

    在 Google Sheets 数据库中 我建立了一个公式 以便为一系列公司分配参考号 每个公司都应该有其唯一的编号 其形式为RET00XX其中 XX 代表唯一的公司编号 我希望这些数字是连续的 从 1 开始 然后继续 1 每当在数据库中插
  • Python 交换函数

    我很难用 Python 表达这一点 这是需要做什么的描述 swap cards int int 列表 gt NoneType swap cards 3 2 1 4 5 6 0 5 3 2 1 4 5 0 6 swap cards 3 2 1
  • 需要正则表达式来匹配多行,直到在公共分隔符之间找到匹配

    我正在尝试编写一个正则表达式 它将从日志文件返回多行匹配 使用下面的示例 我想匹配整个 事务 其开头和结尾与日志中所有其他事务 开始和结束 的文本相同 然而 在这些行之间有一个自定义标识符 在本例中是一个电子邮件地址 可以将一笔交易与另一笔
  • 如何将 Fluent NHibernate Automapping 与实体中相同类型的多个列表一起使用?

    看来 NHibernate 无法自动映射实体中给定类型的多个 IList 考虑以下两个实体 基于 Fluent NHibernate 源代码中包含的 Examples FirstProject 示例代码 public class Emplo
  • 如何在 LESS CSS 嵌套类上指定 html 标签?

    我有一个类用于article and a sectionHTML5 标签 在家里
  • 在创建位图之前如何从InputStream知道位图的大小?

    我需要在创建图像之前对其进行缩放 并且仅当图像超过 1024KB 例如 时才进行缩放 通过执行以下操作 我可以缩放图像 但我只需要缩放大于给定尺寸的图像 Bitmap bmImg null InputStream is url openSt
  • 如何在不等待事件侦听器运行的情况下触发事件?

    我对 NET C 中的事件有疑问 我必须为几种情况编写代码 在这些情况下 我正在运行后台任务 并且我想通知主线程或控制器类发生了某些事情 例如任务已完成或完成了文件复制 但我不这样做不希望后台任务等待主线程的委托来处理事件 我想做一些类似消
  • java 最优雅的 isNumeric() 解决方案

    我现在正在将一小段 PHP 代码移植到 java 并且我依赖于该函数is numeric x 确定是否 x是一个数字还是不是一个数字 java中似乎没有等效的函数 而且我对目前找到的解决方案并不满意 我倾向于这里找到的正则表达式解决方案 h
  • 如何选择一个CSS使用最深的类?

    如何选择一个css类的使用最深 下面的列表中 如何选择使用最深的类 active 在这种情况下是 li 包裹 span Item 1 1 1 1 span ul li class active span Item 1 span ul li
  • angularjs:在 ng-switch 中更改控制器的父范围

    因此 我可以从子控制器更改模型值 但是当子控制器处于ng switch然后就不行了 为什么呢 我创建一个例子 http plnkr co edit R7D8Xa1HBmYnwffbHQGD p preview来展示它 避免这种情况的一种方法
  • 如何传递动态参数 Airflow 运算符?

    我正在使用 Airflow 在 Google Cloud Composer 上运行 Spark 作业 我需要 创建集群 用户提供的YAML参数 Spark 作业列表 作业参数也由每个作业 YAML 提供 借助 Airflow API 我可以
  • gcc 自动矢量化(未处理的数据引用)

    我不明白为什么这样的代码没有用 gcc 4 4 6 进行矢量化 int MyFunc const float pfTab float pfResult int iSize int iIndex for int i 0 i lt iSize