Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

[Attributor?] Smart noalias deduction #43633

Open Quuxplusone opened 4 years ago

Quuxplusone commented 4 years ago
Bugzilla Link PR44663
Status NEW
Importance P enhancement
Reported by Roman Lebedev (lebedev.ri@gmail.com)
Reported on 2020-01-25 10:56:48 -0800
Last modified on 2020-01-25 17:17:17 -0800
Version trunk
Hardware PC Linux
CC florian_hahn@apple.com, johannes@jdoerfert.de, llvm-bugs@lists.llvm.org, pankajgode@gmail.com, sstipanovic@s-energize.com, uenoku.tokotoko@gmail.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also PR44662

In this example sink() is static, we know all it's call sites.

We should be able to tell in all the call sites, it's third argument (highpass.data) does not alias with any other pointers used in sink() (namely highhigh.data and lowhigh.data), because we should be able to see how highpass.data is being set to a fresh noalias pointer.

https://godbolt.org/z/32edkj

include // for assert

include

include // for vector

include // for vector

include // for vector

template class Array2DRef { int _pitch = 0; T* _data = nullptr;

friend Array2DRef; // We need to be able to convert to const version.

inline T& operator[](int row) const;

public: using value_type = T; using cvless_value_type = typename std::remove_cv::type;

int width = 0, height = 0;

Array2DRef() = default;

Array2DRef(T* data, int dataWidth, int dataHeight, int dataPitch = 0);

// Conversion from Array2DRef to Array2DRef. template <class T2, typename = std::enable_if_t<std::is_same< typename std::remove_const::type, T2>::value>> Array2DRef(Array2DRef RHS) { // NOLINT google-explicit-constructor _data = RHS._data; _pitch = RHS._pitch; width = RHS.width; height = RHS.height; }

template <typename AllocatorType = typename std::vector::allocator_type> static Array2DRef create(std::vector<cvless_value_type, AllocatorType> storage, int width, int height) { storage->resize(width height); return {storage->data(), width, height}; }

inline T& operator()(int row, int col) const; };

template Array2DRef::Array2DRef(T data, const int dataWidth, const int dataHeight, const int dataPitch / = 0 */) : _data(data), width(dataWidth), height(dataHeight) { assert(width >= 0); assert(height >= 0); _pitch = (dataPitch == 0 ? dataWidth : dataPitch); }

template T& Array2DRef::operator[](const int row) const { assert(_data); assert(row >= 0); assert(row < height); return _data[row * _pitch]; }

template T& Array2DRef::operator()(const int row, const int col) const { assert(col >= 0); assert(col < width); return (&(operator))[col]; }

static attribute((noinline)) void sink(const Array2DRef highhigh, const Array2DRef lowhigh, Array2DRef highpass) { for(int row = 0; row < highpass.height; ++row) { for(int col = 0; col < highpass.width; ++col) { // highpass does not alias highhigh/lowhigh ! // this should nicely vectorize. highpass(row, col) = 24 highhigh(row, col) + 18 lowhigh (row, col); } } }

void foo(int width, int height, const Array2DRef highhigh, const Array2DRef lowhigh, std::vector& highpass_storage) { Array2DRef highpass = Array2DRef::create(&highpass_storage, width, height); sink(highhigh, lowhigh, highpass); }

Quuxplusone commented 4 years ago
More reduced example: https://godbolt.org/z/GKerhj

int size;

struct Array2DRef {
  int* data;
};

static __attribute__((noinline)) void
sink(const Array2DRef highhigh, const Array2DRef lowhigh, Array2DRef highpass) {
    for(int row = 0; row < size; ++row) {
        // highpass does not alias highhigh/lowhigh !
        // this should nicely vectorize.
        highpass.data[row] = 24 * highhigh.data[row] + 18 * lowhigh.data[row];
    }
}

void foo(const Array2DRef highhigh,
         const Array2DRef lowhigh,
        int* highpass_storage) {
    highpass_storage = new int[size];
    Array2DRef highpass;
    highpass.data = highpass_storage;
    sink(highhigh, lowhigh, highpass);
}