//===- bolt/Passes/StackAvailableExpressions.cpp --------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the StackAvailableExpressions class. // //===----------------------------------------------------------------------===// #include "bolt/Passes/StackAvailableExpressions.h" #include "bolt/Passes/FrameAnalysis.h" #include "bolt/Passes/RegAnalysis.h" #include "llvm/MC/MCRegisterInfo.h" #define DEBUG_TYPE "sae" namespace llvm { namespace bolt { StackAvailableExpressions::StackAvailableExpressions(const RegAnalysis &RA, const FrameAnalysis &FA, BinaryFunction &BF) : InstrsDataflowAnalysis(BF), RA(RA), FA(FA) {} void StackAvailableExpressions::preflight() { LLVM_DEBUG(dbgs() << "Starting StackAvailableExpressions on \"" << Func.getPrintName() << "\"\n"); // Populate our universe of tracked expressions. We are interested in // tracking available stores to frame position at any given point of the // program. for (BinaryBasicBlock &BB : Func) { for (MCInst &Inst : BB) { ErrorOr FIE = FA.getFIEFor(Inst); if (!FIE) continue; if (FIE->IsStore == true && FIE->IsSimple == true) { Expressions.push_back(&Inst); ExprToIdx[&Inst] = NumInstrs++; } } } } BitVector StackAvailableExpressions::getStartingStateAtBB(const BinaryBasicBlock &BB) { // Entry points start with empty set // All others start with the full set. if (BB.pred_size() == 0 && BB.throw_size() == 0) return BitVector(NumInstrs, false); return BitVector(NumInstrs, true); } BitVector StackAvailableExpressions::getStartingStateAtPoint(const MCInst &Point) { return BitVector(NumInstrs, true); } void StackAvailableExpressions::doConfluence(BitVector &StateOut, const BitVector &StateIn) { StateOut &= StateIn; } namespace { bool isLoadRedundant(const FrameIndexEntry &LoadFIE, const FrameIndexEntry &StoreFIE) { if (LoadFIE.IsLoad == false || LoadFIE.IsSimple == false) return false; if (LoadFIE.StackOffset == StoreFIE.StackOffset && LoadFIE.Size == StoreFIE.Size) return true; return false; } } bool StackAvailableExpressions::doesXKillsY(const MCInst *X, const MCInst *Y) { // if both are stores, and both store to the same stack location, return // true ErrorOr FIEX = FA.getFIEFor(*X); ErrorOr FIEY = FA.getFIEFor(*Y); if (FIEX && FIEY) { if (isLoadRedundant(*FIEX, *FIEY)) return false; if (FIEX->IsStore == true && FIEY->IsStore == true && FIEX->StackOffset + FIEX->Size > FIEY->StackOffset && FIEX->StackOffset < FIEY->StackOffset + FIEY->Size) return true; } // getClobberedRegs for X and Y. If they intersect, return true BitVector XClobbers = BitVector(BC.MRI->getNumRegs(), false); BitVector YClobbers = BitVector(BC.MRI->getNumRegs(), false); RA.getInstClobberList(*X, XClobbers); // If Y is a store to stack, its clobber list is its source reg. This is // different than the rest because we want to check if the store source // reaches its corresponding load untouched. if (FIEY && FIEY->IsStore == true && FIEY->IsStoreFromReg) YClobbers.set(FIEY->RegOrImm); else RA.getInstClobberList(*Y, YClobbers); XClobbers &= YClobbers; return XClobbers.any(); } BitVector StackAvailableExpressions::computeNext(const MCInst &Point, const BitVector &Cur) { BitVector Next = Cur; // Kill for (auto I = expr_begin(Next), E = expr_end(); I != E; ++I) { assert(*I != nullptr && "Lost pointers"); LLVM_DEBUG(dbgs() << "\t\t\tDoes it kill "); LLVM_DEBUG((*I)->dump()); if (doesXKillsY(&Point, *I)) { LLVM_DEBUG(dbgs() << "\t\t\t\tKilling "); LLVM_DEBUG((*I)->dump()); Next.reset(I.getBitVectorIndex()); } } // Gen if (ErrorOr FIE = FA.getFIEFor(Point)) { if (FIE->IsStore == true && FIE->IsSimple == true) Next.set(ExprToIdx[&Point]); } return Next; } } // namespace bolt } // namespace llvm