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) {
191 isa<acc::OutlineRematerializationOpInterface>(definingOp)) {
192 LLVM_DEBUG(llvm::dbgs()
193 <<
"\t\t-> OutlineRematerializationOpInterface (direct)\n");
198 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> not a candidate\n");
202class OffloadLiveInValueCanonicalization
203 :
public acc::impl::OffloadLiveInValueCanonicalizationBase<
204 OffloadLiveInValueCanonicalization> {
206 using acc::impl::OffloadLiveInValueCanonicalizationBase<
207 OffloadLiveInValueCanonicalization>::
208 OffloadLiveInValueCanonicalizationBase;
212 bool canonicalizeLiveInValues(
Region ®ion,
217 LLVM_DEBUG(llvm::dbgs()
218 <<
"\tFound " << liveInValues.size() <<
" live-in value(s)\n");
220 auto isSinkCandidate = [®ion, &accSupport](
Value val) ->
bool {
221 return isRematerializationCandidate(val, accSupport) &&
222 allUsersAreInsideRegion(val, region);
224 auto isCloneCandidate = [®ion, &accSupport](
Value val) ->
bool {
225 return isRematerializationCandidate(val, accSupport) &&
226 !allUsersAreInsideRegion(val, region);
231 llvm::make_filter_range(liveInValues, isSinkCandidate));
233 llvm::make_filter_range(liveInValues, isCloneCandidate));
235 LLVM_DEBUG(llvm::dbgs() <<
"\tSink candidates: " << sinkCandidates.size()
236 <<
", clone candidates: "
237 << rematerializationCandidates.size() <<
"\n");
239 if (rematerializationCandidates.empty() && sinkCandidates.empty())
242 LLVM_DEBUG(llvm::dbgs() <<
"\tCanonicalizing values into "
246 for (
Value sinkCandidate : sinkCandidates) {
247 Operation *sinkOp = sinkCandidate.getDefiningOp();
248 assert(sinkOp &&
"must have op to be considered");
250 LLVM_DEBUG(llvm::dbgs() <<
"\t\tSunk: " << *sinkOp <<
"\n");
257 for (
Value rematerializationCandidate : rematerializationCandidates) {
259 rematerializationCandidate.getDefiningOp();
260 assert(rematerializationOp &&
"must have op to be considered");
261 opsToRematerialize.push_back(rematerializationOp);
264 for (
Operation *rematerializationOp : opsToRematerialize) {
266 for (
auto [oldResult, newResult] : llvm::zip(
267 rematerializationOp->getResults(), clonedOp->
getResults())) {
270 LLVM_DEBUG(llvm::dbgs() <<
"\t\tCloned: " << *clonedOp <<
"\n");
276 void runOnOperation()
override {
277 LLVM_DEBUG(llvm::dbgs() <<
"Enter OffloadLiveInValueCanonicalization\n");
283 if (
auto parentAnalysis = getCachedParentAnalysis<acc::OpenACCSupport>())
284 accSupportPtr = &parentAnalysis->get();
286 accSupportPtr = &getAnalysis<acc::OpenACCSupport>();
289 func::FuncOp
func = getOperation();
290 LLVM_DEBUG(llvm::dbgs()
291 <<
"Processing function: " <<
func.getName() <<
"\n");
294 if (isa<acc::OffloadRegionOpInterface>(op)) {
295 LLVM_DEBUG(llvm::dbgs()
296 <<
"Found offload region: " << op->
getName() <<
"\n");
301 bool changes =
false;
302 [[maybe_unused]]
int iteration = 0;
304 LLVM_DEBUG(llvm::dbgs() <<
"\tIteration " << iteration++ <<
"\n");
305 changes = canonicalizeLiveInValues(op->
getRegion(0), accSupport);
307 LLVM_DEBUG(llvm::dbgs()
308 <<
"\tConverged after " << iteration <<
" iteration(s)\n");
312 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.