Skip to content

Commit 4d4e625

Browse files
ekayaaslancopybara-github
authored andcommitted
Reverts 847b2a2
PiperOrigin-RevId: 899495748
1 parent afd6583 commit 4d4e625

3 files changed

Lines changed: 339 additions & 576 deletions

File tree

shardy/dialect/sdy/transforms/import/constant_or_scalar_splitter.cc

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ limitations under the License.
2626
#include "mlir/IR/OpDefinition.h"
2727
#include "mlir/IR/Operation.h"
2828
#include "mlir/IR/PatternMatch.h"
29-
#include "mlir/IR/SymbolTable.h"
3029
#include "mlir/IR/Value.h"
3130
#include "mlir/IR/Visitors.h"
3231
#include "mlir/Interfaces/SideEffectInterfaces.h"
@@ -49,7 +48,6 @@ namespace sdy {
4948

5049
namespace {
5150

52-
using func::CallOp;
5351
using func::FuncOp;
5452

5553
void cloneShardingGroupUsers(OpResult opResult, IRMapping& mapping,
@@ -67,12 +65,14 @@ void cloneShardingGroupUsers(OpResult opResult, IRMapping& mapping,
6765
// given op is either:
6866
// - A broadcast, reshape or slice op.
6967
// - An elementwise op.
70-
// - A call to a func that all operations are constant preserving.
68+
// - A named computation all operations are constant preserving.
7169
// Assumes the op is not constant or iota.
7270
bool isConstantPreserving(
73-
Operation* op, const llvm::SmallDenseSet<StringRef>& nonConstFuncOps) {
74-
if (CallOp callOp = dyn_cast<CallOp>(op)) {
75-
return !nonConstFuncOps.contains(callOp.getCallee());
71+
Operation* op,
72+
const llvm::SmallDenseSet<StringRef>& nonConstantNamedComputationOps) {
73+
if (auto namedComputationOp = dyn_cast<NamedComputationOp>(op)) {
74+
return !nonConstantNamedComputationOps.contains(
75+
namedComputationOp.getName());
7676
}
7777
if (!isPure(op)) {
7878
return false;
@@ -93,11 +93,11 @@ bool isConstantPreserving(
9393
// constants, that is, exist in `constantOps`.
9494
bool isConstantExpression(
9595
Operation* op, const llvm::SetVector<Operation*>& constantOps,
96-
const llvm::SmallDenseSet<StringRef>& nonConstFuncOps) {
96+
const llvm::SmallDenseSet<StringRef>& nonConstantNamedComputationOps) {
9797
if (isa<ConstantOp, stablehlo::IotaOp>(op)) {
9898
return true;
9999
}
100-
return isConstantPreserving(op, nonConstFuncOps) &&
100+
return isConstantPreserving(op, nonConstantNamedComputationOps) &&
101101
llvm::all_of(op->getOperands(), [&](Value operand) {
102102
return operand.getDefiningOp() &&
103103
constantOps.contains(operand.getDefiningOp());
@@ -117,26 +117,20 @@ bool isScalarExpansion(Operation* op) {
117117
// Recursively clones all operands of the given op, that are not already mapped
118118
// in `mapping`, and finally clones the op itself. We do not clone scalars as
119119
// they do not get sharded.
120-
void cloneSubComputation(OpResult opResult, IRMapping& mapping,
121-
SymbolTable& symbolTable) {
120+
void cloneSubComputation(OpResult opResult, IRMapping& mapping) {
122121
if (isScalar(opResult) || mapping.lookupOrNull(opResult)) {
123122
return;
124123
}
125124
Operation* op = opResult.getOwner();
126125
for (Value operand : op->getOperands()) {
127126
if (auto defOpResult = dyn_cast<OpResult>(operand)) {
128-
cloneSubComputation(defOpResult, mapping, symbolTable);
127+
cloneSubComputation(defOpResult, mapping);
129128
}
130129
}
131130

132131
// This will insert the cloned op right before the original op.
133132
OpBuilder builder(op);
134-
Operation* clonedOp = builder.clone(*op, mapping);
135-
if (CallOp callOp = dyn_cast<CallOp>(clonedOp)) {
136-
FuncOp funcOp = symbolTable.lookup<FuncOp>(callOp.getCallee());
137-
callOp.setCallee(
138-
symbolTable.insert(cloneFuncRecursively(funcOp, symbolTable)));
139-
}
133+
builder.clone(*op, mapping);
140134
cloneShardingGroupUsers(opResult, mapping, builder);
141135
}
142136

@@ -145,19 +139,18 @@ void cloneSubComputation(OpResult opResult, IRMapping& mapping,
145139
// sharded.
146140
//
147141
// Returns the cloned op result.
148-
Value cloneSubComputation(OpResult opResult, SymbolTable& symbolTable) {
142+
Value cloneSubComputation(OpResult opResult) {
149143
if (isScalar(opResult)) {
150144
return opResult;
151145
}
152146
IRMapping mapping;
153-
cloneSubComputation(opResult, mapping, symbolTable);
147+
cloneSubComputation(opResult, mapping);
154148
return mapping.lookup(opResult);
155149
}
156150

157151
void cloneSubComputationOnOperands(
158152
Operation* op, const llvm::SetVector<Operation*>& constantOps,
159-
const llvm::SetVector<Operation*>& scalarExpansionOps,
160-
SymbolTable& symbolTable) {
153+
const llvm::SetVector<Operation*>& scalarExpansionOps) {
161154
for (OpOperand& operand : op->getOpOperands()) {
162155
if (auto defOpResult = dyn_cast<OpResult>(operand.get());
163156
defOpResult && (constantOps.contains(defOpResult.getOwner()) ||
@@ -167,38 +160,38 @@ void cloneSubComputationOnOperands(
167160
// `defOpResult`, and replace the `operand` with the cloned defining
168161
// op. The cloned constant sub-computation has only one user `op`,
169162
// so that it is isolated from the rest of the computation.
170-
operand.set(cloneSubComputation(defOpResult, symbolTable));
163+
operand.set(cloneSubComputation(defOpResult));
171164
}
172165
}
173166
}
174167

175-
void processOp(Operation* op, FuncOp funcOp,
176-
llvm::SetVector<Operation*>& constantOps,
168+
void processOp(Operation* op, llvm::SetVector<Operation*>& constantOps,
177169
llvm::SetVector<Operation*>& scalarExpansionOps,
178-
llvm::SmallDenseSet<StringRef>& nonConstFuncOps,
179-
SymbolTable& symbolTable) {
180-
if (isa<FuncOp, ShardingGroupOp>(op)) {
170+
llvm::SmallDenseSet<StringRef>& nonConstantNamedComputationOps) {
171+
if (isa<ShardingGroupOp>(op)) {
181172
return;
182173
}
183-
if (isConstantExpression(op, constantOps, nonConstFuncOps)) {
174+
if (isConstantExpression(op, constantOps, nonConstantNamedComputationOps)) {
184175
constantOps.insert(op);
185176
return;
186177
}
187178
// NOTE: There are cases that op is an constant expression but may not pass
188179
// the following check such as constant and iota ops. That is fine because if
189180
// the op is a constant expression it is a stronger condition than being just
190-
// constant preserving and it does not make the `funcOp` non-const, and at
191-
// this point, it is guaranteed that the op is not constant expression.
192-
if (!isConstantPreserving(op, nonConstFuncOps) &&
181+
// constant preserving and it does not make the parent named computation
182+
// non-const, and at this point, it is guaranteed that the op is not constant
183+
// expression.
184+
if (!isConstantPreserving(op, nonConstantNamedComputationOps) &&
193185
!op->hasTrait<OpTrait::IsTerminator>()) {
194-
nonConstFuncOps.insert(funcOp.getName());
186+
if (auto namedCompuationOp = op->getParentOfType<NamedComputationOp>()) {
187+
nonConstantNamedComputationOps.insert(namedCompuationOp.getName());
188+
}
195189
}
196190
if (isScalarExpansion(op)) {
197191
scalarExpansionOps.insert(op);
198192
return;
199193
}
200-
cloneSubComputationOnOperands(op, constantOps, scalarExpansionOps,
201-
symbolTable);
194+
cloneSubComputationOnOperands(op, constantOps, scalarExpansionOps);
202195
}
203196

204197
// Converts stablehlo::ConstantOp to sdy::ConstantOp.
@@ -247,14 +240,21 @@ struct ConstantOrScalarSplitterPass
247240
}
248241
}
249242

250-
void walkOnRegion(FuncOp funcOp,
251-
llvm::SmallDenseSet<StringRef>& nonConstFuncOps,
252-
SymbolTable& symbolTable) {
243+
// Assumes that the `NamedComputationOp` of the region are already walked, and
244+
// skips walking on them.
245+
void walkOnRegion(
246+
mlir::Region& region,
247+
llvm::SmallDenseSet<StringRef>& nonConstantNamedComputationOps) {
253248
llvm::SetVector<Operation*> constantOps;
254249
llvm::SetVector<Operation*> scalarExpansionOps;
255-
funcOp.walk<WalkOrder::PreOrder>([&](Operation* op) {
256-
processOp(op, funcOp, constantOps, scalarExpansionOps, nonConstFuncOps,
257-
symbolTable);
250+
region.walk<WalkOrder::PreOrder>([&](Operation* op) {
251+
processOp(op, constantOps, scalarExpansionOps,
252+
nonConstantNamedComputationOps);
253+
// Skip walking on the `NamedComputationOp`.
254+
if (isa<NamedComputationOp>(op)) {
255+
return WalkResult::skip();
256+
}
257+
return WalkResult::advance();
258258
});
259259
// Since for every op in `constantOps` that has a use that isn't in
260260
// `constantOps`, we replaced the use with a clone of the entire
@@ -267,7 +267,6 @@ struct ConstantOrScalarSplitterPass
267267

268268
void runOnOperation() final {
269269
ModuleOp moduleOp = getOperation();
270-
SymbolTable symbolTable(moduleOp);
271270

272271
// We first convert any `stablehlo::ConstantOp` to an `sdy::ConstantOp`, so
273272
// that constants won't be deduped via folding.
@@ -276,13 +275,17 @@ struct ConstantOrScalarSplitterPass
276275
}
277276

278277
// Then we split constant sub-computations for each non-constant user.
279-
llvm::SmallDenseSet<StringRef> nonConstFuncOps;
280-
FuncOp mainFuncOp = walkCallsOrDie(moduleOp, [&](CallOp callOp) {
281-
FuncOp funcOp = symbolTable.lookup<FuncOp>(callOp.getCallee());
282-
walkOnRegion(funcOp, nonConstFuncOps, symbolTable);
283-
return WalkResult::advance();
278+
llvm::SmallDenseSet<StringRef> nonConstantNamedComputationOps;
279+
// Iterate on a post-order of NamedComputationOp blocks.
280+
moduleOp.walk([&](NamedComputationOp namedComputationOp) {
281+
walkOnRegion(namedComputationOp.getBody(),
282+
nonConstantNamedComputationOps);
283+
});
284+
// Iterate order does not matter. Funcs do not call each other. The calls
285+
// are inlined to NamedComputationOps.
286+
moduleOp.walk([&](FuncOp funcOp) {
287+
walkOnRegion(funcOp.getBody(), nonConstantNamedComputationOps);
284288
});
285-
walkOnRegion(mainFuncOp, nonConstFuncOps, symbolTable);
286289
}
287290

288291
private:

shardy/dialect/sdy/transforms/import/import_pipeline.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ void addImportPipeline(OpPassManager& pm, int& dumpIndex,
3030
pm.addPass(createSymbolDCEPass());
3131
pm.addPass(createLiftInlinedMeshesPass());
3232
pm.addPass(createRemoveSizeOneAxesPass());
33+
pm.addPass(createImportFuncCallsPass());
34+
// Keep SymbolDCEPass after ImportFuncCallsPass.
35+
pm.addPass(createSymbolDCEPass());
3336
pm.addPass(createConstantOrScalarSplitterPass());
3437
pm.addPass(createSymbolDCEPass());
3538
pm.addPass(createManualAxesCleanupPass());
@@ -40,7 +43,6 @@ void addImportPipeline(OpPassManager& pm, int& dumpIndex,
4043
// of the propagation itself.
4144
pm.addPass(mlir::sdy::createSaveModuleOpPass(
4245
options.dumpDirectory, "before_propagation", dumpIndex++));
43-
pm.addPass(createImportFuncCallsPass());
4446

4547
pm.addNestedPass<func::FuncOp>(createAddDataFlowEdgesPass(
4648
AddDataFlowEdgesPassOptions{options.enableNativeNonFlatSupport}));

0 commit comments

Comments
 (0)