Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Moore] A new pass to delete local temporary variables. #6990

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

hailongSun2000
Copy link
Member

Hey, @fabianschuiki! Please review this at your convenience! Thanks in advance!
This PR is about deleting local variables.
For example:

int x, y, z;
always_comb begin
  automatic int a;
  a = x + 1;
  y = a;
  a = a + 1;
  z = a;
end

To

int x, y, z;
y = x + 1;
z = (x + 1) + 1;

Anything about code details could be pointed out.

@hailongSun2000
Copy link
Member Author

hailongSun2000 commented May 6, 2024

The further IR details:
From

module {
  moore.module @Foo {
    %x = moore.variable : !moore.int
    %y = moore.variable : !moore.int
    %z = moore.variable : !moore.int
    moore.procedure always_comb {
      %a = moore.variable : !moore.int
      %0 = moore.constant 1 : !moore.int
      %1 = moore.add %x, %0 : !moore.int
      moore.blocking_assign %a, %1 : !moore.int
      moore.blocking_assign %y, %a : !moore.int
      %2 = moore.constant 1 : !moore.int
      %3 = moore.add %a, %2 : !moore.int
      moore.blocking_assign %a, %3 : !moore.int
      moore.blocking_assign %z, %a : !moore.int
    }
  }
}

To

moore.procedure always_comb {
  %0 = moore.constant 1 : !moore.int
  %1 = moore.add %x, %0 : !moore.int
  moore.blocking_assign %y, %1 : !moore.int
  %2 = moore.constant 1 : !moore.int
  %3 = moore.add %1, %2 : !moore.int
  moore.blocking_assign %z, %3 : !moore.int
}

or
From

module Foo;
  int x, y, z;
  bit cond;
  always_latch begin
    automatic int a;
    if(!cond) begin
      a = x + 10;
      y = a;
      if(cond) begin
        a = a + 3;
        z = a;
      end
      else begin
        z = y + a;
      end
    end
  end
endmodule

moore.procedure always_latch {
      %a = moore.variable : !moore.int
      %0 = moore.not %cond : !moore.bit
      %1 = moore.conversion %0 : !moore.bit -> i1
      scf.if %1 {
        %2 = moore.constant 10 : !moore.int
        %3 = moore.add %x, %2 : !moore.int
        moore.blocking_assign %a, %3 : !moore.int
        moore.blocking_assign %y, %a : !moore.int
        %4 = moore.conversion %cond : !moore.bit -> i1
        scf.if %4 {
          %5 = moore.constant 3 : !moore.int
          %6 = moore.add %a, %5 : !moore.int
          moore.blocking_assign %a, %6 : !moore.int
          moore.blocking_assign %z, %a : !moore.int
        } else {
          %5 = moore.add %y, %a : !moore.int
          moore.blocking_assign %z, %5 : !moore.int
        }
      }
    }


To

y = x + 10;
if(cond){
z = x + 10 + 3;
}
else{
z = x + 10 + x + 10
}

moore.procedure always_latch {
  %0 = moore.not %cond : !moore.bit
  %1 = moore.conversion %0 : !moore.bit -> i1
  scf.if %1 {
    %2 = moore.constant 10 : !moore.int
    %3 = moore.add %x, %2 : !moore.int
    moore.blocking_assign %y, %3 : !moore.int
    %4 = moore.conversion %cond : !moore.bit -> i1
    scf.if %4 {
      %5 = moore.constant 3 : !moore.int
      %6 = moore.add %3, %5 : !moore.int
      moore.blocking_assign %z, %6 : !moore.int
    } else {
      %5 = moore.add %y, %3 : !moore.int
      moore.blocking_assign %z, %5 : !moore.int
    }
  }
}

The above-mentioned are just one step before generating the Core IR.

@hailongSun2000
Copy link
Member Author

All Build and Tests are passing on my personal computer. It's so strange!

@hailongSun2000 hailongSun2000 marked this pull request as draft May 6, 2024 11:04
@hailongSun2000 hailongSun2000 added the Verilog/SystemVerilog Involving a Verilog dialect label May 7, 2024
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
include/circt/Dialect/Moore/MoorePasses.td Outdated Show resolved Hide resolved
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
@hailongSun2000 hailongSun2000 force-pushed the hailong/delete-local-variables-pass branch from 6a09633 to f047ad1 Compare May 7, 2024 09:48
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
include/circt/Dialect/Moore/MoorePasses.td Outdated Show resolved Hide resolved
include/circt/Dialect/Moore/MoorePasses.td Outdated Show resolved Hide resolved
Copy link
Contributor

@fabianschuiki fabianschuiki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see this take shape!

It would be nice to have a bunch of tests that make sure all the different code paths through the pass' code work as expected. And that also make sure that things which the pass does not yet support (for example, myStruct.myField[42] = x) either produce an error message or are left in their original state.

lib/Dialect/Moore/Transforms/DeleteLocalVar.cpp Outdated Show resolved Hide resolved
lib/Conversion/MooreToCore/MooreToCore.cpp Outdated Show resolved Hide resolved
include/circt/Dialect/Moore/MoorePasses.h Outdated Show resolved Hide resolved
@hailongSun2000
Copy link
Member Author

Great to see this take shape!

It would be nice to have a bunch of tests that make sure all the different code paths through the pass' code work as expected. And that also make sure that things which the pass does not yet support (for example, myStruct.myField[42] = x) either produce an error message or are left in their original state.

Yeah, I'll test more cases to ensure its correction.

@hailongSun2000 hailongSun2000 force-pushed the hailong/delete-local-variables-pass branch 3 times, most recently from 01e0f6b to 068a28d Compare May 9, 2024 09:53
tools/circt-verilog/circt-verilog.cpp Outdated Show resolved Hide resolved
Comment on lines 223 to 236
/// Parse specified files that had been translated into Moore dialect IR. After
/// that simplify these files like deleting local variables, and then emit the
/// resulting Moore dialect IR .
static LogicalResult populateMooreTransforms(MLIRContext &context,
ModuleOp module) {
PassManager pm(&context);
pm.addNestedPass<moore::SVModuleOp>(circt::moore::createDeleteLocalVarPass());
// TODO: like dedup pass.

if (failed(pm.run(module)))
return failure();

return success();
}

/// Convert Moore dialect IR into core dialect IR
static LogicalResult populateLowMooreToCore(MLIRContext &context,
ModuleOp module) {
PassManager pm(&context);
pm.addPass(createConvertMooreToCorePass());

if (failed(pm.run(module)))
return failure();

return success();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great that you have dedicated populate* functions to populate the pipeline 🥳

Instead of creating a pass manager in these functions and running it immediately, the populate functions should accept the pass manager as a function argument and then just populate it with passes (that's why the function name starts with "populate"). For example: https://github.com/llvm/circt/blob/main/lib/Firtool/Firtool.cpp#L26-L49

The firtool tool then calls these populate functions to fill in its own pass manager, and then at the very end calls pm.run to run everything: https://github.com/llvm/circt/blob/main/tools/firtool/firtool.cpp#L377-L481

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your detailed explanation!
Later, I'll enumerate some examples about DeleteLocalVarPass.

@hailongSun2000 hailongSun2000 force-pushed the hailong/delete-local-variables-pass branch from 068a28d to a336f37 Compare May 10, 2024 03:30
@hailongSun2000
Copy link
Member Author

Great to see this take shape!

It would be nice to have a bunch of tests that make sure all the different code paths through the pass' code work as expected. And that also make sure that things which the pass does not yet support (for example, myStruct.myField[42] = x) either produce an error message or are left in their original state.

I have an example:

module Foo;
  int x, y;
  always_comb begin
    typedef struct packed signed {int a, b;} int64;
    int64 ii;
    ii.a = x + 1;                  // error: unsupported expression: MemberAccess
    ii.b = x;
    y = ii.a;
  end
endmodule

Or

module Foo;
  int x, y;
  always_comb begin
    typedef struct packed signed {int a,b;} int64;
    int64 ii = '{ x+1, x};       // error: unsupported expression: SimpleAssignmentPattern
    y = ii;
  end
endmodule

However, these error messages are thrown by importVerilog because we don't implement them.
So may I handle/verify the local struct int64 after supporting the related struct?

Comment on lines +68 to +75
if (valueSymbols.count(destOp)) {
if (auto srcValue = valueSymbols.lookup(srcOp))
valueSymbols.insert(destOp, srcValue);
else
valueSymbols.insert(destOp, op.getSrc());

isNewValue = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all you need is an else branch here that emits an error. Something like "cannot assign this expression". This will make sure that the user sees a proper error for anything that the pass does not yet fully support.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't misunderstand, I need to add an else branch. Like if(valueSymbols.count(destOp)){...} else{error:...} . But this will lead to global variables also triggering this error.

@fabianschuiki
Copy link
Contributor

By the way, @dtzSiFive has mentioned that MLIR has a mem2reg pass: https://github.com/llvm/llvm-project/blob/main/mlir/lib/Transforms/Mem2Reg.cpp

You might be able to rely on that pass to do the heavy lifting for getting rid of local variables.

@hailongSun2000
Copy link
Member Author

By the way, @dtzSiFive has mentioned that MLIR has a mem2reg pass: https://github.com/llvm/llvm-project/blob/main/mlir/lib/Transforms/Mem2Reg.cpp

You might be able to rely on that pass to do the heavy lifting for getting rid of local variables.

I'll try it again. Originally, I attempted to call createMem2Reg, but it didn't work to delete local variables. Maybe I got the call createMem2Reg wrong.

@hailongSun2000
Copy link
Member Author

hailongSun2000 commented May 11, 2024

Yeah, Mem2Reg doesn't handle moore IR. It just looks like --parse-only.

image

@fabianschuiki
Copy link
Contributor

fabianschuiki commented May 11, 2024 via email

@hailongSun2000 hailongSun2000 added Moore and removed Verilog/SystemVerilog Involving a Verilog dialect labels May 11, 2024
@cepheus69
Copy link
Contributor

cepheus69 commented May 11, 2024

That means we need new interfaces for specified operations 🤔 So MooreOpInterface is coming ?

@fabianschuiki
Copy link
Contributor

I think all you need is to add the PromotableOpInterface, PromotableOpInterface, or other interface that Mem2Reg uses to the list of traits of the corresponding Moore op definition. The InstanceOp already does this for the SymbolUserOpInterface: https://github.com/llvm/circt/blob/main/include/circt/Dialect/Moore/MooreOps.td#L64-L66

As far as I can tell, only the MemRef and LLVMIR dialects in MLIR support mem2reg, or at least have a test for it: https://github.com/llvm/llvm-project/blob/main/mlir/test/Dialect/MemRef/mem2reg.mlir. But you may be able to look at the op definitions in the MemRef dialect to see which of the Mem2Reg op interfaces you have to implement.

@hailongSun2000
Copy link
Member Author

hailongSun2000 commented May 12, 2024

Yeah, that's right! We don't create a new OpInterface for moore dialect. At least not for now. I was yesterday referred to LLVMIR which also uses the PromotableOpInterface and other Promotable*OpInterface. However, I met the ld.lld error(undefined symbol). Maybe I forgot something to link it in the CMakeLists.
img_v3_02ap_2ce28d57-6424-4773-ac2e-88e65e342d7g
Like the above image, I separately added the MemoryslotInterfaces.h and MemoryslotInterfaces.td to the MooreOp.h and MooreOp.td, and added MLIRMemorySlotInterfaces/MLIRTransforms(just one of them, I forgot 😢 ) into CMakeLists. But I'll solve it tomorrow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants