Skip to content

feat(DeadCodeElimination - While loop and Function wrapper): Add WhileStatementElimination and UnusedFunctionElimination in DCE pass#39

Open
shanjiang98 wants to merge 4 commits intogoogle:dcefrom
shanjiang98:dce

Conversation

@shanjiang98
Copy link

Introduces a new WhileStatementElimination pass to the Dead Code Elimination framework. This pass identifies 'while' loops with a constantly false condition and removes them entirely.

Introduces a new WhileStatementElimination pass to the Dead Code Elimination
framework. This pass identifies 'while' loops with a constantly false condition
and removes them entirely.

Also includes minor header reordering and adjusts pointer syntax
for consistency within 'pass.cc'.
@google-cla
Copy link

google-cla bot commented Nov 21, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@shanjiang98 shanjiang98 changed the title feat(DeadCodeElimination - While loop): Add WhileStatementElimination in DCE pass feat(DeadCodeElimination - While loop and Function wrapper): Add WhileStatementElimination and UnusedFunctionElimination in DCE pass Nov 22, 2025
@phisiart phisiart self-requested a review November 22, 2025 23:47
Comment on lines 177 to 178
mlir::Operation *current_op = def_op->getParentOp();
while (current_op != nullptr)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (mlir::Operation *current_op = def_op->getParentOp();
     current_op != nullptr;
     current_op = current_op->getParentOp()) {
  if (current_trivia == nullptr) {
    continue;
  }
  ...
}

- Updated BUILD file to correct the path for lit test files.
- Simplified the passes in the README and run generated files by removing unnecessary passes.
- Adjusted indentation in input.js for better readability.
- Cleaned up output.generated.txt by removing excessive comments and irrelevant sections.
struct SymbolInfo {
std::vector<mlir::Operation*> definitions;
std::vector<mlir::Operation*> references;
// Symbols defined within the scope of this symbol's definition (e.g., if
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this vector computed recursively? Or does it only include the variables one level deeper?

For example, the current symbol f is a function. Within f there's an inner function g, which contains yet another inner function h. Does this vector include h or only g?

absl::flat_hash_map<JsSymbolId, SymbolInfo> symbol_infos;

root_op->walk([&](mlir::Operation* op) {
// TODO: We can remove this special handling once the trivia is fixed.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you mention the issue number in the comment?

// TODO(#xx)


for (auto& [symbol, info] : symbol_infos) {
if (info.definitions.empty()) {
continue;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check this scenario:

let a = 1;
b = a;
let c = b;

I remember that JavaScript spec says b is treated as a global variable. This also requires non-strict mode during parsing.

current_op != nullptr; current_op = current_op->getParentOp()) {
auto current_trivia =
llvm::dyn_cast<JsirTriviaAttr>(current_op->getLoc());
if (current_trivia != nullptr) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (current_trivia == nullptr) {
  continue;
}

}

// Check if info.definitions contains duplicates across symbol_infos? If so,
// print warning
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make this comment consistent with the code. If you don't want spamming the log, you can use CHECK(...).

}

for (auto& [symbol, info] : symbol_infos) {
if (info.references.empty()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// TODO: Also consider if the symbol is written to.

// When we remove a function declaration, we are also removing all ops
// in the function body, including definitions of local variables.
// This means we need to remove those SymbolInfo records.
std::vector<JsSymbolId> worklist = info.inner_definitions;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a stack instead of a queue - does this matter?


auto it = symbol_infos.find(current_symbol_id);
if (it != symbol_infos.end()) {
it->second.definitions.clear();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this unnecessary? We are erasing it anyway.

symbol_infos.erase(it);
}
}
def_op->erase();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that we should also remove the symbol info entry for def_op itself - we are already removing the symbol infos for all its inner symbols, but not itself.

You might need to change the for (auto& [symbol, info] : symbol_infos) { into something like:

for (auto it = symbol_infos.begin(); it != symbol_infos.end(); ??) {
  ...
  if `it` should be erased:
    it = symbol_infos.erase(it);
  if `it` should not be erased:
    it++;
}

auto outer_it = symbol_infos.find(outer_symbol);
if (outer_it != symbol_infos.end()) {
auto& outer_info = outer_it->second;
outer_info.inner_definitions.erase(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: You can check if inner_definitions can be a set instead of a vector.

If you want to keep insertion order, use llvm::SetVector.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants