[Calyx] Improve error handling in calyx emitter (#3198)

This commit is contained in:
Morten Borup Petersen 2022-05-25 22:08:16 +02:00 committed by GitHub
parent 539e148b1d
commit b3f0634e7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 14 deletions

View File

@ -70,41 +70,67 @@ static bool isValidCalyxAttribute(StringRef identifier) {
llvm::find(booleanAttributes, identifier) != booleanAttributes.end();
}
/// Additional information about an unsupported operation.
static Optional<StringRef> unsupportedOpInfo(Operation *op) {
return llvm::TypeSwitch<Operation *, Optional<StringRef>>(op)
.Case<ExtSILibOp>([](auto) -> Optional<StringRef> {
static std::string_view info =
"calyx.std_extsi is currently not available in the native Rust "
"compiler (see github.com/cucapra/calyx/issues/1009)";
return {info};
})
.Default([](auto) { return Optional<StringRef>(); });
}
/// A tracker to determine which libraries should be imported for a given
/// program.
struct ImportTracker {
public:
/// Returns the list of library names used for in this program.
/// E.g. if `primitives/core.futil` is used, returns { "core" }.
llvm::SmallSet<StringRef, 4> getLibraryNames(ProgramOp program) {
program.walk([&](ComponentOp component) {
FailureOr<llvm::SmallSet<StringRef, 4>> getLibraryNames(ProgramOp program) {
auto walkRes = program.walk([&](ComponentOp component) {
for (auto &op : *component.getBody()) {
if (!isa<CellInterface>(op) || isa<InstanceOp>(op))
// It is not a primitive.
continue;
usedLibraries.insert(getLibraryFor(&op));
auto libraryName = getLibraryFor(&op);
if (failed(libraryName))
return WalkResult::interrupt();
usedLibraries.insert(libraryName.getValue());
}
return WalkResult::advance();
});
if (walkRes.wasInterrupted())
return failure();
return usedLibraries;
}
private:
/// Returns the library name for a given Operation Type.
StringRef getLibraryFor(Operation *op) {
StringRef library;
TypeSwitch<Operation *>(op)
FailureOr<StringRef> getLibraryFor(Operation *op) {
return TypeSwitch<Operation *, FailureOr<StringRef>>(op)
.Case<MemoryOp, RegisterOp, NotLibOp, AndLibOp, OrLibOp, XorLibOp,
AddLibOp, SubLibOp, GtLibOp, LtLibOp, EqLibOp, NeqLibOp, GeLibOp,
LeLibOp, LshLibOp, RshLibOp, SliceLibOp, PadLibOp, WireLibOp>(
[&](auto op) { library = "core"; })
[&](auto op) -> FailureOr<StringRef> {
static std::string_view sCore = "core";
return {sCore};
})
.Case<SgtLibOp, SltLibOp, SeqLibOp, SneqLibOp, SgeLibOp, SleLibOp,
SrshLibOp, MultPipeLibOp, DivPipeLibOp>(
[&](auto op) { library = "binary_operators"; })
[&](auto op) -> FailureOr<StringRef> {
static std::string_view sBinaryOperators = "binary_operators";
return {sBinaryOperators};
})
/*.Case<>([&](auto op) { library = "math"; })*/
.Default([&](auto op) {
llvm_unreachable("Type matching failed for this operation.");
auto diag = op->emitOpError() << "not supported for emission";
auto note = unsupportedOpInfo(op);
if (note)
diag.attachNote() << *note;
return diag;
});
return library;
}
/// Maintains a unique list of libraries used throughout the lifetime of the
/// tracker.
@ -150,7 +176,7 @@ struct Emitter {
}
/// Import emission.
void emitImports(ProgramOp op) {
LogicalResult emitImports(ProgramOp op) {
auto emitImport = [&](StringRef library) {
// Libraries share a common relative path:
// primitives/<library-name>.futil
@ -158,8 +184,14 @@ struct Emitter {
<< "futil" << delimiter() << semicolonEndL();
};
for (StringRef library : importTracker.getLibraryNames(op))
auto libraryNames = importTracker.getLibraryNames(op);
if (failed(libraryNames))
return failure();
for (StringRef library : libraryNames.getValue())
emitImport(library);
return success();
}
// Component emission
@ -680,10 +712,14 @@ mlir::LogicalResult circt::calyx::exportCalyx(mlir::ModuleOp module,
llvm::raw_ostream &os) {
Emitter emitter(os);
for (auto &op : *module.getBody()) {
op.walk([&](ProgramOp program) {
emitter.emitImports(program);
auto walkRes = op.walk([&](ProgramOp program) {
if (failed(emitter.emitImports(program)))
return WalkResult::interrupt();
emitter.emitProgram(program);
return WalkResult::advance();
});
if (walkRes.wasInterrupted())
return failure();
}
emitter.emitCiderMetadata(module);
return emitter.finalize();

View File

@ -0,0 +1,16 @@
// RUN: circt-translate -split-input-file --export-calyx --verify-diagnostics %s
calyx.program "main" {
calyx.component @main(%in0: i4, %clk: i1 {clk}, %reset: i1 {reset}, %go: i1 {go}) -> (%out0: i8, %done: i1 {done}) {
%true = hw.constant true
// expected-error @+2 {{'calyx.std_extsi' op not supported for emission}}
// expected-note @+1 {{calyx.std_extsi is currently not available in the native Rust compiler (see github.com/cucapra/calyx/issues/1009)}}
%std_extsi.in, %std_extsi.out = calyx.std_extsi @std_extsi : i4, i8
calyx.wires {
calyx.assign %std_extsi.in = %in0 : i4
calyx.assign %out0 = %std_extsi.out : i8
calyx.assign %done = %true : i1
}
calyx.control {}
}
}