Skip to content

Commit dcc692a

Browse files
authored
[MLIR][Target/Cpp] Natural induction variable naming. (#136102)
Changed naming of loop induction variables to follow natural naming (i, j, k, ...). This helps readability and locating positions referred to. Created new scopes to represent different behavior at function and loop level, to still enable re-using value names between different functions (as before). Removed unused scoping at other levels.
1 parent 99df642 commit dcc692a

File tree

2 files changed

+157
-27
lines changed

2 files changed

+157
-27
lines changed

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ struct CppEmitter {
186186
/// Return the existing or a new name for a Value.
187187
StringRef getOrCreateName(Value val);
188188

189+
/// Return the existing or a new name for a loop induction variable of an
190+
/// emitc::ForOp.
191+
StringRef getOrCreateInductionVarName(Value val);
192+
189193
// Returns the textual representation of a subscript operation.
190194
std::string getSubscriptName(emitc::SubscriptOp op);
191195

@@ -201,23 +205,39 @@ struct CppEmitter {
201205
/// Whether to map an mlir integer to a unsigned integer in C++.
202206
bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
203207

204-
/// RAII helper function to manage entering/exiting C++ scopes.
208+
/// Abstract RAII helper function to manage entering/exiting C++ scopes.
205209
struct Scope {
210+
~Scope() { emitter.labelInScopeCount.pop(); }
211+
212+
private:
213+
llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
214+
llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
215+
216+
protected:
206217
Scope(CppEmitter &emitter)
207218
: valueMapperScope(emitter.valueMapper),
208219
blockMapperScope(emitter.blockMapper), emitter(emitter) {
209-
emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
210220
emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
211221
}
212-
~Scope() {
213-
emitter.valueInScopeCount.pop();
214-
emitter.labelInScopeCount.pop();
222+
CppEmitter &emitter;
223+
};
224+
225+
/// RAII helper function to manage entering/exiting functions, while re-using
226+
/// value names.
227+
struct FunctionScope : Scope {
228+
FunctionScope(CppEmitter &emitter) : Scope(emitter) {
229+
// Re-use value names.
230+
emitter.resetValueCounter();
215231
}
232+
};
216233

217-
private:
218-
llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
219-
llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
220-
CppEmitter &emitter;
234+
/// RAII helper function to manage entering/exiting emitc::forOp loops and
235+
/// handle induction variable naming.
236+
struct LoopScope : Scope {
237+
LoopScope(CppEmitter &emitter) : Scope(emitter) {
238+
emitter.increaseLoopNestingLevel();
239+
}
240+
~LoopScope() { emitter.decreaseLoopNestingLevel(); }
221241
};
222242

223243
/// Returns wether the Value is assigned to a C++ variable in the scope.
@@ -253,6 +273,15 @@ struct CppEmitter {
253273
return operandExpression == emittedExpression;
254274
};
255275

276+
// Resets the value counter to 0.
277+
void resetValueCounter();
278+
279+
// Increases the loop nesting level by 1.
280+
void increaseLoopNestingLevel();
281+
282+
// Decreases the loop nesting level by 1.
283+
void decreaseLoopNestingLevel();
284+
256285
private:
257286
using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
258287
using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
@@ -274,11 +303,19 @@ struct CppEmitter {
274303
/// Map from block to name of C++ label.
275304
BlockMapper blockMapper;
276305

277-
/// The number of values in the current scope. This is used to declare the
278-
/// names of values in a scope.
279-
std::stack<int64_t> valueInScopeCount;
306+
/// Default values representing outermost scope.
307+
llvm::ScopedHashTableScope<Value, std::string> defaultValueMapperScope;
308+
llvm::ScopedHashTableScope<Block *, std::string> defaultBlockMapperScope;
309+
280310
std::stack<int64_t> labelInScopeCount;
281311

312+
/// Keeps track of the amount of nested loops the emitter currently operates
313+
/// in.
314+
uint64_t loopNestingLevel{0};
315+
316+
/// Emitter-level count of created values to enable unique identifiers.
317+
unsigned int valueCount{0};
318+
282319
/// State of the current expression being emitted.
283320
ExpressionOp emittedExpression;
284321
SmallVector<int> emittedExpressionPrecedence;
@@ -860,7 +897,6 @@ static LogicalResult printOperation(CppEmitter &emitter,
860897
}
861898

862899
static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) {
863-
864900
raw_indented_ostream &os = emitter.ostream();
865901

866902
// Utility function to determine whether a value is an expression that will be
@@ -879,12 +915,12 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) {
879915
emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
880916
return failure();
881917
os << " ";
882-
os << emitter.getOrCreateName(forOp.getInductionVar());
918+
os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
883919
os << " = ";
884920
if (failed(emitter.emitOperand(forOp.getLowerBound())))
885921
return failure();
886922
os << "; ";
887-
os << emitter.getOrCreateName(forOp.getInductionVar());
923+
os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
888924
os << " < ";
889925
Value upperBound = forOp.getUpperBound();
890926
bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
@@ -895,13 +931,15 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) {
895931
if (upperBoundRequiresParentheses)
896932
os << ")";
897933
os << "; ";
898-
os << emitter.getOrCreateName(forOp.getInductionVar());
934+
os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
899935
os << " += ";
900936
if (failed(emitter.emitOperand(forOp.getStep())))
901937
return failure();
902938
os << ") {\n";
903939
os.indent();
904940

941+
CppEmitter::LoopScope lScope(emitter);
942+
905943
Region &forRegion = forOp.getRegion();
906944
auto regionOps = forRegion.getOps();
907945

@@ -988,8 +1026,6 @@ static LogicalResult printOperation(CppEmitter &emitter,
9881026
}
9891027

9901028
static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
991-
CppEmitter::Scope scope(emitter);
992-
9931029
for (Operation &op : moduleOp) {
9941030
if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
9951031
return failure();
@@ -998,7 +1034,6 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
9981034
}
9991035

10001036
static LogicalResult printOperation(CppEmitter &emitter, ClassOp classOp) {
1001-
CppEmitter::Scope classScope(emitter);
10021037
raw_indented_ostream &os = emitter.ostream();
10031038
os << "class " << classOp.getSymName();
10041039
if (classOp.getFinalSpecifier())
@@ -1044,8 +1079,6 @@ static LogicalResult printOperation(CppEmitter &emitter, FileOp file) {
10441079
if (!emitter.shouldEmitFile(file))
10451080
return success();
10461081

1047-
CppEmitter::Scope scope(emitter);
1048-
10491082
for (Operation &op : file) {
10501083
if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
10511084
return failure();
@@ -1161,7 +1194,7 @@ static LogicalResult printOperation(CppEmitter &emitter,
11611194
return functionOp.emitOpError() << "cannot emit array type as result type";
11621195
}
11631196

1164-
CppEmitter::Scope scope(emitter);
1197+
CppEmitter::FunctionScope scope(emitter);
11651198
raw_indented_ostream &os = emitter.ostream();
11661199
if (failed(emitter.emitTypes(functionOp.getLoc(),
11671200
functionOp.getFunctionType().getResults())))
@@ -1189,7 +1222,7 @@ static LogicalResult printOperation(CppEmitter &emitter,
11891222
"with multiple blocks needs variables declared at top");
11901223
}
11911224

1192-
CppEmitter::Scope scope(emitter);
1225+
CppEmitter::FunctionScope scope(emitter);
11931226
raw_indented_ostream &os = emitter.ostream();
11941227
if (functionOp.getSpecifiers()) {
11951228
for (Attribute specifier : functionOp.getSpecifiersAttr()) {
@@ -1223,7 +1256,6 @@ static LogicalResult printOperation(CppEmitter &emitter,
12231256

12241257
static LogicalResult printOperation(CppEmitter &emitter,
12251258
DeclareFuncOp declareFuncOp) {
1226-
CppEmitter::Scope scope(emitter);
12271259
raw_indented_ostream &os = emitter.ostream();
12281260

12291261
auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
@@ -1255,8 +1287,8 @@ static LogicalResult printOperation(CppEmitter &emitter,
12551287
CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
12561288
StringRef fileId)
12571289
: os(os), declareVariablesAtTop(declareVariablesAtTop),
1258-
fileId(fileId.str()) {
1259-
valueInScopeCount.push(0);
1290+
fileId(fileId.str()), defaultValueMapperScope(valueMapper),
1291+
defaultBlockMapperScope(blockMapper) {
12601292
labelInScopeCount.push(0);
12611293
}
12621294

@@ -1297,7 +1329,26 @@ StringRef CppEmitter::getOrCreateName(Value val) {
12971329
assert(!hasDeferredEmission(val.getDefiningOp()) &&
12981330
"cacheDeferredOpResult should have been called on this value, "
12991331
"update the emitOperation function.");
1300-
valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top()));
1332+
1333+
valueMapper.insert(val, formatv("v{0}", ++valueCount));
1334+
}
1335+
return *valueMapper.begin(val);
1336+
}
1337+
1338+
/// Return the existing or a new name for a loop induction variable Value.
1339+
/// Loop induction variables follow natural naming: i, j, k, ..., t, uX.
1340+
StringRef CppEmitter::getOrCreateInductionVarName(Value val) {
1341+
if (!valueMapper.count(val)) {
1342+
1343+
int64_t identifier = 'i' + loopNestingLevel;
1344+
1345+
if (identifier >= 'i' && identifier <= 't') {
1346+
valueMapper.insert(val,
1347+
formatv("{0}{1}", (char)identifier, ++valueCount));
1348+
} else {
1349+
// If running out of letters, continue with uX.
1350+
valueMapper.insert(val, formatv("u{0}", ++valueCount));
1351+
}
13011352
}
13021353
return *valueMapper.begin(val);
13031354
}
@@ -1838,6 +1889,12 @@ LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
18381889
return success();
18391890
}
18401891

1892+
void CppEmitter::resetValueCounter() { valueCount = 0; }
1893+
1894+
void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; }
1895+
1896+
void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; }
1897+
18411898
LogicalResult emitc::translateToCpp(Operation *op, raw_ostream &os,
18421899
bool declareVariablesAtTop,
18431900
StringRef fileId) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s
2+
3+
// CHECK-LABEL: test_for_siblings
4+
func.func @test_for_siblings() {
5+
%start = emitc.literal "0" : index
6+
%stop = emitc.literal "10" : index
7+
%step = emitc.literal "1" : index
8+
9+
%var1 = "emitc.variable"() <{value = 0 : index}> : () -> !emitc.lvalue<index>
10+
%var2 = "emitc.variable"() <{value = 0 : index}> : () -> !emitc.lvalue<index>
11+
12+
// CHECK: for (size_t [[ITER0:i[0-9]*]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) {
13+
emitc.for %i0 = %start to %stop step %step {
14+
// CHECK: for (size_t [[ITER1:j[0-9]*]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) {
15+
emitc.for %i1 = %start to %stop step %step {
16+
// CHECK: {{.*}} = [[ITER0]];
17+
//"emitc.assign"(%var1,%i0) : (!emitc.lvalue<!emitc.size_t>, !emitc.size_t) -> ()
18+
emitc.assign %i0 : index to %var1 : !emitc.lvalue<index>
19+
// CHECK: {{.*}} = [[ITER1]];
20+
//"emitc.assign"(%var2,%i1) : (!emitc.lvalue<!emitc.size_t>, !emitc.size_t) -> ()
21+
emitc.assign %i1 : index to %var2 : !emitc.lvalue<index>
22+
}
23+
}
24+
// CHECK: for (size_t [[ITER2:i[0-9]*]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}})
25+
emitc.for %ki2 = %start to %stop step %step {
26+
// CHECK: for (size_t [[ITER3:j[0-9]*]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}})
27+
emitc.for %i3 = %start to %stop step %step {
28+
%1 = emitc.call_opaque "f"() : () -> i32
29+
}
30+
}
31+
return
32+
}
33+
34+
// CHECK-LABEL: test_for_nesting
35+
func.func @test_for_nesting() {
36+
%start = emitc.literal "0" : index
37+
%stop = emitc.literal "10" : index
38+
%step = emitc.literal "1" : index
39+
40+
// CHECK-COUNT-12: for (size_t [[ITER:[i-t][0-9]*]] = {{.*}}; [[ITER]] < {{.*}}; [[ITER]] += {{.*}}) {
41+
emitc.for %i0 = %start to %stop step %step {
42+
emitc.for %i1 = %start to %stop step %step {
43+
emitc.for %i2 = %start to %stop step %step {
44+
emitc.for %i3 = %start to %stop step %step {
45+
emitc.for %i4 = %start to %stop step %step {
46+
emitc.for %i5 = %start to %stop step %step {
47+
emitc.for %i6 = %start to %stop step %step {
48+
emitc.for %i7 = %start to %stop step %step {
49+
emitc.for %i8 = %start to %stop step %step {
50+
emitc.for %i9 = %start to %stop step %step {
51+
emitc.for %i10 = %start to %stop step %step {
52+
emitc.for %i11 = %start to %stop step %step {
53+
// CHECK: for (size_t [[ITERu0:u13]] = {{.*}}; [[ITERu0]] < {{.*}}; [[ITERu0]] += {{.*}}) {
54+
emitc.for %i14 = %start to %stop step %step {
55+
// CHECK: for (size_t [[ITERu1:u14]] = {{.*}}; [[ITERu1]] < {{.*}}; [[ITERu1]] += {{.*}}) {
56+
emitc.for %i15 = %start to %stop step %step {
57+
%0 = emitc.call_opaque "f"() : () -> i32
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}
69+
}
70+
}
71+
}
72+
return
73+
}

0 commit comments

Comments
 (0)