首页 > 解决方案 > 编译器优化忽略循环中的非无效函数调用

问题描述

我正在对一些代码进行基准测试,但是当我设置优化标志时,编译器bh_b = bh_b + bh_a + bh_a + bh_a + bh_a;会在循环中忽略我的函数调用()。当我删除优化标志时,代码工作正常。

我使用表达式模板编写了我的 Matrix 类

很抱歉最后一篇文章不可复制。

代码

#include <iostream>
#include <chrono>
#include "matrix.h"

int main(){
    int calc_num = 100000;
    
    Matx<double, 3, 3> bh_a(1, 0, 0,
                            0, 1, 0,
                            0, 0, 1);
    Matx<double, 3, 3> bh_b(0, 0, 0, 0, 0, 0, 0, 0, 0);
    
    auto t_begin = std::chrono::high_resolution_clock::now();
    for(int i=0; i<calc_num; ++i)
        bh_b = bh_b + bh_a + bh_a + bh_a + bh_a;  // this part
    auto t_end = std::chrono::high_resolution_clock::now();
    
    std::cout << "Elapsed: " << std::chrono::duration_cast<std::chrono::microseconds>(t_end - t_begin).count() << "us" << std::endl;
    
    for(int i=0; i<bh_b.cols; ++i) {
        for (int j = 0; j < bh_b.cols; ++j)
            std::cout << bh_b(i * bh_b.cols + j) << ' ';
        std::cout << std::endl;
    }
    
    return 0;
}
#ifndef UNTITLED3_MATRIX_H
#define UNTITLED3_MATRIX_H

template <typename T, typename E>
class MatExpr{
public:
    const T& operator () (int i) const { return static_cast<E const&>(*this)(i); }
};

template<typename T, int m, int n>
class Matx : public MatExpr<T, Matx<T, m, n>> {
public:
    enum {
        rows     = m,
        cols     = n,
        channels = rows*cols,
        shortdim = (m < n ? m : n)
    };
    
    Matx(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8) : val{v0, v1, v2, v3, v4, v5, v6, v7, v8} {}
    
    template <typename E>
    Matx(MatExpr<T, E> const& expr){
        for(int i=0; i<channels; ++i) val[i] = expr(i);
    }
    
    const T& operator () (int i) const { return val[i]; }
    
    T val[m*n];
};

template <typename T, typename E1, typename E2>
class MatOp : public MatExpr<T, MatOp<T, E1, E2>> {
private:
    E1 const& u;
    E2 const& v;

public:
    MatOp(E1 const& u, E2 const& v) : u(u), v(v) {}
    
    const T& operator () (int i) const { return u(i) + v(i); }
};

template <typename T, typename E1, typename E2>
MatOp<T, E1, E2>
operator + (MatExpr<T, E1> const& u, MatExpr<T, E2> const& v){
    return MatOp<T, E1, E2>(*static_cast<const E1*>(&u), *static_cast<const E2*>(&v));
}


#endif //UNTITLED3_MATRIX_H
cmake_minimum_required(VERSION 3.15)
project(untitled3)

set(CMAKE_CXX_STANDARD 14)

add_executable(untitled3 main.cpp)

# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2" ) // Compiler optimization flag

输出

Elapsed: 32308us
400000 0 0 
0 400000 0 
0 0 400000 
Elapsed: 16268us
0 0 0 
0 0 0 
0 0 0 
Elapsed: 1us
0 0 0 
0 0 0 
0 0 0 

编译器

➜  ~ clang --version
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.4.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

标签: c++optimizationclang

解决方案


代码包含未定义的行为。

在这条线上

const T& operator () (int i) const { return u(i) + v(i); }

您正在返回一个临时地址(因为operator +会产生一个临时地址)。

同样在这里

const T& operator () (int i) const { return static_cast<E const&>(*this)(i); }

如果它调用上述方法,也可以产生一个临时的。

一个可能的解决方法是按值返回它(不知道这是否是正确的选择)。


推荐阅读