Files
sdk/runtime/vm/il_printer.cc
T
vegorov@google.com 932a05420a Reland r17365.
Introduce InvokeMathCFunction that can be used to directly invoke mathematical
function provided by runtime.

Use it to unconditionally inline _Double.pow.

Use it to inline floor, ceil, round, truncate, round when SSE4.1 is not
available.

Perform representation selection phase after constant propagation to minimize
boxing.

Add support for enter instruction in the x64 disassembler.

Add test for optimized pow and fix compilation on windows.

R=fschneider@google.com
BUG=dart:8002

Review URL: https://codereview.chromium.org//12038013

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@17393 260f80e4-7a28-3924-810f-c04153c831b5
2013-01-22 12:18:31 +00:00

699 lines
18 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/il_printer.h"
#include "vm/intermediate_language.h"
#include "vm/os.h"
#include "vm/parser.h"
namespace dart {
DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
void BufferFormatter::Print(const char* format, ...) {
va_list args;
va_start(args, format);
VPrint(format, args);
va_end(args);
}
void BufferFormatter::VPrint(const char* format, va_list args) {
intptr_t available = size_ - position_;
if (available <= 0) return;
intptr_t written =
OS::VSNPrint(buffer_ + position_, available, format, args);
if (written >= 0) {
position_ += (available <= written) ? available : written;
}
}
void FlowGraphPrinter::PrintBlocks() {
if (!function_.IsNull()) {
OS::Print("==== %s\n", function_.ToFullyQualifiedCString());
}
for (intptr_t i = 0; i < block_order_.length(); ++i) {
// Print the block entry.
PrintInstruction(block_order_[i]);
// And all the successors until an exit, branch, or a block entry.
Instruction* current = block_order_[i];
for (ForwardInstructionIterator it(current->AsBlockEntry());
!it.Done();
it.Advance()) {
current = it.Current();
OS::Print("\n");
PrintInstruction(current);
}
if (current->next() != NULL) {
ASSERT(current->next()->IsBlockEntry());
OS::Print(" goto %"Pd"", current->next()->AsBlockEntry()->block_id());
}
OS::Print("\n");
}
}
void FlowGraphPrinter::PrintInstruction(Instruction* instr) {
PrintOneInstruction(instr, print_locations_);
}
void FlowGraphPrinter::PrintOneInstruction(Instruction* instr,
bool print_locations) {
char str[1000];
BufferFormatter f(str, sizeof(str));
instr->PrintTo(&f);
if (FLAG_print_environments && (instr->env() != NULL)) {
instr->env()->PrintTo(&f);
}
if (print_locations && (instr->locs() != NULL)) {
instr->locs()->PrintTo(&f);
}
if (instr->lifetime_position() != -1) {
OS::Print("%3"Pd": ", instr->lifetime_position());
}
if (!instr->IsBlockEntry()) OS::Print(" ");
OS::Print("%s", str);
}
void FlowGraphPrinter::PrintTypeCheck(const ParsedFunction& parsed_function,
intptr_t token_pos,
Value* value,
const AbstractType& dst_type,
const String& dst_name,
bool eliminated) {
const Script& script = Script::Handle(parsed_function.function().script());
const char* compile_type_name = "unknown";
if (value != NULL) {
const AbstractType& type = AbstractType::Handle(value->CompileType());
if (!type.IsNull()) {
compile_type_name = String::Handle(type.Name()).ToCString();
}
}
Parser::PrintMessage(script, token_pos, "",
"%s type check: compile type '%s' is %s specific than "
"type '%s' of '%s'.",
eliminated ? "Eliminated" : "Generated",
compile_type_name,
eliminated ? "more" : "not more",
String::Handle(dst_type.Name()).ToCString(),
dst_name.ToCString());
}
static void PrintICData(BufferFormatter* f, const ICData& ic_data) {
f->Print(" IC[%"Pd": ", ic_data.NumberOfChecks());
Function& target = Function::Handle();
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
GrowableArray<intptr_t> class_ids;
ic_data.GetCheckAt(i, &class_ids, &target);
const intptr_t count = ic_data.GetCountAt(i);
if (i > 0) {
f->Print(" | ");
}
for (intptr_t k = 0; k < class_ids.length(); k++) {
if (k > 0) {
f->Print(", ");
}
const Class& cls =
Class::Handle(Isolate::Current()->class_table()->At(class_ids[k]));
f->Print("%s", String::Handle(cls.Name()).ToCString());
}
if (count > 0) {
f->Print(" #%"Pd, count);
}
f->Print(" <%p>", static_cast<void*>(target.raw()));
}
f->Print("]");
}
static void PrintPropagatedType(BufferFormatter* f, const Definition& def) {
if (def.HasPropagatedType()) {
String& name = String::Handle();
name = AbstractType::Handle(def.PropagatedType()).Name();
f->Print(" {PT: %s}", name.ToCString());
}
if (def.has_propagated_cid()) {
const Class& cls = Class::Handle(
Isolate::Current()->class_table()->At(def.propagated_cid()));
f->Print(" {PCid: %s}", String::Handle(cls.Name()).ToCString());
}
}
static void PrintUse(BufferFormatter* f, const Definition& definition) {
if (definition.is_used()) {
if (definition.HasSSATemp()) {
f->Print("v%"Pd, definition.ssa_temp_index());
} else if (definition.temp_index() != -1) {
f->Print("t%"Pd, definition.temp_index());
}
}
}
void Instruction::PrintTo(BufferFormatter* f) const {
f->Print("%s:%"Pd"(", DebugName(), GetDeoptId());
PrintOperandsTo(f);
f->Print(")");
}
void Instruction::PrintOperandsTo(BufferFormatter* f) const {
for (int i = 0; i < InputCount(); ++i) {
if (i > 0) f->Print(", ");
if (InputAt(i) != NULL) InputAt(i)->PrintTo(f);
}
}
void Definition::PrintTo(BufferFormatter* f) const {
PrintUse(f, *this);
if (is_used()) {
if (HasSSATemp() || (temp_index() != -1)) f->Print(" <- ");
}
f->Print("%s:%"Pd"(", DebugName(), GetDeoptId());
PrintOperandsTo(f);
f->Print(")");
PrintPropagatedType(f, *this);
if (range_ != NULL) {
f->Print(" ");
range_->PrintTo(f);
}
}
void Definition::PrintOperandsTo(BufferFormatter* f) const {
for (int i = 0; i < InputCount(); ++i) {
if (i > 0) f->Print(", ");
if (InputAt(i) != NULL) InputAt(i)->PrintTo(f);
}
}
void Value::PrintTo(BufferFormatter* f) const {
PrintUse(f, *definition());
}
void ConstantInstr::PrintOperandsTo(BufferFormatter* f) const {
const char* cstr = value().ToCString();
const char* new_line = strchr(cstr, '\n');
if (new_line == NULL) {
f->Print("#%s", cstr);
} else {
const intptr_t pos = new_line - cstr;
char* buffer = Isolate::Current()->current_zone()->Alloc<char>(pos + 1);
strncpy(buffer, cstr, pos);
buffer[pos] = '\0';
f->Print("#%s\\n...", buffer);
}
}
void ConstraintInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
f->Print(" ^ ");
constraint()->PrintTo(f);
}
void Range::PrintTo(BufferFormatter* f) const {
f->Print("[");
min_.PrintTo(f);
f->Print(", ");
max_.PrintTo(f);
f->Print("]");
}
const char* Range::ToCString(Range* range) {
if (range == NULL) return "[_|_, _|_]";
char buffer[256];
BufferFormatter f(buffer, sizeof(buffer));
range->PrintTo(&f);
return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
}
void RangeBoundary::PrintTo(BufferFormatter* f) const {
switch (kind_) {
case kSymbol:
f->Print("v%"Pd, reinterpret_cast<Definition*>(value_)->ssa_temp_index());
if (offset_ != 0) f->Print("%+"Pd, offset_);
break;
case kConstant:
if (value_ == kMinusInfinity) {
f->Print("-inf");
} else if (value_ == kPlusInfinity) {
f->Print("+inf");
} else {
f->Print("%"Pd, value_);
}
break;
case kUnknown:
f->Print("_|_");
break;
}
}
const char* RangeBoundary::ToCString() const {
char buffer[256];
BufferFormatter f(buffer, sizeof(buffer));
PrintTo(&f);
return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
}
void AssertAssignableInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
f->Print(", %s, '%s'%s",
String::Handle(dst_type().Name()).ToCString(),
dst_name().ToCString(),
is_eliminated() ? " eliminated" : "");
f->Print(" instantiator(");
instantiator()->PrintTo(f);
f->Print(")");
f->Print(" instantiator_type_arguments(");
instantiator_type_arguments()->PrintTo(f);
f->Print(")");
}
void AssertBooleanInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
f->Print("%s", is_eliminated() ? " eliminated" : "");
}
void ArgumentDefinitionTestInstr::PrintOperandsTo(BufferFormatter* f) const {
saved_arguments_descriptor()->PrintTo(f);
f->Print(", ?%s @%"Pd"",
formal_parameter_name().ToCString(),
formal_parameter_index());
}
void ClosureCallInstr::PrintOperandsTo(BufferFormatter* f) const {
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
if (i > 0) f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
}
void InstanceCallInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s", function_name().ToCString());
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
if (HasICData()) {
PrintICData(f, *ic_data());
}
}
void PolymorphicInstanceCallInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s", instance_call()->function_name().ToCString());
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
PrintICData(f, ic_data());
}
void StrictCompareInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(kind()));
left()->PrintTo(f);
f->Print(", ");
right()->PrintTo(f);
}
void EqualityCompareInstr::PrintOperandsTo(BufferFormatter* f) const {
left()->PrintTo(f);
f->Print(" %s ", Token::Str(kind()));
right()->PrintTo(f);
if (HasICData()) {
PrintICData(f, *ic_data());
}
}
void StaticCallInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s ", String::Handle(function().name()).ToCString());
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
if (i > 0) f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
}
void LoadLocalInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s lvl:%"Pd"", local().name().ToCString(), context_level());
}
void StoreLocalInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", local().name().ToCString());
value()->PrintTo(f);
f->Print(", lvl: %"Pd"", context_level());
}
void NativeCallInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s", native_name().ToCString());
}
void StoreInstanceFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s {%"Pd"}, ",
String::Handle(field().name()).ToCString(),
field().Offset());
instance()->PrintTo(f);
f->Print(", ");
value()->PrintTo(f);
}
void LoadStaticFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s", String::Handle(field().name()).ToCString());
}
void StoreStaticFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", String::Handle(field().name()).ToCString());
value()->PrintTo(f);
}
void InstanceOfInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
f->Print(" %s %s",
negate_result() ? "ISNOT" : "IS",
String::Handle(type().Name()).ToCString());
f->Print(" instantiator(");
instantiator()->PrintTo(f);
f->Print(")");
f->Print(" type-arg(");
instantiator_type_arguments()->PrintTo(f);
f->Print(")");
}
void RelationalOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(kind()));
left()->PrintTo(f);
f->Print(", ");
right()->PrintTo(f);
if (HasICData()) {
PrintICData(f, *ic_data());
}
}
void AllocateObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s", Class::Handle(constructor().Owner()).ToCString());
for (intptr_t i = 0; i < ArgumentCount(); i++) {
f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
}
void AllocateObjectWithBoundsCheckInstr::PrintOperandsTo(
BufferFormatter* f) const {
f->Print("%s", Class::Handle(constructor().Owner()).ToCString());
for (intptr_t i = 0; i < InputCount(); i++) {
f->Print(", ");
InputAt(i)->PrintTo(f);
}
}
void CreateArrayInstr::PrintOperandsTo(BufferFormatter* f) const {
for (int i = 0; i < ArgumentCount(); ++i) {
if (i != 0) f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
if (ArgumentCount() > 0) f->Print(", ");
element_type()->PrintTo(f);
}
void CreateClosureInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s", function().ToCString());
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
if (i > 0) f->Print(", ");
ArgumentAt(i)->value()->PrintTo(f);
}
}
void LoadFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
f->Print(", %"Pd", immutable=%d", offset_in_bytes(), immutable_);
}
void StoreVMFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
dest()->PrintTo(f);
f->Print(", %"Pd", ", offset_in_bytes());
value()->PrintTo(f);
}
void InstantiateTypeArgumentsInstr::PrintOperandsTo(BufferFormatter* f) const {
const String& type_args = String::Handle(type_arguments().Name());
f->Print("%s, ", type_args.ToCString());
instantiator()->PrintTo(f);
}
void ExtractConstructorTypeArgumentsInstr::PrintOperandsTo(
BufferFormatter* f) const {
const String& type_args = String::Handle(type_arguments().Name());
f->Print("%s, ", type_args.ToCString());
instantiator()->PrintTo(f);
}
void AllocateContextInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%"Pd"", num_context_variables());
}
void CatchEntryInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, %s",
exception_var().name().ToCString(),
stacktrace_var().name().ToCString());
}
void BinarySmiOpInstr::PrintTo(BufferFormatter* f) const {
Definition::PrintTo(f);
f->Print(" %co", overflow_ ? '+' : '-');
}
void BinarySmiOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
left()->PrintTo(f);
f->Print(", ");
right()->PrintTo(f);
}
void BinaryDoubleOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
left()->PrintTo(f);
f->Print(", ");
right()->PrintTo(f);
}
void BinaryMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
left()->PrintTo(f);
f->Print(", ");
right()->PrintTo(f);
}
void ShiftMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
left()->PrintTo(f);
f->Print(", ");
right()->PrintTo(f);
}
void UnaryMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
value()->PrintTo(f);
}
void UnarySmiOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
value()->PrintTo(f);
}
void CheckClassInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
PrintICData(f, unary_checks());
}
void InvokeMathCFunctionInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", MethodRecognizer::KindToCString(recognized_kind_));
Definition::PrintOperandsTo(f);
}
void GraphEntryInstr::PrintTo(BufferFormatter* f) const {
const GrowableArray<Definition*>& defns = initial_definitions_;
f->Print("B%"Pd"[graph]", block_id());
if (defns.length() > 0) {
f->Print(" {");
for (intptr_t i = 0; i < defns.length(); ++i) {
Definition* def = defns[i];
f->Print("\n ");
def->PrintTo(f);
}
f->Print("\n}");
}
}
void JoinEntryInstr::PrintTo(BufferFormatter* f) const {
f->Print("B%"Pd"[join] pred(", block_id());
for (intptr_t i = 0; i < predecessors_.length(); ++i) {
if (i > 0) f->Print(", ");
f->Print("B%"Pd, predecessors_[i]->block_id());
}
f->Print(")");
if (phis_ != NULL) {
f->Print(" {");
for (intptr_t i = 0; i < phis_->length(); ++i) {
if ((*phis_)[i] == NULL) continue;
f->Print("\n ");
(*phis_)[i]->PrintTo(f);
}
f->Print("\n}");
}
if (HasParallelMove()) {
f->Print(" ");
parallel_move()->PrintTo(f);
}
}
void PhiInstr::PrintTo(BufferFormatter* f) const {
f->Print("v%"Pd" <- phi(", ssa_temp_index());
for (intptr_t i = 0; i < inputs_.length(); ++i) {
if (inputs_[i] != NULL) inputs_[i]->PrintTo(f);
if (i < inputs_.length() - 1) f->Print(", ");
}
f->Print(")");
PrintPropagatedType(f, *this);
if (is_alive()) {
f->Print(" alive");
} else {
f->Print(" dead");
}
if (range_ != NULL) {
f->Print(" ");
range_->PrintTo(f);
}
}
void ParameterInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%"Pd, index());
}
void TargetEntryInstr::PrintTo(BufferFormatter* f) const {
f->Print("B%"Pd"[target", block_id());
if (IsCatchEntry()) {
f->Print(" catch %"Pd"]", catch_try_index());
} else {
f->Print("]");
}
if (HasParallelMove()) {
f->Print(" ");
parallel_move()->PrintTo(f);
}
}
void PushArgumentInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
}
void GotoInstr::PrintTo(BufferFormatter* f) const {
if (HasParallelMove()) {
parallel_move()->PrintTo(f);
f->Print(" ");
}
f->Print("goto:%"Pd" %"Pd"", GetDeoptId(), successor()->block_id());
}
void BranchInstr::PrintTo(BufferFormatter* f) const {
f->Print("%s ", DebugName());
f->Print("if ");
comparison()->PrintTo(f);
f->Print(" goto (%"Pd", %"Pd")",
true_successor()->block_id(),
false_successor()->block_id());
}
void ParallelMoveInstr::PrintTo(BufferFormatter* f) const {
f->Print("%s ", DebugName());
for (intptr_t i = 0; i < moves_.length(); i++) {
if (i != 0) f->Print(", ");
moves_[i]->dest().PrintTo(f);
f->Print(" <- ");
moves_[i]->src().PrintTo(f);
}
}
void Environment::PrintTo(BufferFormatter* f) const {
f->Print(" env={ ");
int arg_count = 0;
for (intptr_t i = 0; i < values_.length(); ++i) {
if (i > 0) f->Print(", ");
if (values_[i]->definition()->IsPushArgument()) {
f->Print("a%d", arg_count++);
} else {
values_[i]->PrintTo(f);
}
if ((locations_ != NULL) && !locations_[i].IsInvalid()) {
f->Print(" [");
locations_[i].PrintTo(f);
f->Print("]");
}
}
f->Print(" }");
if (outer_ != NULL) outer_->PrintTo(f);
}
} // namespace dart