[ArrayPartition] Partition arrays and access - #1036
Conversation
josh-anderegg
commented
Aug 17, 2026
- Create allocas according to the partition pragmas.
- Create branching logic based on partition pragmas.
- Include tests to verify partition.
| if (!gepInst) { | ||
| llvm::report_fatal_error( | ||
| "__dyn_array_partition: expected a GEP for this access"); | ||
| } |
There was a problem hiding this comment.
BTW if there is no GEP it means that we are accessing ARRAY[0]
| // %p = getelementptr [10 x [10 x i32]], ptr %arr, i64 0, i64 1, 5 | ||
| // and dimension = 2 we'd want origIdx to be value 5 in this example | ||
| Value *origIdx = *(gepInst->idx_begin() + partInfo.dimension); | ||
| Type *addrTy = origIdx->getType(); |
There was a problem hiding this comment.
I think it is more reliable to look at the alloca instead of GEP?
BTW i don't quite get the example (for instance what is 5?
| // Creation of bank specific target index | ||
| // newTargetIdx = (origIdx - firstIndex) / step | ||
| // e.g. firstIndex=50, step=1 (block bank covering global 50..99): | ||
| // %sub = sub i64 %origIdx, 50 | ||
| // %part.idx = udiv i64 %sub, 1 ; a[73] -> bank[23] |
There was a problem hiding this comment.
Does the same logic work for block partitioning?
| return result; | ||
| } | ||
|
|
||
| void rewriteAccessWithBranching(Instruction *inst, AllocaInst *baseAlloca, |
There was a problem hiding this comment.
I think it helps to put a high-level example in C to get a sense how it works (maybe the one in the project description)?
And explain the hope is that some LLVM optimizations will clean up some branches that are never accessed
| } | ||
|
|
||
| } // namespace | ||
| // Function that returns map of arrayNames -> partitionInfo for later partition |
There was a problem hiding this comment.
Maybe remind the reader the pragma syntax here
| origIdx, ConstantInt::get(addrTy, chunkSize), "bank.raw"); | ||
| if (remainder != 0) { | ||
| Value *maxBank = ConstantInt::get(addrTy, factor - 1); | ||
| Value *tooLarge = preBuilder.CreateICmpUGT(raw, maxBank); |
There was a problem hiding this comment.
Why cyclic doesn't need too large?
| struct PartitionInfo { | ||
| unsigned dimension; | ||
| unsigned factor; | ||
| std::string style; |
There was a problem hiding this comment.
maybe change it to enum {BLOCK, CYCLIC, COMPLETE} and verify it only once
| $LLVM_OPT -S \ | ||
| -load-pass-plugin "$DYNAMATIC_DIR/build/lib/ArrayPartition.so" \ | ||
| -passes="array-partition" \ | ||
| -polly-process-unprofitable \ | ||
| "$F_CLANG_OPTIMIZED_DEPENDENCY" \ | ||
| > "$F_CLANG_OPTIMIZED_DEPENDENCY_PARTITIONED" | ||
| exit_on_fail "Failed to perform array partitioning in LLVM IR" | ||
|
|
||
| $LLVM_OPT -S \ | ||
| -load-pass-plugin "$DYNAMATIC_DIR/build/lib/GuardLoadStore.so" \ | ||
| -passes="function(guard-load-store,instcombine),always-inline" \ | ||
| -polly-process-unprofitable \ | ||
| "$F_CLANG_OPTIMIZED_DEPENDENCY_PARTITIONED" \ | ||
| > "$F_CLANG_OPTIMIZED_DEPENDENCY_PARTITIONED_CLEANED" | ||
| exit_on_fail "Failed to clean up after array partitioning in LLVM IR" |
There was a problem hiding this comment.
Should we move this pipeline before the memory dep analysis? I don't think it is currently handling the metadata that tracks the memory dependency edges
There was a problem hiding this comment.
(BTW the guard-load-store probably destroyed the memory analysis results so you see tests failing
Issues found with test: - LLVM reuses GEP instructions, which is problematic when the partition mechanism deletes them at times. - LLVM will not produce unnecessary GEP instructions, e.g. when accessing 0 index in an array. Fixes: - Only delete GEP instructions that do not have further use. They should still be deleted eventually since all accesses are modified in the long term. - Duplicate GEP instructions when reusal happens. This way we can still use them for code insertions and have them removed later via `instcombine` - Early return when working with 0 indices, since they lie in the 0th bank by definition for all partition patterns.