MLIR-AIE 1.4.5.dev
AIE2PShufflePlanner.h
Go to the documentation of this file.
1//===- AIE2PShufflePlanner.h - Static shuffles on AIE2P ---------*- C++ -*-===//
2//
3// Copyright (C) 2026 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7// Plans a static vector shuffle as a short sequence of AIE2P vshuffle modes
8// and splats, and lowers vector.shuffle and vector.transpose through it.
9//===----------------------------------------------------------------------===//
10
11#ifndef AIE_DIALECT_AIEVEC_TRANSFORMS_AIE2PSHUFFLEPLANNER_H
12#define AIE_DIALECT_AIEVEC_TRANSFORMS_AIE2PSHUFFLEPLANNER_H
13
15
16#include "mlir/Dialect/Vector/IR/VectorOps.h"
17#include "mlir/IR/PatternMatch.h"
18#include "mlir/Transforms/DialectConversion.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringMap.h"
21
22#include <memory>
23#include <optional>
24
25namespace xilinx::aievec {
26
27// A static shuffle as a gather over labelled lanes. Source k contributes the
28// labels offset(k) .. offset(k) + lanes(k) - 1, or the single label offset(k)
29// when it is a splat. Lane i of the result must hold label target[i]; a
30// negative target lane may hold anything.
32 unsigned elemBits = 0;
33 // Splats can be built with aievec.broadcast_scalar for this element type.
34 bool canSplat = false;
35 llvm::SmallVector<int64_t> sourceLanes;
36 llvm::SmallVector<bool> sourceIsSplat;
37 llvm::SmallVector<int32_t> target;
38
39 int32_t sourceOffset(unsigned k) const;
40 int32_t numLabels() const { return sourceOffset(sourceLanes.size()); }
41 std::string key() const;
42};
43
44// A gather to lower: lane i of a `resultType` value is lane mask[i] of
45// v1:v2, or poison for a negative mask entry. `user` is the op that reads v1
46// and v2; a vector.shuffle feeding only it may be folded into the gather.
48 mlir::Value v1, v2;
49 llvm::SmallVector<int64_t> mask;
50 mlir::VectorType resultType;
51 mlir::Operation *user;
52};
53
54// The registers a plan builds, in an order where operands come first, and the
55// register that holds each 512-bit part of the result.
57 struct Node {
59 // Source: the 512-bit part `chunk` of source `source`, padded when the
60 // source is smaller. Splat: every lane holds `label`. Shuffle: `mode`
61 // applied to nodes `lhs` and `rhs` (equal for one-input modes).
62 unsigned source = 0, chunk = 0;
63 int32_t label = -1;
64 ShuffleMode mode = ShuffleMode::T512_1X2_LO;
65 int lhs = -1, rhs = -1;
66 };
67 llvm::SmallVector<Node> nodes;
68 // -1 for a part with no lane to fill.
69 llvm::SmallVector<int> results;
70 // Vector instructions: shuffles and splats.
71 unsigned cost = 0;
72
73 // The distinct modes of the shuffles.
74 llvm::SmallVector<ShuffleMode> modes() const;
75};
76
77// Plans and caches the lowering of shuffles. A pattern and the legality
78// callback of the same conversion share one planner, so each distinct gather
79// is searched once. The planner also remembers the modes of the plans it has
80// lowered, so later plans prefer modes already loaded into registers.
82public:
83 // Plans for the gather, cheapest first, each the cheapest found for the
84 // modes it needs. Deterministic and bounded.
85 const llvm::SmallVector<ShufflePlan, 2> &
86 candidates(const ShuffleGather &gather);
87
88 // The plan to lower the request with, when one is cheaper than what LLVM
89 // makes of it. `gather` and `leaves` receive the gather the plan is for and
90 // the value behind each of its sources.
91 std::optional<ShufflePlan>
92 planFor(const ShuffleRequest &request, ShuffleGather *gather = nullptr,
93 llvm::SmallVector<mlir::Value> *leaves = nullptr);
94
95 // Records that `plan` has been emitted.
96 void noteUsed(const ShufflePlan &plan);
97
98private:
99 llvm::StringMap<llvm::SmallVector<ShufflePlan, 2>> cache;
100 llvm::SmallVector<ShuffleMode> usedModes;
101};
102
103// Estimated vector instructions LLVM spends on the gather: nothing for moves
104// of whole 256-bit halves, one per lane splat or lane-wise select, and about
105// one per lane when it falls back to inserting lanes one at a time.
106unsigned estimateLLVMShuffleCost(const ShuffleGather &gather);
107
108// Checks the plan by running it on lane labels with the byte permutation of
109// each mode. Returns false if any result lane differs from the target.
110bool simulateShufflePlan(const ShuffleGather &gather, const ShufflePlan &plan);
111
113 mlir::RewritePatternSet &patterns,
114 std::shared_ptr<AIE2PShufflePlanner> planner);
115
116// vector.shuffle, and rank-1 vector.interleave and vector.deinterleave, stay
117// legal unless the planner lowers them.
119 mlir::ConversionTarget &target,
120 std::shared_ptr<AIE2PShufflePlanner> planner);
121
122} // namespace xilinx::aievec
123
124#endif // AIE_DIALECT_AIEVEC_TRANSFORMS_AIE2PSHUFFLEPLANNER_H
std::optional< ShufflePlan > planFor(const ShuffleRequest &request, ShuffleGather *gather=nullptr, llvm::SmallVector< mlir::Value > *leaves=nullptr)
const llvm::SmallVector< ShufflePlan, 2 > & candidates(const ShuffleGather &gather)
void noteUsed(const ShufflePlan &plan)
void populateAIE2PShufflePlannerPatterns(mlir::RewritePatternSet &patterns, std::shared_ptr< AIE2PShufflePlanner > planner)
unsigned estimateLLVMShuffleCost(const ShuffleGather &gather)
void configureAIE2PShufflePlannerLegality(mlir::ConversionTarget &target, std::shared_ptr< AIE2PShufflePlanner > planner)
bool simulateShufflePlan(const ShuffleGather &gather, const ShufflePlan &plan)
llvm::SmallVector< int64_t > sourceLanes
int32_t sourceOffset(unsigned k) const
llvm::SmallVector< int32_t > target
llvm::SmallVector< bool > sourceIsSplat
enum xilinx::aievec::ShufflePlan::Node::Kind kind
llvm::SmallVector< int > results
llvm::SmallVector< Node > nodes
llvm::SmallVector< ShuffleMode > modes() const
llvm::SmallVector< int64_t > mask