89#define GEN_PASS_DEF_OFFLOADLIVEINVALUECANONICALIZATION
90#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
94#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
202 :
public acc::impl::OffloadLiveInValueCanonicalizationBase<
203 OffloadLiveInValueCanonicalization> {
205 using acc::impl::OffloadLiveInValueCanonicalizationBase<
206 OffloadLiveInValueCanonicalization>::
207 OffloadLiveInValueCanonicalizationBase;
211 bool canonicalizeLiveInValues(
Region ®ion,
216 LLVM_DEBUG(llvm::dbgs()
217 <<
"\tFound " << liveInValues.size() <<
" live-in value(s)\n");
219 auto isSinkCandidate = [®ion, &accSupport](
Value val) ->
bool {
220 return isRematerializationCandidate(val, accSupport) &&
221 allUsersAreInsideRegion(val, region);
223 auto isCloneCandidate = [®ion, &accSupport](
Value val) ->
bool {
224 return isRematerializationCandidate(val, accSupport) &&
225 !allUsersAreInsideRegion(val, region);
230 llvm::make_filter_range(liveInValues, isSinkCandidate));
232 llvm::make_filter_range(liveInValues, isCloneCandidate));
234 LLVM_DEBUG(llvm::dbgs() <<
"\tSink candidates: " << sinkCandidates.size()
235 <<
", clone candidates: "
236 << rematerializationCandidates.size() <<
"\n");
238 if (rematerializationCandidates.empty() && sinkCandidates.empty())
241 LLVM_DEBUG(llvm::dbgs() <<
"\tCanonicalizing values into "
245 for (
Value sinkCandidate : sinkCandidates) {
246 Operation *sinkOp = sinkCandidate.getDefiningOp();
247 assert(sinkOp &&
"must have op to be considered");
249 LLVM_DEBUG(llvm::dbgs() <<
"\t\tSunk: " << *sinkOp <<
"\n");
256 for (
Value rematerializationCandidate : rematerializationCandidates) {
258 rematerializationCandidate.getDefiningOp();
259 assert(rematerializationOp &&
"must have op to be considered");
260 opsToRematerialize.push_back(rematerializationOp);
263 for (
Operation *rematerializationOp : opsToRematerialize) {
265 for (
auto [oldResult, newResult] : llvm::zip(
266 rematerializationOp->getResults(), clonedOp->
getResults())) {
269 LLVM_DEBUG(llvm::dbgs() <<
"\t\tCloned: " << *clonedOp <<
"\n");
275 void runOnOperation()
override {
276 LLVM_DEBUG(llvm::dbgs() <<
"Enter OffloadLiveInValueCanonicalization\n");
282 if (
auto parentAnalysis = getCachedParentAnalysis<acc::OpenACCSupport>())
283 accSupportPtr = &parentAnalysis->get();
285 accSupportPtr = &getAnalysis<acc::OpenACCSupport>();
288 func::FuncOp
func = getOperation();
289 LLVM_DEBUG(llvm::dbgs()
290 <<
"Processing function: " <<
func.getName() <<
"\n");
293 if (isa<acc::OffloadRegionOpInterface>(op)) {
294 LLVM_DEBUG(llvm::dbgs()
295 <<
"Found offload region: " << op->
getName() <<
"\n");
300 bool changes =
false;
301 [[maybe_unused]]
int iteration = 0;
303 LLVM_DEBUG(llvm::dbgs() <<
"\tIteration " << iteration++ <<
"\n");
304 changes = canonicalizeLiveInValues(op->
getRegion(0), accSupport);
306 LLVM_DEBUG(llvm::dbgs()
307 <<
"\tConverged after " << iteration <<
" iteration(s)\n");
311 LLVM_DEBUG(llvm::dbgs() <<
"Exit OffloadLiveInValueCanonicalization\n");
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.
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.