90#define GEN_PASS_DEF_OFFLOADLIVEINVALUECANONICALIZATION
91#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
95#define DEBUG_TYPE "offload-livein-value-canonicalization"
101static bool allUsersAreInsideRegion(
Value val,
Region ®ion) {
103 if (!region.
isAncestor(user->getParentRegion()))
112 while (val && val != prev) {
114 if (
auto viewLikeOp = val.
getDefiningOp<ViewLikeOpInterface>())
115 val = viewLikeOp.getViewSource();
116 if (
auto partialAccess =
118 Value base = partialAccess.getBaseEntity();
133static bool isRematerializationCandidate(
Value val,
136 Value origVal = getOriginalValue(val);
141 LLVM_DEBUG(llvm::dbgs() <<
"\tChecking candidate: " << *definingOp <<
"\n");
145 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> constant pattern matched\n");
150 if (isa<acc::OutlineRematerializationOpInterface>(definingOp)) {
151 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> OutlineRematerializationOpInterface\n");
157 if (
auto addrOfOp = dyn_cast<acc::AddressOfGlobalOpInterface>(definingOp)) {
158 SymbolRefAttr symbol = addrOfOp.getSymbol();
159 LLVM_DEBUG(llvm::dbgs()
160 <<
"\t\tAddressOfGlobalOpInterface, symbol: " << symbol <<
"\n");
166 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> isValidSymbolUse: true\n");
169 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> isValidSymbolUse: false\n");
174 if (
auto globalVarOp =
175 dyn_cast<acc::GlobalVariableOpInterface>(globalOp)) {
176 if (globalVarOp.isConstant()) {
177 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> constant global\n");
188 if (origVal != val) {
189 if (isa_and_nonnull<acc::OutlineRematerializationOpInterface>(
191 LLVM_DEBUG(llvm::dbgs()
192 <<
"\t\t-> OutlineRematerializationOpInterface (direct)\n");
197 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> not a candidate\n");
201class OffloadLiveInValueCanonicalization
203 OffloadLiveInValueCanonicalization> {
206 OffloadLiveInValueCanonicalization>::
207 OffloadLiveInValueCanonicalizationBase;
211 OffloadLiveInValueCanonicalization>::getDependentDialects(registry);
217 bool canonicalizeLiveInValues(
Region ®ion,
222 LLVM_DEBUG(llvm::dbgs()
223 <<
"\tFound " << liveInValues.size() <<
" live-in value(s)\n");
225 auto isSinkCandidate = [®ion, &accSupport](
Value val) ->
bool {
226 return isRematerializationCandidate(val, accSupport) &&
227 allUsersAreInsideRegion(val, region);
229 auto isCloneCandidate = [®ion, &accSupport](
Value val) ->
bool {
230 return isRematerializationCandidate(val, accSupport) &&
231 !allUsersAreInsideRegion(val, region);
236 llvm::make_filter_range(liveInValues, isSinkCandidate));
238 llvm::make_filter_range(liveInValues, isCloneCandidate));
240 LLVM_DEBUG(llvm::dbgs() <<
"\tSink candidates: " << sinkCandidates.size()
241 <<
", clone candidates: "
242 << rematerializationCandidates.size() <<
"\n");
244 if (rematerializationCandidates.empty() && sinkCandidates.empty())
247 LLVM_DEBUG(llvm::dbgs() <<
"\tCanonicalizing values into "
251 for (
Value sinkCandidate : sinkCandidates) {
252 Operation *sinkOp = sinkCandidate.getDefiningOp();
253 assert(sinkOp &&
"must have op to be considered");
259 if (
auto identityOp =
260 dyn_cast<acc::OutlineIdentityOperandOpInterface>(sinkOp))
261 identityOp.dropOutlinedIdentityOperands();
262 LLVM_DEBUG(llvm::dbgs() <<
"\t\tSunk: " << *sinkOp <<
"\n");
269 for (
Value rematerializationCandidate : rematerializationCandidates) {
271 rematerializationCandidate.getDefiningOp();
272 assert(rematerializationOp &&
"must have op to be considered");
273 opsToRematerialize.push_back(rematerializationOp);
276 for (
Operation *rematerializationOp : opsToRematerialize) {
283 if (
auto identityOp =
284 dyn_cast<acc::OutlineIdentityOperandOpInterface>(clonedOp))
285 identityOp.dropOutlinedIdentityOperands();
286 for (
auto [oldResult, newResult] : llvm::zip(
287 rematerializationOp->getResults(), clonedOp->
getResults())) {
290 LLVM_DEBUG(llvm::dbgs() <<
"\t\tCloned: " << *clonedOp <<
"\n");
296 void runOnOperation()
override {
297 LLVM_DEBUG(llvm::dbgs() <<
"Enter OffloadLiveInValueCanonicalization\n");
303 if (
auto parentAnalysis = getCachedParentAnalysis<acc::OpenACCSupport>())
304 accSupportPtr = &parentAnalysis->get();
306 accSupportPtr = &getAnalysis<acc::OpenACCSupport>();
309 func::FuncOp
func = getOperation();
310 LLVM_DEBUG(llvm::dbgs()
311 <<
"Processing function: " <<
func.getName() <<
"\n");
314 if (isa<acc::OffloadRegionOpInterface>(op)) {
315 LLVM_DEBUG(llvm::dbgs()
316 <<
"Found offload region: " << op->
getName() <<
"\n");
321 bool changes =
false;
322 [[maybe_unused]]
int iteration = 0;
324 LLVM_DEBUG(llvm::dbgs() <<
"\tIteration " << iteration++ <<
"\n");
325 changes = canonicalizeLiveInValues(op->
getRegion(0), accSupport);
327 LLVM_DEBUG(llvm::dbgs()
328 <<
"\tConverged after " << iteration <<
" iteration(s)\n");
332 LLVM_DEBUG(llvm::dbgs() <<
"Exit OffloadLiveInValueCanonicalization\n");
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
This class helps build Operations.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
Operation is the basic unit of execution within MLIR.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
unsigned getNumRegions()
Returns the number of regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
result_range getResults()
This class contains a list of basic blocks and a link to the parent operation it is attached to.
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
Operation * getParentOp()
Return the parent operation this region is attached to.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol, Operation **definingOpPtr=nullptr)
Check if a symbol use is valid for use in an OpenACC region.
void registerAllExtensions(DialectRegistry ®istry)
Register the standard OpenACC models for GPU, LLVM and MemRef IR.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
void replaceAllUsesInRegionWith(Value orig, Value replacement, Region ®ion)
Replace all uses of orig within the given region with replacement.
bool computeTopologicalSorting(MutableArrayRef< Operation * > ops, function_ref< bool(Value, Operation *)> isOperandReady=nullptr)
Compute a topological ordering of the given ops.
llvm::SetVector< T, Vector, Set, N > SetVector
void getUsedValuesDefinedAbove(Region ®ion, Region &limit, SetVector< Value > &values)
Fill values with a list of values defined at the ancestors of the limit region and used within region...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.