Skip to content

Commit 169cbbd

Browse files
committed
[Sim] Set the GetFileOp operation to procedural only
1 parent 2cdd246 commit 169cbbd

6 files changed

Lines changed: 64 additions & 114 deletions

File tree

include/circt/Dialect/Sim/SimOps.td

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -610,17 +610,22 @@ def PrintFormattedProcOp : SimOp<"proc.print", [ProceduralOp]> {
610610
let assemblyFormat = "$input (`to` $stream^)? attr-dict";
611611
}
612612

613-
def GetFileOp : SimOp<"get_file", [Pure]> {
614-
let summary = "Get an output stream for a formatted file name";
613+
def GetFileOp : SimOp<"get_file", [ProceduralOp]> {
614+
let summary = "Create an output stream for a formatted file name";
615615
let description = [{
616-
Resolves a file name from a `!sim.fstring` value and returns an output
617-
stream resource that can be consumed by `sim.print` or `sim.proc.print`.
618-
The file-name format string should be constructed using `sim.fmt.*`
619-
operations, just like any other Sim format-string value.
620-
The file-name format string is evaluated whenever the stream is accessed.
616+
Resolves a file name from a `!sim.fstring` value, immediately creates the
617+
corresponding file, and returns an output stream resource that can be
618+
consumed by `sim.proc.print`. The file-name format string should be
619+
constructed using `sim.fmt.*` operations, just like any other Sim
620+
format-string value.
621+
622+
This operation has an immediate side effect: executing it creates the file,
623+
even if the returned stream is never subsequently consumed.
621624

622625
The concrete runtime representation and lifetime management of the returned
623626
stream are backend-defined.
627+
628+
This operation must be within a procedural region.
624629
}];
625630

626631
let arguments = (ins FormatStringType:$fileName);

lib/Conversion/SimToSV/SimToSV.cpp

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -731,11 +731,37 @@ FailureOr<Value> createFileDescriptorGetterForGetFile(GetFileOp getFileOp,
731731
LogicalResult lowerPrintFormattedProcToSV(hw::HWModuleOp module,
732732
const TypeConverter &typeConverter,
733733
SimConversionState &state) {
734+
SmallVector<GetFileOp> getFileOps;
734735
SmallVector<PrintFormattedProcOp> printOps;
735-
module.walk([&](PrintFormattedProcOp op) { printOps.push_back(op); });
736+
module.walk([&](Operation *op) {
737+
if (auto getFileOp = dyn_cast<GetFileOp>(op))
738+
getFileOps.push_back(getFileOp);
739+
if (auto printOp = dyn_cast<PrintFormattedProcOp>(op))
740+
printOps.push_back(printOp);
741+
});
736742

737743
llvm::SmallPtrSet<Operation *, 8> dceRoots;
738744

745+
for (auto getFileOp : getFileOps) {
746+
OpBuilder builder(getFileOp);
747+
auto fdOrFailure = createFileDescriptorGetterForGetFile(getFileOp, builder);
748+
if (failed(fdOrFailure))
749+
return failure();
750+
751+
auto stream = mlir::UnrealizedConversionCastOp::create(
752+
builder, getFileOp.getLoc(), getFileOp.getResult().getType(),
753+
*fdOrFailure);
754+
getFileOp.replaceAllUsesWith(stream.getResult(0));
755+
state.usedFileDescriptorRuntime = true;
756+
state.usedSynthesisMacro = true;
757+
758+
auto *procRoot =
759+
getFileOp->getParentWithTrait<mlir::OpTrait::IsIsolatedFromAbove>();
760+
if (procRoot)
761+
dceRoots.insert(procRoot);
762+
getFileOp.erase();
763+
}
764+
739765
for (auto printOp : printOps) {
740766
OpBuilder builder(printOp);
741767
SmallString<128> formatString;
@@ -752,22 +778,11 @@ LogicalResult lowerPrintFormattedProcToSV(hw::HWModuleOp module,
752778
// no stream is specified, emit sv.write.
753779
sv::WriteOp::create(builder, printOp.getLoc(), formatString, args);
754780
} else {
755-
Value fd;
756-
if (auto getFileOp = stream.getDefiningOp<GetFileOp>()) {
757-
auto fdOrFailure =
758-
createFileDescriptorGetterForGetFile(getFileOp, builder);
759-
if (failed(fdOrFailure))
760-
return failure();
761-
fd = *fdOrFailure;
762-
state.usedFileDescriptorRuntime = true;
763-
state.usedSynthesisMacro = true;
764-
} else {
765-
auto fdType = typeConverter.convertType(stream.getType());
766-
assert(fdType && "expected output stream type conversion");
767-
fd = mlir::UnrealizedConversionCastOp::create(builder, printOp.getLoc(),
768-
fdType, stream)
769-
->getResult(0);
770-
}
781+
auto fdType = typeConverter.convertType(stream.getType());
782+
assert(fdType && "expected output stream type conversion");
783+
Value fd = mlir::UnrealizedConversionCastOp::create(
784+
builder, printOp.getLoc(), fdType, stream)
785+
->getResult(0);
771786
sv::FWriteOp::create(builder, printOp.getLoc(), fd, formatString, args);
772787
}
773788
auto *procRoot =

test/Conversion/SimToSV/lower-print-formatted-proc-to-sv.mlir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ hw.module @print_to_file_under_condition(in %clk : i1, in %idx : i8, in %en : i1
173173
scf.if %en_in {
174174
%msg = sim.fmt.literal "enabled"
175175
// CHECK: ^bb0(%[[IDX:.+]]: i8, %[[EN:.+]]: i1):
176+
// CHECK-NEXT: %[[UNSIGNED:.+]] = sv.system "unsigned"(%[[IDX]]) : (i8) -> i8
177+
// CHECK-NEXT: %[[FILENAME:.+]] = sv.sformatf "trace_%02d.log"(%[[UNSIGNED]]) : i8
178+
// CHECK-NEXT: %[[FD:.+]] = sv.func.call.procedural @"__circt_lib_logging::FileDescriptor::get"(%[[FILENAME]]) : (!hw.string) -> i32
176179
// CHECK-NEXT: scf.if %[[EN]] {
177-
// CHECK-NEXT: %[[UNSIGNED:.+]] = sv.system "unsigned"(%[[IDX]]) : (i8) -> i8
178-
// CHECK-NEXT: %[[FILENAME:.+]] = sv.sformatf "trace_%02d.log"(%[[UNSIGNED]]) : i8
179-
// CHECK-NEXT: %[[FD:.+]] = sv.func.call.procedural @"__circt_lib_logging::FileDescriptor::get"(%[[FILENAME]]) : (!hw.string) -> i32
180180
// CHECK-NEXT: sv.fwrite %[[FD]], "enabled"
181181
sim.proc.print %msg to %file
182182
}

test/Dialect/Sim/proceduralize-sim.mlir

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -282,84 +282,3 @@ hw.module @condition_as_val(in %clk: !seq.clock, in %condval: i1) {
282282
%bin = sim.fmt.bin %condval specifierWidth 1 : i1
283283
sim.print %bin on %clk if %condval
284284
}
285-
286-
// CHECK-LABEL: @print_with_stream
287-
// CHECK-NEXT: %[[TRG:.*]] = seq.from_clock %clk
288-
// CHECK-NEXT: hw.triggered posedge %[[TRG]](%cond, %idx) : i1, i32 {
289-
// CHECK-NEXT: ^bb0(%[[ARGCOND:.*]]: i1, %[[ARGIDX:.*]]: i32):
290-
// CHECK-DAG: %[[FMT:.*]] = sim.fmt.literal "stream"
291-
// CHECK-DAG: %[[PFX:.*]] = sim.fmt.literal "out_"
292-
// CHECK-DAG: %[[NUM:.*]] = sim.fmt.dec %[[ARGIDX]] : i32
293-
// CHECK-DAG: %[[SFX:.*]] = sim.fmt.literal ".log"
294-
// CHECK-DAG: %[[FNAME:.*]] = sim.fmt.concat (%[[PFX]], %[[NUM]], %[[SFX]])
295-
// CHECK-DAG: %[[FILE:.*]] = sim.get_file %[[FNAME]]
296-
// CHECK: scf.if %[[ARGCOND]] {
297-
// CHECK-NEXT: sim.proc.print %[[FMT]] to %[[FILE]]
298-
// CHECK-NEXT: }
299-
// CHECK-NEXT: }
300-
hw.module @print_with_stream(in %clk: !seq.clock, in %cond: i1, in %idx: i32) {
301-
%fmt = sim.fmt.literal "stream"
302-
%prefix = sim.fmt.literal "out_"
303-
%idxFmt = sim.fmt.dec %idx : i32
304-
%suffix = sim.fmt.literal ".log"
305-
%fileName = sim.fmt.concat (%prefix, %idxFmt, %suffix)
306-
%file = sim.get_file %fileName
307-
sim.print %fmt on %clk if %cond to %file
308-
}
309-
310-
// CHECK-LABEL: @print_with_stream_two_conditions
311-
// CHECK-NEXT: %[[TRG:.*]] = seq.from_clock %clk
312-
// CHECK-NEXT: hw.triggered posedge %[[TRG]](%c1, %idx, %c2) : i1, i32, i1 {
313-
// CHECK-NEXT: ^bb0(%[[ARGC1:.*]]: i1, %[[ARGIDX:.*]]: i32, %[[ARGC2:.*]]: i1):
314-
// CHECK-DAG: %[[FMT:.*]] = sim.fmt.literal "stream2"
315-
// CHECK-DAG: %[[PFX:.*]] = sim.fmt.literal "out2_"
316-
// CHECK-DAG: %[[NUM:.*]] = sim.fmt.dec %[[ARGIDX]] : i32
317-
// CHECK-DAG: %[[SFX:.*]] = sim.fmt.literal ".log"
318-
// CHECK-DAG: %[[FNAME:.*]] = sim.fmt.concat (%[[PFX]], %[[NUM]], %[[SFX]])
319-
// CHECK-DAG: %[[FILE:.*]] = sim.get_file %[[FNAME]]
320-
// CHECK: scf.if %[[ARGC1]] {
321-
// CHECK-NEXT: sim.proc.print %[[FMT]] to %[[FILE]]
322-
// CHECK-NEXT: }
323-
// CHECK-NEXT: scf.if %[[ARGC2]] {
324-
// CHECK-NEXT: sim.proc.print %[[FMT]] to %[[FILE]]
325-
// CHECK-NEXT: }
326-
// CHECK-NEXT: }
327-
hw.module @print_with_stream_two_conditions(in %clk: !seq.clock, in %c1: i1, in %c2: i1, in %idx: i32) {
328-
%fmt = sim.fmt.literal "stream2"
329-
%prefix = sim.fmt.literal "out2_"
330-
%idxFmt = sim.fmt.dec %idx : i32
331-
%suffix = sim.fmt.literal ".log"
332-
%fileName = sim.fmt.concat (%prefix, %idxFmt, %suffix)
333-
%file = sim.get_file %fileName
334-
sim.print %fmt on %clk if %c1 to %file
335-
sim.print %fmt on %clk if %c2 to %file
336-
}
337-
338-
// CHECK-LABEL: @shared_fmt_between_print_and_get_file
339-
// CHECK-NEXT: %[[TRG:.*]] = seq.from_clock %clk
340-
// CHECK-NEXT: hw.triggered posedge %[[TRG]](%cond, %idx) : i1, i32 {
341-
// CHECK-NEXT: ^bb0(%[[ARGCOND:.*]]: i1, %[[ARGIDX:.*]]: i32):
342-
// CHECK-DAG: %[[SHARED:.*]] = sim.fmt.dec %[[ARGIDX]] : i32
343-
// CHECK-DAG: %[[MSGPFX:.*]] = sim.fmt.literal "value="
344-
// CHECK-DAG: %[[FILEPFX:.*]] = sim.fmt.literal "out_"
345-
// CHECK-DAG: %[[FILESFX:.*]] = sim.fmt.literal ".log"
346-
// CHECK-DAG: %[[MSG:.*]] = sim.fmt.concat (%[[MSGPFX]], %[[SHARED]])
347-
// CHECK-DAG: %[[FNAME:.*]] = sim.fmt.concat (%[[FILEPFX]], %[[SHARED]], %[[FILESFX]])
348-
// CHECK-DAG: %[[FILE:.*]] = sim.get_file %[[FNAME]]
349-
// CHECK: scf.if %[[ARGCOND]] {
350-
// CHECK-NEXT: sim.proc.print %[[MSG]] to %[[FILE]]
351-
// CHECK-NEXT: }
352-
// CHECK-NEXT: }
353-
hw.module @shared_fmt_between_print_and_get_file(
354-
in %clk: !seq.clock, in %cond: i1, in %idx: i32) {
355-
%shared = sim.fmt.dec %idx : i32
356-
%msgPrefix = sim.fmt.literal "value="
357-
%msg = sim.fmt.concat (%msgPrefix, %shared)
358-
359-
%filePrefix = sim.fmt.literal "out_"
360-
%fileSuffix = sim.fmt.literal ".log"
361-
%fileName = sim.fmt.concat (%filePrefix, %shared, %fileSuffix)
362-
%file = sim.get_file %fileName
363-
364-
sim.print %msg on %clk if %cond to %file
365-
}

test/Dialect/Sim/round-trip.mlir

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ func.func @DynamicStrings(%idx: i32) {
102102
return
103103
}
104104

105-
// CHECK-LABEL: hw.module @PrintFormattedWithStream
106-
hw.module @PrintFormattedWithStream(in %clock: !seq.clock, in %condition: i1, in %idx: i32) {
105+
// CHECK-LABEL: hw.module @ProceduralPrintWithGetFile
106+
hw.module @ProceduralPrintWithGetFile(in %clock: !seq.clock, in %condition: i1, in %idx: i32) {
107107
// CHECK: %[[FMT:.*]] = sim.fmt.literal "literal string"
108108
%str = sim.fmt.literal "literal string"
109109
// CHECK: %[[FN0:.*]] = sim.fmt.literal "output_"
@@ -114,12 +114,15 @@ hw.module @PrintFormattedWithStream(in %clock: !seq.clock, in %condition: i1, in
114114
%fn2 = sim.fmt.literal ".txt"
115115
// CHECK: %[[FNAME:.*]] = sim.fmt.concat (%[[FN0]], %[[FN1]], %[[FN2]])
116116
%fileName = sim.fmt.concat (%fn0, %fn1, %fn2)
117-
// CHECK: %[[FILE:.*]] = sim.get_file %[[FNAME]]
118-
%file = sim.get_file %fileName
119117
// CHECK: sim.print %[[FMT]] on %clock if %condition
120118
sim.print %str on %clock if %condition
121-
// CHECK: sim.print %[[FMT]] on %clock if %condition to %[[FILE]]
122-
sim.print %str on %clock if %condition to %file
119+
// CHECK: sim.triggered %clock if %condition {
120+
sim.triggered %clock if %condition {
121+
// CHECK: %[[FILE:.*]] = sim.get_file %[[FNAME]]
122+
%file = sim.get_file %fileName
123+
// CHECK: sim.proc.print %[[FMT]] to %[[FILE]]
124+
sim.proc.print %str to %file
125+
}
123126
}
124127

125128
// CHECK-LABEL: hw.module @ProceduralPrint

test/Dialect/Sim/sim-errors.mlir

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ hw.module @procedural_ops_terminate() {
4848

4949
// -----
5050

51+
hw.module @procedural_ops_get_file() {
52+
%name = sim.fmt.literal "out.log"
53+
// expected-error @below {{must not be in a non-procedural region}}
54+
%file = sim.get_file %name
55+
}
56+
57+
// -----
58+
5159
hw.module @nonprocedural_ops_print(in %trigger : i1, in %clock : !seq.clock, in %cond : i1) {
5260
hw.triggered posedge %trigger {
5361
%lit = sim.fmt.literal "Nope"

0 commit comments

Comments
 (0)