LCOV - code coverage report
Current view: top level - src/compiler - register-allocator-verifier.h (source / functions) Hit Total Coverage
Test: app.info Lines: 23 24 95.8 %
Date: 2017-04-26 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_REGISTER_ALLOCATOR_VERIFIER_H_
       6             : #define V8_REGISTER_ALLOCATOR_VERIFIER_H_
       7             : 
       8             : #include "src/compiler/instruction.h"
       9             : #include "src/zone/zone-containers.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : namespace compiler {
      14             : 
      15             : class InstructionBlock;
      16             : class InstructionSequence;
      17             : 
      18             : // The register allocator validator traverses instructions in the instruction
      19             : // sequence, and verifies the correctness of machine operand substitutions of
      20             : // virtual registers. It collects the virtual register instruction signatures
      21             : // before register allocation. Then, after the register allocation pipeline
      22             : // completes, it compares the operand substitutions against the pre-allocation
      23             : // data.
      24             : // At a high level, validation works as follows: we iterate through each block,
      25             : // and, in a block, through each instruction; then:
      26             : // - when an operand is the output of an instruction, we associate it to the
      27             : // virtual register that the instruction sequence declares as its output. We
      28             : // use the concept of "FinalAssessment" to model this.
      29             : // - when an operand is used in an instruction, we check that the assessment
      30             : // matches the expectation of the instruction
      31             : // - moves simply copy the assessment over to the new operand
      32             : // - blocks with more than one predecessor associate to each operand a "Pending"
      33             : // assessment. The pending assessment remembers the operand and block where it
      34             : // was created. Then, when the value is used (which may be as a different
      35             : // operand, because of moves), we check that the virtual register at the use
      36             : // site matches the definition of this pending operand: either the phi inputs
      37             : // match, or, if it's not a phi, all the predecessors at the point the pending
      38             : // assessment was defined have that operand assigned to the given virtual
      39             : // register.
      40             : // If a block is a loop header - so one or more of its predecessors are it or
      41             : // below - we still treat uses of operands as above, but we record which operand
      42             : // assessments haven't been made yet, and what virtual register they must
      43             : // correspond to, and verify that when we are done with the respective
      44             : // predecessor blocks.
      45             : // This way, the algorithm always makes a final decision about the operands
      46             : // in an instruction, ensuring convergence.
      47             : // Operand assessments are recorded per block, as the result at the exit from
      48             : // the block. When moving to a new block, we copy assessments from its single
      49             : // predecessor, or, if the block has multiple predecessors, the mechanism was
      50             : // described already.
      51             : 
      52             : enum AssessmentKind { Final, Pending };
      53             : 
      54             : class Assessment : public ZoneObject {
      55             :  public:
      56         658 :   AssessmentKind kind() const { return kind_; }
      57             : 
      58             :  protected:
      59         373 :   explicit Assessment(AssessmentKind kind) : kind_(kind) {}
      60             :   AssessmentKind kind_;
      61             : 
      62             :  private:
      63             :   DISALLOW_COPY_AND_ASSIGN(Assessment);
      64             : };
      65             : 
      66             : // PendingAssessments are associated to operands coming from the multiple
      67             : // predecessors of a block. We only record the operand and the block, and
      68             : // will determine if the way the operand is defined (from the predecessors)
      69             : // matches a particular use. This handles scenarios where multiple phis are
      70             : // defined with identical operands, and the move optimizer moved down the moves
      71             : // separating the 2 phis in the block defining them.
      72             : class PendingAssessment final : public Assessment {
      73             :  public:
      74             :   explicit PendingAssessment(const InstructionBlock* origin,
      75             :                              InstructionOperand operand)
      76         145 :       : Assessment(Pending), origin_(origin), operand_(operand) {}
      77             : 
      78          87 :   static const PendingAssessment* cast(const Assessment* assessment) {
      79          87 :     CHECK(assessment->kind() == Pending);
      80          87 :     return static_cast<const PendingAssessment*>(assessment);
      81             :   }
      82             : 
      83             :   const InstructionBlock* origin() const { return origin_; }
      84             :   InstructionOperand operand() const { return operand_; }
      85             : 
      86             :  private:
      87             :   const InstructionBlock* const origin_;
      88             :   InstructionOperand operand_;
      89             : 
      90             :   DISALLOW_COPY_AND_ASSIGN(PendingAssessment);
      91             : };
      92             : 
      93             : // FinalAssessments are associated to operands that we know to be a certain
      94             : // virtual register.
      95             : class FinalAssessment final : public Assessment {
      96             :  public:
      97             :   explicit FinalAssessment(int virtual_register,
      98             :                            const PendingAssessment* original_pending = nullptr)
      99             :       : Assessment(Final),
     100             :         virtual_register_(virtual_register),
     101         228 :         original_pending_assessment_(original_pending) {}
     102             : 
     103             :   int virtual_register() const { return virtual_register_; }
     104         242 :   static const FinalAssessment* cast(const Assessment* assessment) {
     105         242 :     CHECK(assessment->kind() == Final);
     106         242 :     return static_cast<const FinalAssessment*>(assessment);
     107             :   }
     108             : 
     109             :   const PendingAssessment* original_pending_assessment() const {
     110             :     return original_pending_assessment_;
     111             :   }
     112             : 
     113             :  private:
     114             :   int virtual_register_;
     115             :   const PendingAssessment* original_pending_assessment_;
     116             : 
     117             :   DISALLOW_COPY_AND_ASSIGN(FinalAssessment);
     118             : };
     119             : 
     120             : struct OperandAsKeyLess {
     121             :   bool operator()(const InstructionOperand& a,
     122             :                   const InstructionOperand& b) const {
     123             :     return a.CompareCanonicalized(b);
     124             :   }
     125             : };
     126             : 
     127             : // Assessments associated with a basic block.
     128             : class BlockAssessments : public ZoneObject {
     129             :  public:
     130             :   typedef ZoneMap<InstructionOperand, Assessment*, OperandAsKeyLess> OperandMap;
     131             :   explicit BlockAssessments(Zone* zone)
     132         142 :       : map_(zone), map_for_moves_(zone), zone_(zone) {}
     133             :   void Drop(InstructionOperand operand) { map_.erase(operand); }
     134             :   void DropRegisters();
     135         177 :   void AddDefinition(InstructionOperand operand, int virtual_register) {
     136             :     auto existent = map_.find(operand);
     137         177 :     if (existent != map_.end()) {
     138             :       // Drop the assignment
     139             :       map_.erase(existent);
     140             :     }
     141             :     map_.insert(
     142         531 :         std::make_pair(operand, new (zone_) FinalAssessment(virtual_register)));
     143         177 :   }
     144             : 
     145             :   void PerformMoves(const Instruction* instruction);
     146             :   void PerformParallelMoves(const ParallelMove* moves);
     147          79 :   void CopyFrom(const BlockAssessments* other) {
     148          79 :     CHECK(map_.empty());
     149          79 :     CHECK_NOT_NULL(other);
     150             :     map_.insert(other->map_.begin(), other->map_.end());
     151          79 :   }
     152             : 
     153             :   OperandMap& map() { return map_; }
     154             :   const OperandMap& map() const { return map_; }
     155             :   void Print() const;
     156             : 
     157             :  private:
     158             :   OperandMap map_;
     159             :   OperandMap map_for_moves_;
     160             :   Zone* zone_;
     161             : 
     162             :   DISALLOW_COPY_AND_ASSIGN(BlockAssessments);
     163             : };
     164             : 
     165             : class RegisterAllocatorVerifier final : public ZoneObject {
     166             :  public:
     167             :   RegisterAllocatorVerifier(Zone* zone, const RegisterConfiguration* config,
     168             :                             const InstructionSequence* sequence);
     169             : 
     170             :   void VerifyAssignment();
     171             :   void VerifyGapMoves();
     172             : 
     173             :  private:
     174             :   enum ConstraintType {
     175             :     kConstant,
     176             :     kImmediate,
     177             :     kRegister,
     178             :     kFixedRegister,
     179             :     kFPRegister,
     180             :     kFixedFPRegister,
     181             :     kSlot,
     182             :     kFixedSlot,
     183             :     kNone,
     184             :     kNoneFP,
     185             :     kExplicit,
     186             :     kSameAsFirst,
     187             :     kRegisterAndSlot
     188             :   };
     189             : 
     190             :   struct OperandConstraint {
     191             :     ConstraintType type_;
     192             :     // Constant or immediate value, register code, slot index, or slot size
     193             :     // when relevant.
     194             :     int value_;
     195             :     int spilled_slot_;
     196             :     int virtual_register_;
     197             :   };
     198             : 
     199             :   struct InstructionConstraint {
     200             :     const Instruction* instruction_;
     201             :     size_t operand_constaints_size_;
     202             :     OperandConstraint* operand_constraints_;
     203             :   };
     204             : 
     205             :   typedef ZoneVector<InstructionConstraint> Constraints;
     206             : 
     207             :   class DelayedAssessments : public ZoneObject {
     208             :    public:
     209             :     explicit DelayedAssessments(Zone* zone) : map_(zone) {}
     210             : 
     211             :     const ZoneMap<InstructionOperand, int, OperandAsKeyLess>& map() const {
     212             :       return map_;
     213             :     }
     214             : 
     215           6 :     void AddDelayedAssessment(InstructionOperand op, int vreg) {
     216             :       auto it = map_.find(op);
     217           6 :       if (it == map_.end()) {
     218          12 :         map_.insert(std::make_pair(op, vreg));
     219             :       } else {
     220           0 :         CHECK_EQ(it->second, vreg);
     221             :       }
     222           6 :     }
     223             : 
     224             :    private:
     225             :     ZoneMap<InstructionOperand, int, OperandAsKeyLess> map_;
     226             :   };
     227             : 
     228             :   Zone* zone() const { return zone_; }
     229             :   const RegisterConfiguration* config() { return config_; }
     230             :   const InstructionSequence* sequence() const { return sequence_; }
     231             :   Constraints* constraints() { return &constraints_; }
     232             : 
     233             :   static void VerifyInput(const OperandConstraint& constraint);
     234             :   static void VerifyTemp(const OperandConstraint& constraint);
     235             :   static void VerifyOutput(const OperandConstraint& constraint);
     236             : 
     237             :   void BuildConstraint(const InstructionOperand* op,
     238             :                        OperandConstraint* constraint);
     239             :   void CheckConstraint(const InstructionOperand* op,
     240             :                        const OperandConstraint* constraint);
     241             :   BlockAssessments* CreateForBlock(const InstructionBlock* block);
     242             : 
     243             :   void ValidatePendingAssessment(RpoNumber block_id, InstructionOperand op,
     244             :                                  BlockAssessments* current_assessments,
     245             :                                  const PendingAssessment* assessment,
     246             :                                  int virtual_register);
     247             :   void ValidateFinalAssessment(RpoNumber block_id, InstructionOperand op,
     248             :                                BlockAssessments* current_assessments,
     249             :                                const FinalAssessment* assessment,
     250             :                                int virtual_register);
     251             :   void ValidateUse(RpoNumber block_id, BlockAssessments* current_assessments,
     252             :                    InstructionOperand op, int virtual_register);
     253             : 
     254             :   Zone* const zone_;
     255             :   const RegisterConfiguration* config_;
     256             :   const InstructionSequence* const sequence_;
     257             :   Constraints constraints_;
     258             :   ZoneMap<RpoNumber, BlockAssessments*> assessments_;
     259             :   ZoneMap<RpoNumber, DelayedAssessments*> outstanding_assessments_;
     260             : 
     261             :   DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorVerifier);
     262             : };
     263             : 
     264             : }  // namespace compiler
     265             : }  // namespace internal
     266             : }  // namespace v8
     267             : 
     268             : #endif

Generated by: LCOV version 1.10