| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| #include "codegen/instruction-counter.h" | |
| #include "common/logging.h" | |
| #include "common/names.h" | |
| using namespace impala; | |
| using std::make_pair; | |
| using std::max; | |
| const char* InstructionCounter::TOTAL_INSTS = "Total Instructions"; | |
| const char* InstructionCounter::TOTAL_BLOCKS = "Total Blocks"; | |
| const char* InstructionCounter::TOTAL_FUNCTIONS = "Total Functions"; | |
| const char* InstructionCounter::TERMINATOR_INSTS = "Terminator Instructions "; | |
| const char* InstructionCounter::BINARY_INSTS = "Binary Instructions "; | |
| const char* InstructionCounter::MEMORY_INSTS = "Memory Instructions "; | |
| const char* InstructionCounter::CAST_INSTS = "Cast Instructions "; | |
| const char* InstructionCounter::OTHER_INSTS = "Other Instructions "; | |
| InstructionCounter::InstructionCounter() { | |
| // Create top level counters and put them into counters_ | |
| counters_.insert(make_pair(TOTAL_INSTS, 0)); | |
| counters_.insert(make_pair(TOTAL_BLOCKS, 0)); | |
| counters_.insert(make_pair(TOTAL_FUNCTIONS, 0)); | |
| // Create all instruction counter and put them into counters_. Any InstructionCount | |
| // that has instructions delegated to it in InstructionCounter::visit(const | |
| // Instruction &I) must be created and inserted into counters_ here. | |
| counters_.insert(make_pair(TERMINATOR_INSTS, 0)); | |
| counters_.insert(make_pair(BINARY_INSTS, 0)); | |
| counters_.insert(make_pair(MEMORY_INSTS, 0)); | |
| counters_.insert(make_pair(CAST_INSTS, 0)); | |
| counters_.insert(make_pair(OTHER_INSTS, 0)); | |
| } | |
| void InstructionCounter::visit(const llvm::Module& M) { | |
| visit(M.begin(), M.end()); | |
| } | |
| void InstructionCounter::visit(const llvm::Function& F) { | |
| // Declarations (e.g. intrinsics left behind by optimization) have no code to count. | |
| if (F.isDeclaration()) return; | |
| IncrementCount(TOTAL_FUNCTIONS); | |
| visit(F.begin(), F.end()); | |
| } | |
| void InstructionCounter::visit(const llvm::BasicBlock& BB) { | |
| IncrementCount(TOTAL_BLOCKS); | |
| visit(BB.begin(), BB.end()); | |
| } | |
| int InstructionCounter::GetCount(const char* name) { | |
| CounterMap::const_iterator counter = counters_.find(name); | |
| DCHECK(counter != counters_.end()); | |
| return counter->second; | |
| } | |
| void InstructionCounter::visit(const llvm::Instruction& I) { | |
| IncrementCount(TOTAL_INSTS); | |
| switch (I.getOpcode()) { | |
| case llvm::Instruction::Ret: | |
| case llvm::Instruction::Br: | |
| case llvm::Instruction::Switch: | |
| case llvm::Instruction::IndirectBr: | |
| case llvm::Instruction::Invoke: | |
| case llvm::Instruction::Resume: | |
| case llvm::Instruction::Unreachable: | |
| case llvm::Instruction::CleanupRet: | |
| case llvm::Instruction::CatchRet: | |
| case llvm::Instruction::CallBr: | |
| IncrementCount(TERMINATOR_INSTS); | |
| break; | |
| case llvm::Instruction::Add: | |
| case llvm::Instruction::FAdd: | |
| case llvm::Instruction::Sub: | |
| case llvm::Instruction::FSub: | |
| case llvm::Instruction::Mul: | |
| case llvm::Instruction::FMul: | |
| case llvm::Instruction::UDiv: | |
| case llvm::Instruction::SDiv: | |
| case llvm::Instruction::FDiv: | |
| case llvm::Instruction::URem: | |
| case llvm::Instruction::SRem: | |
| case llvm::Instruction::FRem: | |
| case llvm::Instruction::Shl: | |
| case llvm::Instruction::LShr: | |
| case llvm::Instruction::AShr: | |
| case llvm::Instruction::And: | |
| case llvm::Instruction::Or: | |
| case llvm::Instruction::Xor: | |
| IncrementCount(BINARY_INSTS); | |
| break; | |
| case llvm::Instruction::Alloca: | |
| case llvm::Instruction::Load: | |
| case llvm::Instruction::Store: | |
| case llvm::Instruction::GetElementPtr: | |
| case llvm::Instruction::Fence: | |
| case llvm::Instruction::AtomicCmpXchg: | |
| case llvm::Instruction::AtomicRMW: | |
| IncrementCount(MEMORY_INSTS); | |
| break; | |
| case llvm::Instruction::Trunc: | |
| case llvm::Instruction::ZExt: | |
| case llvm::Instruction::SExt: | |
| case llvm::Instruction::FPToUI: | |
| case llvm::Instruction::FPToSI: | |
| case llvm::Instruction::UIToFP: | |
| case llvm::Instruction::SIToFP: | |
| case llvm::Instruction::FPTrunc: | |
| case llvm::Instruction::FPExt: | |
| case llvm::Instruction::PtrToInt: | |
| case llvm::Instruction::IntToPtr: | |
| case llvm::Instruction::BitCast: | |
| case llvm::Instruction::AddrSpaceCast: | |
| IncrementCount(CAST_INSTS); | |
| break; | |
| case llvm::Instruction::ICmp: | |
| case llvm::Instruction::FCmp: | |
| case llvm::Instruction::PHI: | |
| case llvm::Instruction::Call: | |
| case llvm::Instruction::Select: | |
| case llvm::Instruction::UserOp1: | |
| case llvm::Instruction::UserOp2: | |
| case llvm::Instruction::VAArg: | |
| case llvm::Instruction::ExtractElement: | |
| case llvm::Instruction::InsertElement: | |
| case llvm::Instruction::ShuffleVector: | |
| case llvm::Instruction::ExtractValue: | |
| case llvm::Instruction::InsertValue: | |
| case llvm::Instruction::LandingPad: | |
| case llvm::Instruction::Freeze: | |
| case llvm::Instruction::FNeg: | |
| case llvm::Instruction::CleanupPad: | |
| case llvm::Instruction::CatchPad: | |
| IncrementCount(OTHER_INSTS); | |
| break; | |
| default: | |
| DCHECK(false); | |
| } | |
| } | |
| void InstructionCounter::ResetCount() { | |
| for (CounterMap::value_type& counter: counters_) counter.second = 0; | |
| } | |
| void InstructionCounter::PrintCounter(const char* name, int count, int max_count_len, | |
| stringstream* stream) const { | |
| if (count > 0) { | |
| *stream << left << setw(max_count_len + 1) << setfill(' ') << count << setw(35) | |
| << setfill(' ') << name << left << setw(10 - max_count_len) << setfill(' ') | |
| << "Number of " << name << endl; | |
| } | |
| } | |
| string InstructionCounter::PrintCounters() const { | |
| // Find the longest length of all the InstructionCount count_ strings. | |
| int max_count_len = 0; | |
| stringstream count_stream; | |
| for (const CounterMap::value_type& counter: counters_) { | |
| count_stream << counter.second; | |
| max_count_len = | |
| max(max_count_len, static_cast<int>(strlen(count_stream.str().c_str()))); | |
| count_stream.str(""); | |
| } | |
| stringstream stream; | |
| // Print header | |
| stream << "\n===" << string(73, '-') << "===\n\n" | |
| << " ... Instruction Counts ...\n\n" | |
| << "===" << string(73, '-') << "===\n\n"; | |
| for (const CounterMap::value_type& counter: counters_) { | |
| // Conditional is only used in order to print the top level counters | |
| // separate from the other counters. | |
| if (strcmp(counter.first.c_str(), TOTAL_BLOCKS) == 0) { | |
| stream << "\n===" << string(73, '-') << "===\n" | |
| << " ... Totals ...\n" | |
| << "===" << string(73, '-') << "===\n\n"; | |
| } | |
| PrintCounter(counter.first.c_str(), counter.second, max_count_len, &stream); | |
| } | |
| stream << '\n'; | |
| return stream.str(); | |
| } | |
| void InstructionCounter::IncrementCount(const char* name) { | |
| CounterMap::iterator iter = counters_.find(name); | |
| DCHECK(iter != counters_.end()); | |
| iter->second++; | |
| } |