17#include "llvm/Support/Debug.h"
19#define DEBUG_TYPE "llhd-sig2reg"
23#define GEN_PASS_DEF_SIG2REG
24#include "circt/Dialect/LLHD/Transforms/LLHDPasses.h.inc"
36 Offset(uint64_t min, uint64_t max, ArrayRef<Value> dynamic)
37 : min(min), max(max), dynamic(dynamic) {}
39 Offset(uint64_t idx) : min(idx), max(idx) {}
46 SmallVector<Value> dynamic;
49 bool isStatic()
const {
return min == max; }
55 Interval(
const Offset &low, uint64_t bitwidth, Value value,
56 llhd::TimeAttr delay = llhd::TimeAttr())
57 : low(low), bitwidth(bitwidth), value(value), delay(delay) {}
72 SigPromoter(llhd::SignalOp sigOp) : sigOp(sigOp) {}
76 LogicalResult computeIntervals() {
77 SmallVector<std::pair<Operation *, Offset>> stack;
79 for (
auto *user : sigOp->getUsers())
80 stack.emplace_back(user, Offset(0));
82 while (!stack.empty()) {
83 auto currAndOffset = stack.pop_back_val();
84 auto *curr = currAndOffset.first;
85 auto offset = currAndOffset.second;
87 if (curr->getBlock() != sigOp->getBlock()) {
88 LLVM_DEBUG(llvm::dbgs() <<
" - User in other block, skipping...\n\n");
93 TypeSwitch<Operation *, LogicalResult>(curr)
94 .Case<llhd::PrbOp>([&](llhd::PrbOp probeOp) {
95 auto bw = hw::getBitWidth(probeOp.getResult().getType());
99 readIntervals.emplace_back(offset, bw, probeOp.getResult());
102 .Case<llhd::DrvOp>([&](llhd::DrvOp driveOp) {
103 if (driveOp.getEnable()) {
104 LLVM_DEBUG(llvm::dbgs()
105 <<
" - Conditional driver, skipping...\n\n");
110 driveOp.getTime().getDefiningOp<llhd::ConstantTimeOp>();
112 LLVM_DEBUG(llvm::dbgs()
113 <<
" - Unknown drive delay, skipping...\n\n");
117 auto bw = hw::getBitWidth(driveOp.getValue().getType());
121 intervals.emplace_back(offset, bw, driveOp.getValue(),
122 timeOp.getValueAttr());
125 .Case<llhd::SigExtractOp>([&](llhd::SigExtractOp extractOp) {
128 constOp && offset.isStatic()) {
129 for (
auto *user : extractOp->getUsers())
132 Offset(constOp.getValue().getZExtValue() + offset.min));
137 auto bw = hw::getBitWidth(
138 cast<hw::InOutType>(extractOp.getInput().getType())
143 SmallVector<Value> indices(offset.dynamic);
144 indices.push_back(extractOp.getLowBit());
146 for (
auto *user : extractOp->getUsers())
148 user, Offset(offset.min, offset.max + bw - 1, indices));
152 .Default([](
auto *op) {
153 LLVM_DEBUG(llvm::dbgs() <<
" - User that is not a probe or "
154 "drive, skipping...\n "
162 toDelete.push_back(curr);
165 llvm::sort(intervals, [](
const Interval &a,
const Interval &b) {
166 return a.low.min < b.low.min;
170 llvm::dbgs() <<
" - Detected intervals:\n";
171 dumpIntervals(llvm::dbgs(), 4);
180 void dumpIntervals(llvm::raw_ostream &os,
unsigned indent = 0) {
181 os << llvm::indent(indent) <<
"[\n";
182 for (
const auto &interval : intervals) {
183 os << llvm::indent(indent + 2) <<
"<from [" << interval.low.min <<
", "
184 << interval.low.max <<
"]\n";
185 os << llvm::indent(indent + 3) <<
"width " << interval.bitwidth <<
"\n";
187 for (
auto idx : interval.low.dynamic)
188 os <<
llvm::indent(indent + 3) << idx <<
"\n";
190 os << llvm::indent(indent + 3) <<
"value: " << interval.value <<
"\n";
191 os << llvm::indent(indent + 3) <<
"delay: " << interval.delay <<
"\n";
192 os << llvm::indent(indent + 2) <<
">,\n";
194 os << llvm::indent(indent) <<
"]\n";
201 bool isPromotable() {
202 for (
unsigned i = 0; i < intervals.size(); ++i) {
203 if (i >= intervals.size() - 1)
206 if (intervals[i].low.max + intervals[i].bitwidth - 1 >
207 intervals[i + 1].low.min) {
209 llvm::dbgs() <<
" - Potentially overlapping drives, skipping...\n\n";
221 auto bw = hw::getBitWidth(sigOp.getInit().getType());
222 assert(bw > 0 &&
"bw must be known and non-zero");
224 OpBuilder builder(sigOp);
225 Value val = sigOp.getInit();
226 Location loc = sigOp->getLoc();
227 auto type = builder.getIntegerType(bw);
232 for (
auto interval : intervals) {
234 loc, APInt::getAllOnes(interval.bitwidth));
236 if (uint64_t(bw) > interval.bitwidth) {
238 loc, APInt::getZero(bw - interval.bitwidth));
239 invMask = builder.createOrFold<
comb::ConcatOp>(loc, pad, invMask);
242 Value amt = buildDynamicIndex(builder, loc, interval.low.min,
243 interval.low.dynamic, bw);
244 invMask = builder.createOrFold<
comb::ShlOp>(loc, invMask, amt);
251 loc, builder.getIntegerType(interval.bitwidth), interval.value);
253 if (uint64_t(bw) > interval.bitwidth) {
255 loc, APInt::getZero(bw - interval.bitwidth));
256 assignVal = builder.createOrFold<
comb::ConcatOp>(loc, pad, assignVal);
259 assignVal = builder.createOrFold<
comb::ShlOp>(loc, assignVal, amt);
260 if (!isImmediate(interval.delay))
262 builder.createOrFold<llhd::DelayOp>(loc, assignVal, interval.delay);
263 val = builder.createOrFold<
comb::OrOp>(loc, assignVal, val);
267 for (
auto interval : readIntervals) {
268 if (interval.low.isStatic()) {
270 loc, builder.getIntegerType(interval.bitwidth), val,
273 loc, interval.value.getType(), read);
274 interval.value.replaceAllUsesWith(read);
278 Value read = buildDynamicIndex(builder, loc, interval.low.min,
279 interval.low.dynamic, bw);
280 read = builder.createOrFold<
comb::ShrUOp>(loc, val, read);
282 loc, builder.getIntegerType(interval.bitwidth), read, 0);
283 read = builder.createOrFold<
hw::BitcastOp>(loc, interval.value.getType(),
285 interval.value.replaceAllUsesWith(read);
289 for (
auto *op :
llvm::reverse(toDelete))
299 Value buildDynamicIndex(OpBuilder &builder, Location loc,
300 uint64_t constOffset, ArrayRef<Value> indices,
303 loc, builder.getIntegerType(width), constOffset);
305 for (
auto idx : indices) {
306 auto bw = hw::getBitWidth(idx.getType());
310 index = builder.createOrFold<
comb::AddOp>(loc, index, idx);
316 bool isImmediate(llhd::TimeAttr attr)
const {
317 return attr.getTime() == 0 && attr.getDelta() == 0 &&
318 attr.getEpsilon() == 1;
322 llhd::SignalOp sigOp;
324 SmallVector<Interval> intervals;
326 SmallVector<Interval> readIntervals;
328 SmallVector<Operation *> toDelete;
331struct Sig2RegPass :
public circt::llhd::impl::Sig2RegBase<Sig2RegPass> {
332 void runOnOperation()
override;
336void Sig2RegPass::runOnOperation() {
339 LLVM_DEBUG(llvm::dbgs() <<
"=== Sig2Reg in module " << moduleOp.getSymName()
343 llvm::make_early_inc_range(moduleOp.getOps<llhd::SignalOp>())) {
344 LLVM_DEBUG(llvm::dbgs() <<
" - Attempting to promote signal "
345 << sigOp.getName() <<
"\n");
346 SigPromoter promoter(sigOp);
347 if (failed(promoter.computeIntervals()) || !promoter.isPromotable())
351 LLVM_DEBUG(llvm::dbgs() <<
" - Successfully promoted!\n\n");
355 if (moduleOp.getOps<llhd::SignalOp>().empty())
356 llvm::dbgs() <<
" Successfully promoted all signals in module!\n";
359 LLVM_DEBUG(llvm::dbgs() <<
"\n");
assert(baseType &&"element must be base type")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.