.. _program_listing_file_lib_Target_LaksaCommon_BufferInfo.cpp: Program Listing for File BufferInfo.cpp ======================================= |exhale_lsh| :ref:`Return to documentation for file ` (``lib/Target/LaksaCommon/BufferInfo.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // Implementation of the buffer analysis shared by the laksa-hls-kria-driver // translations // // @file // @author Jiahong Bi (jiahong.bi@tu-dresden.de) #include "laksa-mlir/Target/LaksaCommon/BufferInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" using namespace mlir; using namespace mlir::emithls; static LogicalResult getElementBitWidth(Location loc, Type type, unsigned &bits) { if (auto intTy = dyn_cast(type)) { bits = intTy.getWidth(); return success(); } if (auto floatTy = dyn_cast(type)) { bits = floatTy.getIntOrFloatBitWidth(); return success(); } return emitError( loc, "unsupported pointer element type for buffer " "sizing: ") << type; } // Returns the number of times `op` executes, i.e. the product of the trip // counts of every emithls.for enclosing it up to (but not including) // `boundary`. static int64_t countEnclosingIterations(Operation* op, Operation* boundary) { int64_t count = 1; for (Operation* parent = op->getParentOp(); parent && parent != boundary; parent = parent->getParentOp()) if (auto forOp = dyn_cast(parent)) count *= forOp.getTripCount(); return count; } // Follows `pointer` through every array.ptr_read/array.ptr_write that // touches it directly, and through every emithls.call that forwards it into // a callee's argument, accumulating direction and size facts into `info`. static LogicalResult analyzeBuffer( Value pointer, LaksaBufferInfo &info, llvm::SmallPtrSetImpl &visited) { if (!visited.insert(pointer).second) return success(); for (Operation* user : pointer.getUsers()) { if (auto readOp = dyn_cast(user)) { if (readOp.getPointer() != pointer) continue; unsigned bits; if (failed(getElementBitWidth( readOp.getLoc(), readOp.getResult().getType(), bits))) return failure(); info.isReadByKernel = true; info.elementBits = bits; FuncOp parentFunc = readOp->getParentOfType(); info.numElements = std::max( info.numElements, countEnclosingIterations(readOp, parentFunc)); } else if (auto writeOp = dyn_cast(user)) { if (writeOp.getPointer() != pointer) continue; unsigned bits; if (failed(getElementBitWidth( writeOp.getLoc(), writeOp.getValue().getType(), bits))) return failure(); info.isWrittenByKernel = true; info.elementBits = bits; FuncOp parentFunc = writeOp->getParentOfType(); info.numElements = std::max( info.numElements, countEnclosingIterations(writeOp, parentFunc)); } else if (auto callOp = dyn_cast(user)) { auto moduleOp = callOp->getParentOfType(); auto callee = moduleOp.lookupSymbol(callOp.getCalleeAttr()); if (!callee) continue; for (auto [idx, operand] : llvm::enumerate(callOp.getArgOperands())) { if (operand != pointer) continue; if (failed( analyzeBuffer(callee.getArgument(idx), info, visited))) return failure(); } } } return success(); } FailureOr emithls::findLaksaTopFunc(ModuleOp moduleOp) { FuncOp topFunc = nullptr; auto result = moduleOp.walk([&](PragmaTopInterfaceOp topInterfaceOp) { FuncOp funcOp = topInterfaceOp->getParentOfType(); if (!funcOp || topFunc) return WalkResult::interrupt(); topFunc = funcOp; return WalkResult::advance(); }); if (result.wasInterrupted() || !topFunc) return moduleOp->emitError( "expected exactly one function containing a top_interface " "pragma"); return topFunc; } LogicalResult emithls::collectLaksaBufferInfos( FuncOp topFunc, SmallVectorImpl &buffers) { buffers.assign(topFunc.getNumArguments(), LaksaBufferInfo{}); for (auto [idx, info] : llvm::enumerate(buffers)) { llvm::SmallPtrSet visited; if (failed(analyzeBuffer(topFunc.getArgument(idx), info, visited))) return failure(); if (info.numElements == 0) return topFunc.emitError( "could not determine buffer size for argument ") << idx << "; expected an array.ptr_read or array.ptr_write " "reachable through it"; } return success(); } std::string emithls::getLaksaMacroPrefix(StringRef designName) { std::string prefix = designName.str(); for (char &c : prefix) c = llvm::toUpper(c); return prefix; }