Skip to content

Commit 5cd55b4

Browse files
Artem Gindinsonvmaksimo
authored andcommitted
Fix IVDep translation for accesses to kernel closure fields
When IVDep is applied to a regular kernel-scope array/pointer variable, the GEP instructions that access this variable are marked with index group metadata. When IVDep is applied to a captured argument of a kernel, however, the pointer operand of index group-marked instructions becomes a GEP itself. The latter GEP accesses the closure of a kernel lambda with an offset that signifies the number of the captured parameter in the closure layout. To treat the second case: 1. In forward translation, we ensure that for each memory block, all pointer accesses marked into IVDep index groups are recognized and translated into LoopControl parameters. Previously, only the latest pointer access would get listed in the SPIR-V representation of attribute parameters. 2. In backward translation, we also differentiate between GEP instructions that access an array variable directly and the GEPs accessing the "closure field accesses". An additional map stores 1 index group metadata node per each "pointer to closure + integer offset" pair. This ensures that all accesses to the same kernel parameter are marked into the same index group on a given loop nest level. Signed-off-by: Artem Gindinson <artem.gindinson@intel.com>
1 parent 05b4cda commit 5cd55b4

File tree

4 files changed

+653
-19
lines changed

4 files changed

+653
-19
lines changed

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "VectorComputeUtil.h"
5454

5555
#include "llvm/ADT/DenseMap.h"
56+
#include "llvm/ADT/SmallSet.h"
5657
#include "llvm/Analysis/LoopInfo.h"
5758
#include "llvm/BinaryFormat/Dwarf.h"
5859
#include "llvm/IR/Constants.h"
@@ -803,18 +804,18 @@ void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM,
803804
"Missing loop control parameter!");
804805
}
805806
if (LC & LoopControlDependencyArrayINTELMask) {
806-
// Collect array variable <-> safelen information
807-
std::map<Value *, unsigned> ArraySflnMap;
807+
// Collect pointer variable <-> safelen information
808+
std::map<Value *, unsigned> PointerSflnMap;
808809
unsigned NumOperandPairs = LoopControlParameters[NumParam];
809810
unsigned OperandsEndIndex = NumParam + NumOperandPairs * 2;
810811
assert(OperandsEndIndex <= LoopControlParameters.size() &&
811812
"Missing loop control parameter!");
812813
SPIRVModule *M = LM->getModule();
813814
while (NumParam < OperandsEndIndex) {
814815
SPIRVId ArraySPIRVId = LoopControlParameters[++NumParam];
815-
Value *ArrayVar = ValueMap[M->getValue(ArraySPIRVId)];
816+
Value *PointerVar = ValueMap[M->getValue(ArraySPIRVId)];
816817
unsigned Safelen = LoopControlParameters[++NumParam];
817-
ArraySflnMap.emplace(ArrayVar, Safelen);
818+
PointerSflnMap.emplace(PointerVar, Safelen);
818819
}
819820

820821
// A single run over the loop to retrieve all GetElementPtr instructions
@@ -826,24 +827,54 @@ void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM,
826827
if (!GEP)
827828
continue;
828829

829-
Value *AccessedArray = GEP->getPointerOperand();
830-
auto ArraySflnIt = ArraySflnMap.find(AccessedArray);
831-
if (ArraySflnIt != ArraySflnMap.end())
832-
ArrayGEPMap[AccessedArray].push_back(GEP);
830+
Value *AccessedPointer = GEP->getPointerOperand();
831+
auto PointerSflnIt = PointerSflnMap.find(AccessedPointer);
832+
if (PointerSflnIt != PointerSflnMap.end()) {
833+
ArrayGEPMap[AccessedPointer].push_back(GEP);
834+
}
833835
}
834836
}
835837

836-
// Create index group metadata nodes - one per each array
838+
// Create index group metadata nodes - one per each of the array
837839
// variables. Mark each GEP accessing a particular array variable
838840
// into a corresponding index group
839-
std::map<unsigned, std::vector<MDNode *>> SafelenIdxGroupMap;
841+
std::map<unsigned, SmallSet<MDNode *, 4>> SafelenIdxGroupMap;
842+
// Whenever a kernel closure field access is pointed to instead of
843+
// an array/pointer variable, ensure that all GEPs to that memory
844+
// share the same index group by hashing the newly added index groups.
845+
// "Memory offset info" represents a handle to the whole closure block
846+
// + an integer offset to a particular captured parameter.
847+
using MemoryOffsetInfo = std::pair<Value *, unsigned>;
848+
std::map<MemoryOffsetInfo, MDNode *> OffsetIdxGroupMap;
849+
840850
for (auto &ArrayGEPIt : ArrayGEPMap) {
841-
// Emit a distinct index group that will be referenced from
842-
// llvm.loop.parallel_access_indices metadata
843-
auto *CurrentDepthIdxGroup = llvm::MDNode::getDistinct(*Context, None);
844-
unsigned Safelen = ArraySflnMap.find(ArrayGEPIt.first)->second;
845-
SafelenIdxGroupMap[Safelen].push_back(CurrentDepthIdxGroup);
851+
MDNode *CurrentDepthIdxGroup = nullptr;
852+
if (auto *PrecedingGEP = dyn_cast<GetElementPtrInst>(ArrayGEPIt.first)) {
853+
Value *ClosureFieldPointer = PrecedingGEP->getPointerOperand();
854+
unsigned Offset =
855+
cast<ConstantInt>(PrecedingGEP->getOperand(2))->getZExtValue();
856+
MemoryOffsetInfo Info{ClosureFieldPointer, Offset};
857+
auto OffsetIdxGroupIt = OffsetIdxGroupMap.find(Info);
858+
if (OffsetIdxGroupIt == OffsetIdxGroupMap.end()) {
859+
// This is the first GEP encountered for this closure field.
860+
// Emit a distinct index group that will be referenced from
861+
// llvm.loop.parallel_access_indices metadata; hash the new
862+
// MDNode for future accesses to the same memory.
863+
CurrentDepthIdxGroup = llvm::MDNode::getDistinct(*Context, None);
864+
OffsetIdxGroupMap.emplace(Info, CurrentDepthIdxGroup);
865+
} else {
866+
// Previous accesses to that field have already been indexed,
867+
// just use the already-existing metadata.
868+
CurrentDepthIdxGroup = OffsetIdxGroupIt->second;
869+
}
870+
} else /* Regular kernel-scope array/pointer variable */ {
871+
// Emit a distinct index group that will be referenced from
872+
// llvm.loop.parallel_access_indices metadata
873+
CurrentDepthIdxGroup = llvm::MDNode::getDistinct(*Context, None);
874+
}
846875

876+
unsigned Safelen = PointerSflnMap.find(ArrayGEPIt.first)->second;
877+
SafelenIdxGroupMap[Safelen].insert(CurrentDepthIdxGroup);
847878
for (auto *GEP : ArrayGEPIt.second) {
848879
StringRef IdxGroupMDName("llvm.index.group");
849880
llvm::MDNode *PreviousIdxGroup = GEP->getMetadata(IdxGroupMDName);

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,8 @@ class LLVMParallelAccessIndices {
951951
// survive the translation. This check should be replaced with an
952952
// assertion once all known cases are handled.
953953
if (IdxGroupArrayPairIt != IndexGroupArrayMap.end())
954-
ArrayVariablesVec.push_back(IdxGroupArrayPairIt->second);
954+
for (SPIRVId ArrayAccessId : IdxGroupArrayPairIt->second)
955+
ArrayVariablesVec.push_back(ArrayAccessId);
955956
}
956957
}
957958

@@ -1476,13 +1477,13 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
14761477
// 1) The metadata node has no operands. It will be directly referenced
14771478
// from within the optimization hint metadata.
14781479
if (NumOperands == 0)
1479-
IndexGroupArrayMap[IndexGroup] = AccessedArrayId;
1480+
IndexGroupArrayMap[IndexGroup].insert(AccessedArrayId);
14801481
// 2) The metadata node has several operands. It serves to link an index
14811482
// group specific to some embedded loop with other index groups that
14821483
// mark the same array variable for the outer loop(s).
14831484
for (unsigned I = 0; I < NumOperands; ++I) {
14841485
auto *ContainedIndexGroup = getMDOperandAsMDNode(IndexGroup, I);
1485-
IndexGroupArrayMap[ContainedIndexGroup] = AccessedArrayId;
1486+
IndexGroupArrayMap[ContainedIndexGroup].insert(AccessedArrayId);
14861487
}
14871488
}
14881489

llvm-spirv/lib/SPIRV/SPIRVWriter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "SPIRVType.h"
5454
#include "SPIRVValue.h"
5555

56+
#include "llvm/ADT/SmallSet.h"
5657
#include "llvm/Analysis/CallGraph.h"
5758
#include "llvm/IR/IntrinsicInst.h"
5859

@@ -138,7 +139,7 @@ class LLVMToSPIRV : public ModulePass {
138139

139140
typedef DenseMap<Type *, SPIRVType *> LLVMToSPIRVTypeMap;
140141
typedef DenseMap<Value *, SPIRVValue *> LLVMToSPIRVValueMap;
141-
typedef DenseMap<MDNode *, SPIRVId> LLVMToSPIRVMetadataMap;
142+
typedef DenseMap<MDNode *, SmallSet<SPIRVId, 2>> LLVMToSPIRVMetadataMap;
142143

143144
private:
144145
Module *M;

0 commit comments

Comments
 (0)