Skip to content

Commit 7d6f713

Browse files
jgu222igcbot
authored andcommitted
Fix non-deterministic code generation
std::map with ptr as key has non-deterministic order of iterating its members as ptr would be different from run to run. This non- deterministic order causes visa to generate different code. This PR fixes it by sorting map using a fixed value id. With this, it will generate the same order of cvariables for vector alias for the same input function.
1 parent 9deaebf commit 7d6f713

File tree

3 files changed

+61
-7
lines changed

3 files changed

+61
-7
lines changed

IGC/Compiler/CISACodeGen/CShader.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,9 @@ void CShader::CreateAliasVars()
494494
{
495495
// For each vector alias root, generate cvariable
496496
// for it and all its component sub-vector
497-
for (auto& II : m_VRA->m_baseVecMap)
497+
for (auto& II : m_VRA->m_sortedBaseVec)
498498
{
499-
SBaseVecDesc* BV = II.second;
499+
SBaseVecDesc* BV = II;
500500
Value* baseVal = BV->BaseVector;
501501
if (BV->Align != EALIGN_AUTO) {
502502
// Need to set align on root cvar

IGC/Compiler/CISACodeGen/VariableReuseAnalysis.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ bool VariableReuseAnalysis::runOnFunction(Function& F)
184184

185185
postProcessing();
186186

187+
sortAliasResult();
188+
187189
if (IGC_IS_FLAG_ENABLED(DumpVariableAlias))
188190
{
189191
auto name =
@@ -751,6 +753,55 @@ void VariableReuseAnalysis::printAlias(raw_ostream& OS, const Function* F) const
751753
OS << "\n";
752754
}
753755

756+
// Sort the final aliase info (baseVecmap) so that its order is deterministic.
757+
// CreateAliasVars() relies on this to generate cvariables in order.
758+
// (todo: use vector instead of map in the algorithm to avoid sorting.)
759+
void VariableReuseAnalysis::sortAliasResult()
760+
{
761+
if (m_baseVecMap.empty()) {
762+
return;
763+
}
764+
765+
Function* F = m_F;
766+
// Assign each inst/arg a unique integer so that the output
767+
// would be in order. It is useful when doing comparison.
768+
DenseMap<const Value*, int> Val2IntMap;
769+
int id = 0;
770+
if (F) {
771+
// All arguments
772+
for (auto AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) {
773+
const Value* aVal = AI;
774+
Val2IntMap[aVal] = (++id);
775+
}
776+
// All instructions
777+
for (auto II = inst_begin(F), IE = inst_end(F); II != IE; ++II) {
778+
const Instruction* Inst = &*II;
779+
Val2IntMap[(Value*)Inst] = (++id);
780+
}
781+
}
782+
783+
auto SubVecCmp = [&](const SSubVecDesc* SV0, const SSubVecDesc* SV1) {
784+
int n0 = Val2IntMap[SV0->Aliaser];
785+
int n1 = Val2IntMap[SV1->Aliaser];
786+
return n0 < n1;
787+
};
788+
789+
auto BaseVecCmp = [&](const SBaseVecDesc* BV0, const SBaseVecDesc* BV1) {
790+
int n0 = Val2IntMap[BV0->BaseVector];
791+
int n1 = Val2IntMap[BV1->BaseVector];
792+
return n0 < n1;
793+
};
794+
795+
796+
m_sortedBaseVec.clear();
797+
for (auto& MI : m_baseVecMap) {
798+
SBaseVecDesc* BV = MI.second;
799+
std::sort(BV->Aliasers.begin(), BV->Aliasers.end(), SubVecCmp);
800+
m_sortedBaseVec.push_back(BV);
801+
}
802+
std::sort(m_sortedBaseVec.begin(), m_sortedBaseVec.end(), BaseVecCmp);
803+
}
804+
754805
void VariableReuseAnalysis::dumpAlias() const
755806
{
756807
printAlias(dbgs(), m_F);

IGC/Compiler/CISACodeGen/VariableReuseAnalysis.hpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ SPDX-License-Identifier: MIT
2727
#include "common/LLVMWarningsPop.hpp"
2828
#include "Compiler/CISACodeGen/RegisterEstimator.hpp"
2929
#include <list>
30-
#include <map>
30+
#include <unordered_map>
3131
#include <algorithm>
3232
#include "Probe/Assertion.h"
3333

@@ -190,8 +190,8 @@ namespace IGC {
190190
~VariableReuseAnalysis() {}
191191

192192
typedef llvm::SmallVector<SVecInsEltInfo, 32> VecInsEltInfoTy;
193-
typedef std::map<llvm::Value*, SSubVecDesc*> AliasMapTy; // ordered map
194-
typedef std::map<llvm::Value*, SBaseVecDesc*> BaseVecMapTy;
193+
typedef std::unordered_map<llvm::Value*, SSubVecDesc*> AliasMapTy;
194+
typedef std::unordered_map<llvm::Value*, SBaseVecDesc*> BaseVecMapTy;
195195
typedef llvm::SmallVector<llvm::Value*, 32> ValueVectorTy;
196196
typedef llvm::DenseMap<llvm::Value*, llvm::Value*> Val2ValMapTy;
197197

@@ -324,11 +324,11 @@ namespace IGC {
324324
// subAlias(v, 2, 2) = {s2, s3, v} // only s2&s3 overlaps V[2:3]
325325
// dessaCC(s0) = { values in the same dessa CC }
326326
//
327-
// [todo] add Algo here.
328-
//
329327
AliasMapTy m_aliasMap;
330328
BaseVecMapTy m_baseVecMap;
331329

330+
// sorted m_baseVecMap for creating cvar in derministic order
331+
llvm::SmallVector<SBaseVecDesc*, 16> m_sortedBaseVec;
332332

333333
// Function argument cannot be made a sub-part of another bigger
334334
// value as it has been assigned a fixed physical GRF. The following
@@ -380,6 +380,7 @@ namespace IGC {
380380
m_IsBlockPressureLow = Status::Undef;
381381
m_aliasMap.clear();
382382
m_baseVecMap.clear();
383+
m_sortedBaseVec.clear();
383384
m_root2AliasMap.clear();
384385
m_HasBecomeNoopInsts.clear();
385386
m_LifetimeAt1stDefOfBB.clear();
@@ -412,6 +413,8 @@ namespace IGC {
412413
BlockCoalescing* theBC);
413414
void postProcessing();
414415

416+
void sortAliasResult();
417+
415418
// Return true if this instruction can be converted to an alias
416419
bool canBeAlias(llvm::CastInst* I);
417420

0 commit comments

Comments
 (0)