brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · 7b2b354 Raw
173 lines · cpp
1//===--- VarBypassDetector.cpp - Bypass jumps detector ------------*- C++ -*-=//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "VarBypassDetector.h"10 11#include "CodeGenModule.h"12#include "clang/AST/Decl.h"13#include "clang/AST/Expr.h"14#include "clang/AST/Stmt.h"15 16using namespace clang;17using namespace CodeGen;18 19/// Clear the object and pre-process for the given statement, usually function20/// body statement.21void VarBypassDetector::Init(CodeGenModule &CGM, const Stmt *Body) {22  FromScopes.clear();23  ToScopes.clear();24  Bypasses.clear();25  Scopes = {{~0U, nullptr}};26  unsigned ParentScope = 0;27  AlwaysBypassed = !BuildScopeInformation(CGM, Body, ParentScope);28  if (!AlwaysBypassed)29    Detect();30}31 32/// Build scope information for a declaration that is part of a DeclStmt.33/// Returns false if we failed to build scope information and can't tell for34/// which vars are being bypassed.35bool VarBypassDetector::BuildScopeInformation(CodeGenModule &CGM, const Decl *D,36                                              unsigned &ParentScope) {37  const VarDecl *VD = dyn_cast<VarDecl>(D);38  if (VD && VD->hasLocalStorage()) {39    Scopes.push_back({ParentScope, VD});40    ParentScope = Scopes.size() - 1;41  }42 43  if (const VarDecl *VD = dyn_cast<VarDecl>(D))44    if (const Expr *Init = VD->getInit())45      return BuildScopeInformation(CGM, Init, ParentScope);46 47  return true;48}49 50/// Walk through the statements, adding any labels or gotos to51/// LabelAndGotoScopes and recursively walking the AST as needed.52/// Returns false if we failed to build scope information and can't tell for53/// which vars are being bypassed.54bool VarBypassDetector::BuildScopeInformation(CodeGenModule &CGM, const Stmt *S,55                                              unsigned &origParentScope) {56  // If this is a statement, rather than an expression, scopes within it don't57  // propagate out into the enclosing scope. Otherwise we have to worry about58  // block literals, which have the lifetime of their enclosing statement.59  unsigned independentParentScope = origParentScope;60  unsigned &ParentScope =61      ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope62                                           : independentParentScope);63 64  unsigned StmtsToSkip = 0u;65 66  switch (S->getStmtClass()) {67  case Stmt::IndirectGotoStmtClass:68    return false;69 70  case Stmt::SwitchStmtClass:71    if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {72      if (!BuildScopeInformation(CGM, Init, ParentScope))73        return false;74      ++StmtsToSkip;75    }76    if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {77      if (!BuildScopeInformation(CGM, Var, ParentScope))78        return false;79      ++StmtsToSkip;80    }81    [[fallthrough]];82 83  case Stmt::GotoStmtClass:84    FromScopes.push_back({S, ParentScope});85    break;86 87  case Stmt::DeclStmtClass: {88    const DeclStmt *DS = cast<DeclStmt>(S);89    for (auto *I : DS->decls())90      if (!BuildScopeInformation(CGM, I, origParentScope))91        return false;92    return true;93  }94 95  case Stmt::CaseStmtClass:96  case Stmt::DefaultStmtClass:97  case Stmt::LabelStmtClass:98    llvm_unreachable("the loop below handles labels and cases");99    break;100 101  default:102    break;103  }104 105  for (const Stmt *SubStmt : S->children()) {106    if (!SubStmt)107      continue;108    if (StmtsToSkip) {109      --StmtsToSkip;110      continue;111    }112 113    // Cases, labels, and defaults aren't "scope parents".  It's also114    // important to handle these iteratively instead of recursively in115    // order to avoid blowing out the stack.116    while (true) {117      const Stmt *Next;118      if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))119        Next = SC->getSubStmt();120      else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))121        Next = LS->getSubStmt();122      else123        break;124 125      ToScopes[SubStmt] = ParentScope;126      SubStmt = Next;127    }128 129    // Recursively walk the AST.130    bool Result;131    CGM.runWithSufficientStackSpace(S->getEndLoc(), [&] {132      Result = BuildScopeInformation(CGM, SubStmt, ParentScope);133    });134    if (!Result)135      return false;136  }137  return true;138}139 140/// Checks each jump and stores each variable declaration they bypass.141void VarBypassDetector::Detect() {142  for (const auto &S : FromScopes) {143    const Stmt *St = S.first;144    unsigned from = S.second;145    if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {146      if (const LabelStmt *LS = GS->getLabel()->getStmt())147        Detect(from, ToScopes[LS]);148    } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {149      for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;150           SC = SC->getNextSwitchCase()) {151        Detect(from, ToScopes[SC]);152      }153    } else {154      llvm_unreachable("goto or switch was expected");155    }156  }157}158 159/// Checks the jump and stores each variable declaration it bypasses.160void VarBypassDetector::Detect(unsigned From, unsigned To) {161  while (From != To) {162    if (From < To) {163      assert(Scopes[To].first < To);164      const auto &ScopeTo = Scopes[To];165      To = ScopeTo.first;166      Bypasses.insert(ScopeTo.second);167    } else {168      assert(Scopes[From].first < From);169      From = Scopes[From].first;170    }171  }172}173