Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <fstream>
     18 #include <stdint.h>
     19 
     20 #include "builder.h"
     21 #include "code_generator.h"
     22 #include "compilers.h"
     23 #include "driver/compiler_driver.h"
     24 #include "driver/dex_compilation_unit.h"
     25 #include "graph_visualizer.h"
     26 #include "nodes.h"
     27 #include "register_allocator.h"
     28 #include "ssa_phi_elimination.h"
     29 #include "ssa_liveness_analysis.h"
     30 #include "utils/arena_allocator.h"
     31 
     32 namespace art {
     33 
     34 /**
     35  * Used by the code generator, to allocate the code in a vector.
     36  */
     37 class CodeVectorAllocator FINAL : public CodeAllocator {
     38  public:
     39   CodeVectorAllocator() { }
     40 
     41   virtual uint8_t* Allocate(size_t size) {
     42     size_ = size;
     43     memory_.resize(size);
     44     return &memory_[0];
     45   }
     46 
     47   size_t GetSize() const { return size_; }
     48   const std::vector<uint8_t>& GetMemory() const { return memory_; }
     49 
     50  private:
     51   std::vector<uint8_t> memory_;
     52   size_t size_;
     53 
     54   DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
     55 };
     56 
     57 /**
     58  * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
     59  */
     60 static bool kIsVisualizerEnabled = false;
     61 
     62 /**
     63  * Filter to apply to the visualizer. Methods whose name contain that filter will
     64  * be in the file.
     65  */
     66 static const char* kStringFilter = "";
     67 
     68 OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) {
     69   if (kIsVisualizerEnabled) {
     70     visualizer_output_.reset(new std::ofstream("art.cfg"));
     71   }
     72 }
     73 
     74 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
     75                                                uint32_t access_flags,
     76                                                InvokeType invoke_type,
     77                                                uint16_t class_def_idx,
     78                                                uint32_t method_idx,
     79                                                jobject class_loader,
     80                                                const DexFile& dex_file) const {
     81   InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
     82   // Always use the thumb2 assembler: some runtime functionality (like implicit stack
     83   // overflow checks) assume thumb2.
     84   if (instruction_set == kArm) {
     85     instruction_set = kThumb2;
     86   }
     87 
     88   // Do not attempt to compile on architectures we do not support.
     89   if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) {
     90     return nullptr;
     91   }
     92 
     93   DexCompilationUnit dex_compilation_unit(
     94     nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item,
     95     class_def_idx, method_idx, access_flags,
     96     GetCompilerDriver()->GetVerifiedMethod(&dex_file, method_idx));
     97 
     98   // For testing purposes, we put a special marker on method names that should be compiled
     99   // with this compiler. This makes sure we're not regressing.
    100   bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos;
    101   bool shouldOptimize =
    102       dex_compilation_unit.GetSymbol().find("00024reg_00024") != std::string::npos;
    103 
    104   ArenaPool pool;
    105   ArenaAllocator arena(&pool);
    106   HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file, GetCompilerDriver());
    107 
    108   HGraph* graph = builder.BuildGraph(*code_item);
    109   if (graph == nullptr) {
    110     if (shouldCompile) {
    111       LOG(FATAL) << "Could not build graph in optimizing compiler";
    112     }
    113     return nullptr;
    114   }
    115 
    116   CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, instruction_set);
    117   if (codegen == nullptr) {
    118     if (shouldCompile) {
    119       LOG(FATAL) << "Could not find code generator for optimizing compiler";
    120     }
    121     return nullptr;
    122   }
    123 
    124   HGraphVisualizer visualizer(
    125       visualizer_output_.get(), graph, kStringFilter, *codegen, dex_compilation_unit);
    126   visualizer.DumpGraph("builder");
    127 
    128   CodeVectorAllocator allocator;
    129 
    130   if (RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
    131     graph->BuildDominatorTree();
    132     graph->TransformToSSA();
    133     visualizer.DumpGraph("ssa");
    134     graph->FindNaturalLoops();
    135 
    136     SsaRedundantPhiElimination(graph).Run();
    137     SsaDeadPhiElimination(graph).Run();
    138 
    139     SsaLivenessAnalysis liveness(*graph, codegen);
    140     liveness.Analyze();
    141     visualizer.DumpGraph(kLivenessPassName);
    142 
    143     RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
    144     register_allocator.AllocateRegisters();
    145 
    146     visualizer.DumpGraph(kRegisterAllocatorPassName);
    147     codegen->CompileOptimized(&allocator);
    148   } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
    149     LOG(FATAL) << "Could not allocate registers in optimizing compiler";
    150   } else {
    151     codegen->CompileBaseline(&allocator);
    152 
    153     // Run these phases to get some test coverage.
    154     graph->BuildDominatorTree();
    155     graph->TransformToSSA();
    156     visualizer.DumpGraph("ssa");
    157     graph->FindNaturalLoops();
    158     SsaLivenessAnalysis liveness(*graph, codegen);
    159     liveness.Analyze();
    160     visualizer.DumpGraph(kLivenessPassName);
    161   }
    162 
    163   std::vector<uint8_t> mapping_table;
    164   codegen->BuildMappingTable(&mapping_table);
    165   std::vector<uint8_t> vmap_table;
    166   codegen->BuildVMapTable(&vmap_table);
    167   std::vector<uint8_t> gc_map;
    168   codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
    169 
    170   return CompiledMethod::SwapAllocCompiledMethod(GetCompilerDriver(),
    171                                                  instruction_set,
    172                                                  ArrayRef<const uint8_t>(allocator.GetMemory()),
    173                                                  codegen->GetFrameSize(),
    174                                                  codegen->GetCoreSpillMask(),
    175                                                  0, /* FPR spill mask, unused */
    176                                                  ArrayRef<const uint8_t>(mapping_table),
    177                                                  ArrayRef<const uint8_t>(vmap_table),
    178                                                  ArrayRef<const uint8_t>(gc_map),
    179                                                  ArrayRef<const uint8_t>());
    180 }
    181 
    182 }  // namespace art
    183