This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
#include "mlir/Dialect/SCF/IR/SCF.h"
|
||||||
|
|
||||||
#include "llvm/ADT/MapVector.h"
|
#include "llvm/ADT/MapVector.h"
|
||||||
|
|
||||||
#include "DeferredBoundaryPlanning.hpp"
|
#include "DeferredBoundaryPlanning.hpp"
|
||||||
@@ -99,6 +101,7 @@ static size_t hashSemanticKey(const SemanticKey& key) {
|
|||||||
key.emission.payload.getAsOpaquePointer(),
|
key.emission.payload.getAsOpaquePointer(),
|
||||||
key.emission.fragmentType.getAsOpaquePointer(),
|
key.emission.fragmentType.getAsOpaquePointer(),
|
||||||
key.emission.hasGraphLane,
|
key.emission.hasGraphLane,
|
||||||
|
key.emission.hasProducerProjection,
|
||||||
key.emission.sourceIsBatch);
|
key.emission.sourceIsBatch);
|
||||||
if (key.kind == SemanticKind::Result)
|
if (key.kind == SemanticKind::Result)
|
||||||
return llvm::hash_combine(key.kind, key.exchange);
|
return llvm::hash_combine(key.kind, key.exchange);
|
||||||
@@ -343,6 +346,44 @@ static bool matchesProjectionAssembly(ArrayRef<CanonicalAction> actions,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t getReceiveBundleLength(ArrayRef<CanonicalAction> actions,
|
||||||
|
size_t begin,
|
||||||
|
const LaneSet& lanes) {
|
||||||
|
if (begin >= actions.size())
|
||||||
|
return 0;
|
||||||
|
const CanonicalAction& first = actions[begin];
|
||||||
|
if (first.key.kind != SemanticKind::Availability)
|
||||||
|
return 0;
|
||||||
|
Type fragmentType = first.key.fragmentType;
|
||||||
|
auto rankedFragment = dyn_cast<RankedTensorType>(fragmentType);
|
||||||
|
if (!rankedFragment || !rankedFragment.hasStaticShape())
|
||||||
|
return 0;
|
||||||
|
Value firstOutput = first.key.exchange->deferred.getOutput();
|
||||||
|
if (!firstOutput.hasOneUse())
|
||||||
|
return 0;
|
||||||
|
Operation* firstUser = *firstOutput.getUsers().begin();
|
||||||
|
auto selection = firstUser->getParentOfType<scf::IndexSwitchOp>();
|
||||||
|
if (!selection)
|
||||||
|
return 0;
|
||||||
|
size_t end = begin;
|
||||||
|
while (end < actions.size()) {
|
||||||
|
const CanonicalAction& action = actions[end];
|
||||||
|
Value output = action.key.exchange
|
||||||
|
? action.key.exchange->deferred.getOutput()
|
||||||
|
: Value();
|
||||||
|
Operation* user = output && output.hasOneUse()
|
||||||
|
? *output.getUsers().begin()
|
||||||
|
: nullptr;
|
||||||
|
if (action.key.kind != SemanticKind::Availability || !action.locals.empty()
|
||||||
|
|| action.slices.empty() || !(action.receiveLanes == lanes)
|
||||||
|
|| action.key.fragmentType != fragmentType
|
||||||
|
|| !user || user->getParentOfType<scf::IndexSwitchOp>() != selection)
|
||||||
|
break;
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
return end - begin >= 2 ? end - begin : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static BoundaryInstructionList materializeInstructions(ArrayRef<CanonicalAction> actions,
|
static BoundaryInstructionList materializeInstructions(ArrayRef<CanonicalAction> actions,
|
||||||
const LaneSet& lanes) {
|
const LaneSet& lanes) {
|
||||||
BoundaryInstructionList result;
|
BoundaryInstructionList result;
|
||||||
@@ -393,6 +434,20 @@ static BoundaryInstructionList materializeInstructions(ArrayRef<CanonicalAction>
|
|||||||
index += projectionPositions.size();
|
index += projectionPositions.size();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (size_t bundleLength = getReceiveBundleLength(actions, index, lanes)) {
|
||||||
|
EmitReceiveBundle bundle;
|
||||||
|
for (size_t offset = 0; offset < bundleLength; ++offset) {
|
||||||
|
const CanonicalAction& entry = actions[index + offset];
|
||||||
|
EmitReceiveRun receive;
|
||||||
|
receive.slices = entry.slices;
|
||||||
|
receive.entryOffsets = {0, receive.slices.size()};
|
||||||
|
receive.lanes = entry.receiveLanes;
|
||||||
|
bundle.entries.push_back(std::move(receive));
|
||||||
|
}
|
||||||
|
instructions.push_back(std::move(bundle));
|
||||||
|
index += bundleLength;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (action.key.kind == SemanticKind::Availability) {
|
if (action.key.kind == SemanticKind::Availability) {
|
||||||
ResolveAvailability availability;
|
ResolveAvailability availability;
|
||||||
availability.exchange = action.key.exchange;
|
availability.exchange = action.key.exchange;
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ struct EmitReceiveRun {
|
|||||||
llvm::SmallVector<size_t> entryOffsets;
|
llvm::SmallVector<size_t> entryOffsets;
|
||||||
LaneSet lanes;
|
LaneSet lanes;
|
||||||
};
|
};
|
||||||
|
struct EmitReceiveBundle {
|
||||||
|
llvm::SmallVector<EmitReceiveRun> entries;
|
||||||
|
};
|
||||||
struct EmitReceiveAssemblyRun {
|
struct EmitReceiveAssemblyRun {
|
||||||
llvm::SmallVector<ScheduledTransferSlice> slices;
|
llvm::SmallVector<ScheduledTransferSlice> slices;
|
||||||
llvm::SmallVector<size_t> entryOffsets;
|
llvm::SmallVector<size_t> entryOffsets;
|
||||||
@@ -57,7 +60,7 @@ struct ProduceDeferredResult {
|
|||||||
struct BoundaryInstructionList;
|
struct BoundaryInstructionList;
|
||||||
struct LaneDispatch;
|
struct LaneDispatch;
|
||||||
using BoundaryInstruction = std::variant<EmitSendRun, ResolveAvailability,
|
using BoundaryInstruction = std::variant<EmitSendRun, ResolveAvailability,
|
||||||
EmitReceiveAssemblyRun, ProduceDeferredResult,
|
EmitReceiveBundle, EmitReceiveAssemblyRun, ProduceDeferredResult,
|
||||||
std::unique_ptr<LaneDispatch>>;
|
std::unique_ptr<LaneDispatch>>;
|
||||||
struct BoundaryInstructionList {
|
struct BoundaryInstructionList {
|
||||||
llvm::SmallVector<BoundaryInstruction, 0> instructions;
|
llvm::SmallVector<BoundaryInstruction, 0> instructions;
|
||||||
|
|||||||
+254
-12
@@ -21,6 +21,9 @@ struct LogicalTransferMetadataView {
|
|||||||
StaticIntSequenceChain targetCores;
|
StaticIntSequenceChain targetCores;
|
||||||
StaticIntSequenceChain targetLanes;
|
StaticIntSequenceChain targetLanes;
|
||||||
StaticIntSequenceChain localOffsets;
|
StaticIntSequenceChain localOffsets;
|
||||||
|
SmallVector<StaticIntSequenceChain> projectionOffsets;
|
||||||
|
SmallVector<StaticIntSequenceChain> projectionSizes;
|
||||||
|
SmallVector<StaticIntSequenceChain> projectionStrides;
|
||||||
|
|
||||||
size_t size() const { return channels.size(); }
|
size_t size() const { return channels.size(); }
|
||||||
};
|
};
|
||||||
@@ -48,6 +51,25 @@ static void appendMetadata(const ScheduledTransferSlice& slice,
|
|||||||
targetLane - requirementLanes.begin, count);
|
targetLane - requirementLanes.begin, count);
|
||||||
else
|
else
|
||||||
metadata.localOffsets.append(StaticIntSequence::uniform(0, count));
|
metadata.localOffsets.append(StaticIntSequence::uniform(0, count));
|
||||||
|
if (family.requirement->producerProjection) {
|
||||||
|
const DeferredStaticSliceGeometry& geometry =
|
||||||
|
*family.requirement->producerProjection;
|
||||||
|
if (metadata.projectionOffsets.empty()) {
|
||||||
|
metadata.projectionOffsets.resize(geometry.offsets.size());
|
||||||
|
metadata.projectionSizes.resize(geometry.sizes.size());
|
||||||
|
metadata.projectionStrides.resize(geometry.strides.size());
|
||||||
|
}
|
||||||
|
size_t geometryIndex = targetLane - requirementLanes.begin;
|
||||||
|
for (auto [target, source] :
|
||||||
|
llvm::zip_equal(metadata.projectionOffsets, geometry.offsets))
|
||||||
|
target.append(source, geometryIndex, count);
|
||||||
|
for (auto [target, source] :
|
||||||
|
llvm::zip_equal(metadata.projectionSizes, geometry.sizes))
|
||||||
|
target.append(source, geometryIndex, count);
|
||||||
|
for (auto [target, source] :
|
||||||
|
llvm::zip_equal(metadata.projectionStrides, geometry.strides))
|
||||||
|
target.append(source, geometryIndex, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static LogicalTransferMetadataView
|
static LogicalTransferMetadataView
|
||||||
@@ -106,9 +128,18 @@ static OpFoldResult lookupGeometry(
|
|||||||
|
|
||||||
static FailureOr<Value> materializeSendPayload(const RequirementFamily& requirement,
|
static FailureOr<Value> materializeSendPayload(const RequirementFamily& requirement,
|
||||||
Value localOffset,
|
Value localOffset,
|
||||||
|
const MixedSliceGeometry* producerProjection,
|
||||||
DeferredEmissionContext& context,
|
DeferredEmissionContext& context,
|
||||||
Location loc) {
|
Location loc) {
|
||||||
Value payload = requirement.producer->payload;
|
Value payload = requirement.producer->payload;
|
||||||
|
if (producerProjection) {
|
||||||
|
auto fragmentType = dyn_cast<RankedTensorType>(
|
||||||
|
requirement.publicationFragmentType);
|
||||||
|
if (!fragmentType)
|
||||||
|
return failure();
|
||||||
|
return extractMixedSliceOrIdentity(
|
||||||
|
context.rewriter, loc, payload, fragmentType, *producerProjection);
|
||||||
|
}
|
||||||
if (payload.getType() == requirement.publicationFragmentType)
|
if (payload.getType() == requirement.publicationFragmentType)
|
||||||
return payload;
|
return payload;
|
||||||
auto payloadType = dyn_cast<RankedTensorType>(payload.getType());
|
auto payloadType = dyn_cast<RankedTensorType>(payload.getType());
|
||||||
@@ -148,6 +179,20 @@ emitSendRun(const EmitSendRun& run, Value lane, unsigned laneCount, DeferredEmis
|
|||||||
actionCount * laneCount, logical.targetCores.valueAt(0));
|
actionCount * laneCount, logical.targetCores.valueAt(0));
|
||||||
SmallVector<int64_t> offsetTable(
|
SmallVector<int64_t> offsetTable(
|
||||||
actionCount * laneCount, logical.localOffsets.valueAt(0));
|
actionCount * laneCount, logical.localOffsets.valueAt(0));
|
||||||
|
SmallVector<SmallVector<int64_t>> projectionOffsetTables;
|
||||||
|
SmallVector<SmallVector<int64_t>> projectionSizeTables;
|
||||||
|
SmallVector<SmallVector<int64_t>> projectionStrideTables;
|
||||||
|
auto initializeGeometryTables = [&](ArrayRef<StaticIntSequenceChain> source,
|
||||||
|
SmallVectorImpl<SmallVector<int64_t>>& target) {
|
||||||
|
for (const StaticIntSequenceChain& sequence : source)
|
||||||
|
target.emplace_back(actionCount * laneCount, sequence.valueAt(0));
|
||||||
|
};
|
||||||
|
initializeGeometryTables(logical.projectionOffsets,
|
||||||
|
projectionOffsetTables);
|
||||||
|
initializeGeometryTables(logical.projectionSizes,
|
||||||
|
projectionSizeTables);
|
||||||
|
initializeGeometryTables(logical.projectionStrides,
|
||||||
|
projectionStrideTables);
|
||||||
SmallVector<int64_t> counts(laneCount);
|
SmallVector<int64_t> counts(laneCount);
|
||||||
for (unsigned sourceLane = 0; sourceLane < laneCount; ++sourceLane) {
|
for (unsigned sourceLane = 0; sourceLane < laneCount; ++sourceLane) {
|
||||||
const LogicalTransferMetadataView& source = metadataByLane[sourceLane];
|
const LogicalTransferMetadataView& source = metadataByLane[sourceLane];
|
||||||
@@ -158,6 +203,18 @@ emitSendRun(const EmitSendRun& run, Value lane, unsigned laneCount, DeferredEmis
|
|||||||
sourceTable[index] = source.sourceCores.valueAt(action);
|
sourceTable[index] = source.sourceCores.valueAt(action);
|
||||||
targetTable[index] = source.targetCores.valueAt(action);
|
targetTable[index] = source.targetCores.valueAt(action);
|
||||||
offsetTable[index] = source.localOffsets.valueAt(action);
|
offsetTable[index] = source.localOffsets.valueAt(action);
|
||||||
|
for (auto [table, sequence] :
|
||||||
|
llvm::zip_equal(projectionOffsetTables,
|
||||||
|
source.projectionOffsets))
|
||||||
|
table[index] = sequence.valueAt(action);
|
||||||
|
for (auto [table, sequence] :
|
||||||
|
llvm::zip_equal(projectionSizeTables,
|
||||||
|
source.projectionSizes))
|
||||||
|
table[index] = sequence.valueAt(action);
|
||||||
|
for (auto [table, sequence] :
|
||||||
|
llvm::zip_equal(projectionStrideTables,
|
||||||
|
source.projectionStrides))
|
||||||
|
table[index] = sequence.valueAt(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExternalTransferFamily& firstFamily = *run.slices.front().family;
|
ExternalTransferFamily& firstFamily = *run.slices.front().family;
|
||||||
@@ -166,7 +223,20 @@ emitSendRun(const EmitSendRun& run, Value lane, unsigned laneCount, DeferredEmis
|
|||||||
Location loc = requirement.exchange->deferred.getLoc();
|
Location loc = requirement.exchange->deferred.getLoc();
|
||||||
auto emitOne = [&](Value position) -> LogicalResult {
|
auto emitOne = [&](Value position) -> LogicalResult {
|
||||||
Value localOffset = lookup(offsetTable, position, anchor, context, loc);
|
Value localOffset = lookup(offsetTable, position, anchor, context, loc);
|
||||||
auto payload = materializeSendPayload(requirement, localOffset, context, loc);
|
MixedSliceGeometry projection;
|
||||||
|
for (ArrayRef<int64_t> table : projectionOffsetTables)
|
||||||
|
projection.offsets.push_back(
|
||||||
|
lookupGeometry(table, position, anchor, context, loc));
|
||||||
|
for (ArrayRef<int64_t> table : projectionSizeTables)
|
||||||
|
projection.sizes.push_back(
|
||||||
|
lookupGeometry(table, position, anchor, context, loc));
|
||||||
|
for (ArrayRef<int64_t> table : projectionStrideTables)
|
||||||
|
projection.strides.push_back(
|
||||||
|
lookupGeometry(table, position, anchor, context, loc));
|
||||||
|
auto payload = materializeSendPayload(
|
||||||
|
requirement, localOffset,
|
||||||
|
projectionOffsetTables.empty() ? nullptr : &projection,
|
||||||
|
context, loc);
|
||||||
if (failed(payload))
|
if (failed(payload))
|
||||||
return failure();
|
return failure();
|
||||||
auto send = SpatChannelSendOp::create(context.rewriter,
|
auto send = SpatChannelSendOp::create(context.rewriter,
|
||||||
@@ -231,6 +301,125 @@ emitReceiveValue(const EmitReceiveRun& run, Value lane, unsigned laneCount, Defe
|
|||||||
return receive.getOutput();
|
return receive.getOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LogicalResult emitReceiveBundle(const EmitReceiveBundle& bundle,
|
||||||
|
Value lane,
|
||||||
|
unsigned laneCount,
|
||||||
|
DeferredEmissionContext& context) {
|
||||||
|
if (bundle.entries.size() < 2)
|
||||||
|
return failure();
|
||||||
|
RequirementFamily& reference =
|
||||||
|
*bundle.entries.front().slices.front().family->requirement;
|
||||||
|
auto fragmentType = dyn_cast<RankedTensorType>(
|
||||||
|
reference.publicationFragmentType);
|
||||||
|
if (!fragmentType || !fragmentType.hasStaticShape())
|
||||||
|
return failure();
|
||||||
|
for (const EmitReceiveRun& entry : bundle.entries) {
|
||||||
|
if (entry.slices.empty()
|
||||||
|
|| entry.slices.front().family->requirement->publicationFragmentType
|
||||||
|
!= fragmentType)
|
||||||
|
return failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVector<ScheduledTransferSlice> slices;
|
||||||
|
for (const EmitReceiveRun& entry : bundle.entries)
|
||||||
|
llvm::append_range(slices, entry.slices);
|
||||||
|
LogicalTransferMetadataView metadata = buildMetadataView(slices);
|
||||||
|
size_t entryCount = bundle.entries.size();
|
||||||
|
SmallVector<int64_t> channelTable(
|
||||||
|
entryCount * laneCount, metadata.channels.valueAt(0));
|
||||||
|
SmallVector<int64_t> sourceTable(
|
||||||
|
entryCount * laneCount, metadata.sourceCores.valueAt(0));
|
||||||
|
SmallVector<int64_t> targetTable(
|
||||||
|
entryCount * laneCount, metadata.targetCores.valueAt(0));
|
||||||
|
for (auto [entryIndex, entry] : llvm::enumerate(bundle.entries)) {
|
||||||
|
LogicalTransferMetadataView item = buildMetadataView(entry.slices);
|
||||||
|
for (size_t index = 0; index < item.size(); ++index) {
|
||||||
|
size_t tableIndex =
|
||||||
|
entryIndex * laneCount + item.targetLanes.valueAt(index);
|
||||||
|
channelTable[tableIndex] = item.channels.valueAt(index);
|
||||||
|
sourceTable[tableIndex] = item.sourceCores.valueAt(index);
|
||||||
|
targetTable[tableIndex] = item.targetCores.valueAt(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeferredExchangePlan* exchange = reference.exchange;
|
||||||
|
Location loc = exchange->deferred.getLoc();
|
||||||
|
SmallVector<int64_t> bundleShape {static_cast<int64_t>(entryCount)};
|
||||||
|
llvm::append_range(bundleShape, fragmentType.getShape());
|
||||||
|
auto bundleType = RankedTensorType::get(
|
||||||
|
bundleShape, fragmentType.getElementType());
|
||||||
|
Value initial = tensor::EmptyOp::create(
|
||||||
|
context.rewriter, loc, bundleShape, fragmentType.getElementType());
|
||||||
|
auto loop = buildNormalizedScfFor(
|
||||||
|
context.rewriter,
|
||||||
|
loc,
|
||||||
|
context.constants.getIndex(0),
|
||||||
|
context.constants.getIndex(entryCount),
|
||||||
|
context.constants.getIndex(1),
|
||||||
|
ValueRange {initial},
|
||||||
|
[&](OpBuilder&, Location, Value entry, ValueRange iterArgs,
|
||||||
|
SmallVectorImpl<Value>& yielded) -> LogicalResult {
|
||||||
|
Value tableIndex = entry;
|
||||||
|
if (lane) {
|
||||||
|
Value base = affineMulConst(
|
||||||
|
context.rewriter, loc, entry, laneCount, exchange->deferred);
|
||||||
|
tableIndex = arith::AddIOp::create(
|
||||||
|
context.rewriter, loc, base, lane);
|
||||||
|
}
|
||||||
|
auto receive = SpatChannelReceiveOp::create(
|
||||||
|
context.rewriter,
|
||||||
|
loc,
|
||||||
|
fragmentType,
|
||||||
|
lookup(channelTable, tableIndex, exchange->deferred, context, loc),
|
||||||
|
lookup(sourceTable, tableIndex, exchange->deferred, context, loc),
|
||||||
|
lookup(targetTable, tableIndex, exchange->deferred, context, loc));
|
||||||
|
setLogicalTransferMetadata(receive, metadata);
|
||||||
|
auto source = addLeadingUnitTensorDimension(
|
||||||
|
context.rewriter, loc, receive.getOutput());
|
||||||
|
if (failed(source))
|
||||||
|
return failure();
|
||||||
|
MixedSliceGeometry geometry;
|
||||||
|
geometry.offsets.assign(bundleType.getRank(),
|
||||||
|
context.rewriter.getIndexAttr(0));
|
||||||
|
geometry.offsets.front() = entry;
|
||||||
|
for (int64_t dimension : cast<RankedTensorType>(source->getType()).getShape())
|
||||||
|
geometry.sizes.push_back(
|
||||||
|
context.rewriter.getIndexAttr(dimension));
|
||||||
|
geometry.strides.assign(bundleType.getRank(),
|
||||||
|
context.rewriter.getIndexAttr(1));
|
||||||
|
yielded.push_back(insertMixedSlice(
|
||||||
|
context.rewriter, loc, *source, iterArgs.front(), geometry));
|
||||||
|
return success();
|
||||||
|
});
|
||||||
|
if (failed(loop))
|
||||||
|
return failure();
|
||||||
|
|
||||||
|
SmallVector<int64_t> unitShape {1};
|
||||||
|
llvm::append_range(unitShape, fragmentType.getShape());
|
||||||
|
auto unitType = RankedTensorType::get(
|
||||||
|
unitShape, fragmentType.getElementType());
|
||||||
|
for (auto [entryIndex, entry] : llvm::enumerate(bundle.entries)) {
|
||||||
|
MixedSliceGeometry geometry;
|
||||||
|
geometry.offsets.assign(bundleType.getRank(),
|
||||||
|
context.rewriter.getIndexAttr(0));
|
||||||
|
geometry.offsets.front() = context.rewriter.getIndexAttr(entryIndex);
|
||||||
|
for (int64_t dimension : unitShape)
|
||||||
|
geometry.sizes.push_back(
|
||||||
|
context.rewriter.getIndexAttr(dimension));
|
||||||
|
geometry.strides.assign(bundleType.getRank(),
|
||||||
|
context.rewriter.getIndexAttr(1));
|
||||||
|
Value unit = extractMixedSliceOrIdentity(
|
||||||
|
context.rewriter, loc, loop->results.front(), unitType, geometry);
|
||||||
|
auto fragment = removeLeadingUnitTensorDimension(
|
||||||
|
context.rewriter, loc, unit, fragmentType);
|
||||||
|
if (failed(fragment))
|
||||||
|
return failure();
|
||||||
|
for (const ScheduledTransferSlice& slice : entry.slices)
|
||||||
|
context.receives[slice.family->requirement] = *fragment;
|
||||||
|
}
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
static LogicalResult
|
static LogicalResult
|
||||||
emitConditionalSendRun(const EmitSendRun& run, Value lane, unsigned laneCount, DeferredEmissionContext& context) {
|
emitConditionalSendRun(const EmitSendRun& run, Value lane, unsigned laneCount, DeferredEmissionContext& context) {
|
||||||
if (run.lanes.size() == laneCount)
|
if (run.lanes.size() == laneCount)
|
||||||
@@ -259,19 +448,67 @@ static FailureOr<Value> materializeLocalValue(const MaterializeLocalFamily& loca
|
|||||||
DeferredEmissionContext& context) {
|
DeferredEmissionContext& context) {
|
||||||
RequirementFamily& reference = *local.families.front()->requirement;
|
RequirementFamily& reference = *local.families.front()->requirement;
|
||||||
Value fragment = reference.producer->payload;
|
Value fragment = reference.producer->payload;
|
||||||
if (fragment.getType() != reference.publicationFragmentType) {
|
if (reference.producerProjection
|
||||||
|
|| fragment.getType() != reference.publicationFragmentType) {
|
||||||
SmallVector<int64_t> offsets(laneCount);
|
SmallVector<int64_t> offsets(laneCount);
|
||||||
|
SmallVector<SmallVector<int64_t>> projectionOffsets;
|
||||||
|
SmallVector<SmallVector<int64_t>> projectionSizes;
|
||||||
|
SmallVector<SmallVector<int64_t>> projectionStrides;
|
||||||
|
auto initializeGeometry = [&](ArrayRef<StaticIntSequence> source,
|
||||||
|
SmallVectorImpl<SmallVector<int64_t>>& target) {
|
||||||
|
for (const StaticIntSequence& sequence : source)
|
||||||
|
target.emplace_back(laneCount, sequence.valueAt(0));
|
||||||
|
};
|
||||||
|
if (reference.producerProjection) {
|
||||||
|
initializeGeometry(reference.producerProjection->offsets,
|
||||||
|
projectionOffsets);
|
||||||
|
initializeGeometry(reference.producerProjection->sizes,
|
||||||
|
projectionSizes);
|
||||||
|
initializeGeometry(reference.producerProjection->strides,
|
||||||
|
projectionStrides);
|
||||||
|
}
|
||||||
for (LocalAvailabilityFamily* family : local.families) {
|
for (LocalAvailabilityFamily* family : local.families) {
|
||||||
RequirementFamily& requirement = *family->requirement;
|
RequirementFamily& requirement = *family->requirement;
|
||||||
LaneInterval requirementLanes = requirement.targetLanes.intervals().front();
|
LaneInterval requirementLanes = requirement.targetLanes.intervals().front();
|
||||||
for (LaneInterval interval : family->targetLanes.intervals())
|
for (LaneInterval interval : family->targetLanes.intervals())
|
||||||
for (unsigned targetLane = interval.begin; targetLane < interval.end; ++targetLane)
|
for (unsigned targetLane = interval.begin;
|
||||||
offsets[targetLane] = requirement.producerLocalOffsets->valueAt(targetLane - requirementLanes.begin);
|
targetLane < interval.end; ++targetLane) {
|
||||||
|
size_t position = targetLane - requirementLanes.begin;
|
||||||
|
if (requirement.producerLocalOffsets)
|
||||||
|
offsets[targetLane] =
|
||||||
|
requirement.producerLocalOffsets->valueAt(position);
|
||||||
|
if (requirement.producerProjection) {
|
||||||
|
for (auto [table, sequence] :
|
||||||
|
llvm::zip_equal(projectionOffsets,
|
||||||
|
requirement.producerProjection->offsets))
|
||||||
|
table[targetLane] = sequence.valueAt(position);
|
||||||
|
for (auto [table, sequence] :
|
||||||
|
llvm::zip_equal(projectionSizes,
|
||||||
|
requirement.producerProjection->sizes))
|
||||||
|
table[targetLane] = sequence.valueAt(position);
|
||||||
|
for (auto [table, sequence] :
|
||||||
|
llvm::zip_equal(projectionStrides,
|
||||||
|
requirement.producerProjection->strides))
|
||||||
|
table[targetLane] = sequence.valueAt(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Location loc = reference.exchange->deferred.getLoc();
|
Location loc = reference.exchange->deferred.getLoc();
|
||||||
Value position = lane ? lane : context.constants.getIndex(0);
|
Value position = lane ? lane : context.constants.getIndex(0);
|
||||||
|
MixedSliceGeometry projection;
|
||||||
|
for (ArrayRef<int64_t> table : projectionOffsets)
|
||||||
|
projection.offsets.push_back(lookupGeometry(
|
||||||
|
table, position, reference.exchange->deferred, context, loc));
|
||||||
|
for (ArrayRef<int64_t> table : projectionSizes)
|
||||||
|
projection.sizes.push_back(lookupGeometry(
|
||||||
|
table, position, reference.exchange->deferred, context, loc));
|
||||||
|
for (ArrayRef<int64_t> table : projectionStrides)
|
||||||
|
projection.strides.push_back(lookupGeometry(
|
||||||
|
table, position, reference.exchange->deferred, context, loc));
|
||||||
auto materialized = materializeSendPayload(
|
auto materialized = materializeSendPayload(
|
||||||
reference, lookup(offsets, position, reference.exchange->deferred, context, loc), context, loc);
|
reference,
|
||||||
|
lookup(offsets, position, reference.exchange->deferred, context, loc),
|
||||||
|
projectionOffsets.empty() ? nullptr : &projection, context, loc);
|
||||||
if (failed(materialized))
|
if (failed(materialized))
|
||||||
return failure();
|
return failure();
|
||||||
fragment = *materialized;
|
fragment = *materialized;
|
||||||
@@ -721,6 +958,11 @@ static FailureOr<SmallVector<Value>> emitInstructions(
|
|||||||
return failure();
|
return failure();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (auto bundle = std::get_if<EmitReceiveBundle>(&instruction)) {
|
||||||
|
if (failed(emitReceiveBundle(*bundle, lane, laneCount, context)))
|
||||||
|
return failure();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (auto assembly = std::get_if<EmitReceiveAssemblyRun>(&instruction)) {
|
if (auto assembly = std::get_if<EmitReceiveAssemblyRun>(&instruction)) {
|
||||||
auto value = assembly->projectionLeaf
|
auto value = assembly->projectionLeaf
|
||||||
? emitProjectionAssemblyRun(
|
? emitProjectionAssemblyRun(
|
||||||
@@ -774,12 +1016,12 @@ static void setInsertionAtBoundary(IRRewriter& rewriter, const BoundaryKey& key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LogicalResult
|
static LogicalResult
|
||||||
replaceResults(ArrayRef<DeferredExchangePlan*> exchanges, ValueRange replacements, DeferredEraseSet& erase) {
|
replaceResults(ArrayRef<DeferredExchangePlan*> exchanges, ValueRange replacements,
|
||||||
|
DeferredReplacementMap& deferredReplacements) {
|
||||||
if (exchanges.size() != replacements.size())
|
if (exchanges.size() != replacements.size())
|
||||||
return failure();
|
return failure();
|
||||||
for (auto [exchange, replacement] : llvm::zip_equal(exchanges, replacements)) {
|
for (auto [exchange, replacement] : llvm::zip_equal(exchanges, replacements)) {
|
||||||
exchange->deferred.getOutput().replaceAllUsesWith(replacement);
|
deferredReplacements.insert({exchange->deferred, replacement});
|
||||||
erase.insert(exchange->deferred);
|
|
||||||
}
|
}
|
||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
@@ -787,7 +1029,7 @@ replaceResults(ArrayRef<DeferredExchangePlan*> exchanges, ValueRange replacement
|
|||||||
static LogicalResult emitBoundary(const BoundaryProgram& boundary,
|
static LogicalResult emitBoundary(const BoundaryProgram& boundary,
|
||||||
ArrayRef<DeferredResultPlan> results,
|
ArrayRef<DeferredResultPlan> results,
|
||||||
DeferredEmissionContext& context,
|
DeferredEmissionContext& context,
|
||||||
DeferredEraseSet& erase) {
|
DeferredReplacementMap& replacements) {
|
||||||
setInsertionAtBoundary(context.rewriter, boundary.key);
|
setInsertionAtBoundary(context.rewriter, boundary.key);
|
||||||
unsigned laneCount = boundary.key.scheduled->cores.size();
|
unsigned laneCount = boundary.key.scheduled->cores.size();
|
||||||
Value lane;
|
Value lane;
|
||||||
@@ -798,7 +1040,7 @@ static LogicalResult emitBoundary(const BoundaryProgram& boundary,
|
|||||||
auto values = emitInstructions(
|
auto values = emitInstructions(
|
||||||
boundary.root, lane, laneCount, results, context);
|
boundary.root, lane, laneCount, results, context);
|
||||||
return failed(values) ? failure()
|
return failed(values) ? failure()
|
||||||
: replaceResults(exchanges, *values, erase);
|
: replaceResults(exchanges, *values, replacements);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -806,7 +1048,7 @@ static LogicalResult emitBoundary(const BoundaryProgram& boundary,
|
|||||||
LogicalResult realizeDeferredBoundaries(ArrayRef<BoundaryProgram> boundaries,
|
LogicalResult realizeDeferredBoundaries(ArrayRef<BoundaryProgram> boundaries,
|
||||||
ArrayRef<DeferredResultPlan> results,
|
ArrayRef<DeferredResultPlan> results,
|
||||||
DeferredEmissionContext& context,
|
DeferredEmissionContext& context,
|
||||||
DeferredEraseSet& erase) {
|
DeferredReplacementMap& replacements) {
|
||||||
ScheduledInfo* scheduled = nullptr;
|
ScheduledInfo* scheduled = nullptr;
|
||||||
for (const BoundaryProgram& boundary : boundaries) {
|
for (const BoundaryProgram& boundary : boundaries) {
|
||||||
if (scheduled != boundary.key.scheduled) {
|
if (scheduled != boundary.key.scheduled) {
|
||||||
@@ -815,7 +1057,7 @@ LogicalResult realizeDeferredBoundaries(ArrayRef<BoundaryProgram> boundaries,
|
|||||||
context.projectionAssemblies.clear();
|
context.projectionAssemblies.clear();
|
||||||
scheduled = boundary.key.scheduled;
|
scheduled = boundary.key.scheduled;
|
||||||
}
|
}
|
||||||
if (failed(emitBoundary(boundary, results, context, erase)))
|
if (failed(emitBoundary(boundary, results, context, replacements)))
|
||||||
return boundary.key.scheduled->op->emitOpError("phase 2 failed to realize a communication boundary");
|
return boundary.key.scheduled->op->emitOpError("phase 2 failed to realize a communication boundary");
|
||||||
}
|
}
|
||||||
return success();
|
return success();
|
||||||
|
|||||||
+5
-2
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "llvm/ADT/MapVector.h"
|
||||||
|
|
||||||
#include "mlir/IR/PatternMatch.h"
|
#include "mlir/IR/PatternMatch.h"
|
||||||
|
|
||||||
#include "DeferredBoundaryPlanning.hpp"
|
#include "DeferredBoundaryPlanning.hpp"
|
||||||
@@ -20,11 +22,12 @@ struct DeferredEmissionContext {
|
|||||||
projectionAssemblies;
|
projectionAssemblies;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DeferredEraseSet = llvm::SetVector<mlir::Operation*>;
|
using DeferredReplacementMap =
|
||||||
|
llvm::MapVector<mlir::Operation*, mlir::Value>;
|
||||||
|
|
||||||
mlir::LogicalResult realizeDeferredBoundaries(mlir::ArrayRef<BoundaryProgram> boundaries,
|
mlir::LogicalResult realizeDeferredBoundaries(mlir::ArrayRef<BoundaryProgram> boundaries,
|
||||||
mlir::ArrayRef<DeferredResultPlan> results,
|
mlir::ArrayRef<DeferredResultPlan> results,
|
||||||
DeferredEmissionContext& context,
|
DeferredEmissionContext& context,
|
||||||
DeferredEraseSet& erase);
|
DeferredReplacementMap& replacements);
|
||||||
|
|
||||||
} // namespace onnx_mlir::spatial
|
} // namespace onnx_mlir::spatial
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ struct RequirementCoordinate {
|
|||||||
|
|
||||||
enum class DeferredLeafForm {
|
enum class DeferredLeafForm {
|
||||||
DirectSource,
|
DirectSource,
|
||||||
|
ScalarProjection,
|
||||||
GraphBatchProjection
|
GraphBatchProjection
|
||||||
};
|
};
|
||||||
enum class DeferredAssemblySourceTransform {
|
enum class DeferredAssemblySourceTransform {
|
||||||
@@ -128,6 +129,12 @@ struct DeferredSliceTemplate {
|
|||||||
llvm::SmallVector<mlir::OpFoldResult> strides;
|
llvm::SmallVector<mlir::OpFoldResult> strides;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DeferredStaticSliceGeometry {
|
||||||
|
llvm::SmallVector<StaticIntSequence> offsets;
|
||||||
|
llvm::SmallVector<StaticIntSequence> sizes;
|
||||||
|
llvm::SmallVector<StaticIntSequence> strides;
|
||||||
|
};
|
||||||
|
|
||||||
struct DeferredProjectionLeafTemplate {
|
struct DeferredProjectionLeafTemplate {
|
||||||
DeferredLeafForm form = DeferredLeafForm::DirectSource;
|
DeferredLeafForm form = DeferredLeafForm::DirectSource;
|
||||||
mlir::Value sourceRoot;
|
mlir::Value sourceRoot;
|
||||||
@@ -201,6 +208,7 @@ struct RequirementFamily {
|
|||||||
mlir::Type publicationFragmentType;
|
mlir::Type publicationFragmentType;
|
||||||
std::optional<StaticIntSequence> graphLanes;
|
std::optional<StaticIntSequence> graphLanes;
|
||||||
std::optional<StaticIntSequence> producerLocalOffsets;
|
std::optional<StaticIntSequence> producerLocalOffsets;
|
||||||
|
std::optional<DeferredStaticSliceGeometry> producerProjection;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LocalAvailabilityFamily {
|
struct LocalAvailabilityFamily {
|
||||||
|
|||||||
+7
-3
@@ -244,11 +244,15 @@ LogicalResult realizeDeferredCommunication(func::FuncOp funcOp) {
|
|||||||
return failure();
|
return failure();
|
||||||
ConstantPool constants(funcOp, rewriter);
|
ConstantPool constants(funcOp, rewriter);
|
||||||
DeferredEmissionContext context(rewriter, constants);
|
DeferredEmissionContext context(rewriter, constants);
|
||||||
DeferredEraseSet erase;
|
DeferredReplacementMap replacements;
|
||||||
if (failed(realizeDeferredBoundaries(
|
if (failed(realizeDeferredBoundaries(
|
||||||
boundaries->boundaries, boundaries->results, context, erase)))
|
boundaries->boundaries, boundaries->results, context, replacements)))
|
||||||
return failure();
|
return failure();
|
||||||
for (Operation *op : erase) {
|
for (auto [op, replacement] : replacements) {
|
||||||
|
if (op->getResult(0) == replacement)
|
||||||
|
return op->emitOpError(
|
||||||
|
"phase 2 cannot replace deferred communication with itself");
|
||||||
|
op->getResult(0).replaceAllUsesWith(replacement);
|
||||||
if (!op->use_empty())
|
if (!op->use_empty())
|
||||||
return op->emitOpError(
|
return op->emitOpError(
|
||||||
"phase 2 cannot erase deferred communication with live uses");
|
"phase 2 cannot erase deferred communication with live uses");
|
||||||
|
|||||||
+2
@@ -39,6 +39,7 @@ static size_t hashSignature(const TransferEmissionSignature& signature) {
|
|||||||
signature.payload.getAsOpaquePointer(),
|
signature.payload.getAsOpaquePointer(),
|
||||||
signature.fragmentType.getAsOpaquePointer(),
|
signature.fragmentType.getAsOpaquePointer(),
|
||||||
signature.hasGraphLane,
|
signature.hasGraphLane,
|
||||||
|
signature.hasProducerProjection,
|
||||||
signature.sourceIsBatch);
|
signature.sourceIsBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +219,7 @@ TransferEmissionSignature getTransferEmissionSignature(const ExternalTransferFam
|
|||||||
producer->payload,
|
producer->payload,
|
||||||
family.requirement->publicationFragmentType,
|
family.requirement->publicationFragmentType,
|
||||||
family.requirement->graphLanes.has_value(),
|
family.requirement->graphLanes.has_value(),
|
||||||
|
family.requirement->producerProjection.has_value(),
|
||||||
producer->scheduled->isBatch()};
|
producer->scheduled->isBatch()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -26,12 +26,14 @@ struct TransferEmissionSignature {
|
|||||||
mlir::Value payload;
|
mlir::Value payload;
|
||||||
mlir::Type fragmentType;
|
mlir::Type fragmentType;
|
||||||
bool hasGraphLane = false;
|
bool hasGraphLane = false;
|
||||||
|
bool hasProducerProjection = false;
|
||||||
bool sourceIsBatch = false;
|
bool sourceIsBatch = false;
|
||||||
|
|
||||||
bool operator==(const TransferEmissionSignature& other) const {
|
bool operator==(const TransferEmissionSignature& other) const {
|
||||||
return scheduled == other.scheduled && payload == other.payload
|
return scheduled == other.scheduled && payload == other.payload
|
||||||
&& fragmentType == other.fragmentType
|
&& fragmentType == other.fragmentType
|
||||||
&& hasGraphLane == other.hasGraphLane
|
&& hasGraphLane == other.hasGraphLane
|
||||||
|
&& hasProducerProjection == other.hasProducerProjection
|
||||||
&& sourceIsBatch == other.sourceIsBatch;
|
&& sourceIsBatch == other.sourceIsBatch;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+16
-9
@@ -518,9 +518,15 @@ FailureOr<DeferredProgramTemplate> analyzeDeferredProgramTemplate(
|
|||||||
auto result = dyn_cast<OpResult>(deferred.getSources()[index]);
|
auto result = dyn_cast<OpResult>(deferred.getSources()[index]);
|
||||||
return result && isa<SpatGraphComputeBatch>(result.getOwner());
|
return result && isa<SpatGraphComputeBatch>(result.getOwner());
|
||||||
});
|
});
|
||||||
if (graphProjection) {
|
bool scalarProjection = succeeded(sources)
|
||||||
|
&& llvm::all_of(*sources, [&](unsigned index) {
|
||||||
|
auto result = dyn_cast<OpResult>(deferred.getSources()[index]);
|
||||||
|
return result && isa<SpatGraphCompute>(result.getOwner());
|
||||||
|
});
|
||||||
|
if (graphProjection || scalarProjection) {
|
||||||
DeferredProjectionLeafTemplate leaf;
|
DeferredProjectionLeafTemplate leaf;
|
||||||
leaf.form = DeferredLeafForm::GraphBatchProjection;
|
leaf.form = graphProjection ? DeferredLeafForm::GraphBatchProjection
|
||||||
|
: DeferredLeafForm::ScalarProjection;
|
||||||
leaf.sourceRoot = slice.getSource();
|
leaf.sourceRoot = slice.getSource();
|
||||||
leaf.replacementRoot = value;
|
leaf.replacementRoot = value;
|
||||||
leaf.leadingProjection = slice;
|
leaf.leadingProjection = slice;
|
||||||
@@ -528,13 +534,14 @@ FailureOr<DeferredProgramTemplate> analyzeDeferredProgramTemplate(
|
|||||||
SmallVector<OpFoldResult>(slice.getMixedOffsets()),
|
SmallVector<OpFoldResult>(slice.getMixedOffsets()),
|
||||||
SmallVector<OpFoldResult>(slice.getMixedSizes()),
|
SmallVector<OpFoldResult>(slice.getMixedSizes()),
|
||||||
SmallVector<OpFoldResult>(slice.getMixedStrides())};
|
SmallVector<OpFoldResult>(slice.getMixedStrides())};
|
||||||
leaf.innerGeometry = {
|
if (graphProjection)
|
||||||
SmallVector<OpFoldResult>(
|
leaf.innerGeometry = {
|
||||||
ArrayRef(slice.getMixedOffsets()).drop_front()),
|
SmallVector<OpFoldResult>(
|
||||||
SmallVector<OpFoldResult>(
|
ArrayRef(slice.getMixedOffsets()).drop_front()),
|
||||||
ArrayRef(slice.getMixedSizes()).drop_front()),
|
SmallVector<OpFoldResult>(
|
||||||
SmallVector<OpFoldResult>(
|
ArrayRef(slice.getMixedSizes()).drop_front()),
|
||||||
ArrayRef(slice.getMixedStrides()).drop_front())};
|
SmallVector<OpFoldResult>(
|
||||||
|
ArrayRef(slice.getMixedStrides()).drop_front())};
|
||||||
leaf.reconstructedType = cast<RankedTensorType>(value.getType());
|
leaf.reconstructedType = cast<RankedTensorType>(value.getType());
|
||||||
program.leaves.push_back(std::move(leaf));
|
program.leaves.push_back(std::move(leaf));
|
||||||
return success();
|
return success();
|
||||||
|
|||||||
@@ -235,6 +235,20 @@ FailureOr<Value> materializeDeferredRequirement(RequirementFamily& requirement,
|
|||||||
return received;
|
return received;
|
||||||
ProducedValue& producer = *requirement.producer;
|
ProducedValue& producer = *requirement.producer;
|
||||||
Value payload = producer.payload;
|
Value payload = producer.payload;
|
||||||
|
Location loc = requirement.exchange->deferred.getLoc();
|
||||||
|
Value position = getSequencePosition(
|
||||||
|
requirement.targetLanes, lane, requirement.exchange->deferred, context, loc);
|
||||||
|
if (requirement.producerProjection) {
|
||||||
|
auto fragmentType = dyn_cast<RankedTensorType>(
|
||||||
|
requirement.publicationFragmentType);
|
||||||
|
if (!fragmentType)
|
||||||
|
return failure();
|
||||||
|
MixedSliceGeometry geometry = materializeGeometry(
|
||||||
|
*requirement.producerProjection, position,
|
||||||
|
requirement.exchange->deferred, context, loc);
|
||||||
|
return extractMixedSliceOrIdentity(
|
||||||
|
context.rewriter, loc, payload, fragmentType, geometry);
|
||||||
|
}
|
||||||
if (payload.getType() == requirement.publicationFragmentType)
|
if (payload.getType() == requirement.publicationFragmentType)
|
||||||
return payload;
|
return payload;
|
||||||
auto payloadType = dyn_cast<RankedTensorType>(payload.getType());
|
auto payloadType = dyn_cast<RankedTensorType>(payload.getType());
|
||||||
@@ -242,8 +256,6 @@ FailureOr<Value> materializeDeferredRequirement(RequirementFamily& requirement,
|
|||||||
if (!payloadType || !fragmentType || !requirement.producerLocalOffsets
|
if (!payloadType || !fragmentType || !requirement.producerLocalOffsets
|
||||||
|| payloadType.getRank() != fragmentType.getRank() + 1)
|
|| payloadType.getRank() != fragmentType.getRank() + 1)
|
||||||
return failure();
|
return failure();
|
||||||
Location loc = requirement.exchange->deferred.getLoc();
|
|
||||||
Value position = getSequencePosition(requirement.targetLanes, lane, requirement.exchange->deferred, context, loc);
|
|
||||||
Value offset = emitStaticIntLookup(*requirement.producerLocalOffsets,
|
Value offset = emitStaticIntLookup(*requirement.producerLocalOffsets,
|
||||||
position,
|
position,
|
||||||
requirement.exchange->deferred,
|
requirement.exchange->deferred,
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ struct DeferredEmissionContext;
|
|||||||
struct DeferredResultPlan {
|
struct DeferredResultPlan {
|
||||||
DeferredExchangePlan* exchange = nullptr;
|
DeferredExchangePlan* exchange = nullptr;
|
||||||
llvm::SmallVector<RequirementFamily*> requirements;
|
llvm::SmallVector<RequirementFamily*> requirements;
|
||||||
struct SliceGeometry {
|
using SliceGeometry = DeferredStaticSliceGeometry;
|
||||||
llvm::SmallVector<StaticIntSequence> offsets;
|
|
||||||
llvm::SmallVector<StaticIntSequence> sizes;
|
|
||||||
llvm::SmallVector<StaticIntSequence> strides;
|
|
||||||
};
|
|
||||||
llvm::SmallVector<SliceGeometry, 0> innerGeometry;
|
llvm::SmallVector<SliceGeometry, 0> innerGeometry;
|
||||||
llvm::SmallVector<SliceGeometry, 0> assemblyGeometry;
|
llvm::SmallVector<SliceGeometry, 0> assemblyGeometry;
|
||||||
llvm::DenseMap<mlir::Value, StaticIntSequence> residualValues;
|
llvm::DenseMap<mlir::Value, StaticIntSequence> residualValues;
|
||||||
|
|||||||
@@ -294,16 +294,38 @@ static FailureOr<ProducedValue*> findProducer(DeferredTransferPlan& plan,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct RequirementPoint {
|
struct RequirementPoint {
|
||||||
|
struct SliceGeometry {
|
||||||
|
SmallVector<int64_t> offsets;
|
||||||
|
SmallVector<int64_t> sizes;
|
||||||
|
SmallVector<int64_t> strides;
|
||||||
|
};
|
||||||
|
|
||||||
ProducedValue* producer = nullptr;
|
ProducedValue* producer = nullptr;
|
||||||
Type fragmentType;
|
Type fragmentType;
|
||||||
std::optional<int64_t> graphLane;
|
std::optional<int64_t> graphLane;
|
||||||
std::optional<int64_t> localOffset;
|
std::optional<int64_t> localOffset;
|
||||||
|
std::optional<SliceGeometry> producerProjection;
|
||||||
|
|
||||||
bool sameFamily(const RequirementPoint& other) const {
|
bool sameFamily(const RequirementPoint& other) const {
|
||||||
return producer == other.producer && fragmentType == other.fragmentType;
|
return producer == other.producer && fragmentType == other.fragmentType;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static FailureOr<SmallVector<int64_t>> evaluateGeometryValues(
|
||||||
|
ArrayRef<OpFoldResult> values,
|
||||||
|
DeferredLaneValueEvaluator& evaluator,
|
||||||
|
unsigned lane) {
|
||||||
|
SmallVector<int64_t> result;
|
||||||
|
result.reserve(values.size());
|
||||||
|
for (OpFoldResult value : values) {
|
||||||
|
auto sequence = evaluator.evaluate(value);
|
||||||
|
if (failed(sequence))
|
||||||
|
return failure();
|
||||||
|
result.push_back(sequence->valueAt(lane));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static FailureOr<std::optional<RequirementPoint>>
|
static FailureOr<std::optional<RequirementPoint>>
|
||||||
resolveRequirementPoint(DeferredTransferPlan& plan,
|
resolveRequirementPoint(DeferredTransferPlan& plan,
|
||||||
DeferredExchangePlan& exchange,
|
DeferredExchangePlan& exchange,
|
||||||
@@ -355,11 +377,25 @@ resolveRequirementPoint(DeferredTransferPlan& plan,
|
|||||||
else {
|
else {
|
||||||
if (position != 0 || !isa<SpatGraphCompute>(source.getOwner()))
|
if (position != 0 || !isa<SpatGraphCompute>(source.getOwner()))
|
||||||
return std::optional<RequirementPoint>();
|
return std::optional<RequirementPoint>();
|
||||||
point.fragmentType = source.getType();
|
point.fragmentType = leaf.form == DeferredLeafForm::ScalarProjection
|
||||||
|
? Type(leaf.reconstructedType)
|
||||||
|
: source.getType();
|
||||||
auto producer = findProducer(plan, exchange.deferred, graphId.getInt(), source.getResultNumber(), std::nullopt);
|
auto producer = findProducer(plan, exchange.deferred, graphId.getInt(), source.getResultNumber(), std::nullopt);
|
||||||
if (failed(producer))
|
if (failed(producer))
|
||||||
return failure();
|
return failure();
|
||||||
point.producer = *producer;
|
point.producer = *producer;
|
||||||
|
if (leaf.form == DeferredLeafForm::ScalarProjection) {
|
||||||
|
RequirementPoint::SliceGeometry geometry;
|
||||||
|
auto offsets = evaluateGeometryValues(leaf.leadingGeometry.offsets, evaluator, lane);
|
||||||
|
auto sizes = evaluateGeometryValues(leaf.leadingGeometry.sizes, evaluator, lane);
|
||||||
|
auto strides = evaluateGeometryValues(leaf.leadingGeometry.strides, evaluator, lane);
|
||||||
|
if (failed(offsets) || failed(sizes) || failed(strides))
|
||||||
|
return failure();
|
||||||
|
geometry.offsets = std::move(*offsets);
|
||||||
|
geometry.sizes = std::move(*sizes);
|
||||||
|
geometry.strides = std::move(*strides);
|
||||||
|
point.producerProjection = std::move(geometry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return std::optional<RequirementPoint>(point);
|
return std::optional<RequirementPoint>(point);
|
||||||
}
|
}
|
||||||
@@ -384,6 +420,27 @@ static void appendRequirementFamily(DeferredExchangePlan& exchange,
|
|||||||
};
|
};
|
||||||
family.graphLanes = sequence(&RequirementPoint::graphLane);
|
family.graphLanes = sequence(&RequirementPoint::graphLane);
|
||||||
family.producerLocalOffsets = sequence(&RequirementPoint::localOffset);
|
family.producerLocalOffsets = sequence(&RequirementPoint::localOffset);
|
||||||
|
if (points.front().producerProjection) {
|
||||||
|
family.producerProjection.emplace();
|
||||||
|
auto appendGeometry = [&](auto member,
|
||||||
|
SmallVectorImpl<StaticIntSequence>& target) {
|
||||||
|
for (size_t dimension = 0;
|
||||||
|
dimension < ((*points.front().producerProjection).*member).size();
|
||||||
|
++dimension) {
|
||||||
|
SmallVector<int64_t> values;
|
||||||
|
values.reserve(points.size());
|
||||||
|
for (const RequirementPoint& point : points)
|
||||||
|
values.push_back(((*point.producerProjection).*member)[dimension]);
|
||||||
|
target.push_back(StaticIntSequence::fromValues(values));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
appendGeometry(&RequirementPoint::SliceGeometry::offsets,
|
||||||
|
family.producerProjection->offsets);
|
||||||
|
appendGeometry(&RequirementPoint::SliceGeometry::sizes,
|
||||||
|
family.producerProjection->sizes);
|
||||||
|
appendGeometry(&RequirementPoint::SliceGeometry::strides,
|
||||||
|
family.producerProjection->strides);
|
||||||
|
}
|
||||||
exchange.requirements.push_back(std::move(family));
|
exchange.requirements.push_back(std::move(family));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user