From 05a9c3b807221233c71010b61bcaceaa5cc20147 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Tue, 8 Apr 2025 06:35:19 -0600 Subject: [PATCH 01/19] Working implementation --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 45 +++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index a2911386f12af..2f98fb5a6e01a 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -185,6 +185,9 @@ struct CppEmitter { /// Return the existing or a new name for a Value. StringRef getOrCreateName(Value val); + // Return the existing or a new name for an iteration variable Value + StringRef getOrCreateName(emitc::ForOp forOp); + // Returns the textual representation of a subscript operation. std::string getSubscriptName(emitc::SubscriptOp op); @@ -204,17 +207,22 @@ struct CppEmitter { struct Scope { Scope(CppEmitter &emitter) : valueMapperScope(emitter.valueMapper), + iterationVarMapperScope(emitter.iterationVarMapper), blockMapperScope(emitter.blockMapper), emitter(emitter) { emitter.valueInScopeCount.push(emitter.valueInScopeCount.top()); + emitter.iterationVarInScopeCount.push( + emitter.iterationVarInScopeCount.top()); emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); } ~Scope() { emitter.valueInScopeCount.pop(); + emitter.iterationVarInScopeCount.pop(); emitter.labelInScopeCount.pop(); } private: llvm::ScopedHashTableScope valueMapperScope; + llvm::ScopedHashTableScope iterationVarMapperScope; llvm::ScopedHashTableScope blockMapperScope; CppEmitter &emitter; }; @@ -285,12 +293,16 @@ struct CppEmitter { /// Map from value to name of C++ variable that contain the name. ValueMapper valueMapper; + // Map from value to name of C++ iteration variable that contains the name. + ValueMapper iterationVarMapper; + /// Map from block to name of C++ label. BlockMapper blockMapper; /// The number of values in the current scope. This is used to declare the /// names of values in a scope. std::stack valueInScopeCount; + std::stack iterationVarInScopeCount; std::stack labelInScopeCount; /// State of the current expression being emitted. @@ -930,12 +942,12 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType()))) return failure(); os << " "; - os << emitter.getOrCreateName(forOp.getInductionVar()); + os << emitter.getOrCreateName(forOp); os << " = "; if (failed(emitter.emitOperand(forOp.getLowerBound()))) return failure(); os << "; "; - os << emitter.getOrCreateName(forOp.getInductionVar()); + os << emitter.getOrCreateName(forOp); os << " < "; Value upperBound = forOp.getUpperBound(); bool upperBoundRequiresParentheses = requiresParentheses(upperBound); @@ -946,7 +958,7 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { if (upperBoundRequiresParentheses) os << ")"; os << "; "; - os << emitter.getOrCreateName(forOp.getInductionVar()); + os << emitter.getOrCreateName(forOp); os << " += "; if (failed(emitter.emitOperand(forOp.getStep()))) return failure(); @@ -1312,6 +1324,7 @@ CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, : os(os), declareVariablesAtTop(declareVariablesAtTop), onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { valueInScopeCount.push(0); + iterationVarInScopeCount.push(0); labelInScopeCount.push(0); } @@ -1348,15 +1361,39 @@ void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { - if (!valueMapper.count(val)) { + if (!valueMapper.count(val) && !iterationVarMapper.count(val)) { assert(!hasDeferredEmission(val.getDefiningOp()) && "cacheDeferredOpResult should have been called on this value, " "update the emitOperation function."); + valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); } + // Check whether value belongs to iteration variable + if (iterationVarMapper.count(val)) { + return *iterationVarMapper.begin(val); + } return *valueMapper.begin(val); } +/// Return the existing or a new name for an iteration variable Value. +// Iteration variables follow natural naming: i,j,k,... +StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { + Value val = forOp.getInductionVar(); + + if (!iterationVarMapper.count(val)) { + int64_t incdCount = iterationVarInScopeCount.top()++; + + if (incdCount >= 0 && incdCount <= 'z' - 'i') { + iterationVarMapper.insert(val, std::string(1, (char)(incdCount + 'i'))); + } else { + // If running out of letters, continue with iX + iterationVarMapper.insert(val, + formatv("i{0}", incdCount - ('z' - 'i') - 1)); + } + } + return *iterationVarMapper.begin(val); +} + /// Return the existing or a new label for a Block. StringRef CppEmitter::getOrCreateName(Block &block) { if (!blockMapper.count(&block)) From 4ba947887dba16eaa97fca88271155c64febef02 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Tue, 8 Apr 2025 06:36:47 -0600 Subject: [PATCH 02/19] Added test cases --- mlir/test/Target/Cpp/for_iteration_vars.mlir | 145 +++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 mlir/test/Target/Cpp/for_iteration_vars.mlir diff --git a/mlir/test/Target/Cpp/for_iteration_vars.mlir b/mlir/test/Target/Cpp/for_iteration_vars.mlir new file mode 100644 index 0000000000000..dee712192e7d0 --- /dev/null +++ b/mlir/test/Target/Cpp/for_iteration_vars.mlir @@ -0,0 +1,145 @@ +// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT + +func.func @test_for_siblings(%arg0 : !emitc.size_t, %arg1 : !emitc.size_t, %arg2 : !emitc.size_t) { + %lb = emitc.expression : !emitc.size_t { + %a = emitc.add %arg0, %arg1 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + emitc.yield %a : !emitc.size_t + } + %ub = emitc.expression : !emitc.size_t { + %a = emitc.mul %arg1, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + emitc.yield %a : !emitc.size_t + } + %step = emitc.expression : !emitc.size_t { + %a = emitc.div %arg0, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + emitc.yield %a : !emitc.size_t + } + emitc.for %i0 = %lb to %ub step %step { + emitc.for %i1 = %lb to %ub step %step { + %0 = emitc.call_opaque "f"() : () -> i32 + } + } + emitc.for %ki2 = %lb to %ub step %step { + emitc.for %i3 = %lb to %ub step %step { + %1 = emitc.call_opaque "f"() : () -> i32 + } + } + return +} +// CPP-DEFAULT: void test_for_siblings(size_t [[V1:[^ ]*]], size_t [[V2:[^ ]*]], size_t [[V3:[^ ]*]]) { +// CPP-DEFAULT-NEXT: size_t [[V4:[^ ]*]] = [[V1]] + [[V2]]; +// CPP-DEFAULT-NEXT: size_t [[V5:[^ ]*]] = [[V2]] * [[V3]]; +// CPP-DEFAULT-NEXT: size_t [[V6:[^ ]*]] = [[V1]] / [[V3]]; +// CPP-DEFAULT-NEXT: for (size_t [[ITER0:i]] = [[V4]]; [[ITER0]] < [[V5]]; [[ITER0]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITER1:j]] = [[V4]]; [[ITER1]] < [[V5]]; [[ITER1]] += [[V6]]) { +// CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]] = f(); +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: for (size_t [[ITER2:k]] = [[V4]]; [[ITER2]] < [[V5]]; [[ITER2]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITER3:l]] = [[V4]]; [[ITER3]] < [[V5]]; [[ITER3]] += [[V6]]) { +// CPP-DEFAULT-NEXT: int32_t [[V8:[^ ]*]] = f(); +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: return; + +func.func @test_for_nesting(%arg0 : !emitc.size_t, %arg1 : !emitc.size_t, %arg2 : !emitc.size_t) { + %lb = emitc.expression : !emitc.size_t { + %a = emitc.add %arg0, %arg1 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + emitc.yield %a : !emitc.size_t + } + %ub = emitc.expression : !emitc.size_t { + %a = emitc.mul %arg1, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + emitc.yield %a : !emitc.size_t + } + %step = emitc.expression : !emitc.size_t { + %a = emitc.div %arg0, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + emitc.yield %a : !emitc.size_t + } + emitc.for %i0 = %lb to %ub step %step { + emitc.for %i1 = %lb to %ub step %step { + emitc.for %i2 = %lb to %ub step %step { + emitc.for %i3 = %lb to %ub step %step { + emitc.for %i4 = %lb to %ub step %step { + emitc.for %i5 = %lb to %ub step %step { + emitc.for %i6 = %lb to %ub step %step { + emitc.for %i7 = %lb to %ub step %step { + emitc.for %i8 = %lb to %ub step %step { + emitc.for %i9 = %lb to %ub step %step { + emitc.for %i10 = %lb to %ub step %step { + emitc.for %i11 = %lb to %ub step %step { + emitc.for %i12 = %lb to %ub step %step { + emitc.for %i13 = %lb to %ub step %step { + emitc.for %i14 = %lb to %ub step %step { + emitc.for %i15 = %lb to %ub step %step { + emitc.for %i16 = %lb to %ub step %step { + emitc.for %i17 = %lb to %ub step %step { + emitc.for %i18 = %lb to %ub step %step { + emitc.for %i19 = %lb to %ub step %step { + %0 = emitc.call_opaque "f"() : () -> i32 + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + return +} +// CPP-DEFAULT: void test_for_nesting(size_t [[V1:[^ ]*]], size_t [[V2:[^ ]*]], size_t [[V3:[^ ]*]]) { +// CPP-DEFAULT-NEXT: size_t [[V4:[^ ]*]] = [[V1]] + [[V2]]; +// CPP-DEFAULT-NEXT: size_t [[V5:[^ ]*]] = [[V2]] * [[V3]]; +// CPP-DEFAULT-NEXT: size_t [[V6:[^ ]*]] = [[V1]] / [[V3]]; +// CPP-DEFAULT-NEXT: for (size_t [[ITERi:i]] = [[V4]]; [[ITERi]] < [[V5]]; [[ITERi]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERj:j]] = [[V4]]; [[ITERj]] < [[V5]]; [[ITERj]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERk:[i-z]]] = [[V4]]; [[ITERk]] < [[V5]]; [[ITERk]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERl:[i-z]]] = [[V4]]; [[ITERl]] < [[V5]]; [[ITERl]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERm:[i-z]]] = [[V4]]; [[ITERm]] < [[V5]]; [[ITERm]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERn:[i-z]]] = [[V4]]; [[ITERn]] < [[V5]]; [[ITERn]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERo:[i-z]]] = [[V4]]; [[ITERo]] < [[V5]]; [[ITERo]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERp:[i-z]]] = [[V4]]; [[ITERp]] < [[V5]]; [[ITERp]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERq:[i-z]]] = [[V4]]; [[ITERq]] < [[V5]]; [[ITERq]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERr:[i-z]]] = [[V4]]; [[ITERr]] < [[V5]]; [[ITERr]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERs:[i-z]]] = [[V4]]; [[ITERs]] < [[V5]]; [[ITERs]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERt:[i-z]]] = [[V4]]; [[ITERt]] < [[V5]]; [[ITERt]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERu:[i-z]]] = [[V4]]; [[ITERu]] < [[V5]]; [[ITERu]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERv:[i-z]]] = [[V4]]; [[ITERv]] < [[V5]]; [[ITERv]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERw:[i-z]]] = [[V4]]; [[ITERw]] < [[V5]]; [[ITERw]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERx:[i-z]]] = [[V4]]; [[ITERx]] < [[V5]]; [[ITERx]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERy:[i-z]]] = [[V4]]; [[ITERy]] < [[V5]]; [[ITERy]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERz:z]] = [[V4]]; [[ITERz]] < [[V5]]; [[ITERz]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERi0:i0]] = [[V4]]; [[ITERi0]] < [[V5]]; [[ITERi0]] += [[V6]]) { +// CPP-DEFAULT-NEXT: for (size_t [[ITERi1:i1]] = [[V4]]; [[ITERi1]] < [[V5]]; [[ITERi1]] += [[V6]]) { +// CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]] = f(); +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: return; \ No newline at end of file From 2118dfb941d5298ffa58766e643467c71c5e963b Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Tue, 8 Apr 2025 07:43:09 -0600 Subject: [PATCH 03/19] Test relied on old variable naming --- mlir/test/Target/Cpp/emitc-constants-as-variables.mlir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir index f4f02cec96421..f7d09362f4f0f 100644 --- a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir +++ b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir @@ -12,7 +12,7 @@ func.func @test() { return } // CPP-DEFAULT-LABEL: void test() { -// CPP-DEFAULT-NEXT: for (size_t v1 = (size_t) 0; v1 < (size_t) 10; v1 += (size_t) 1) { +// CPP-DEFAULT-NEXT: for (size_t [[V1:[^ ]*]] = (size_t) 0; [[V1]] < (size_t) 10; [[V1]] += (size_t) 1) { // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: return; // CPP-DEFAULT-NEXT: } From 634e37108ace594959db1eb65b0ed84dcfdc5445 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Thu, 10 Apr 2025 01:57:27 -0600 Subject: [PATCH 04/19] Removed unnecessary vars and checks, added indents, reduced nesting check --- mlir/test/Target/Cpp/for_iteration_vars.mlir | 183 +++++++------------ 1 file changed, 70 insertions(+), 113 deletions(-) diff --git a/mlir/test/Target/Cpp/for_iteration_vars.mlir b/mlir/test/Target/Cpp/for_iteration_vars.mlir index dee712192e7d0..46a7e14bf65fb 100644 --- a/mlir/test/Target/Cpp/for_iteration_vars.mlir +++ b/mlir/test/Target/Cpp/for_iteration_vars.mlir @@ -1,79 +1,66 @@ -// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT +// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -func.func @test_for_siblings(%arg0 : !emitc.size_t, %arg1 : !emitc.size_t, %arg2 : !emitc.size_t) { - %lb = emitc.expression : !emitc.size_t { - %a = emitc.add %arg0, %arg1 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t - emitc.yield %a : !emitc.size_t - } - %ub = emitc.expression : !emitc.size_t { - %a = emitc.mul %arg1, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t - emitc.yield %a : !emitc.size_t - } - %step = emitc.expression : !emitc.size_t { - %a = emitc.div %arg0, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t - emitc.yield %a : !emitc.size_t - } - emitc.for %i0 = %lb to %ub step %step { - emitc.for %i1 = %lb to %ub step %step { - %0 = emitc.call_opaque "f"() : () -> i32 +func.func @test_for_siblings() { + %start = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t + %stop = "emitc.constant"() <{value = 10 : index}> : () -> !emitc.size_t + %step = "emitc.constant"() <{value = 1 : index}> : () -> !emitc.size_t + + %var1 = "emitc.variable"() <{value = 0 : index}> : () -> !emitc.lvalue + %var2 = "emitc.variable"() <{value = 0 : index}> : () -> !emitc.lvalue + + emitc.for %i0 = %start to %stop step %step { + emitc.for %i1 = %start to %stop step %step { + "emitc.assign"(%var1,%i0) : (!emitc.lvalue, !emitc.size_t) -> () + "emitc.assign"(%var2,%i1) : (!emitc.lvalue, !emitc.size_t) -> () } } - emitc.for %ki2 = %lb to %ub step %step { - emitc.for %i3 = %lb to %ub step %step { + emitc.for %ki2 = %start to %stop step %step { + emitc.for %i3 = %start to %stop step %step { %1 = emitc.call_opaque "f"() : () -> i32 } } return } -// CPP-DEFAULT: void test_for_siblings(size_t [[V1:[^ ]*]], size_t [[V2:[^ ]*]], size_t [[V3:[^ ]*]]) { -// CPP-DEFAULT-NEXT: size_t [[V4:[^ ]*]] = [[V1]] + [[V2]]; -// CPP-DEFAULT-NEXT: size_t [[V5:[^ ]*]] = [[V2]] * [[V3]]; -// CPP-DEFAULT-NEXT: size_t [[V6:[^ ]*]] = [[V1]] / [[V3]]; -// CPP-DEFAULT-NEXT: for (size_t [[ITER0:i]] = [[V4]]; [[ITER0]] < [[V5]]; [[ITER0]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITER1:j]] = [[V4]]; [[ITER1]] < [[V5]]; [[ITER1]] += [[V6]]) { -// CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]] = f(); -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: for (size_t [[ITER2:k]] = [[V4]]; [[ITER2]] < [[V5]]; [[ITER2]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITER3:l]] = [[V4]]; [[ITER3]] < [[V5]]; [[ITER3]] += [[V6]]) { -// CPP-DEFAULT-NEXT: int32_t [[V8:[^ ]*]] = f(); -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: return; +// CHECK-LABEL: test_for_siblings +// CHECK-COUNT-5: size_t {{.*}} = {{.*}}; +// CHECK-NEXT: for (size_t [[ITER0:i]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITER1:j]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { + // CHECK-NEXT: {{.*}} = i; + // CHECK-NEXT: {{.*}} = j; + // CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: for (size_t [[ITER2:i]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITER3:j]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) { + // CHECK-NEXT: int32_t [[V8:[^ ]*]] = f(); + // CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return; -func.func @test_for_nesting(%arg0 : !emitc.size_t, %arg1 : !emitc.size_t, %arg2 : !emitc.size_t) { - %lb = emitc.expression : !emitc.size_t { - %a = emitc.add %arg0, %arg1 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t - emitc.yield %a : !emitc.size_t - } - %ub = emitc.expression : !emitc.size_t { - %a = emitc.mul %arg1, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t - emitc.yield %a : !emitc.size_t - } - %step = emitc.expression : !emitc.size_t { - %a = emitc.div %arg0, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t - emitc.yield %a : !emitc.size_t - } - emitc.for %i0 = %lb to %ub step %step { - emitc.for %i1 = %lb to %ub step %step { - emitc.for %i2 = %lb to %ub step %step { - emitc.for %i3 = %lb to %ub step %step { - emitc.for %i4 = %lb to %ub step %step { - emitc.for %i5 = %lb to %ub step %step { - emitc.for %i6 = %lb to %ub step %step { - emitc.for %i7 = %lb to %ub step %step { - emitc.for %i8 = %lb to %ub step %step { - emitc.for %i9 = %lb to %ub step %step { - emitc.for %i10 = %lb to %ub step %step { - emitc.for %i11 = %lb to %ub step %step { - emitc.for %i12 = %lb to %ub step %step { - emitc.for %i13 = %lb to %ub step %step { - emitc.for %i14 = %lb to %ub step %step { - emitc.for %i15 = %lb to %ub step %step { - emitc.for %i16 = %lb to %ub step %step { - emitc.for %i17 = %lb to %ub step %step { - emitc.for %i18 = %lb to %ub step %step { - emitc.for %i19 = %lb to %ub step %step { +func.func @test_for_nesting() { + %start = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t + %stop = "emitc.constant"() <{value = 10 : index}> : () -> !emitc.size_t + %step = "emitc.constant"() <{value = 1 : index}> : () -> !emitc.size_t + + emitc.for %i0 = %start to %stop step %step { + emitc.for %i1 = %start to %stop step %step { + emitc.for %i2 = %start to %stop step %step { + emitc.for %i3 = %start to %stop step %step { + emitc.for %i4 = %start to %stop step %step { + emitc.for %i5 = %start to %stop step %step { + emitc.for %i6 = %start to %stop step %step { + emitc.for %i7 = %start to %stop step %step { + emitc.for %i8 = %start to %stop step %step { + emitc.for %i9 = %start to %stop step %step { + emitc.for %i10 = %start to %stop step %step { + emitc.for %i11 = %start to %stop step %step { + emitc.for %i12 = %start to %stop step %step { + emitc.for %i13 = %start to %stop step %step { + emitc.for %i14 = %start to %stop step %step { + emitc.for %i15 = %start to %stop step %step { + emitc.for %i16 = %start to %stop step %step { + emitc.for %i17 = %start to %stop step %step { + emitc.for %i18 = %start to %stop step %step { + emitc.for %i19 = %start to %stop step %step { %0 = emitc.call_opaque "f"() : () -> i32 } } @@ -97,49 +84,19 @@ func.func @test_for_nesting(%arg0 : !emitc.size_t, %arg1 : !emitc.size_t, %arg2 } return } -// CPP-DEFAULT: void test_for_nesting(size_t [[V1:[^ ]*]], size_t [[V2:[^ ]*]], size_t [[V3:[^ ]*]]) { -// CPP-DEFAULT-NEXT: size_t [[V4:[^ ]*]] = [[V1]] + [[V2]]; -// CPP-DEFAULT-NEXT: size_t [[V5:[^ ]*]] = [[V2]] * [[V3]]; -// CPP-DEFAULT-NEXT: size_t [[V6:[^ ]*]] = [[V1]] / [[V3]]; -// CPP-DEFAULT-NEXT: for (size_t [[ITERi:i]] = [[V4]]; [[ITERi]] < [[V5]]; [[ITERi]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERj:j]] = [[V4]]; [[ITERj]] < [[V5]]; [[ITERj]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERk:[i-z]]] = [[V4]]; [[ITERk]] < [[V5]]; [[ITERk]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERl:[i-z]]] = [[V4]]; [[ITERl]] < [[V5]]; [[ITERl]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERm:[i-z]]] = [[V4]]; [[ITERm]] < [[V5]]; [[ITERm]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERn:[i-z]]] = [[V4]]; [[ITERn]] < [[V5]]; [[ITERn]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERo:[i-z]]] = [[V4]]; [[ITERo]] < [[V5]]; [[ITERo]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERp:[i-z]]] = [[V4]]; [[ITERp]] < [[V5]]; [[ITERp]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERq:[i-z]]] = [[V4]]; [[ITERq]] < [[V5]]; [[ITERq]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERr:[i-z]]] = [[V4]]; [[ITERr]] < [[V5]]; [[ITERr]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERs:[i-z]]] = [[V4]]; [[ITERs]] < [[V5]]; [[ITERs]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERt:[i-z]]] = [[V4]]; [[ITERt]] < [[V5]]; [[ITERt]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERu:[i-z]]] = [[V4]]; [[ITERu]] < [[V5]]; [[ITERu]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERv:[i-z]]] = [[V4]]; [[ITERv]] < [[V5]]; [[ITERv]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERw:[i-z]]] = [[V4]]; [[ITERw]] < [[V5]]; [[ITERw]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERx:[i-z]]] = [[V4]]; [[ITERx]] < [[V5]]; [[ITERx]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERy:[i-z]]] = [[V4]]; [[ITERy]] < [[V5]]; [[ITERy]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERz:z]] = [[V4]]; [[ITERz]] < [[V5]]; [[ITERz]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERi0:i0]] = [[V4]]; [[ITERi0]] < [[V5]]; [[ITERi0]] += [[V6]]) { -// CPP-DEFAULT-NEXT: for (size_t [[ITERi1:i1]] = [[V4]]; [[ITERi1]] < [[V5]]; [[ITERi1]] += [[V6]]) { -// CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]] = f(); -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: return; \ No newline at end of file +// CHECK-LABEL: test_for_nesting +// CHECK-COUNT-3: size_t {{.*}} = {{.*}}; +// CHECK-NEXT: for (size_t [[ITERi:i]] = {{.*}}; [[ITERi]] < {{.*}}; [[ITERi]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERj:j]] = {{.*}}; [[ITERj]] < {{.*}}; [[ITERj]] += {{.*}}) { + // CHECK-COUNT-15: for (size_t [[ITERk:[k-y]]] = {{.*}}; [[ITERk]] < {{.*}}; [[ITERk]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERz:z]] = {{.*}}; [[ITERz]] < {{.*}}; [[ITERz]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERz0:z0]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERz1:z1]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { + // CHECK-NEXT: int32_t [[V7:[^ ]*]] = f(); + // CHECK-NEXT: } + // CHECK-NEXT: } + // CHECK-NEXT: } + //CHECK-COUNT-15: } + // CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return; From 5dc64f20ea47cd278b13f4659131b8c18d93271d Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Thu, 10 Apr 2025 02:48:27 -0600 Subject: [PATCH 05/19] Updated name, added separate emitc::forOp scoping, reduced constants --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 61 ++++++++++++++++---------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 2f98fb5a6e01a..f346098e72ea8 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -185,7 +185,7 @@ struct CppEmitter { /// Return the existing or a new name for a Value. StringRef getOrCreateName(Value val); - // Return the existing or a new name for an iteration variable Value + // Return the existing or a new name for a loop induction variable of an emitc::ForOp StringRef getOrCreateName(emitc::ForOp forOp); // Returns the textual representation of a subscript operation. @@ -207,26 +207,37 @@ struct CppEmitter { struct Scope { Scope(CppEmitter &emitter) : valueMapperScope(emitter.valueMapper), - iterationVarMapperScope(emitter.iterationVarMapper), blockMapperScope(emitter.blockMapper), emitter(emitter) { emitter.valueInScopeCount.push(emitter.valueInScopeCount.top()); - emitter.iterationVarInScopeCount.push( - emitter.iterationVarInScopeCount.top()); emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); } ~Scope() { emitter.valueInScopeCount.pop(); - emitter.iterationVarInScopeCount.pop(); emitter.labelInScopeCount.pop(); } private: llvm::ScopedHashTableScope valueMapperScope; - llvm::ScopedHashTableScope iterationVarMapperScope; llvm::ScopedHashTableScope blockMapperScope; CppEmitter &emitter; }; + /// RAII helper function to manage entering/exiting emitc::ForOp scopes only + struct ForOpScope { + ForOpScope(CppEmitter &emitter) + : loopInductionVarMapperScope(emitter.loopInductionVarMapper), emitter(emitter){ + emitter.loopInductionVarInScopeCount.push( + emitter.loopInductionVarInScopeCount.top()); + } + ~ForOpScope() { + emitter.loopInductionVarInScopeCount.pop(); + } + + private: + llvm::ScopedHashTableScope loopInductionVarMapperScope; + CppEmitter &emitter; + }; + /// Returns wether the Value is assigned to a C++ variable in the scope. bool hasValueInScope(Value val); @@ -293,8 +304,8 @@ struct CppEmitter { /// Map from value to name of C++ variable that contain the name. ValueMapper valueMapper; - // Map from value to name of C++ iteration variable that contains the name. - ValueMapper iterationVarMapper; + // Map from value to name of C++ loop induction variable that contains the name. + ValueMapper loopInductionVarMapper; /// Map from block to name of C++ label. BlockMapper blockMapper; @@ -302,7 +313,7 @@ struct CppEmitter { /// The number of values in the current scope. This is used to declare the /// names of values in a scope. std::stack valueInScopeCount; - std::stack iterationVarInScopeCount; + std::stack loopInductionVarInScopeCount; std::stack labelInScopeCount; /// State of the current expression being emitted. @@ -923,6 +934,7 @@ static LogicalResult printOperation(CppEmitter &emitter, } static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { + CppEmitter::ForOpScope fScope(emitter); raw_indented_ostream &os = emitter.ostream(); @@ -1324,7 +1336,7 @@ CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, : os(os), declareVariablesAtTop(declareVariablesAtTop), onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { valueInScopeCount.push(0); - iterationVarInScopeCount.push(0); + loopInductionVarInScopeCount.push(0); labelInScopeCount.push(0); } @@ -1361,37 +1373,38 @@ void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { - if (!valueMapper.count(val) && !iterationVarMapper.count(val)) { + if (!valueMapper.count(val) && !loopInductionVarMapper.count(val)) { assert(!hasDeferredEmission(val.getDefiningOp()) && "cacheDeferredOpResult should have been called on this value, " "update the emitOperation function."); valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); } - // Check whether value belongs to iteration variable - if (iterationVarMapper.count(val)) { - return *iterationVarMapper.begin(val); + // Check whether value belongs to a loop induction variable + if (loopInductionVarMapper.count(val)) { + return *loopInductionVarMapper.begin(val); } return *valueMapper.begin(val); } -/// Return the existing or a new name for an iteration variable Value. -// Iteration variables follow natural naming: i,j,k,... +/// Return the existing or a new name for a loop induction variable Value. +// loop induction variables follow natural naming: i, j, k,... StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { Value val = forOp.getInductionVar(); - if (!iterationVarMapper.count(val)) { - int64_t incdCount = iterationVarInScopeCount.top()++; + if (!loopInductionVarMapper.count(val)) { + int64_t incdCount = loopInductionVarInScopeCount.top()++; - if (incdCount >= 0 && incdCount <= 'z' - 'i') { - iterationVarMapper.insert(val, std::string(1, (char)(incdCount + 'i'))); + char range = 'z' - 'i'; + if (incdCount >= 0 && incdCount <= range) { + loopInductionVarMapper.insert(val, std::string(1, (char)(incdCount + 'i'))); } else { - // If running out of letters, continue with iX - iterationVarMapper.insert(val, - formatv("i{0}", incdCount - ('z' - 'i') - 1)); + // If running out of letters, continue with zX + loopInductionVarMapper.insert(val, + formatv("z{0}", incdCount - range - 1)); } } - return *iterationVarMapper.begin(val); + return *loopInductionVarMapper.begin(val); } /// Return the existing or a new label for a Block. From ae1ed6ed0855a90f781ddb9adda1e5363555c95d Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Thu, 10 Apr 2025 02:50:05 -0600 Subject: [PATCH 06/19] Renamed test, removed additional unnecessary checks --- .../{for_iteration_vars.mlir => for_loop_induction_vars.mlir} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename mlir/test/Target/Cpp/{for_iteration_vars.mlir => for_loop_induction_vars.mlir} (97%) diff --git a/mlir/test/Target/Cpp/for_iteration_vars.mlir b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir similarity index 97% rename from mlir/test/Target/Cpp/for_iteration_vars.mlir rename to mlir/test/Target/Cpp/for_loop_induction_vars.mlir index 46a7e14bf65fb..fb9e8ac98bde4 100644 --- a/mlir/test/Target/Cpp/for_iteration_vars.mlir +++ b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir @@ -31,7 +31,7 @@ func.func @test_for_siblings() { // CHECK-NEXT: } // CHECK-NEXT: for (size_t [[ITER2:i]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) { // CHECK-NEXT: for (size_t [[ITER3:j]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) { - // CHECK-NEXT: int32_t [[V8:[^ ]*]] = f(); + // CHECK-NEXT: int32_t {{.*}} = f(); // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: return; @@ -92,7 +92,7 @@ func.func @test_for_nesting() { // CHECK-NEXT: for (size_t [[ITERz:z]] = {{.*}}; [[ITERz]] < {{.*}}; [[ITERz]] += {{.*}}) { // CHECK-NEXT: for (size_t [[ITERz0:z0]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { // CHECK-NEXT: for (size_t [[ITERz1:z1]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { - // CHECK-NEXT: int32_t [[V7:[^ ]*]] = f(); + // CHECK-NEXT: int32_t {{.*}} = f(); // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: } From fdc39d1c9a867e979e79d6a81ba09906b2621cff Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Thu, 10 Apr 2025 02:50:59 -0600 Subject: [PATCH 07/19] Auto updated formatting --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index f346098e72ea8..bfe5e6dfc8bbd 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -185,7 +185,8 @@ struct CppEmitter { /// Return the existing or a new name for a Value. StringRef getOrCreateName(Value val); - // Return the existing or a new name for a loop induction variable of an emitc::ForOp + // Return the existing or a new name for a loop induction variable of an + // emitc::ForOp StringRef getOrCreateName(emitc::ForOp forOp); // Returns the textual representation of a subscript operation. @@ -225,13 +226,12 @@ struct CppEmitter { /// RAII helper function to manage entering/exiting emitc::ForOp scopes only struct ForOpScope { ForOpScope(CppEmitter &emitter) - : loopInductionVarMapperScope(emitter.loopInductionVarMapper), emitter(emitter){ + : loopInductionVarMapperScope(emitter.loopInductionVarMapper), + emitter(emitter) { emitter.loopInductionVarInScopeCount.push( emitter.loopInductionVarInScopeCount.top()); } - ~ForOpScope() { - emitter.loopInductionVarInScopeCount.pop(); - } + ~ForOpScope() { emitter.loopInductionVarInScopeCount.pop(); } private: llvm::ScopedHashTableScope loopInductionVarMapperScope; @@ -304,7 +304,8 @@ struct CppEmitter { /// Map from value to name of C++ variable that contain the name. ValueMapper valueMapper; - // Map from value to name of C++ loop induction variable that contains the name. + // Map from value to name of C++ loop induction variable that contains the + // name. ValueMapper loopInductionVarMapper; /// Map from block to name of C++ label. @@ -1397,11 +1398,12 @@ StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { char range = 'z' - 'i'; if (incdCount >= 0 && incdCount <= range) { - loopInductionVarMapper.insert(val, std::string(1, (char)(incdCount + 'i'))); + loopInductionVarMapper.insert(val, + std::string(1, (char)(incdCount + 'i'))); } else { // If running out of letters, continue with zX loopInductionVarMapper.insert(val, - formatv("z{0}", incdCount - range - 1)); + formatv("z{0}", incdCount - range - 1)); } } return *loopInductionVarMapper.begin(val); From 350a0f47a5e0da967c7e0f339217d842fbf7a710 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Thu, 10 Apr 2025 05:49:28 -0600 Subject: [PATCH 08/19] Removed unused var --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index bfe5e6dfc8bbd..fb8d6bda3c70f 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -225,16 +225,13 @@ struct CppEmitter { /// RAII helper function to manage entering/exiting emitc::ForOp scopes only struct ForOpScope { - ForOpScope(CppEmitter &emitter) - : loopInductionVarMapperScope(emitter.loopInductionVarMapper), - emitter(emitter) { + ForOpScope(CppEmitter &emitter) : emitter(emitter) { emitter.loopInductionVarInScopeCount.push( emitter.loopInductionVarInScopeCount.top()); } ~ForOpScope() { emitter.loopInductionVarInScopeCount.pop(); } private: - llvm::ScopedHashTableScope loopInductionVarMapperScope; CppEmitter &emitter; }; From 7a24817cf1b666b36a31bd6bc31a61e41297f185 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Fri, 11 Apr 2025 07:35:06 -0600 Subject: [PATCH 09/19] Removed additional scoping, updated naming system --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 110 ++++++++++++++++--------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index fb8d6bda3c70f..da88d57851c24 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -185,8 +185,8 @@ struct CppEmitter { /// Return the existing or a new name for a Value. StringRef getOrCreateName(Value val); - // Return the existing or a new name for a loop induction variable of an - // emitc::ForOp + /// Return the existing or a new name for a loop induction variable of an + /// emitc::ForOp. StringRef getOrCreateName(emitc::ForOp forOp); // Returns the textual representation of a subscript operation. @@ -206,32 +206,30 @@ struct CppEmitter { /// RAII helper function to manage entering/exiting C++ scopes. struct Scope { - Scope(CppEmitter &emitter) + Scope(CppEmitter &emitter, bool reuseVarNames = false) : valueMapperScope(emitter.valueMapper), - blockMapperScope(emitter.blockMapper), emitter(emitter) { - emitter.valueInScopeCount.push(emitter.valueInScopeCount.top()); + blockMapperScope(emitter.blockMapper), + inductionVarMapperScope(emitter.loopInductionVarMapper), + emitter(emitter) { emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); + emitter.loopInductionVarInScopeCount.push( + emitter.loopInductionVarInScopeCount.top()); + + // Reset emitter-level value counters + if (!reuseVarNames) { + emitter.valueCount = 1; + emitter.inductionVarCount = 1; + } } ~Scope() { - emitter.valueInScopeCount.pop(); emitter.labelInScopeCount.pop(); + emitter.loopInductionVarInScopeCount.pop(); } private: llvm::ScopedHashTableScope valueMapperScope; llvm::ScopedHashTableScope blockMapperScope; - CppEmitter &emitter; - }; - - /// RAII helper function to manage entering/exiting emitc::ForOp scopes only - struct ForOpScope { - ForOpScope(CppEmitter &emitter) : emitter(emitter) { - emitter.loopInductionVarInScopeCount.push( - emitter.loopInductionVarInScopeCount.top()); - } - ~ForOpScope() { emitter.loopInductionVarInScopeCount.pop(); } - - private: + llvm::ScopedHashTableScope inductionVarMapperScope; CppEmitter &emitter; }; @@ -308,12 +306,29 @@ struct CppEmitter { /// Map from block to name of C++ label. BlockMapper blockMapper; - /// The number of values in the current scope. This is used to declare the - /// names of values in a scope. - std::stack valueInScopeCount; - std::stack loopInductionVarInScopeCount; + /// Keeps track of original value of element + struct TrackingStackElem { + TrackingStackElem() = default; + TrackingStackElem(const TrackingStackElem &parent) + : origVal(parent.currentVal), currentVal(parent.currentVal) { + if (parent.level != 0) { + level = parent.level + 1; + } + }; + + int64_t origVal{0}; + int64_t currentVal{0}; + // Stores level at which changes begin + int64_t level{0}; + }; + + std::stack loopInductionVarInScopeCount; std::stack labelInScopeCount; + /// Emitter-level count of created values to enable unique identifiers + unsigned int valueCount{1}; + unsigned int inductionVarCount{1}; + /// State of the current expression being emitted. ExpressionOp emittedExpression; SmallVector emittedExpressionPrecedence; @@ -932,8 +947,6 @@ static LogicalResult printOperation(CppEmitter &emitter, } static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { - CppEmitter::ForOpScope fScope(emitter); - raw_indented_ostream &os = emitter.ostream(); // Utility function to determine whether a value is an expression that will be @@ -978,6 +991,8 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { Region &forRegion = forOp.getRegion(); auto regionOps = forRegion.getOps(); + CppEmitter::Scope scope(emitter, true); + // We skip the trailing yield op. for (auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) { if (failed(emitter.emitOperation(*it, /*trailingSemicolon=*/true))) @@ -1333,9 +1348,8 @@ CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, StringRef onlyTu, bool constantsAsVariables) : os(os), declareVariablesAtTop(declareVariablesAtTop), onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { - valueInScopeCount.push(0); - loopInductionVarInScopeCount.push(0); labelInScopeCount.push(0); + loopInductionVarInScopeCount.emplace(); } std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) { @@ -1365,43 +1379,59 @@ std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) { } void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { - if (!valueMapper.count(value)) + if (!valueMapper.count(value)) { valueMapper.insert(value, str.str()); + valueCount++; + } } /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { - if (!valueMapper.count(val) && !loopInductionVarMapper.count(val)) { + // Check whether value belongs to a loop induction variable + if (loopInductionVarMapper.count(val)) { + return *loopInductionVarMapper.begin(val); + } + + if (!valueMapper.count(val)) { assert(!hasDeferredEmission(val.getDefiningOp()) && "cacheDeferredOpResult should have been called on this value, " "update the emitOperation function."); - valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); - } - // Check whether value belongs to a loop induction variable - if (loopInductionVarMapper.count(val)) { - return *loopInductionVarMapper.begin(val); + valueMapper.insert(val, formatv("v{0}", valueCount)); + valueCount++; } return *valueMapper.begin(val); } /// Return the existing or a new name for a loop induction variable Value. -// loop induction variables follow natural naming: i, j, k,... +/// Loop induction variables follow natural naming: i, j, k,... StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { Value val = forOp.getInductionVar(); if (!loopInductionVarMapper.count(val)) { - int64_t incdCount = loopInductionVarInScopeCount.top()++; + + // Only increase induction var id on creating sibling loops + if (loopInductionVarInScopeCount.top().currentVal > + loopInductionVarInScopeCount.top().origVal) { + inductionVarCount++; + } + // If called on first loop, start keeping track of nesting level + if (loopInductionVarInScopeCount.top().level == 0) + loopInductionVarInScopeCount.top().level = 1; + + int64_t identifier = loopInductionVarInScopeCount.top().level - 1; char range = 'z' - 'i'; - if (incdCount >= 0 && incdCount <= range) { - loopInductionVarMapper.insert(val, - std::string(1, (char)(incdCount + 'i'))); + if (identifier >= 0 && identifier <= range) { + loopInductionVarMapper.insert( + val, formatv("{0}_{1}", (char)(identifier + 'i'), inductionVarCount)); } else { // If running out of letters, continue with zX - loopInductionVarMapper.insert(val, - formatv("z{0}", incdCount - range - 1)); + loopInductionVarMapper.insert( + val, formatv("z{0}_{1}", identifier - range - 1, inductionVarCount)); } + + loopInductionVarInScopeCount.top().currentVal++; } return *loopInductionVarMapper.begin(val); } From 12199bcfa3b4ce18afd2ef82395cadf81b8ef4c5 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 01:14:29 -0600 Subject: [PATCH 10/19] Fixed issues that resulted in test failure --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index da88d57851c24..b0f8fed945f1c 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -1381,7 +1381,6 @@ std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) { void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { if (!valueMapper.count(value)) { valueMapper.insert(value, str.str()); - valueCount++; } } From ac7203226cecb32761055e1816a917f602fa6691 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 01:28:26 -0600 Subject: [PATCH 11/19] Updated naming test --- .../Target/Cpp/for_loop_induction_vars.mlir | 41 ++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/mlir/test/Target/Cpp/for_loop_induction_vars.mlir b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir index fb9e8ac98bde4..38cdb16a610a4 100644 --- a/mlir/test/Target/Cpp/for_loop_induction_vars.mlir +++ b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir @@ -22,19 +22,12 @@ func.func @test_for_siblings() { return } // CHECK-LABEL: test_for_siblings -// CHECK-COUNT-5: size_t {{.*}} = {{.*}}; -// CHECK-NEXT: for (size_t [[ITER0:i]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITER1:j]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { - // CHECK-NEXT: {{.*}} = i; - // CHECK-NEXT: {{.*}} = j; - // CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: for (size_t [[ITER2:i]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITER3:j]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) { - // CHECK-NEXT: int32_t {{.*}} = f(); - // CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: return; +// CHECK: for (size_t [[ITER0:i_1]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { + // CHECK: for (size_t [[ITER1:j_1]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { + // CHECK-NEXT: {{.*}} = i_1; + // CHECK-NEXT: {{.*}} = j_1; +// CHECK: for (size_t [[ITER2:i_2]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) + // CHECK: for (size_t [[ITER3:j_2]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) func.func @test_for_nesting() { %start = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t @@ -85,18 +78,10 @@ func.func @test_for_nesting() { return } // CHECK-LABEL: test_for_nesting -// CHECK-COUNT-3: size_t {{.*}} = {{.*}}; -// CHECK-NEXT: for (size_t [[ITERi:i]] = {{.*}}; [[ITERi]] < {{.*}}; [[ITERi]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERj:j]] = {{.*}}; [[ITERj]] < {{.*}}; [[ITERj]] += {{.*}}) { - // CHECK-COUNT-15: for (size_t [[ITERk:[k-y]]] = {{.*}}; [[ITERk]] < {{.*}}; [[ITERk]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERz:z]] = {{.*}}; [[ITERz]] < {{.*}}; [[ITERz]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERz0:z0]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERz1:z1]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { - // CHECK-NEXT: int32_t {{.*}} = f(); - // CHECK-NEXT: } - // CHECK-NEXT: } - // CHECK-NEXT: } - //CHECK-COUNT-15: } - // CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: return; +// CHECK: for (size_t [[ITERi:i_1]] = {{.*}}; [[ITERi]] < {{.*}}; [[ITERi]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERj:j_1]] = {{.*}}; [[ITERj]] < {{.*}}; [[ITERj]] += {{.*}}) { + // CHECK-COUNT-15: for (size_t [[ITERk:[k-y]_1]] = {{.*}}; [[ITERk]] < {{.*}}; [[ITERk]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERz:z_1]] = {{.*}}; [[ITERz]] < {{.*}}; [[ITERz]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERz0:z0_1]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { + // CHECK-NEXT: for (size_t [[ITERz1:z1_1]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { + From 3606ec3afc377d5892b62c46601b86b873d9354c Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 07:33:20 -0600 Subject: [PATCH 12/19] Reverted changes to Scope, removed unnecessary struct --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 102 ++++++++++++------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index b0f8fed945f1c..a10af8b99b768 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -25,6 +25,7 @@ #include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" +#include #include #include @@ -206,25 +207,15 @@ struct CppEmitter { /// RAII helper function to manage entering/exiting C++ scopes. struct Scope { - Scope(CppEmitter &emitter, bool reuseVarNames = false) + Scope(CppEmitter &emitter) : valueMapperScope(emitter.valueMapper), blockMapperScope(emitter.blockMapper), inductionVarMapperScope(emitter.loopInductionVarMapper), emitter(emitter) { + emitter.valueInScopeCount.push(emitter.valueInScopeCount.top()); emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); - emitter.loopInductionVarInScopeCount.push( - emitter.loopInductionVarInScopeCount.top()); - - // Reset emitter-level value counters - if (!reuseVarNames) { - emitter.valueCount = 1; - emitter.inductionVarCount = 1; - } - } - ~Scope() { - emitter.labelInScopeCount.pop(); - emitter.loopInductionVarInScopeCount.pop(); } + ~Scope() { emitter.popStacksAndUpdate(); } private: llvm::ScopedHashTableScope valueMapperScope; @@ -278,6 +269,15 @@ struct CppEmitter { /// This emitter will only emit translation units whos id matches this value. StringRef willOnlyEmitTu() { return onlyTu; } + /// Reduces stacks and updates value counter + void popStacksAndUpdate(); + + // Resets the value counter to 0 + void resetValueCounter(); + + // Decreases the loop nesting level by 1 + void decreaseLoopNestingLevel(); + private: using ValueMapper = llvm::ScopedHashTable; using BlockMapper = llvm::ScopedHashTable; @@ -306,28 +306,13 @@ struct CppEmitter { /// Map from block to name of C++ label. BlockMapper blockMapper; - /// Keeps track of original value of element - struct TrackingStackElem { - TrackingStackElem() = default; - TrackingStackElem(const TrackingStackElem &parent) - : origVal(parent.currentVal), currentVal(parent.currentVal) { - if (parent.level != 0) { - level = parent.level + 1; - } - }; - - int64_t origVal{0}; - int64_t currentVal{0}; - // Stores level at which changes begin - int64_t level{0}; - }; - - std::stack loopInductionVarInScopeCount; + std::stack valueInScopeCount; std::stack labelInScopeCount; + uint64_t loopNestingLevel{0}; + /// Emitter-level count of created values to enable unique identifiers - unsigned int valueCount{1}; - unsigned int inductionVarCount{1}; + unsigned int valueCount{0}; /// State of the current expression being emitted. ExpressionOp emittedExpression; @@ -947,6 +932,7 @@ static LogicalResult printOperation(CppEmitter &emitter, } static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { + CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); // Utility function to determine whether a value is an expression that will be @@ -991,8 +977,6 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { Region &forRegion = forOp.getRegion(); auto regionOps = forRegion.getOps(); - CppEmitter::Scope scope(emitter, true); - // We skip the trailing yield op. for (auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) { if (failed(emitter.emitOperation(*it, /*trailingSemicolon=*/true))) @@ -1001,6 +985,8 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { os.unindent() << "}"; + emitter.decreaseLoopNestingLevel(); + return success(); } @@ -1076,6 +1062,7 @@ static LogicalResult printOperation(CppEmitter &emitter, } static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) { + emitter.resetValueCounter(); CppEmitter::Scope scope(emitter); for (Operation &op : moduleOp) { @@ -1089,6 +1076,7 @@ static LogicalResult printOperation(CppEmitter &emitter, TranslationUnitOp tu) { if (!emitter.shouldEmitTu(tu)) return success(); + emitter.resetValueCounter(); CppEmitter::Scope scope(emitter); for (Operation &op : tu) { @@ -1253,6 +1241,7 @@ static LogicalResult printOperation(CppEmitter &emitter, return functionOp.emitOpError() << "cannot emit array type as result type"; } + emitter.resetValueCounter(); CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); if (failed(emitter.emitTypes(functionOp.getLoc(), @@ -1281,6 +1270,7 @@ static LogicalResult printOperation(CppEmitter &emitter, "with multiple blocks needs variables declared at top"); } + emitter.resetValueCounter(); CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); if (functionOp.getSpecifiers()) { @@ -1315,6 +1305,7 @@ static LogicalResult printOperation(CppEmitter &emitter, static LogicalResult printOperation(CppEmitter &emitter, DeclareFuncOp declareFuncOp) { + emitter.resetValueCounter(); CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); @@ -1347,9 +1338,10 @@ static LogicalResult printOperation(CppEmitter &emitter, CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, StringRef onlyTu, bool constantsAsVariables) : os(os), declareVariablesAtTop(declareVariablesAtTop), - onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { + onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables), + loopNestingLevel(0) { + valueInScopeCount.push(0); labelInScopeCount.push(0); - loopInductionVarInScopeCount.emplace(); } std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) { @@ -1396,8 +1388,8 @@ StringRef CppEmitter::getOrCreateName(Value val) { "cacheDeferredOpResult should have been called on this value, " "update the emitOperation function."); - valueMapper.insert(val, formatv("v{0}", valueCount)); - valueCount++; + valueMapper.insert(val, + formatv("v{0}", ++valueInScopeCount.top() + valueCount)); } return *valueMapper.begin(val); } @@ -1409,28 +1401,20 @@ StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { if (!loopInductionVarMapper.count(val)) { - // Only increase induction var id on creating sibling loops - if (loopInductionVarInScopeCount.top().currentVal > - loopInductionVarInScopeCount.top().origVal) { - inductionVarCount++; - } - // If called on first loop, start keeping track of nesting level - if (loopInductionVarInScopeCount.top().level == 0) - loopInductionVarInScopeCount.top().level = 1; - - int64_t identifier = loopInductionVarInScopeCount.top().level - 1; + int64_t identifier = loopNestingLevel; + loopNestingLevel++; char range = 'z' - 'i'; if (identifier >= 0 && identifier <= range) { loopInductionVarMapper.insert( - val, formatv("{0}_{1}", (char)(identifier + 'i'), inductionVarCount)); + val, formatv("{0}_{1}", (char)(identifier + 'i'), + ++valueInScopeCount.top() + valueCount)); } else { // If running out of letters, continue with zX loopInductionVarMapper.insert( - val, formatv("z{0}_{1}", identifier - range - 1, inductionVarCount)); + val, formatv("z{0}_{1}", identifier - range - 1, + ++valueInScopeCount.top() + valueCount)); } - - loopInductionVarInScopeCount.top().currentVal++; } return *loopInductionVarMapper.begin(val); } @@ -2024,6 +2008,20 @@ LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { return success(); } +void CppEmitter::popStacksAndUpdate() { + uint64_t newValues = valueInScopeCount.top(); + + valueInScopeCount.pop(); + labelInScopeCount.pop(); + + newValues -= valueInScopeCount.top(); + valueCount += newValues; +} + +void CppEmitter::resetValueCounter() { valueCount = 0; } + +void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; } + LogicalResult emitc::translateToCpp(Operation *op, raw_ostream &os, bool declareVariablesAtTop, StringRef onlyTu, From 8750f4be31da33d90ca3870e24e2a326e93aaefa Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 07:34:11 -0600 Subject: [PATCH 13/19] Adjusted test case, removed redundant checks --- .../Target/Cpp/for_loop_induction_vars.mlir | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/mlir/test/Target/Cpp/for_loop_induction_vars.mlir b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir index 38cdb16a610a4..365313168cede 100644 --- a/mlir/test/Target/Cpp/for_loop_induction_vars.mlir +++ b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir @@ -22,12 +22,12 @@ func.func @test_for_siblings() { return } // CHECK-LABEL: test_for_siblings -// CHECK: for (size_t [[ITER0:i_1]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { - // CHECK: for (size_t [[ITER1:j_1]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { - // CHECK-NEXT: {{.*}} = i_1; - // CHECK-NEXT: {{.*}} = j_1; -// CHECK: for (size_t [[ITER2:i_2]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) - // CHECK: for (size_t [[ITER3:j_2]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) +// CHECK: for (size_t [[ITER0:i_[0-9]*]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { + // CHECK: for (size_t [[ITER1:j_[0-9]*]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { + // CHECK-NEXT: {{.*}} = [[ITER0]]; + // CHECK-NEXT: {{.*}} = [[ITER1]]; +// CHECK: for (size_t [[ITER2:i_[0-9]*]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) + // CHECK: for (size_t [[ITER3:j_[0-9]*]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) func.func @test_for_nesting() { %start = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t @@ -78,10 +78,7 @@ func.func @test_for_nesting() { return } // CHECK-LABEL: test_for_nesting -// CHECK: for (size_t [[ITERi:i_1]] = {{.*}}; [[ITERi]] < {{.*}}; [[ITERi]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERj:j_1]] = {{.*}}; [[ITERj]] < {{.*}}; [[ITERj]] += {{.*}}) { - // CHECK-COUNT-15: for (size_t [[ITERk:[k-y]_1]] = {{.*}}; [[ITERk]] < {{.*}}; [[ITERk]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERz:z_1]] = {{.*}}; [[ITERz]] < {{.*}}; [[ITERz]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERz0:z0_1]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { - // CHECK-NEXT: for (size_t [[ITERz1:z1_1]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { +// CHECK-COUNT-18: for (size_t [[ITER:[i-z]_[0-9]*]] = {{.*}}; [[ITER]] < {{.*}}; [[ITER]] += {{.*}}) { + // CHECK: for (size_t [[ITERz0:z0_[0-9]*]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { + // CHECK: for (size_t [[ITERz1:z1_[0-9]*]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { From f627d3e5fa63c257adcda2a98d0863b3bab92b3b Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 07:40:23 -0600 Subject: [PATCH 14/19] Minor clean-up --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index a10af8b99b768..76af680175a6c 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -1338,8 +1338,7 @@ static LogicalResult printOperation(CppEmitter &emitter, CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, StringRef onlyTu, bool constantsAsVariables) : os(os), declareVariablesAtTop(declareVariablesAtTop), - onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables), - loopNestingLevel(0) { + onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { valueInScopeCount.push(0); labelInScopeCount.push(0); } @@ -1401,8 +1400,7 @@ StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { if (!loopInductionVarMapper.count(val)) { - int64_t identifier = loopNestingLevel; - loopNestingLevel++; + int64_t identifier = loopNestingLevel++; char range = 'z' - 'i'; if (identifier >= 0 && identifier <= range) { From 8b588c037709e6ce679336280224a2f8dd35a819 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 08:05:01 -0600 Subject: [PATCH 15/19] Removed auto-added include --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 76af680175a6c..17970fd811e99 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -25,7 +25,6 @@ #include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" -#include #include #include From b139e8d3fb87307fcc279388dd11178bdd156bad Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 08:38:46 -0600 Subject: [PATCH 16/19] Replaced value stack by counter --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 17970fd811e99..75fa6cb659360 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -211,10 +211,9 @@ struct CppEmitter { blockMapperScope(emitter.blockMapper), inductionVarMapperScope(emitter.loopInductionVarMapper), emitter(emitter) { - emitter.valueInScopeCount.push(emitter.valueInScopeCount.top()); emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); } - ~Scope() { emitter.popStacksAndUpdate(); } + ~Scope() { emitter.labelInScopeCount.pop(); } private: llvm::ScopedHashTableScope valueMapperScope; @@ -305,7 +304,6 @@ struct CppEmitter { /// Map from block to name of C++ label. BlockMapper blockMapper; - std::stack valueInScopeCount; std::stack labelInScopeCount; uint64_t loopNestingLevel{0}; @@ -1338,7 +1336,6 @@ CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, StringRef onlyTu, bool constantsAsVariables) : os(os), declareVariablesAtTop(declareVariablesAtTop), onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { - valueInScopeCount.push(0); labelInScopeCount.push(0); } @@ -1386,8 +1383,7 @@ StringRef CppEmitter::getOrCreateName(Value val) { "cacheDeferredOpResult should have been called on this value, " "update the emitOperation function."); - valueMapper.insert(val, - formatv("v{0}", ++valueInScopeCount.top() + valueCount)); + valueMapper.insert(val, formatv("v{0}", ++valueCount)); } return *valueMapper.begin(val); } @@ -1404,13 +1400,11 @@ StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { char range = 'z' - 'i'; if (identifier >= 0 && identifier <= range) { loopInductionVarMapper.insert( - val, formatv("{0}_{1}", (char)(identifier + 'i'), - ++valueInScopeCount.top() + valueCount)); + val, formatv("{0}_{1}", (char)(identifier + 'i'), ++valueCount)); } else { // If running out of letters, continue with zX loopInductionVarMapper.insert( - val, formatv("z{0}_{1}", identifier - range - 1, - ++valueInScopeCount.top() + valueCount)); + val, formatv("z{0}_{1}", identifier - range - 1, ++valueCount)); } } return *loopInductionVarMapper.begin(val); @@ -2005,16 +1999,6 @@ LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { return success(); } -void CppEmitter::popStacksAndUpdate() { - uint64_t newValues = valueInScopeCount.top(); - - valueInScopeCount.pop(); - labelInScopeCount.pop(); - - newValues -= valueInScopeCount.top(); - valueCount += newValues; -} - void CppEmitter::resetValueCounter() { valueCount = 0; } void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; } From 59a3b4c77cf143fdccf40d1c91f03ef1b227db6f Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Mon, 14 Apr 2025 08:56:16 -0600 Subject: [PATCH 17/19] Recombined scoped hashtables --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 75fa6cb659360..4c27863567304 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -208,9 +208,7 @@ struct CppEmitter { struct Scope { Scope(CppEmitter &emitter) : valueMapperScope(emitter.valueMapper), - blockMapperScope(emitter.blockMapper), - inductionVarMapperScope(emitter.loopInductionVarMapper), - emitter(emitter) { + blockMapperScope(emitter.blockMapper), emitter(emitter) { emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); } ~Scope() { emitter.labelInScopeCount.pop(); } @@ -218,7 +216,6 @@ struct CppEmitter { private: llvm::ScopedHashTableScope valueMapperScope; llvm::ScopedHashTableScope blockMapperScope; - llvm::ScopedHashTableScope inductionVarMapperScope; CppEmitter &emitter; }; @@ -297,10 +294,6 @@ struct CppEmitter { /// Map from value to name of C++ variable that contain the name. ValueMapper valueMapper; - // Map from value to name of C++ loop induction variable that contains the - // name. - ValueMapper loopInductionVarMapper; - /// Map from block to name of C++ label. BlockMapper blockMapper; @@ -1373,11 +1366,6 @@ void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { - // Check whether value belongs to a loop induction variable - if (loopInductionVarMapper.count(val)) { - return *loopInductionVarMapper.begin(val); - } - if (!valueMapper.count(val)) { assert(!hasDeferredEmission(val.getDefiningOp()) && "cacheDeferredOpResult should have been called on this value, " @@ -1393,21 +1381,21 @@ StringRef CppEmitter::getOrCreateName(Value val) { StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { Value val = forOp.getInductionVar(); - if (!loopInductionVarMapper.count(val)) { + if (!valueMapper.count(val)) { int64_t identifier = loopNestingLevel++; char range = 'z' - 'i'; if (identifier >= 0 && identifier <= range) { - loopInductionVarMapper.insert( + valueMapper.insert( val, formatv("{0}_{1}", (char)(identifier + 'i'), ++valueCount)); } else { // If running out of letters, continue with zX - loopInductionVarMapper.insert( + valueMapper.insert( val, formatv("z{0}_{1}", identifier - range - 1, ++valueCount)); } } - return *loopInductionVarMapper.begin(val); + return *valueMapper.begin(val); } /// Return the existing or a new label for a Block. From c0240fa3da7cb01ad16c75b01c9ace3923f79d95 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Tue, 15 Apr 2025 04:41:16 -0600 Subject: [PATCH 18/19] Added polymorphic scope, removed unnecessary scopes, refactored code --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 85 +++++++++++++++----------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 4c27863567304..7417b2a22c7b5 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -204,21 +204,41 @@ struct CppEmitter { /// Whether to map an mlir integer to a unsigned integer in C++. bool shouldMapToUnsigned(IntegerType::SignednessSemantics val); - /// RAII helper function to manage entering/exiting C++ scopes. + /// Abstract RAII helper function to manage entering/exiting C++ scopes. struct Scope { - Scope(CppEmitter &emitter) - : valueMapperScope(emitter.valueMapper), - blockMapperScope(emitter.blockMapper), emitter(emitter) { - emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); - } ~Scope() { emitter.labelInScopeCount.pop(); } private: llvm::ScopedHashTableScope valueMapperScope; llvm::ScopedHashTableScope blockMapperScope; + + protected: + Scope(CppEmitter &emitter) + : valueMapperScope(emitter.valueMapper), + blockMapperScope(emitter.blockMapper), emitter(emitter) { + emitter.labelInScopeCount.push(emitter.labelInScopeCount.top()); + } CppEmitter &emitter; }; + /// RAII helper function to manage entering/exiting functions, while re-using + /// value names. + struct FunctionScope : Scope { + FunctionScope(CppEmitter &emitter) : Scope(emitter) { + // Re-use value names + emitter.resetValueCounter(); + } + }; + + /// RAII helper function to manage entering/exiting emitc::forOp loops and + /// handle induction variable naming. + struct LoopScope : Scope { + LoopScope(CppEmitter &emitter) : Scope(emitter) { + emitter.increaseLoopNestingLevel(); + } + ~LoopScope() { emitter.decreaseLoopNestingLevel(); } + }; + /// Returns wether the Value is assigned to a C++ variable in the scope. bool hasValueInScope(Value val); @@ -264,12 +284,12 @@ struct CppEmitter { /// This emitter will only emit translation units whos id matches this value. StringRef willOnlyEmitTu() { return onlyTu; } - /// Reduces stacks and updates value counter - void popStacksAndUpdate(); - // Resets the value counter to 0 void resetValueCounter(); + // Increases the loop nesting level by 1 + void increaseLoopNestingLevel(); + // Decreases the loop nesting level by 1 void decreaseLoopNestingLevel(); @@ -297,11 +317,17 @@ struct CppEmitter { /// Map from block to name of C++ label. BlockMapper blockMapper; + /// Default values representing outermost scope + llvm::ScopedHashTableScope defaultValueMapperScope; + llvm::ScopedHashTableScope defaultBlockMapperScope; + std::stack labelInScopeCount; + /// Keeps track of the amount of nested loops the emitter currently operates + /// in. uint64_t loopNestingLevel{0}; - /// Emitter-level count of created values to enable unique identifiers + /// Emitter-level count of created values to enable unique identifiers. unsigned int valueCount{0}; /// State of the current expression being emitted. @@ -922,7 +948,6 @@ static LogicalResult printOperation(CppEmitter &emitter, } static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { - CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); // Utility function to determine whether a value is an expression that will be @@ -964,6 +989,8 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { os << ") {\n"; os.indent(); + CppEmitter::LoopScope lScope(emitter); + Region &forRegion = forOp.getRegion(); auto regionOps = forRegion.getOps(); @@ -975,8 +1002,6 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { os.unindent() << "}"; - emitter.decreaseLoopNestingLevel(); - return success(); } @@ -1052,9 +1077,6 @@ static LogicalResult printOperation(CppEmitter &emitter, } static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) { - emitter.resetValueCounter(); - CppEmitter::Scope scope(emitter); - for (Operation &op : moduleOp) { if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false))) return failure(); @@ -1066,9 +1088,6 @@ static LogicalResult printOperation(CppEmitter &emitter, TranslationUnitOp tu) { if (!emitter.shouldEmitTu(tu)) return success(); - emitter.resetValueCounter(); - CppEmitter::Scope scope(emitter); - for (Operation &op : tu) { if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false))) return failure(); @@ -1231,8 +1250,7 @@ static LogicalResult printOperation(CppEmitter &emitter, return functionOp.emitOpError() << "cannot emit array type as result type"; } - emitter.resetValueCounter(); - CppEmitter::Scope scope(emitter); + CppEmitter::FunctionScope scope(emitter); raw_indented_ostream &os = emitter.ostream(); if (failed(emitter.emitTypes(functionOp.getLoc(), functionOp.getFunctionType().getResults()))) @@ -1260,8 +1278,7 @@ static LogicalResult printOperation(CppEmitter &emitter, "with multiple blocks needs variables declared at top"); } - emitter.resetValueCounter(); - CppEmitter::Scope scope(emitter); + CppEmitter::FunctionScope scope(emitter); raw_indented_ostream &os = emitter.ostream(); if (functionOp.getSpecifiers()) { for (Attribute specifier : functionOp.getSpecifiersAttr()) { @@ -1295,8 +1312,6 @@ static LogicalResult printOperation(CppEmitter &emitter, static LogicalResult printOperation(CppEmitter &emitter, DeclareFuncOp declareFuncOp) { - emitter.resetValueCounter(); - CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); auto functionOp = SymbolTable::lookupNearestSymbolFrom( @@ -1328,7 +1343,9 @@ static LogicalResult printOperation(CppEmitter &emitter, CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop, StringRef onlyTu, bool constantsAsVariables) : os(os), declareVariablesAtTop(declareVariablesAtTop), - onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables) { + onlyTu(onlyTu.str()), constantsAsVariables(constantsAsVariables), + defaultValueMapperScope(valueMapper), + defaultBlockMapperScope(blockMapper) { labelInScopeCount.push(0); } @@ -1359,9 +1376,8 @@ std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) { } void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { - if (!valueMapper.count(value)) { + if (!valueMapper.count(value)) valueMapper.insert(value, str.str()); - } } /// Return the existing or a new name for a Value. @@ -1383,16 +1399,15 @@ StringRef CppEmitter::getOrCreateName(emitc::ForOp forOp) { if (!valueMapper.count(val)) { - int64_t identifier = loopNestingLevel++; + int64_t identifier = 'i' + loopNestingLevel; - char range = 'z' - 'i'; - if (identifier >= 0 && identifier <= range) { - valueMapper.insert( - val, formatv("{0}_{1}", (char)(identifier + 'i'), ++valueCount)); + if (identifier >= 'i' && identifier <= 'z') { + valueMapper.insert(val, + formatv("{0}_{1}", (char)identifier, ++valueCount)); } else { // If running out of letters, continue with zX valueMapper.insert( - val, formatv("z{0}_{1}", identifier - range - 1, ++valueCount)); + val, formatv("z{0}_{1}", identifier - 'z' - 1, ++valueCount)); } } return *valueMapper.begin(val); @@ -1989,6 +2004,8 @@ LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { void CppEmitter::resetValueCounter() { valueCount = 0; } +void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; } + void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; } LogicalResult emitc::translateToCpp(Operation *op, raw_ostream &os, From 0635689b4e8536165f41bd1364c15a7277e03381 Mon Sep 17 00:00:00 2001 From: ndegener-amd Date: Tue, 15 Apr 2025 04:41:45 -0600 Subject: [PATCH 19/19] Interleaved check statements in test --- .../Target/Cpp/for_loop_induction_vars.mlir | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/mlir/test/Target/Cpp/for_loop_induction_vars.mlir b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir index 365313168cede..c27c93b14583e 100644 --- a/mlir/test/Target/Cpp/for_loop_induction_vars.mlir +++ b/mlir/test/Target/Cpp/for_loop_induction_vars.mlir @@ -1,5 +1,6 @@ // RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s +// CHECK-LABEL: test_for_siblings func.func @test_for_siblings() { %start = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t %stop = "emitc.constant"() <{value = 10 : index}> : () -> !emitc.size_t @@ -8,32 +9,33 @@ func.func @test_for_siblings() { %var1 = "emitc.variable"() <{value = 0 : index}> : () -> !emitc.lvalue %var2 = "emitc.variable"() <{value = 0 : index}> : () -> !emitc.lvalue + // CHECK: for (size_t [[ITER0:i_[0-9]*]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { emitc.for %i0 = %start to %stop step %step { + // CHECK: for (size_t [[ITER1:j_[0-9]*]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { emitc.for %i1 = %start to %stop step %step { + // CHECK: {{.*}} = [[ITER0]]; "emitc.assign"(%var1,%i0) : (!emitc.lvalue, !emitc.size_t) -> () + // CHECK: {{.*}} = [[ITER1]]; "emitc.assign"(%var2,%i1) : (!emitc.lvalue, !emitc.size_t) -> () } } + // CHECK: for (size_t [[ITER2:i_[0-9]*]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) emitc.for %ki2 = %start to %stop step %step { + // CHECK: for (size_t [[ITER3:j_[0-9]*]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) emitc.for %i3 = %start to %stop step %step { %1 = emitc.call_opaque "f"() : () -> i32 } } return } -// CHECK-LABEL: test_for_siblings -// CHECK: for (size_t [[ITER0:i_[0-9]*]] = {{.*}}; [[ITER0]] < {{.*}}; [[ITER0]] += {{.*}}) { - // CHECK: for (size_t [[ITER1:j_[0-9]*]] = {{.*}}; [[ITER1]] < {{.*}}; [[ITER1]] += {{.*}}) { - // CHECK-NEXT: {{.*}} = [[ITER0]]; - // CHECK-NEXT: {{.*}} = [[ITER1]]; -// CHECK: for (size_t [[ITER2:i_[0-9]*]] = {{.*}}; [[ITER2]] < {{.*}}; [[ITER2]] += {{.*}}) - // CHECK: for (size_t [[ITER3:j_[0-9]*]] = {{.*}}; [[ITER3]] < {{.*}}; [[ITER3]] += {{.*}}) +// CHECK-LABEL: test_for_nesting func.func @test_for_nesting() { %start = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t %stop = "emitc.constant"() <{value = 10 : index}> : () -> !emitc.size_t %step = "emitc.constant"() <{value = 1 : index}> : () -> !emitc.size_t + // CHECK-COUNT-18: for (size_t [[ITER:[i-z]_[0-9]*]] = {{.*}}; [[ITER]] < {{.*}}; [[ITER]] += {{.*}}) { emitc.for %i0 = %start to %stop step %step { emitc.for %i1 = %start to %stop step %step { emitc.for %i2 = %start to %stop step %step { @@ -52,7 +54,9 @@ func.func @test_for_nesting() { emitc.for %i15 = %start to %stop step %step { emitc.for %i16 = %start to %stop step %step { emitc.for %i17 = %start to %stop step %step { + // CHECK: for (size_t [[ITERz0:z0_[0-9]*]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { emitc.for %i18 = %start to %stop step %step { + // CHECK: for (size_t [[ITERz1:z1_[0-9]*]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { emitc.for %i19 = %start to %stop step %step { %0 = emitc.call_opaque "f"() : () -> i32 } @@ -77,8 +81,3 @@ func.func @test_for_nesting() { } return } -// CHECK-LABEL: test_for_nesting -// CHECK-COUNT-18: for (size_t [[ITER:[i-z]_[0-9]*]] = {{.*}}; [[ITER]] < {{.*}}; [[ITER]] += {{.*}}) { - // CHECK: for (size_t [[ITERz0:z0_[0-9]*]] = {{.*}}; [[ITERz0]] < {{.*}}; [[ITERz0]] += {{.*}}) { - // CHECK: for (size_t [[ITERz1:z1_[0-9]*]] = {{.*}}; [[ITERz1]] < {{.*}}; [[ITERz1]] += {{.*}}) { -