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");
184 LLVM_DEBUG(llvm::dbgs() <<
"\t\t-> not a candidate\n");
188class OffloadLiveInValueCanonicalization
189 :
public acc::impl::OffloadLiveInValueCanonicalizationBase<
190 OffloadLiveInValueCanonicalization> {
192 using acc::impl::OffloadLiveInValueCanonicalizationBase<
193 OffloadLiveInValueCanonicalization>::
194 OffloadLiveInValueCanonicalizationBase;
198 bool canonicalizeLiveInValues(
Region ®ion,
203 LLVM_DEBUG(llvm::dbgs()
204 <<
"\tFound " << liveInValues.size() <<
" live-in value(s)\n");
206 auto isSinkCandidate = [®ion, &accSupport](
Value val) ->
bool {
207 return isRematerializationCandidate(val, accSupport) &&
208 allUsersAreInsideRegion(val, region);
210 auto isCloneCandidate = [®ion, &accSupport](
Value val) ->
bool {
211 return isRematerializationCandidate(val, accSupport) &&
212 !allUsersAreInsideRegion(val, region);
217 llvm::make_filter_range(liveInValues, isSinkCandidate));
219 llvm::make_filter_range(liveInValues, isCloneCandidate));
221 LLVM_DEBUG(llvm::dbgs() <<
"\tSink candidates: " << sinkCandidates.size()
222 <<
", clone candidates: "
223 << rematerializationCandidates.size() <<
"\n");
225 if (rematerializationCandidates.empty() && sinkCandidates.empty())
228 LLVM_DEBUG(llvm::dbgs() <<
"\tCanonicalizing values into "
232 for (
Value sinkCandidate : sinkCandidates) {
233 Operation *sinkOp = sinkCandidate.getDefiningOp();
234 assert(sinkOp &&
"must have op to be considered");
236 LLVM_DEBUG(llvm::dbgs() <<
"\t\tSunk: " << *sinkOp <<
"\n");
243 for (
Value rematerializationCandidate : rematerializationCandidates) {
245 rematerializationCandidate.getDefiningOp();
246 assert(rematerializationOp &&
"must have op to be considered");
247 opsToRematerialize.push_back(rematerializationOp);
250 for (
Operation *rematerializationOp : opsToRematerialize) {
252 for (
auto [oldResult, newResult] : llvm::zip(
253 rematerializationOp->getResults(), clonedOp->
getResults())) {
256 LLVM_DEBUG(llvm::dbgs() <<
"\t\tCloned: " << *clonedOp <<
"\n");
262 void runOnOperation()
override {
263 LLVM_DEBUG(llvm::dbgs() <<
"Enter OffloadLiveInValueCanonicalization\n");
269 if (
auto parentAnalysis = getCachedParentAnalysis<acc::OpenACCSupport>())
270 accSupportPtr = &parentAnalysis->get();
272 accSupportPtr = &getAnalysis<acc::OpenACCSupport>();
275 func::FuncOp
func = getOperation();
276 LLVM_DEBUG(llvm::dbgs()
277 <<
"Processing function: " <<
func.getName() <<
"\n");
280 if (isa<acc::OffloadRegionOpInterface>(op)) {
281 LLVM_DEBUG(llvm::dbgs()
282 <<
"Found offload region: " << op->
getName() <<
"\n");
287 bool changes =
false;
288 [[maybe_unused]]
int iteration = 0;
290 LLVM_DEBUG(llvm::dbgs() <<
"\tIteration " << iteration++ <<
"\n");
291 changes = canonicalizeLiveInValues(op->
getRegion(0), accSupport);
293 LLVM_DEBUG(llvm::dbgs()
294 <<
"\tConverged after " << iteration <<
" iteration(s)\n");
298 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.