20#include <mlir/IR/BuiltinOps.h>
22#include <llvm/ADT/SmallVector.h>
23#include <llvm/Support/Debug.h>
28#define GEN_PASS_DECL_UNUSEDDECLARATIONELIMINATIONPASS
29#define GEN_PASS_DEF_UNUSEDDECLARATIONELIMINATIONPASS
37#define DEBUG_TYPE "llzk-unused-declaration-elim"
47class UnusedDeclarationEliminationPass
53 DenseMap<SymbolRefAttr, StructDefOp> symbolToStruct;
54 DenseMap<StructDefOp, SymbolRefAttr> structToSymbol;
56 const SymbolRefAttr &getSymbol(
StructDefOp s)
const {
return structToSymbol.at(s); }
57 StructDefOp getStruct(
const SymbolRefAttr &sym)
const {
return symbolToStruct.at(sym); }
59 static PassContext populate(ModuleOp modOp) {
62 modOp.walk<WalkOrder::PreOrder>([&ctx](
StructDefOp structDef) {
64 ensure(succeeded(structSymbolRes),
"failed to lookup struct symbol");
65 SymbolRefAttr structSym = *structSymbolRes;
66 ctx.symbolToStruct[structSym] = structDef;
67 ctx.structToSymbol[structDef] = structSym;
73 void runOnOperation()
override {
74 PassContext ctx = PassContext::populate(getOperation());
77 removeUnusedFields(ctx);
81 removeUnusedStructs(ctx);
88 void removeUnusedFields(PassContext &ctx) {
89 ModuleOp modOp = getOperation();
92 DenseMap<SymbolRefAttr, FieldDefOp> fields;
93 for (
auto &[structDef, structSym] : ctx.structToSymbol) {
99 SymbolRefAttr fieldSym =
101 fields[fieldSym] = field;
108 SymbolRefAttr readFieldSym = getFullFieldSymbol(readf);
109 fields.erase(readFieldSym);
115 SymbolRefAttr writtenField = getFullFieldSymbol(writef);
116 if (fields.contains(writtenField)) {
119 llvm::dbgs() <<
"Removing write " << writef <<
" to write-only field " << writtenField
127 for (
auto &[_, fieldDef] : fields) {
128 LLVM_DEBUG(llvm::dbgs() <<
"Removing field " << fieldDef <<
'\n');
137 void removeUnusedStructs(PassContext &ctx) {
138 DenseMap<StructDefOp, DenseSet<StructDefOp>> uses;
139 DenseMap<StructDefOp, DenseSet<StructDefOp>> usedBy;
142 for (
auto &[structDef, _] : ctx.structToSymbol) {
143 uses[structDef] = {};
144 usedBy[structDef] = {};
147 getOperation().walk([&](Operation *op) {
148 auto structParent = op->getParentOfType<
StructDefOp>();
149 if (structParent ==
nullptr) {
150 return WalkResult::advance();
153 auto tryAddUse = [&](Type ty) {
154 if (
auto structTy = dyn_cast<StructType>(ty)) {
156 SymbolRefAttr sym = structTy.getNameRef();
158 if (refStruct != structParent) {
159 uses[structParent].insert(refStruct);
160 usedBy[refStruct].insert(structParent);
169 for (Value operand : op->getOperands()) {
170 tryAddUse(operand.getType());
174 for (Value result : op->getResults()) {
175 tryAddUse(result.getType());
179 for (Region ®ion : op->getRegions()) {
180 for (Block &block : region) {
181 for (BlockArgument arg : block.getArguments()) {
182 tryAddUse(arg.getType());
188 for (
const auto &namedAttr : op->getAttrs()) {
189 namedAttr.getValue().walk([&](TypeAttr typeAttr) { tryAddUse(typeAttr.getValue()); });
192 return WalkResult::advance();
195 SmallVector<StructDefOp> unusedStructs;
197 auto updateUnusedStructs = [&]() {
198 for (
auto &[structDef, users] : usedBy) {
199 if (users.empty() && !structDef.isMainComponent()) {
200 unusedStructs.push_back(structDef);
205 updateUnusedStructs();
207 while (!unusedStructs.empty()) {
209 unusedStructs.pop_back();
212 for (
auto usedStruct : uses[unusedStruct]) {
214 usedBy[usedStruct].erase(unusedStruct);
218 usedBy.erase(unusedStruct);
219 uses.erase(unusedStruct);
220 unusedStruct->erase();
224 if (unusedStructs.empty()) {
225 updateUnusedStructs();
234 return std::make_unique<UnusedDeclarationEliminationPass>();
This file defines methods symbol lookup across LLZK operations and included files.
::mlir::StringAttr getSymNameAttr()
::llzk::component::StructType getStructType()
Gets the struct type of the target component.
::mlir::FlatSymbolRefAttr getFieldNameAttr()
Gets the field name attribute from the FieldRefOp.
::mlir::SymbolRefAttr getNameRef() const
SymbolRefAttr appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
void ensure(bool condition, llvm::Twine errMsg)
FailureOr< SymbolRefAttr > getPathFromTopRoot(StructDefOp &to)
std::unique_ptr< mlir::Pass > createUnusedDeclarationEliminationPass()