Skip to content

[ArrayPartition] Partition arrays and access - #1036

Open
josh-anderegg wants to merge 19 commits into
mainfrom
array-partition/allocate-access
Open

[ArrayPartition] Partition arrays and access#1036
josh-anderegg wants to merge 19 commits into
mainfrom
array-partition/allocate-access

Conversation

@josh-anderegg

Copy link
Copy Markdown
Collaborator
  1. Create allocas according to the partition pragmas.
  2. Create branching logic based on partition pragmas.
  3. Include tests to verify partition.

@josh-anderegg
josh-anderegg requested a review from Jiahui17 August 17, 2026 18:39
@josh-anderegg josh-anderegg changed the title Array partition/allocate access [ArrayPartition] Partition arrays and access Aug 17, 2026
Comment on lines +730 to +733
if (!gepInst) {
llvm::report_fatal_error(
"__dyn_array_partition: expected a GEP for this access");
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BTW if there is no GEP it means that we are accessing ARRAY[0]

Comment on lines +743 to +746
// %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();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

Comment on lines +849 to +853
// 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]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does the same logic work for block partitioning?

return result;
}

void rewriteAccessWithBranching(Instruction *inst, AllocaInst *baseAlloca,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why cyclic doesn't need too large?

struct PartitionInfo {
unsigned dimension;
unsigned factor;
std::string style;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe change it to enum {BLOCK, CYCLIC, COMPLETE} and verify it only once

Comment on lines +225 to +239
$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"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(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.
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