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 removeUnusedMembers(ctx);
81 removeUnusedStructs(ctx);
88 void removeUnusedMembers(PassContext &ctx) {
89 ModuleOp modOp = getOperation();
92 DenseMap<SymbolRefAttr, MemberDefOp> members;
93 for (
auto &[structDef, structSym] : ctx.structToSymbol) {
99 if (!structDef.isMainComponent() || !member.
hasPublicAttr()) {
100 SymbolRefAttr memberSym =
102 members[memberSym] = member;
109 SymbolRefAttr readMemberSym = getFullMemberSymbol(readm);
110 members.erase(readMemberSym);
116 SymbolRefAttr writtenMember = getFullMemberSymbol(writem);
117 if (members.contains(writtenMember)) {
120 llvm::dbgs() <<
"Removing write " << writem <<
" to write-only member " << writtenMember
128 for (
auto &[_, memberDef] : members) {
129 LLVM_DEBUG(llvm::dbgs() <<
"Removing member " << memberDef <<
'\n');
138 void removeUnusedStructs(PassContext &ctx) {
139 DenseMap<StructDefOp, DenseSet<StructDefOp>> uses;
140 DenseMap<StructDefOp, DenseSet<StructDefOp>> usedBy;
143 for (
auto &[structDef, _] : ctx.structToSymbol) {
144 uses[structDef] = {};
145 usedBy[structDef] = {};
148 getOperation().walk([&](Operation *op) {
149 auto structParent = op->getParentOfType<
StructDefOp>();
150 if (structParent ==
nullptr) {
151 return WalkResult::advance();
154 auto tryAddUse = [&](Type ty) {
155 if (
auto structTy = dyn_cast<StructType>(ty)) {
157 SymbolRefAttr sym = structTy.getNameRef();
159 if (refStruct != structParent) {
160 uses[structParent].insert(refStruct);
161 usedBy[refStruct].insert(structParent);
170 for (Value operand : op->getOperands()) {
171 tryAddUse(operand.getType());
175 for (Value result : op->getResults()) {
176 tryAddUse(result.getType());
180 for (Region ®ion : op->getRegions()) {
181 for (Block &block : region) {
182 for (BlockArgument arg : block.getArguments()) {
183 tryAddUse(arg.getType());
189 for (
const auto &namedAttr : op->getAttrs()) {
190 namedAttr.getValue().walk([&](TypeAttr typeAttr) { tryAddUse(typeAttr.getValue()); });
193 return WalkResult::advance();
196 SmallVector<StructDefOp> unusedStructs;
198 auto updateUnusedStructs = [&]() {
199 for (
auto &[structDef, users] : usedBy) {
200 if (users.empty() && !structDef.isMainComponent()) {
201 unusedStructs.push_back(structDef);
206 updateUnusedStructs();
208 while (!unusedStructs.empty()) {
210 unusedStructs.pop_back();
213 for (
auto usedStruct : uses[unusedStruct]) {
215 usedBy[usedStruct].erase(unusedStruct);
219 usedBy.erase(unusedStruct);
220 uses.erase(unusedStruct);
221 unusedStruct->erase();
225 if (unusedStructs.empty()) {
226 updateUnusedStructs();
235 return std::make_unique<UnusedDeclarationEliminationPass>();
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)
std::unique_ptr< mlir::Pass > createUnusedDeclarationEliminationPass()
FailureOr< SymbolRefAttr > getPathFromTopRoot(SymbolOpInterface to, ModuleOp *foundRoot)