Skip to content

Commit

Permalink
Calyx native callout pass (llvm#5879)
Browse files Browse the repository at this point in the history
* start working on adding a calyx native callout pass

* missing entry in CMakeLists for circt-opt

* emit calyx in pass

* progress

* specify primitives lib

* it works!!

* fewer imports

* fix CMakeList

* cleaup and comments

* remove useless stringref

* better error message when `calyx` binary is missing

* header style

* remove primitives folder option and define pass-pipeline

* remove braces

* add native pass to calyx namespace

* remove empty namespace

* add dependency to CAPI

* clang-tidy
  • Loading branch information
rachitnigam authored Aug 24, 2023
1 parent 56e98be commit d35c2de
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ tools/arcilator @fabianschuiki @maerhart
**/Conversion/CalyxToFSM @mortbopet
**/Conversion/CalyxToHW @mortbopet @mikeurbach
**/Conversion/SCFToCalyx @mikeurbach @mortbopet
**/Conversion/CalyxNative @rachitnigam
**/Conversion/LoopScheduleToCalyx @andrewb1999 @mikeurbach

# DC
Expand Down
31 changes: 31 additions & 0 deletions include/circt/Conversion/CalyxNative.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===- CalyxNative.h - Calyx Native pass ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declares passes which together will lower the Calyx dialect to the
// HW dialect.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_CONVERSION_CALYXNATIVE_H
#define CIRCT_CONVERSION_CALYXNATIVE_H

#include "circt/Dialect/Calyx/CalyxOps.h"
#include "circt/Support/LLVM.h"
#include <memory>

namespace mlir {
class Pass;
} // namespace mlir

namespace circt {

std::unique_ptr<mlir::Pass> createCalyxNativePass();

} // namespace circt

#endif // CIRCT_CONVERSION_CALYXNATIVE_H
1 change: 1 addition & 0 deletions include/circt/Conversion/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "circt/Conversion/AffineToLoopSchedule.h"
#include "circt/Conversion/ArcToLLVM.h"
#include "circt/Conversion/CalyxNative.h"
#include "circt/Conversion/CalyxToFSM.h"
#include "circt/Conversion/CalyxToHW.h"
#include "circt/Conversion/CombToArith.h"
Expand Down
19 changes: 19 additions & 0 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,25 @@ def CalyxToHW : Pass<"lower-calyx-to-hw", "mlir::ModuleOp"> {
"seq::SeqDialect", "sv::SVDialect"];
}

//===----------------------------------------------------------------------===//
// CalyxNative
//===----------------------------------------------------------------------===//
def CalyxNative : Pass<"calyx-native", "mlir::ModuleOp"> {
let summary = "Callout to the Calyx native compiler and run a pass pipeline";
let description = [{
This pass calls out to the native, Rust-based Calyx compiler to run passes
with it and generate a new, valid, calyx dialect program.
}];
let constructor = "circt::createCalyxNativePass()";
let dependentDialects = ["calyx::CalyxDialect"];
let options = [
Option<"passPipeline", "pass-pipeline", "std::string",
"", "Passes to run with the native compiler">,
];
}



//===----------------------------------------------------------------------===//
// CalyxToFSM
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions lib/CAPI/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_mlir_public_c_api_library(CIRCTCAPIConversion
CIRCTArcToLLVM
CIRCTCalyxToFSM
CIRCTCalyxToHW
CIRCTCalyxNative
CIRCTCombToArith
CIRCTCombToLLVM
CIRCTConvertToArcs
Expand Down
1 change: 1 addition & 0 deletions lib/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ add_subdirectory(SCFToCalyx)
add_subdirectory(SeqToSV)
add_subdirectory(StandardToHandshake)
add_subdirectory(VerifToSV)
add_subdirectory(CalyxNative)
19 changes: 19 additions & 0 deletions lib/Conversion/CalyxNative/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
add_circt_library(CIRCTCalyxNative
CalyxNative.cpp

ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/CalyxNative

DEPENDS
CIRCTConversionPassIncGen

LINK_COMPONENTS
Core

LINK_LIBS PUBLIC
CIRCTCalyx
CIRCTExportCalyx
MLIRIR
MLIRPass
MLIRSupport
)
160 changes: 160 additions & 0 deletions lib/Conversion/CalyxNative/CalyxNative.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//===- CalyxNative.cpp - Invoke the native Calyx compiler
//----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

//===----------------------------------------------------------------------===//
//
// Calls out to the native, Rust-based Calyx compiler using the `calyx` binary
// to run passes.
//
//===----------------------------------------------------------------------===//

#include "../PassDetail.h"

#include "circt/Conversion/CalyxNative.h"
#include "circt/Dialect/Calyx/CalyxEmitter.h"
#include "mlir/Parser/Parser.h"
#include "mlir/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/ToolOutputFile.h"

using namespace mlir;
using namespace circt;

/// ConversionPatterns.

/// Pass entrypoint.

namespace {
class CalyxNativePass : public CalyxNativeBase<CalyxNativePass> {
public:
void runOnOperation() override;

private:
LogicalResult runOnModule(ModuleOp root);
};
} // end anonymous namespace

void CalyxNativePass::runOnOperation() {
ModuleOp mod = getOperation();
if (failed(runOnModule(mod)))
return signalPassFailure();
}

LogicalResult CalyxNativePass::runOnModule(ModuleOp root) {
SmallString<32> execName = llvm::sys::path::filename("calyx");
llvm::ErrorOr<std::string> exeMb = llvm::sys::findProgramByName(execName);

// If cannot find the executable, then nothing to do, return.
if (!exeMb) {
root.emitError() << "cannot find the `calyx` executable in PATH. "
<< "Consider installing `calyx` using `cargo install "
"calyx` or reading the instructions here: "
"https://docs.calyxir.org/#compiler-installation";
return failure();
}
StringRef calyxExe = exeMb.get();

std::string errMsg;
SmallString<32> nativeInputFileName;
std::error_code errCode = llvm::sys::fs::getPotentiallyUniqueTempFileName(
"calyxNativeTemp", /*suffix=*/"", nativeInputFileName);

if (std::error_code ok; errCode != ok) {
root.emitError(
"cannot generate a unique temporary file for input to Calyx compiler");
return failure();
}

// Emit the current program into a file so the native compiler can operate
// over it.
std::unique_ptr<llvm::ToolOutputFile> inputFile =
mlir::openOutputFile(nativeInputFileName, &errMsg);
if (inputFile == nullptr) {
root.emitError(errMsg);
return failure();
}

auto res = circt::calyx::exportCalyx(root, inputFile->os());
if (failed(res))
return failure();
inputFile->os().flush();

// Create a file for the native compiler to write the results into
SmallString<32> nativeOutputFileName;
errCode = llvm::sys::fs::getPotentiallyUniqueTempFileName(
"calyxNativeOutTemp", /*suffix=*/"", nativeOutputFileName);
if (std::error_code ok; errCode != ok) {
root.emitError(
"cannot generate a unique temporary file name to store output");
return failure();
}

llvm::SmallVector<StringRef> calyxArgs = {
calyxExe, nativeInputFileName, "-o", nativeOutputFileName, "-b", "mlir"};

// Configure the native pass pipeline. If passPipeline is provided, we expect
// it to be a comma separated list of passes to run.
if (!passPipeline.empty()) {
llvm::SmallVector<StringRef> passArgs;
llvm::StringRef ppRef = passPipeline;
ppRef.split(passArgs, ",");
for (auto pass : passArgs) {
if (pass.empty())
continue;
calyxArgs.push_back("-p");
calyxArgs.push_back(pass);
}
} else {
// If no arguments are specified, use the default pipeline.
calyxArgs.push_back("-p");
calyxArgs.push_back("all");
}

std::optional<StringRef> redirects[] = {/*stdin=*/std::nullopt,
/*stdout=*/nativeOutputFileName,
/*stderr=*/std::nullopt};

int result = llvm::sys::ExecuteAndWait(
calyxExe, calyxArgs, /*Env=*/std::nullopt,
/*Redirects=*/redirects,
/*SecondsToWait=*/0, /*MemoryLimit=*/0, &errMsg);

if (result != 0) {
root.emitError() << errMsg;
return failure();
}

// Parse the output buffer into a Calyx operation so that we can insert it
// back into the program.
auto bufferRead = llvm::MemoryBuffer::getFile(nativeInputFileName);
if (!bufferRead || !*bufferRead) {
root.emitError("execution of '" + calyxExe +
"' did not produce any output file named '" +
nativeInputFileName + "'");
return failure();
}

// Load the output from the native compiler as a ModuleOp
auto loadedMod =
parseSourceFile<ModuleOp>(nativeOutputFileName.str(), root.getContext());
auto *loadedBlock = loadedMod->getBody();

// XXX(rachitnigam): This is quite baroque. We insert the new block before the
// previous one and then remove the old block. A better thing to do would be
// to replace the moduleOp completely but I couldn't figure out how to do
// that.
auto *oldBlock = root.getBody();
loadedBlock->moveBefore(oldBlock);
oldBlock->erase();
return success();
}

std::unique_ptr<mlir::Pass> circt::createCalyxNativePass() {
return std::make_unique<CalyxNativePass>();
}
1 change: 1 addition & 0 deletions tools/circt-opt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ target_link_libraries(circt-opt
CIRCTArcTransforms
CIRCTCalyx
CIRCTCalyxToHW
CIRCTCalyxNative
CIRCTCalyxToFSM
CIRCTCalyxTransforms
CIRCTComb
Expand Down
1 change: 1 addition & 0 deletions tools/hlstool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ target_link_libraries(hlstool
CIRCTSVTransforms
CIRCTSCFToCalyx
CIRCTCalyx
CIRCTCalyxNative
CIRCTCalyxTransforms
CIRCTCalyxToHW
CIRCTCalyxToFSM
Expand Down

0 comments on commit d35c2de

Please sign in to comment.