Skip to content

Implement analysis of variable array bounds #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

yukatan1701
Copy link
Contributor

No description provided.

Comment on lines 410 to 416
void removeCollapsed() {
MemorySet Dest;
for (auto &Loc : *this)
if (MemoryInfo::getNumDims(Loc) == 0)
Dest.insert(Loc);
*this = std::move(Dest);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так не получится, можно неконсервативно что-то удалить. Вероятно это и происходит при анализе живых переменных. Например, если это было множество Use, то фактически здесь удаляются какие-то использования. Их надо не удалять, а заменять на более широкий участок памяти, к пример, если это был элемент массива, то должен остаться весь массив. Аналогично для MayDef. Для Def должно быть несколько иначе, если что-то определялось, то участок памяти большего объема должен стать MayDef.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Правильно ли я понимаю, что для анализа живых переменных надо сделать нечто похожее на то, что было в DefinedMemory.cpp в collapse(), где в Def, MayDef и Use добавлялись Loc из ExplicitAccesses (им еще назначался тип Hint)? Тогда участки, которые имеют тип Collapsed, можно будет удалить, потому что их оригинальные версии уже попали в нужные множества.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вопрос не актуален, сделала я в итоге по-другому.

@yukatan1701
Copy link
Contributor Author

Текущие проблемы:

  1. По неизвестным причинам падают все тесты для PassClangLooopInterchange.
  2. Рассмотрим следующий пример:
for (int i = 0; i < N; ++i)
    A[i] = i;
for (int j = 0; j < N + 5; ++j)
    S += A[j];

Во время выполнения SCEVAddRecExpr::evaluateAtIteration() (строка 442 в DefinedMemory.cpp и дальше) получившееся выражение будет приведено к типу i64. Участки получатся такие:

Outward exposed must define locations:
...
<A[0], 0, 4> [0x5586f70632c0], {{Start: 0, End: (zext i32 (-1 + %N) to i64), Step: 1, DimSize: 0}} (Collapsed)
Outward exposed uses:
<A[0], 0, 4> [0x5586f70632c0], {{Start: 0, End: (zext i32 (4 + %N) to i64), Step: 1, DimSize: 0}} (Collapsed) 

Разность полей End у двух участков не будет иметь тип SCEVConstant, соответственно, невозможно понять, какое из них больше, и вычесть кусок [N, N + 5) из Use. Как нужно привести типы, чтобы всё было вычислимо?

Copy link
Member

@kaniandr kaniandr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Посмотрел часть, не успел посмотреть основные изменения (DefinedMemory.cpp и MemoryLocationRange.cpp), постараюсь за выходные посмотреть.

По вопросам:

  1. На тесты из PassClangLooopInterchange не обращайте внимания, там была ошибка, я исправил пока у себя в локальном репозитории. Пока не стал обновлять master, т.к. у меня локально слишком много неполностью проверенных изменений.
  2. Я делал у себя примерно следующее:
    а. Запомнить последовательность приведений типов.
    в. Если последовательности слева и справа совпадают, то сбросить их и взять внутренние SCEV.
    г. Сделать разность.
    д. Восстановить последовательность приведения типов для разности или может даже можно не восстанавливать, если нужно узнать константность такой разности.

Что-то такого типа, здесь правда нет проверок, что последовательности приведений одинаковые:

      SmallVector<PointerIntPair<Type *, 1, bool>, 1> TypeQueue;
      while (auto Cast{dyn_cast<SCEVCastExpr>(ConstTerm)}) {
        if (isa<SCEVSignExtendExpr>(Cast))
          TypeQueue.emplace_back(Cast->getType(), true);
        else
          TypeQueue.emplace_back(Cast->getType(), false);
        ConstTerm = Cast->getOperand();
      }
      .....
       ConstTerm = SE.getMinusSCEV(ConstTerm, Start);
        for (auto &T : reverse(TypeQueue))
          ConstTerm =
              T.getInt()
                  ? SE.getTruncateOrSignExtend(ConstTerm, T.getPointer())
                  : SE.getTruncateOrZeroExtend(ConstTerm, T.getPointer());

return Start == Other.Start && End == Other.End && Step == Other.Step &&
DimSize == Other.DimSize;
}
inline void print(llvm::raw_ostream &OS, bool IsDebug = false) const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Реализацию лучше перенести в .cpp файл и убрать inline, чтобы в .h избавится от лишних include (ScalarEvolution.h и ScalarEvolutionExpression.h). Вместо заголовков добавить объявления нужных классов, чтобы уменьшит количество зависимостей при компиляции.

Comment on lines 247 to 250
if (CmpLeftStartRightEnd &&
(*CmpLeftStartRightEnd == 0 || *CmpLeftStartRightEnd == 1) ||
CmpRightStartLeftEnd &&
(*CmpRightStartLeftEnd == 0 || *CmpRightStartLeftEnd == 1)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Не должно ли быть проверки на то, что шаги одинаковые?

Не слишком ли сильные ограничения, т.е. объединить можно только если (S - start, E - end):
S1 E1 S2 E2
S2 E2 S1 E1

E - включается в диапазон?
Тогда, наверно, S2 - E1 == Step тоже допустимо? Ведь шаг не может быть разным, тогда объединить нельзя?

А если S1 S2 E1 E2, например, то вроде бы тоже можно проверить, что S2 - S1 положительная константа и E2 - E1 положительная константа и если шаг равен 1, то можно объединить? Или даже шаг может быть не 1, но константной и быть делителем S2 - S1 и E2 - E1, тогда тоже ведь можно объединить.

Или простой случай был выбран с целью упростить вычисления, чтобы повысить производительность?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавила проверку на шаг в новой версии кода.

Такие ограничения необходимы, поскольку мы можем анализировать только те участки памяти с переменными границами, у которых шаг равен 1. Если шаг не будет равен 1, мы не сможем сказать, на каком значении достигается End.

Сейчас проверка на join для неконстантных участков заточена только под очень простой случай -- если два диапазона стыкуются. Более сложное взаимное расположение влечет за собой проверку многих случаев (перечислены в MemoryLocationRange.cpp, структура DimPairKind). Так что да, предлагаю ограничиться только стыкуемыми диапазонами в целях повышения производительности.

@yukatan1701 yukatan1701 force-pushed the private-array-bounds branch from 170367b to 5e734b5 Compare May 1, 2023 11:36
@yukatan1701 yukatan1701 force-pushed the private-array-bounds branch from bcfbdc6 to cbb9af3 Compare May 9, 2023 12:32
@yukatan1701 yukatan1701 force-pushed the private-array-bounds branch from cbb9af3 to 3320c0d Compare May 11, 2023 13:57
@yukatan1701 yukatan1701 force-pushed the private-array-bounds branch from 3320c0d to 072d119 Compare May 13, 2023 11:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants