visual studio自动向量化
/////////////////////////////////////////////////
/*
SSE 和 AVX 每个都有16个寄存器
SSE 有 XMM0 ~ XMM15,是128bit
AVX 有 YMM0 ~ YMM15,是256bit
*/
// vs2015 有自动向量化功能,使用 c/c++->command line->additional options->/Qvec-report:2 可输出向量化结果
// 可自动向量化
void loop1()
{
int a[1024];
int b[1024];
int c[1024];
for (int i = 0; i < 1024; i++)
{
c[i] = a[i] + b[i];
}
}
/*
向量化结果
for (int i = 0; i < 1024; i++)
{
c[i] = a[i] + b[i];
}
vmovdqu ymm0, YMMWORD PTR _b$[ebp+eax]
vpaddd ymm0, ymm0, YMMWORD PTR _a$[ebp+eax]
vmovdqu YMMWORD PTR _c$[ebp+eax], ymm0
vmovdqu ymm0, YMMWORD PTR _a$[ebp+eax+32]
vpaddd ymm0, ymm0, YMMWORD PTR _b$[ebp+eax+32]
vmovdqu YMMWORD PTR _c$[ebp+eax+32], ymm0
add eax, 64 ; 00000040H
cmp eax, 4096 ; 00001000H
jl SHORT $LL4@main
*/
// 不可自动向量化(1301)
// 循环步长必须严格为1
void loop2()
{
int a[1024];
int b[1024];
int c[1024];
for (int i = 0; i < 1024; i += 4)
{
c[i] = a[i] + b[i];
c[i + 1] = a[i + 1] + b[i + 1];
c[i + 2] = a[i + 2] + b[i + 2];
c[i + 3] = a[i + 3] + b[i + 3];
}
}
/*
汇编结果
c[i] = a[i] + b[i];
mov ecx, DWORD PTR _b$[ebp+eax]
add DWORD PTR _a$[ebp+eax], ecx
c[i + 1] = a[i + 1] + b[i + 1];
mov ecx, DWORD PTR _a$[ebp+eax+4]
add DWORD PTR _b$[ebp+eax+4], ecx
c[i + 2] = a[i + 2] + b[i + 2];
mov ecx, DWORD PTR _a$[ebp+eax+8]
add DWORD PTR _b$[ebp+eax+8], ecx
c[i + 3] = a[i + 3] + b[i + 3];
mov ecx, DWORD PTR _a$[ebp+eax+12]
add DWORD PTR _b$[ebp+eax+12], ecx
*/
// 不可自动向量化(1203),循环体内包含了非连续内存访问
// 将数组 x[128 * 3] 拆分为 b[128], g[128], r[128] 可实现自动向量化,见 loop4
void loop3()
{
// 该函数实现了 y=Ax 运算,x,y为3*1向量,A为3*3矩阵
// 这是图像处理基本操作,如图像变换,RGB调节等
int x[128 * 3];
int y[128 * 3];
int A[9];
for (int i = 0; i < 128; ++i)
{
y[i * 3 + 0] = x[i * 3 + 0] * A[0] + x[i * 3 + 1] * A[1] + x[i * 3 + 2] * A[2];
y[i * 3 + 1] = x[i * 3 + 0] * A[3] + x[i * 3 + 1] * A[4] + x[i * 3 + 2] * A[5];
y[i * 3 + 2] = x[i * 3 + 0] * A[6] + x[i * 3 + 1] * A[6] + x[i * 3 + 2] * A[6];
}
}
/*
汇编结果
y[i * 3 + 0] = x[i * 3 + 0] * A[0] + x[i * 3 + 1] * A[1] + x[i * 3 + 2] * A[2];
mov edi, DWORD PTR _x$[ebp+eax+4]
mov ecx, edi
imul ecx, DWORD PTR _A$[ebp+4]
mov esi, DWORD PTR _x$[ebp+eax]
mov edx, esi
imul edx, DWORD PTR _A$[ebp]
mov ebx, DWORD PTR _x$[ebp+eax+8]
add edx, ecx
mov ecx, ebx
imul ecx, DWORD PTR _A$[ebp+8]
add edx, ecx
y[i * 3 + 1] = x[i * 3 + 0] * A[3] + x[i * 3 + 1] * A[4] + x[i * 3 + 2] * A[5];
mov ecx, edi
imul ecx, DWORD PTR _A$[ebp+16]
mov DWORD PTR _y$[ebp+eax], edx
mov edx, esi
imul edx, DWORD PTR _A$[ebp+12]
add edx, ecx
mov ecx, ebx
imul ecx, DWORD PTR _A$[ebp+20]
add edx, ecx
y[i * 3 + 2] = x[i * 3 + 0] * A[6] + x[i * 3 + 1] * A[6] + x[i * 3 + 2] * A[6];
lea ecx, DWORD PTR [esi+edi]
add ecx, ebx
mov DWORD PTR _y$[ebp+eax+4], edx
imul ecx, DWORD PTR _A$[ebp+24]
mov DWORD PTR _y$[ebp+eax+8], ecx
add eax, 12 ; 0000000cH
cmp eax, 1536 ; 00000600H
jl SHORT $LL4@loop3
*/
// 可自动向量化
// loop4_ don't need more space to split image data, and memory consitstent is better
void loop4()
{
int b[128], g[128], r[128];
int A[9];
for (int i = 0; i < 128; ++i)
{
int _b = b[i] * A[0] + g[i] * A[1] + r[i] * A[2];
int _g = b[i] * A[3] + g[i] * A[4] + r[i] * A[5];
int _r = b[i] * A[6] + g[i] * A[7] + r[i] * A[8];
b[i] = _b;
g[i] = _g;
r[i] = _r;
}
}
// better than loop4
void loop4_()
{
int bgr[128 * 3];
int b[8];
int g[8];
int r[8];
int A[9];
for (int i = 0; i < 128 / 8; ++i)
{
// split data
int start = i * 8 * 3;
for (int j = 0; j < 8; ++j)
{
b[j] = bgr[start + j * 3];
g[j] = bgr[start + j * 3 + 1];
r[j] = bgr[start + j * 3 + 2];
}
// adjust
for (int j = 0; j < 8; ++j)
{
int _b = b[j] * A[0] + g[j] * A[1] + r[j] * A[2];
int _g = b[j] * A[3] + g[j] * A[4] + r[j] * A[5];
int _r = b[j] * A[6] + g[j] * A[7] + r[j] * A[8];
b[j] = _b;
g[j] = _g;
r[j] = _r;
}
// merge data
for (int j = 0; j < 8; ++j)
{
bgr[start + j * 3] = b[j];
bgr[start + j * 3 + 1] = g[j];
bgr[start + j * 3 + 2] = r[j];
}
}
}
/*
向量化结果
vpbroadcastd ymm1, DWORD PTR _A$[ebp]
vpbroadcastd ymm6, DWORD PTR _A$[ebp+8]
vpbroadcastd ymm7, DWORD PTR _A$[ebp+4]
vmovdqu YMMWORD PTR tv886[ebp], ymm1
vpbroadcastd ymm0, DWORD PTR _A$[ebp+20]
vmovdqu YMMWORD PTR tv881[ebp], ymm0
vpbroadcastd ymm0, DWORD PTR _A$[ebp+16]
vmovdqu YMMWORD PTR tv882[ebp], ymm0
vpbroadcastd ymm0, DWORD PTR _A$[ebp+12]
vmovdqu YMMWORD PTR tv883[ebp], ymm0
vpbroadcastd ymm0, DWORD PTR _A$[ebp+32]
vmovdqu YMMWORD PTR tv878[ebp], ymm0
vpbroadcastd ymm0, DWORD PTR _A$[ebp+28]
vmovdqu YMMWORD PTR tv879[ebp], ymm0
vpbroadcastd ymm0, DWORD PTR _A$[ebp+24]
vmovdqu YMMWORD PTR tv880[ebp], ymm0
xor eax, eax
npad 2
$LL4@loop3_:
vmovdqu ymm3, YMMWORD PTR _b$[ebp+eax]
vmovdqu ymm4, YMMWORD PTR _g$[ebp+eax]
vmovdqu ymm5, YMMWORD PTR _r$[ebp+eax]
vpmulld ymm2, ymm3, ymm1
vpmulld ymm1, ymm4, ymm7
vpmulld ymm0, ymm5, ymm6
vpaddd ymm0, ymm0, ymm1
vpmulld ymm1, ymm4, YMMWORD PTR tv882[ebp]
vpaddd ymm0, ymm0, ymm2
vpmulld ymm2, ymm3, YMMWORD PTR tv883[ebp]
vmovdqu YMMWORD PTR __b$[ebp+eax], ymm0
vpmulld ymm0, ymm5, YMMWORD PTR tv881[ebp]
vpaddd ymm0, ymm0, ymm1
vpmulld ymm1, ymm4, YMMWORD PTR tv879[ebp]
vmovdqu ymm4, YMMWORD PTR _g$[ebp+eax+32]
vpaddd ymm0, ymm0, ymm2
vpmulld ymm2, ymm3, YMMWORD PTR tv880[ebp]
vmovdqu ymm3, YMMWORD PTR _b$[ebp+eax+32]
vmovdqu YMMWORD PTR __g$[ebp+eax], ymm0
vpmulld ymm0, ymm5, YMMWORD PTR tv878[ebp]
vmovdqu ymm5, YMMWORD PTR _r$[ebp+eax+32]
vpaddd ymm0, ymm0, ymm1
vpaddd ymm0, ymm0, ymm2
vpmulld ymm2, ymm3, YMMWORD PTR tv886[ebp]
vmovdqu YMMWORD PTR __r$[ebp+eax], ymm0
vpmulld ymm1, ymm4, ymm7
vpmulld ymm0, ymm5, ymm6
vpaddd ymm0, ymm0, ymm1
vpmulld ymm1, ymm4, YMMWORD PTR tv882[ebp]
vpaddd ymm0, ymm0, ymm2
vpmulld ymm2, ymm3, YMMWORD PTR tv883[ebp]
vmovdqu YMMWORD PTR __b$[ebp+eax+32], ymm0
vpmulld ymm0, ymm5, YMMWORD PTR tv881[ebp]
vpaddd ymm0, ymm0, ymm1
vpmulld ymm1, ymm4, YMMWORD PTR tv879[ebp]
vpaddd ymm0, ymm0, ymm2
vpmulld ymm2, ymm3, YMMWORD PTR tv880[ebp]
vmovdqu YMMWORD PTR __g$[ebp+eax+32], ymm0
vpmulld ymm0, ymm5, YMMWORD PTR tv878[ebp]
vpaddd ymm0, ymm0, ymm1
vmovdqu ymm1, YMMWORD PTR tv886[ebp]
vpaddd ymm0, ymm0, ymm2
vmovdqu YMMWORD PTR __r$[ebp+eax+32], ymm0
add eax, 64 ; 00000040H
cmp eax, 512 ; 00000200H
jl $LL4@loop3_
*/
// 内层for循环期望向量化,VS编译器没有自动向量化(1505)
// 内层循环中使用变量i使得编译器无法优化,loop6使用step使内层循环可优化
void loop5()
{
int *x = new int[1024 * 1024];
int *y = new int[1024 * 1024];
int *z = new int[1024 * 1024];
for (int i = 0; i < 1024; ++i)
{
for (int j = 0; j < 1024; ++j)
{
z[i * 1024 + j] = x[i * 1024 + j] + y[i * 1024 + j];
}
}
delete[]x;
delete[]y;
delete[]z;
}
// 内层for循环自动向量化
void loop6()
{
int *x = new int[1024 * 1024];
int *y = new int[1024 * 1024];
int *z = new int[1024 * 1024];
for (int i = 0; i < 1024; ++i)
{
int step = i * 1024;
for (int j = 0; j < 1024; ++j)
{
z[step + j] = x[step + j] + y[step + j];
}
}
delete []x;
delete []y;
delete []z;
}
// vs编译器提示循环体内包含较少计算,当加入更多计算时提示循环体内包含了非连续内存访问(1203)
// 通过展开内层循环可以实现优化操作,见loop8
// 该函数模拟图像相加操作
void loop7()
{
int *x = new int[1024 * 1024 * 3];
int *y = new int[1024 * 1024 * 3];
int *z = new int[1024 * 1024 * 3];
for (int i = 0; i < 1024; ++i)
{
int step = i * 1024 * 3;
for (int j = 0; j < 1024; ++j)
{
z[step + j * 3 ] = x[step + j * 3 ] + y[step + j * 3 ];
z[step + j * 3 + 1] = x[step + j * 3 + 1] + y[step + j * 3 + 1];
z[step + j * 3 + 2] = x[step + j * 3 + 2] + y[step + j * 3 + 2];
}
}
delete[]x;
delete[]y;
delete[]z;
}
// 可自动向量化化
void loop8()
{
unsigned char *x = new unsigned char[1024 * 1024 * 3];
unsigned char *y = new unsigned char[1024 * 1024 * 3];
unsigned char *z = new unsigned char[1024 * 1024 * 3];
for (int i = 0; i < 1024; ++i)
{
int step = i * 1024 * 3;
for (int j = 0; j < 1024 * 3; ++j)
{
z[step + j] = x[step + j] + y[step + j];
}
}
delete[]x;
delete[]y;
delete[]z;
}
/////////////////////////////////////////////////
visual studio自动向量化的更多相关文章
- [WinForm] - "更新 DataSet 应用程序集对象失败,Visual Studio 自动重启" 之解决
背景 在 WinForm 解决方案中,更新 DataSet 应用程序集对象失败,Visual Studio 自动重启. 试一试 1. 更新 .xsd 时打开对应的 .Designer.cs.2. 如果 ...
- Visual Studio自动添加头部注释 -C#开发2010-2013验证
在团队开发中,头部注释是必不可少的.但在开发每次新建一个类都要复制一个注释模块也很不爽,所以得想个办法让开发工具自动生成我们所需要的模板.....操作方法如下: 找你的vs安装目录, 比如我的是在D盘 ...
- Visual Studio自动添加头部注释
VS2013 自动添加头部注释 1.找到VS2013的安装目录 下文以安装目录 C:\Program Files (x86)\Microsoft Visual Studio 12.0 为例 2.修改C ...
- Visual Studio自动生成XML类和JSON类
Visual Studio 2013及以上版本提供了一个非常实用的功能.可以根据xml文档或json文档自动生成类.有了这个工具反序列化时就不用再手动写类并且实现了强类型操作. 步骤 1. 准备一份j ...
- 让Visual Studio 自动添加头部注释信息
在日常的开发过程中我们经常需要为我们的类文件添加注释和版权等信息,以前都是将信息文本复制.粘贴,要是添加一两个个还好,要是添加很多就显得很麻烦了.为了减少这种重复性的工作,有没有好的解决办法呢?答案是 ...
- Visual Studio自动生成文件版本信息
一. 前言 通常,要控制输出文件的版本信息,只需要手动修改资源rc文件中的Version,即可在输出文件的文件属性里查看到对应的版本信息.如下图: 但是,版本号是会随时都更新的,每次bu ...
- visual studio自动导入 using 的快捷键
快捷键是 shift + alt + f10 ,从 vs 2012开始 还增加了 ctrl+. 功能名称叫: 视图.显示智能标记
- 其他(一)Visual Studio 自动排版快捷键
自动对齐快捷键为:ctrl+k+d 按快捷键前,请先将需要对齐的代码选中.不选中是不行的.
- Visual Studio自动编译gRPC工程的设置
前段时间研究一个java程序,增加一些功能.其中用到java和C#的通信.自然,有多种办法,后来实际上是用javascript调用C#的REST WCF服务实现的.但是在查资料的过程中,发现有个Pro ...
随机推荐
- linux修改默认的SSH远程端口22
1.编辑sshd_config文件 [root@localhost ~]# vim /etc/ssh/sshd_config 搜索 #Port 22行,删除开头的 # 字符,然后将其替换为要使用的端 ...
- 利用 Maven 创建 Docker 镜像并且推送到私有注册中心
利用 Maven 命令生成项目框架 mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -Darchetype ...
- vert.x框架-简单路由使用
package xue.myVertX; import io.vertx.core.AbstractVerticle; import io.vertx.core.Vertx; import io.ve ...
- vue js格式化数字为金额格式
/** * @description 格式化金额 * @param number:要格式化的数字 * @param decimals:保留几位小数 默认0位 * @param decPoint:小数点 ...
- 使用Swing的GUI编程
Swing AWT概述 AWT:抽象窗口工具包,提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具 Swing以AWT为基础的,尽管Swing消除了 ...
- 不会一致性hash算法,劝你简历别写搞过负载均衡
大家好,我是小富~ 个人公众号:程序员内点事,欢迎学习交流 这两天看到技术群里,有小伙伴在讨论一致性hash算法的问题,正愁没啥写的题目就来了,那就简单介绍下它的原理.下边我们以分布式缓存中经典场景举 ...
- MCU软件最佳实践——矩阵键盘驱动
1.矩阵键盘vs独立按键 在mcu应用开发过程中,独立按键比较常见,但是在需要的按键数比较多时,使用矩阵键盘则可以减少io占用,提高系统资源利用率.例如,某mcu项目要求有16个按钮,如果采用独立按键 ...
- 解决twrp中内部存储为0MB的情况
本来打算给备用机红米4a刷个dotos的系统,结果忘记双清就刷了,然后进去系统也是直接黑屏,很神奇的是长按电源键能弹出dotos的关机选项.然后进去twrp准备双清在刷时,发现内部存储变成了0MB,然 ...
- 微服务架构 | *3.5 Nacos 服务注册与发现的源码分析
目录 前言 1. 客户端注册进 Nacos 注册中心(客户端视角) 1.1 Spring Cloud 提供的规范标准 1.2 Nacos 的自动配置类 1.3 监听服务初始化事件 AbstractAu ...
- 使用Outlook欺骗性云附件进行网络钓鱼
滥用Microsoft365 Outlook 云附件的方式发送恶意文件,使恶意可执行云附件规避云查杀检测 介绍 在本文中,我们将探讨如何滥用 O365 上的云附件功能使可执行文件(或任何其他文件类型) ...