Skip to content

Commit

Permalink
Pipeclean AIE2 peano flow (#582)
Browse files Browse the repository at this point in the history
Peano for AIE2 has matured quite a bit, but we haven't been actively
using it for AIE2/phoenix.  This patch enables some simple designs
to go through the flow:
1) aiecc.py now sets the correct architecture for llc when using Peano.
2) We generate the correct target architecture in LLVMIR based on the
DeviceOp in MLIR.
3) We lower lock operations to AIE2 lock intrinsics based on the
DeviceOp as well.
  • Loading branch information
stephenneuendorffer authored Aug 22, 2023
1 parent 0569dd3 commit b94b170
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 17 deletions.
70 changes: 58 additions & 12 deletions lib/Dialect/AIE/Transforms/AIECoreToStandard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,24 @@ struct AIEUseLockToStdLowering : public OpConversionPattern<UseLockOp> {
matchAndRewrite(UseLockOp useLock, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
if (!isa<DeviceOp>(useLock->getParentOp())) {
std::string funcName = "llvm.aie.lock.";
auto device = useLock->getParentOfType<xilinx::AIE::DeviceOp>();
if (!device) {
return module.emitOpError("Device Not found!");
}
const auto &target_model = device.getTargetModel();

// Generate the intrinsic name
std::string funcName = "";
if (target_model.getTargetArch() == AIEArch::AIE1)
funcName = "llvm.aie.lock.";
else
funcName = "llvm.aie2.";
if (useLock.acquire() || useLock.acquire_ge())
funcName += "acquire.reg";
funcName += "acquire";
else if (useLock.release())
funcName += "release.reg";
funcName += "release";
if (target_model.getTargetArch() == AIEArch::AIE1)
funcName += ".reg";

auto useLockFunc = module.lookupSymbol<func::FuncOp>(funcName);
if (!useLockFunc)
Expand Down Expand Up @@ -362,11 +375,27 @@ struct AIECoreToStandardPass
ModuleOp m = getOperation();
OpBuilder builder = OpBuilder::atBlockEnd(m.getBody());

if (m.getOps<DeviceOp>().empty()) {
m.emitOpError("expected AIE.device operation at toplevel");
signalPassFailure();
}
DeviceOp device = *(m.getOps<DeviceOp>().begin());
const auto &target_model = device.getTargetModel();
const char *triple;
switch (target_model.getTargetArch()) {
case AIEArch::AIE1:
triple = "aie";
break;
case AIEArch::AIE2:
triple = "aie2";
break;
}

// Ensure that we don't have an incorrect target triple. This may override
// some bogus target triple in the original mlir. In reality this should
// pick the 'aie' target triple.
m->setAttr(LLVM::LLVMDialect::getTargetTripleAttrName(),
builder.getStringAttr("aie"));
builder.getStringAttr(triple));

// Extract all CoreOps
// Create an LLVM func for each CoreOp
Expand All @@ -379,12 +408,6 @@ struct AIECoreToStandardPass
DenseMap<Operation *, SmallVector<BufferOp, 4>> tileToBuffers;
DenseMap<Operation *, SwitchboxOp> switchboxes;

if (m.getOps<DeviceOp>().empty()) {
m.emitOpError("expected AIE.device operation at toplevel");
signalPassFailure();
}
DeviceOp device = *(m.getOps<DeviceOp>().begin());

NetlistAnalysis NL(device, tiles, cores, mems, locks, tileToBuffers,
switchboxes);
NL.collectTiles(tiles);
Expand All @@ -404,6 +427,9 @@ struct AIECoreToStandardPass
Type int384Type = IntegerType::get(builder.getContext(), 384);
Type floatType = FloatType::getF32(builder.getContext());

// Note that not all of these are valid for a particular design, or needed.
// For right now, we will just accept the noise.

// llvm.func @debug_i32(%val: !llvm.i32) -> ()
builder
.create<func::FuncOp>(
Expand Down Expand Up @@ -498,6 +524,22 @@ struct AIECoreToStandardPass
FunctionType::get(builder.getContext(), {int32Type, int32Type}, {}))
.setPrivate();

// llvm.func @llvm.aie2.acquire(%lock_id: !llvm.i32, %lock_val:
// !llvm.i32) ->()v
builder
.create<func::FuncOp>(
builder.getUnknownLoc(), "llvm.aie2.acquire",
FunctionType::get(builder.getContext(), {int32Type, int32Type}, {}))
.setPrivate();

// llvm.func @llvm.aie2.release(%lock_id: !llvm.i32, %lock_val:
// !llvm.i32) ->()
builder
.create<func::FuncOp>(
builder.getUnknownLoc(), "llvm.aie2.release",
FunctionType::get(builder.getContext(), {int32Type, int32Type}, {}))
.setPrivate();

IRMapping mapper;
ConversionTarget target(getContext());
target.addLegalDialect<func::FuncDialect>();
Expand All @@ -515,11 +557,15 @@ struct AIECoreToStandardPass
AIEEventOpToStdLowering>(m.getContext(), m);

patterns.add<AIEBufferToStandard>(m.getContext(), m, mapper);
patterns.add<AIECoreToStandardFunc>(m.getContext(), m, mapper,
tileToBuffers, 1, tileCol, tileRow);
if (failed(applyPartialConversion(m, target, std::move(patterns))))
signalPassFailure();

RewritePatternSet outlinePatterns(&getContext());
outlinePatterns.add<AIECoreToStandardFunc>(
m.getContext(), m, mapper, tileToBuffers, 1, tileCol, tileRow);
if (failed(applyPartialConversion(m, target, std::move(outlinePatterns))))
signalPassFailure();

// Move all the func.func ops and memref.globals from the device to the
// module
outlineOps<memref::GlobalOp>(device);
Expand Down
8 changes: 5 additions & 3 deletions test/aiecc/simple.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
// RUN: aiecc.py --no-unified --compile --no-link --no-xchesscc -nv --sysroot=%VITIS_SYSROOT% --host-target=aarch64-linux-gnu %s -I%aie_runtime_lib% %aie_runtime_lib%/test_library.cpp %S/test.cpp -o test.elf | FileCheck %s --check-prefix=PEANO
// RUN: aiecc.py --no-unified --no-compile --no-link -nv --sysroot=%VITIS_SYSROOT% --host-target=aarch64-linux-gnu %s -I%aie_runtime_lib% %aie_runtime_lib%/test_library.cpp %S/test.cpp -o test.elf | FileCheck %s --check-prefix=NOCOMPILE

// Note that llc determines the architecture from the llvm IR.

// XCHESSCC-NOT: {{^llc}}
// XCHESSCC: xchesscc_wrapper aie
// XCHESSCC-NOT: {{^llc}}
// PEANO-NOT: xchesscc_wrapper aie
// PEANO-NOT: xchesscc_wrapper
// PEANO: {{^llc}}
// PEANO-SAME: --march=aie
// PEANO-NOT: xchesscc_wrapper aie
// NOCOMPILE-NOT: xchesscc_wrapper aie
// PEANO-NOT: xchesscc_wrapper
// NOCOMPILE-NOT: xchesscc_wrapper
// NOCOMPILE-NOT: {{^llc}}

module {
Expand Down
4 changes: 2 additions & 2 deletions tools/aiecc/aiecc/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ async def process_core(self, core):
if(not opts.unified):
file_core_llvmir_stripped = self.tmpcorefile(core, "stripped.ll")
await self.do_call(task, ['opt', '--passes=default<O2>,strip', '-S', file_core_llvmir, '-o', file_core_llvmir_stripped])
await self.do_call(task, ['llc', file_core_llvmir_stripped, '-O2', '--march=aie', '--function-sections', '--filetype=obj', '-o', file_core_obj])
await self.do_call(task, ['llc', file_core_llvmir_stripped, '-O2', '--march=%s' % self.aie_target.lower(), '--function-sections', '--filetype=obj', '-o', file_core_obj])
else:
file_core_obj = self.file_obj
if(opts.link and opts.xbridge):
Expand Down Expand Up @@ -458,7 +458,7 @@ async def run_flow(self):
self.file_llvmir_opt= os.path.join(self.tmpdirname, 'input.opt.ll')
await self.do_call(progress_bar.task, ['opt', '--opaque-pointers=0', '--passes=default<O2>', '-inline-threshold=10', '-S', self.file_llvmir, '-o', self.file_llvmir_opt])

await self.do_call(progress_bar.task, ['llc', self.file_llvmir_opt, '-O2', '--march=aie', '--function-sections', '--filetype=obj', '-o', self.file_obj])
await self.do_call(progress_bar.task, ['llc', self.file_llvmir_opt, '-O2', '--march=%s' % self.aie_target.lower(), '--function-sections', '--filetype=obj', '-o', self.file_obj])

progress_bar.update(progress_bar.task,advance=0,visible=False)
progress_bar.task_completed = progress_bar.add_task("[green] AIE Compilation:", total=len(cores)+1, command="%d Workers" % nworkers)
Expand Down

0 comments on commit b94b170

Please sign in to comment.