Skip to content

Commit dcade50

Browse files
authored
[arcilator] Add ability to specify args from CLI (#9225)
This enables specifying arguments with which to run entry function. Useful for some local testing/using in a bit more interactive manner from CLI. One can also repeat args, and multiples of arg count is treated as bundles to process in turn.
1 parent 120dd53 commit dcade50

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: arcilator --run %s --jit-entry=entry --args=1,2 --args=3,4 | FileCheck %s
2+
3+
module {
4+
func.func @entry(%arg0: i32, %arg1: i32) {
5+
// CHECK: arg0 = 00000001
6+
// CHECK: arg1 = 00000002
7+
// CHECK: arg0 = 00000003
8+
// CHECK: arg1 = 00000004
9+
arc.sim.emit "arg0", %arg0 : i32
10+
arc.sim.emit "arg1", %arg1 : i32
11+
return
12+
}
13+
}

test/arcilator/jit-args.mlir

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: arcilator --run %s --jit-entry=entry --args=0x10,0x1234567890ABCDEF1234567890ABC | FileCheck %s
2+
3+
module {
4+
func.func @entry(%arg0: i32, %arg1: i116) {
5+
// CHECK: arg0 = 00000010
6+
arc.sim.emit "arg0", %arg0 : i32
7+
// CHECK: arg1 = 1234567890abcdef1234567890abc
8+
arc.sim.emit "arg1", %arg1 : i116
9+
return
10+
}
11+
}

tools/arcilator/arcilator.cpp

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,12 @@ static llvm::cl::list<std::string> sharedLibs{
229229
"shared-libs", llvm::cl::desc("Libraries to link dynamically"),
230230
llvm::cl::MiscFlags::CommaSeparated, llvm::cl::cat(mainCategory)};
231231

232+
static llvm::cl::list<std::string>
233+
jitArgs("args",
234+
llvm::cl::desc("Arguments to pass to the JIT entry function"),
235+
llvm::cl::ZeroOrMore, llvm::cl::CommaSeparated,
236+
llvm::cl::cat(mainCategory));
237+
232238
//===----------------------------------------------------------------------===//
233239
// Main Tool Logic
234240
//===----------------------------------------------------------------------===//
@@ -442,9 +448,23 @@ static LogicalResult processBuffer(
442448
return failure();
443449
}
444450

445-
if (toCallFunc.getNumArguments() != 0) {
451+
unsigned numArgs = toCallFunc.getNumArguments();
452+
if (numArgs) {
453+
if (jitArgs.size() % numArgs != 0) {
454+
llvm::errs() << "entry point '" << jitEntryPoint << "' has " << numArgs
455+
<< " arguments, but provided " << jitArgs.size()
456+
<< " arguments (not a multiple)\n";
457+
return failure();
458+
}
459+
if (jitArgs.empty()) {
460+
llvm::errs() << "entry point '" << jitEntryPoint
461+
<< "' must have no arguments\n";
462+
return failure();
463+
}
464+
} else if (!jitArgs.empty()) {
446465
llvm::errs() << "entry point '" << jitEntryPoint
447-
<< "' must have no arguments\n";
466+
<< "' has no arguments, but provided " << jitArgs.size()
467+
<< "arguments\n";
448468
return failure();
449469
}
450470

@@ -482,7 +502,57 @@ static LogicalResult processBuffer(
482502
}
483503

484504
void (*simulationFunc)(void **) = *expectedFunc;
485-
(*simulationFunc)(nullptr);
505+
506+
for (unsigned i = 0, e = jitArgs.size(); i < e; i += numArgs) {
507+
std::vector<std::vector<uint64_t>> argsStorage;
508+
SmallVector<void *> args;
509+
argsStorage.reserve(numArgs);
510+
args.reserve(numArgs);
511+
512+
// Repeated args are concatenated, so break apart in groups of multiples
513+
// of args.
514+
for (auto [val, arg] :
515+
llvm::zip(llvm::make_range(jitArgs.begin() + i,
516+
jitArgs.begin() + i + numArgs),
517+
toCallFunc.getArguments())) {
518+
auto type = arg.getType();
519+
if (!type.isIntOrIndex()) {
520+
llvm::errs() << "argument " << arg.getArgNumber()
521+
<< " of entry point '" << jitEntryPoint
522+
<< "' is not an integer or index type\n";
523+
return failure();
524+
}
525+
526+
// TODO: This should probably be checking if DLTI is set on module.
527+
unsigned width = type.isIndex() ? 64 : type.getIntOrFloatBitWidth();
528+
APInt apVal(width, 0);
529+
if (StringRef(val).getAsInteger(0, apVal)) {
530+
llvm::errs() << "invalid integer argument: '" << val << "'\n";
531+
return failure();
532+
}
533+
if (apVal.getBitWidth() > width) {
534+
llvm::errs() << "integer argument '" << val << "' (required width "
535+
<< apVal.getBitWidth() << ") is too large for type '"
536+
<< type << "'\n";
537+
return failure();
538+
}
539+
540+
std::vector<uint64_t> argData;
541+
unsigned numWords = apVal.getNumWords();
542+
argData.resize(numWords);
543+
const uint64_t *rawData = apVal.getRawData();
544+
for (unsigned j = 0; j < numWords; ++j)
545+
argData[j] = rawData[j];
546+
547+
argsStorage.push_back(std::move(argData));
548+
args.push_back(argsStorage.back().data());
549+
}
550+
551+
(*simulationFunc)(args.data());
552+
}
553+
// Handle the case without arguments as before.
554+
if (jitArgs.empty())
555+
(*simulationFunc)(nullptr);
486556

487557
return success();
488558
}

0 commit comments

Comments
 (0)