20#include <mlir/IR/BuiltinOps.h>
22#include <llvm/ADT/SmallVector.h>
23#include <llvm/Support/Debug.h>
27#define GEN_PASS_DEF_UNUSEDDECLARATIONELIMINATIONPASS
35#define DEBUG_TYPE "llzk-unused-declaration-elim"
46 using Base = UnusedDeclarationEliminationPassBase<PassImpl>;
52 DenseMap<SymbolRefAttr, StructDefOp> symbolToStruct;
53 DenseMap<StructDefOp, SymbolRefAttr> structToSymbol;
55 const SymbolRefAttr &getSymbol(
StructDefOp s)
const {
return structToSymbol.at(s); }
56 StructDefOp getStruct(
const SymbolRefAttr &sym)
const {
return symbolToStruct.at(sym); }
58 static PassContext populate(ModuleOp modOp) {
61 modOp.walk<WalkOrder::PreOrder>([&ctx](
StructDefOp structDef) {
63 ensure(succeeded(structSymbolRes),
"failed to lookup struct symbol");
64 SymbolRefAttr structSym = *structSymbolRes;
65 ctx.symbolToStruct[structSym] = structDef;
66 ctx.structToSymbol[structDef] = structSym;
72 void runOnOperation()
override {
73 PassContext ctx = PassContext::populate(getOperation());
76 removeUnusedMembers(ctx);
80 removeUnusedStructs(ctx);
87 void removeUnusedMembers(PassContext &ctx) {
88 ModuleOp modOp = getOperation();
91 DenseMap<SymbolRefAttr, MemberDefOp> members;
92 for (
auto &[structDef, structSym] : ctx.structToSymbol) {
98 if (!structDef.isMainComponent() || !member.
hasPublicAttr()) {
99 SymbolRefAttr memberSym =
101 members[memberSym] = member;
108 SymbolRefAttr readMemberSym = getFullMemberSymbol(readm);
109 members.erase(readMemberSym);
115 SymbolRefAttr writtenMember = getFullMemberSymbol(writem);
116 if (members.contains(writtenMember)) {
119 llvm::dbgs() <<
"Removing write " << writem <<
" to write-only member " << writtenMember
127 for (
auto &[_, memberDef] : members) {
128 LLVM_DEBUG(llvm::dbgs() <<
"Removing member " << memberDef <<
'\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();
This file defines methods symbol lookup across LLZK operations and included files.
::mlir::StringAttr getSymNameAttr()
::mlir::FlatSymbolRefAttr getMemberNameAttr()
Gets the member name attribute from the MemberRefOp.
::llzk::component::StructType getStructType()
Gets the struct type of the target component.
::mlir::SymbolRefAttr getNameRef() const
void ensure(bool condition, const llvm::Twine &errMsg)
SymbolRefAttr appendLeaf(SymbolRefAttr orig, FlatSymbolRefAttr newLeaf)
FailureOr< SymbolRefAttr > getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot)