Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/circt/Dialect/Arc/Runtime/IRInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,22 @@ ARC_IR_EXPORT void arcRuntimeIR_onInitialized(uint8_t *modelState);
ARC_IR_EXPORT void
arcRuntimeIR_format(const circt::arc::runtime::FmtDescriptor *fmt, ...);

/// Return the standard output stream.
ARC_IR_EXPORT uint8_t *arcRuntimeIR_getStdoutStream();

/// Return the standard error stream.
ARC_IR_EXPORT uint8_t *arcRuntimeIR_getStderrStream();

/// Prints a formatted string to the given stream.
///
/// `fmt` is an array of `FmtDescriptor` objects, ending in a descriptor with
/// action `Action_End`.
///
/// The values to format are passed as variadic arguments.
ARC_IR_EXPORT void
arcRuntimeIR_formatToStream(uint8_t *stream,
const circt::arc::runtime::FmtDescriptor *fmt, ...);

Comment thread
nanjo712 marked this conversation as resolved.
/// Release the active trace buffer and request an empty new buffer.
///
/// Invoked by the model to signal that the currently active trace buffer,
Expand Down
8 changes: 8 additions & 0 deletions include/circt/Dialect/Arc/Runtime/JITBind.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,21 @@ struct APICallbacks {
void (*fnOnEval)(uint8_t *simState);
void (*fnOnInitialized)(uint8_t *simState);
void (*fnFormat)(const FmtDescriptor *fmt, ...);
uint8_t *(*fnGetStdoutStream)();
uint8_t *(*fnGetStderrStream)();
void (*fnFormatToStream)(uint8_t *stream, const FmtDescriptor *fmt, ...);
uint64_t *(*fnSwapTraceBuffer)(const uint8_t *simState);

static constexpr char symNameAllocInstance[] = "arcRuntimeIR_allocInstance";
static constexpr char symNameDeleteInstance[] = "arcRuntimeIR_deleteInstance";
static constexpr char symNameOnEval[] = "arcRuntimeIR_onEval";
static constexpr char symNameOnInitialized[] = "arcRuntimeIR_onInitialized";
static constexpr char symNameFormat[] = "arcRuntimeIR_format";
static constexpr char symNameGetStdoutStream[] =
"arcRuntimeIR_getStdoutStream";
static constexpr char symNameGetStderrStream[] =
"arcRuntimeIR_getStderrStream";
static constexpr char symNameFormatToStream[] = "arcRuntimeIR_formatToStream";
static constexpr char symNameSwapTraceBuffer[] =
"arcRuntimeIR_swapTraceBuffer";
};
Expand Down
78 changes: 76 additions & 2 deletions lib/Conversion/ArcToLLVM/LowerArcToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,68 @@ FailureOr<LLVM::CallOp> emitFmtCall(OpBuilder &builder, Location loc,
return result;
}

FailureOr<LLVM::CallOp> emitFmtToStreamCall(OpBuilder &builder, Location loc,
StringCache &stringCache,
Value stream,
ArrayRef<FmtDescriptor> descriptors,
ValueRange args) {
Comment thread
nanjo712 marked this conversation as resolved.
Outdated
ModuleOp moduleOp =
builder.getInsertionBlock()->getParent()->getParentOfType<ModuleOp>();
MLIRContext *ctx = builder.getContext();
auto ptrType = LLVM::LLVMPointerType::get(ctx);
SmallVector<Type, 2> paramTypes{ptrType, ptrType};
auto func = LLVM::lookupOrCreateFn(
builder, moduleOp, runtime::APICallbacks::symNameFormatToStream,
paramTypes, LLVM::LLVMVoidType::get(ctx), true);
if (failed(func))
return func;

StringRef rawDescriptors(reinterpret_cast<const char *>(descriptors.data()),
descriptors.size() * sizeof(FmtDescriptor));
Value fmtPtr = stringCache.getOrCreate(builder, rawDescriptors);

SmallVector<Value> argsVec{stream, fmtPtr};
argsVec.append(args.begin(), args.end());
auto result = LLVM::CallOp::create(builder, loc, func.value(), argsVec);

for (Value arg : args) {
Operation *definingOp = arg.getDefiningOp();
if (auto alloca = dyn_cast_if_present<LLVM::AllocaOp>(definingOp))
LLVM::LifetimeEndOp::create(builder, loc, arg);
}

return result;
}

template <typename SourceOp>
struct SimStreamOpLowering : public OpConversionPattern<SourceOp> {
SimStreamOpLowering(const TypeConverter &typeConverter, MLIRContext *context,
StringRef symbolName)
: OpConversionPattern<SourceOp>(typeConverter, context),
symbolName(symbolName) {}

LogicalResult
matchAndRewrite(SourceOp op, typename SourceOp::Adaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
ModuleOp moduleOp = op->template getParentOfType<ModuleOp>();
if (!moduleOp)
return failure();

auto ptrType = LLVM::LLVMPointerType::get(rewriter.getContext());
auto func =
LLVM::lookupOrCreateFn(rewriter, moduleOp, symbolName, {}, ptrType);
if (failed(func))
return failure();

auto call =
LLVM::CallOp::create(rewriter, op.getLoc(), func.value(), ValueRange{});
rewriter.replaceOp(op, call.getResults());
return success();
}

StringRef symbolName;
};

struct SimPrintFormattedProcOpLowering
: public OpConversionPattern<sim::PrintFormattedProcOp> {
SimPrintFormattedProcOpLowering(const TypeConverter &typeConverter,
Expand All @@ -1052,8 +1114,13 @@ struct SimPrintFormattedProcOpLowering
// Add the end descriptor.
formatInfo->descriptors.push_back(FmtDescriptor());

auto result = emitFmtCall(rewriter, op.getLoc(), stringCache,
formatInfo->descriptors, formatInfo->args);
FailureOr<LLVM::CallOp> result =
op.getStream()
? emitFmtToStreamCall(rewriter, op.getLoc(), stringCache,
adaptor.getStream(), formatInfo->descriptors,
formatInfo->args)
: emitFmtCall(rewriter, op.getLoc(), stringCache,
formatInfo->descriptors, formatInfo->args);
if (failed(result))
return failure();
rewriter.replaceOp(op, result.value());
Expand Down Expand Up @@ -1821,6 +1888,9 @@ void LowerArcToLLVMPass::runOnOperation() {
converter.addConversion([&](sim::FormatStringType type) {
return LLVM::LLVMPointerType::get(type.getContext());
});
converter.addConversion([&](sim::OutputStreamType type) {
return LLVM::LLVMPointerType::get(type.getContext());
});
converter.addConversion([&](llhd::TimeType type) {
// LLHD time is represented as i64 femtoseconds.
return IntegerType::get(type.getContext(), 64);
Expand Down Expand Up @@ -1912,6 +1982,10 @@ void LowerArcToLLVMPass::runOnOperation() {
StringCache stringCache;
patterns.add<SimEmitValueOpLowering, SimPrintFormattedProcOpLowering>(
converter, &getContext(), stringCache);
patterns.add<SimStreamOpLowering<sim::StdoutStreamOp>>(
converter, &getContext(), runtime::APICallbacks::symNameGetStdoutStream);
patterns.add<SimStreamOpLowering<sim::StderrStreamOp>>(
converter, &getContext(), runtime::APICallbacks::symNameGetStderrStream);

auto &modelInfo = getAnalysis<ModelInfoAnalysis>();
llvm::DenseMap<StringRef, ModelInfoMap> modelMap(modelInfo.infoMap.size());
Expand Down
43 changes: 35 additions & 8 deletions lib/Dialect/Arc/Runtime/ArcRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,8 @@ void arcRuntimeIR_deleteInstance(uint8_t *modelState) {
arcRuntimeDeleteInstance(arcRuntimeGetStateFromModelState(modelState, 0));
}

void arcRuntimeIR_format(const FmtDescriptor *fmt, ...) {
va_list args;
va_start(args, fmt);

llvm::raw_ostream &os = llvm::outs();
static void formatToStream(llvm::raw_ostream &os, const FmtDescriptor *fmt,
va_list args) {
while (fmt->action != FmtDescriptor::Action_End) {
switch (fmt->action) {
case FmtDescriptor::Action_Literal: {
Expand Down Expand Up @@ -146,6 +143,34 @@ void arcRuntimeIR_format(const FmtDescriptor *fmt, ...) {
}
fmt++;
}
}

void arcRuntimeIR_format(const FmtDescriptor *fmt, ...) {
va_list args;
va_start(args, fmt);

formatToStream(llvm::outs(), fmt, args);

va_end(args);
}

uint8_t *arcRuntimeIR_getStdoutStream() {
return reinterpret_cast<uint8_t *>(&llvm::outs());
}

Comment thread
nanjo712 marked this conversation as resolved.
Outdated
uint8_t *arcRuntimeIR_getStderrStream() {
return reinterpret_cast<uint8_t *>(&llvm::errs());
}

void arcRuntimeIR_formatToStream(uint8_t *stream, const FmtDescriptor *fmt,
...) {
if (!stream)
impl::fatalError("Output stream pointer is null");

va_list args;
va_start(args, fmt);

formatToStream(*reinterpret_cast<llvm::raw_ostream *>(stream), fmt, args);

va_end(args);
}
Expand All @@ -163,9 +188,11 @@ uint64_t *arcRuntimeIR_swapTraceBuffer(const uint8_t *modelState) {
namespace circt::arc::runtime {

static const APICallbacks apiCallbacksGlobal{
&arcRuntimeIR_allocInstance, &arcRuntimeIR_deleteInstance,
&arcRuntimeIR_onEval, &arcRuntimeIR_onInitialized,
&arcRuntimeIR_format, &arcRuntimeIR_swapTraceBuffer};
&arcRuntimeIR_allocInstance, &arcRuntimeIR_deleteInstance,
&arcRuntimeIR_onEval, &arcRuntimeIR_onInitialized,
&arcRuntimeIR_format, &arcRuntimeIR_getStdoutStream,
&arcRuntimeIR_getStderrStream, &arcRuntimeIR_formatToStream,
&arcRuntimeIR_swapTraceBuffer};

const APICallbacks &getArcRuntimeAPICallbacks() { return apiCallbacksGlobal; }

Expand Down
23 changes: 23 additions & 0 deletions test/arcilator/sim-output-streams.mlir
Comment thread
nanjo712 marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: arcilator --emit-mlir %s | FileCheck %s

hw.module @Top(in %clk : !seq.clock) {
sim.triggered %clk {
%stdout = sim.stdout_stream
%stdout_msg = sim.fmt.literal "stdout\n"
sim.proc.print %stdout_msg to %stdout

%stderr = sim.stderr_stream
%stderr_msg = sim.fmt.literal "stderr\n"
sim.proc.print %stderr_msg to %stderr
}
}

// CHECK-DAG: llvm.func @arcRuntimeIR_formatToStream(!llvm.ptr, !llvm.ptr, ...)
// CHECK-DAG: llvm.func @arcRuntimeIR_getStdoutStream() -> !llvm.ptr
// CHECK-DAG: llvm.func @arcRuntimeIR_getStderrStream() -> !llvm.ptr
// CHECK: llvm.call @arcRuntimeIR_getStdoutStream() : () -> !llvm.ptr
// CHECK: llvm.call @arcRuntimeIR_formatToStream
// CHECK-SAME: vararg(!llvm.func<void (ptr, ptr, ...)>)
// CHECK: llvm.call @arcRuntimeIR_getStderrStream() : () -> !llvm.ptr
// CHECK: llvm.call @arcRuntimeIR_formatToStream
// CHECK-SAME: vararg(!llvm.func<void (ptr, ptr, ...)>)
9 changes: 9 additions & 0 deletions tools/arcilator/arcilator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@ static void bindArcRuntimeSymbols(ExecutionEngine &executionEngine) {
bindExecutionEngineSymbol(symbolMap, interner,
runtimeCallbacks.symNameFormat,
runtimeCallbacks.fnFormat);
bindExecutionEngineSymbol(symbolMap, interner,
runtimeCallbacks.symNameGetStdoutStream,
runtimeCallbacks.fnGetStdoutStream);
bindExecutionEngineSymbol(symbolMap, interner,
runtimeCallbacks.symNameGetStderrStream,
runtimeCallbacks.fnGetStderrStream);
bindExecutionEngineSymbol(symbolMap, interner,
runtimeCallbacks.symNameFormatToStream,
runtimeCallbacks.fnFormatToStream);
bindExecutionEngineSymbol(symbolMap, interner,
runtimeCallbacks.symNameSwapTraceBuffer,
runtimeCallbacks.fnSwapTraceBuffer);
Expand Down