
在Visual Studio 2019预览版2中,我们继续通过新功能,新的和改进的优化,改进的生产能力以及生活质量的变化来改进C ++后端。
原始博客新功能
- 添加了新的内联命令行开关:-Ob3。 -Ob3是-Ob2的更积极的版本。 -O2(针对速度优化二进制文件)在默认情况下仍表示-Ob2,但将来可能会有所变化。 如果发现编译器内联不足,请考虑传递-O2 -Ob3。
- 添加了对OpenMP SIMD矢量化的基本支持,这是机器学习(ML)库中使用最广泛的OpenMP功能。 我们的案例研究是Intel MKL-DNN库,该库用作其他著名的开源ML库(包括Tensor Flow)的构建块。 可以使用新的CL开关-openmp:实验性将其打开。 这允许注释为“ #pragma omp simd”的循环。 无法保证向量化,已注释但未向量化的循环将报告警告。 不支持SIMD子句,将简单地忽略它们并报告警告。
- 添加了新的C ++异常处理程序__CxxFrameHandler4,可将异常处理元数据的开销减少66%。 对于使用大量C ++异常处理的二进制文件,这可以将二进制文件的总大小最多提高15%。 当前默认关闭,使用cl.exe编译时通过传递“ / d2FH4”来进行尝试。 请注意,否则/ d2FH4长期未记录,不受支持。 UWP应用程序当前不支持此功能,因为UWP运行时尚不具有此功能。
- 为了支持包含对数学库函数和某些其他运算(如整数除法)的调用的循环的手动矢量化,MSVC现在支持计算矢量等效项的短向量数学库(SVML)内在函数。 大多数功能都支持128位,256位和512位向量,以下列出了例外。 请注意,这些功能不会设置errno。 有关支持的功能的定义,请参阅《英特尔内部指南》。
例外包括:
- 向量整数组合除法和余数仅适用于32位元素以及128位和256位向量长度。 对其他元素大小和向量长度使用单独的除法和余数函数。
- SVML平方根仅在128位和256位向量长度中可用。 您可以将_mm512_sqrt_pd或_mm512_sqrt_ps函数用于512位向量。
- Rint和Nearestint函数仅提供512位向量版本。 在许多情况下,您可以改用舍入函数,例如,将_mm256_round_ps(x,_MM_FROUND_CUR_DIRECTION)用作rint的256位矢量版本,或将_mm256_round_ps(x,_MM_FROUND_TO_NEAREST_INT)用作nearint 。
- 仅提供512位倒数。 您可以使用set1和div函数来计算等效项,例如256位倒数可以计算为_mm256_div_ps(_mm256_set1_ps(1.0f),(x)) 。
- 仅在128位和256位向量长度中,才有SVML函数用于单精度复数平方根,对数和幂运算。
新的和改进的优化
- 现在,展开的内存集和块初始化将使用SSE2指令(或AVX指令(如果允许))。 展开内容的大小阈值相应增加(使用SSE2进行大小编译:展开阈值从31字节移动到63字节,使用SSE2进行速度编译:阈值从79字节移动到159字节)。
- 针对小型内存集优化了代码生成,主要针对受initall保护的功能。
- SSA优化器消除冗余存储的改进:更好的转义分析和循环处理
- 编译器将memmove()识别为内部函数,并进行相应的优化。 这可以改善基于memmove()构建的操作的代码生成,包括std :: copy()以及其他更高级别的库代码,例如std :: vector和std ::字符串构造
- 优化器在优化短,固定长度的memmove(),memcpy()和memcmp()操作方面做得更好。
- 实施了交换机复制优化,以提高热循环内交换机的性能。 我们复制了开关跳转,以帮助提高分支预测的准确性,从而提高运行时性能。
- 对于浮点和整数形式,使用SIMD(向量)本征为表达式添加了常量折叠和算术简化。 现在,大多数常用的表达式优化都可以通过用户代码或自动向量化的结果来处理SSE2和AVX2内部函数。
- 几个新的标量融合乘加(FMA)模式用/ arch:AVX2 / fp:快速标识。 这些包括以下常用表达式:
(x + 1.0) * y; (x – 1.0) * y; (1.0 – x) * y; (-1.0 – x) * y
(x + 1.0) * y; (x – 1.0) * y; (1.0 – x) * y; (-1.0 – x) * y
- 逐个元素标识初始化__m128 SIMD(矢量)值的代码序列,并用_mm_set_ps内在函数替换。 这使新的SIMD优化可以将值视为表达式的一部分,特别在值仅包含常量元素的情况下很有用。 将来的更新将支持更多的值类型。
- 在存在可以通过间接方式修改的变量的情况下,通用子表达式消除(CSE)更为有效,因为它们具有地址。
- 在其他几种情况下,将删除无用的struct /类副本,包括输出参数的副本和返回对象的函数。 这种优化在按值传递对象的C ++程序中特别有效。
- 添加了更强大的分析功能,用于从控制流中提取有关变量的信息(如果/ else / switch语句),该分析用于删除可以证明总是正确或错误的分支,并改善变量范围估计。 使用gsl :: span的代码可以看到改进,现在删除了一些不必要的范围检查。
- 现在,非虚拟化优化将有更多机会,例如在匿名名称空间中定义类时。
建立吞吐量改进
- 在编译期间根据引用的符号和类型过滤调试信息,以减小调试节的大小并提高链接程序的吞吐量。 从15.9更新到16.0可使链接器的输入大小最多减少40%。
- 改进了PDB类型合并和创建中的链接时间。
- 从15.9升级到16.0可以将链接时间缩短2倍。 例如,使用/ DEBUG:full链接Chrome可以使链接时间加速1.75倍,使用/ DEBUG:fastlink链接可以使链接时间加速1.4X。
生活质量改善
- 编译器使用用户提供的大小写形式显示文件名和路径,以前,编译器显示小写的文件名和路径。
- 现在,新的链接器将报告未解析符号的潜在匹配符号,例如:
main.obj : error LNK2019: unresolved external symbol _foo referenced in function _main Hint on symbols that are defined and could potentially match: "int __cdecl foo(int)" (?foo@@YAHH@Z) "bool __cdecl foo(double)" (?foo@@YA_NN@Z) @foo@0 foo@@4 main.exe : fatal error LNK1120: 1 unresolved externals
- 生成静态库时,不再需要将/ LTCG标志传递给LIB.exe。
- 添加了链接器选项/ LINKREPROTARGET:[binary_name],仅为指定的二进制文件生成链接副本。 这允许%LINK_REPRO%或/ LINKREPRO:[directory_name]在具有多个链接的大型版本中设置,并且链接器将仅生成/ linkreprotarget中指定的二进制文件的repro。
我们希望您下载Visual Studio 2019并尝试一下。 一如既往,我们欢迎您的反馈。 可以通过下面的评论或电子邮件( visualcpp@microsoft.com )与我们联系。 如果您在使用Visual Studio或MSVC时遇到问题,或者对我们有建议,请通过帮助>发送反馈>报告问题/在产品中提供建议或通过Developer Community告诉我们。 您还可以在Twitter( @VisualC )和Facebook(msftvisualcpp)上找到我们。