MIPS: Lattice-based representation inference, powered by left/right specific type feedback for BinaryOps and comparisons
Port r12961 (96c0e493) BUG= TEST= Review URL: https://codereview.chromium.org/11280080 Patch from Akos Palfi <palfia@homejinni.com>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13014 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8c5bf4a7e0
commit
0620b1d0d7
File diff suppressed because it is too large
Load Diff
@ -143,108 +143,6 @@ class UnaryOpStub: public CodeStub {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BinaryOpStub: public CodeStub {
|
|
||||||
public:
|
|
||||||
BinaryOpStub(Token::Value op, OverwriteMode mode)
|
|
||||||
: op_(op),
|
|
||||||
mode_(mode),
|
|
||||||
operands_type_(BinaryOpIC::UNINITIALIZED),
|
|
||||||
result_type_(BinaryOpIC::UNINITIALIZED) {
|
|
||||||
use_fpu_ = CpuFeatures::IsSupported(FPU);
|
|
||||||
ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryOpStub(
|
|
||||||
int key,
|
|
||||||
BinaryOpIC::TypeInfo operands_type,
|
|
||||||
BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
|
|
||||||
: op_(OpBits::decode(key)),
|
|
||||||
mode_(ModeBits::decode(key)),
|
|
||||||
use_fpu_(FPUBits::decode(key)),
|
|
||||||
operands_type_(operands_type),
|
|
||||||
result_type_(result_type) { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum SmiCodeGenerateHeapNumberResults {
|
|
||||||
ALLOW_HEAPNUMBER_RESULTS,
|
|
||||||
NO_HEAPNUMBER_RESULTS
|
|
||||||
};
|
|
||||||
|
|
||||||
Token::Value op_;
|
|
||||||
OverwriteMode mode_;
|
|
||||||
bool use_fpu_;
|
|
||||||
|
|
||||||
// Operand type information determined at runtime.
|
|
||||||
BinaryOpIC::TypeInfo operands_type_;
|
|
||||||
BinaryOpIC::TypeInfo result_type_;
|
|
||||||
|
|
||||||
virtual void PrintName(StringStream* stream);
|
|
||||||
|
|
||||||
// Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
|
|
||||||
class ModeBits: public BitField<OverwriteMode, 0, 2> {};
|
|
||||||
class OpBits: public BitField<Token::Value, 2, 7> {};
|
|
||||||
class FPUBits: public BitField<bool, 9, 1> {};
|
|
||||||
class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
|
|
||||||
class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
|
|
||||||
|
|
||||||
Major MajorKey() { return BinaryOp; }
|
|
||||||
int MinorKey() {
|
|
||||||
return OpBits::encode(op_)
|
|
||||||
| ModeBits::encode(mode_)
|
|
||||||
| FPUBits::encode(use_fpu_)
|
|
||||||
| OperandTypeInfoBits::encode(operands_type_)
|
|
||||||
| ResultTypeInfoBits::encode(result_type_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Generate(MacroAssembler* masm);
|
|
||||||
void GenerateGeneric(MacroAssembler* masm);
|
|
||||||
void GenerateSmiSmiOperation(MacroAssembler* masm);
|
|
||||||
void GenerateFPOperation(MacroAssembler* masm,
|
|
||||||
bool smi_operands,
|
|
||||||
Label* not_numbers,
|
|
||||||
Label* gc_required);
|
|
||||||
void GenerateSmiCode(MacroAssembler* masm,
|
|
||||||
Label* use_runtime,
|
|
||||||
Label* gc_required,
|
|
||||||
SmiCodeGenerateHeapNumberResults heapnumber_results);
|
|
||||||
void GenerateLoadArguments(MacroAssembler* masm);
|
|
||||||
void GenerateReturn(MacroAssembler* masm);
|
|
||||||
void GenerateUninitializedStub(MacroAssembler* masm);
|
|
||||||
void GenerateSmiStub(MacroAssembler* masm);
|
|
||||||
void GenerateInt32Stub(MacroAssembler* masm);
|
|
||||||
void GenerateHeapNumberStub(MacroAssembler* masm);
|
|
||||||
void GenerateOddballStub(MacroAssembler* masm);
|
|
||||||
void GenerateStringStub(MacroAssembler* masm);
|
|
||||||
void GenerateBothStringStub(MacroAssembler* masm);
|
|
||||||
void GenerateGenericStub(MacroAssembler* masm);
|
|
||||||
void GenerateAddStrings(MacroAssembler* masm);
|
|
||||||
void GenerateCallRuntime(MacroAssembler* masm);
|
|
||||||
|
|
||||||
void GenerateHeapResultAllocation(MacroAssembler* masm,
|
|
||||||
Register result,
|
|
||||||
Register heap_number_map,
|
|
||||||
Register scratch1,
|
|
||||||
Register scratch2,
|
|
||||||
Label* gc_required);
|
|
||||||
void GenerateRegisterArgsPush(MacroAssembler* masm);
|
|
||||||
void GenerateTypeTransition(MacroAssembler* masm);
|
|
||||||
void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
|
|
||||||
|
|
||||||
virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
|
|
||||||
|
|
||||||
virtual InlineCacheState GetICState() {
|
|
||||||
return BinaryOpIC::ToState(operands_type_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void FinishCode(Handle<Code> code) {
|
|
||||||
code->set_binary_op_type(operands_type_);
|
|
||||||
code->set_binary_op_result_type(result_type_);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend class CodeGenerator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class StringHelper : public AllStatic {
|
class StringHelper : public AllStatic {
|
||||||
public:
|
public:
|
||||||
// Generate code for copying characters using a simple loop. This should only
|
// Generate code for copying characters using a simple loop. This should only
|
||||||
@ -724,20 +622,6 @@ class FloatingPointHelper : public AllStatic {
|
|||||||
Register scratch1,
|
Register scratch1,
|
||||||
Register scratch2);
|
Register scratch2);
|
||||||
|
|
||||||
// Loads objects from a0 and a1 (right and left in binary operations) into
|
|
||||||
// floating point registers. Depending on the destination the values ends up
|
|
||||||
// either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
|
|
||||||
// is floating point registers FPU must be supported. If core registers are
|
|
||||||
// requested when FPU is supported f12 and f14 will still be scratched. If
|
|
||||||
// either a0 or a1 is not a number (not smi and not heap number object) the
|
|
||||||
// not_number label is jumped to with a0 and a1 intact.
|
|
||||||
static void LoadOperands(MacroAssembler* masm,
|
|
||||||
FloatingPointHelper::Destination destination,
|
|
||||||
Register heap_number_map,
|
|
||||||
Register scratch1,
|
|
||||||
Register scratch2,
|
|
||||||
Label* not_number);
|
|
||||||
|
|
||||||
// Convert the smi or heap number in object to an int32 using the rules
|
// Convert the smi or heap number in object to an int32 using the rules
|
||||||
// for ToInt32 as described in ECMAScript 9.5.: the value is truncated
|
// for ToInt32 as described in ECMAScript 9.5.: the value is truncated
|
||||||
// and brought into the range -2^31 .. +2^31 - 1.
|
// and brought into the range -2^31 .. +2^31 - 1.
|
||||||
@ -834,7 +718,12 @@ class FloatingPointHelper : public AllStatic {
|
|||||||
Register heap_number_result,
|
Register heap_number_result,
|
||||||
Register scratch);
|
Register scratch);
|
||||||
|
|
||||||
private:
|
// Loads the objects from |object| into floating point registers.
|
||||||
|
// Depending on |destination| the value ends up either in |dst| or
|
||||||
|
// in |dst1|/|dst2|. If |destination| is kFPURegisters, then FPU
|
||||||
|
// must be supported. If kCoreRegisters are requested and FPU is
|
||||||
|
// supported, |dst| will be scratched. If |object| is neither smi nor
|
||||||
|
// heap number, |not_number| is jumped to with |object| still intact.
|
||||||
static void LoadNumber(MacroAssembler* masm,
|
static void LoadNumber(MacroAssembler* masm,
|
||||||
FloatingPointHelper::Destination destination,
|
FloatingPointHelper::Destination destination,
|
||||||
Register object,
|
Register object,
|
||||||
|
@ -4103,9 +4103,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
JumpPatchSite patch_site(masm_);
|
JumpPatchSite patch_site(masm_);
|
||||||
|
|
||||||
int count_value = expr->op() == Token::INC ? 1 : -1;
|
int count_value = expr->op() == Token::INC ? 1 : -1;
|
||||||
__ li(a1, Operand(Smi::FromInt(count_value)));
|
|
||||||
|
|
||||||
if (ShouldInlineSmiCase(expr->op())) {
|
if (ShouldInlineSmiCase(expr->op())) {
|
||||||
|
__ li(a1, Operand(Smi::FromInt(count_value)));
|
||||||
__ AdduAndCheckForOverflow(v0, a0, a1, t0);
|
__ AdduAndCheckForOverflow(v0, a0, a1, t0);
|
||||||
__ BranchOnOverflow(&stub_call, t0); // Do stub on overflow.
|
__ BranchOnOverflow(&stub_call, t0); // Do stub on overflow.
|
||||||
|
|
||||||
@ -4114,6 +4113,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
patch_site.EmitJumpIfSmi(v0, &done);
|
patch_site.EmitJumpIfSmi(v0, &done);
|
||||||
__ bind(&stub_call);
|
__ bind(&stub_call);
|
||||||
}
|
}
|
||||||
|
__ mov(a1, a0);
|
||||||
|
__ li(a0, Operand(Smi::FromInt(count_value)));
|
||||||
|
|
||||||
// Record position before stub call.
|
// Record position before stub call.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
@ -4336,29 +4337,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
default: {
|
default: {
|
||||||
VisitForAccumulatorValue(expr->right());
|
VisitForAccumulatorValue(expr->right());
|
||||||
Condition cc = eq;
|
Condition cc = CompareIC::ComputeCondition(op);
|
||||||
switch (op) {
|
|
||||||
case Token::EQ_STRICT:
|
|
||||||
case Token::EQ:
|
|
||||||
cc = eq;
|
|
||||||
break;
|
|
||||||
case Token::LT:
|
|
||||||
cc = lt;
|
|
||||||
break;
|
|
||||||
case Token::GT:
|
|
||||||
cc = gt;
|
|
||||||
break;
|
|
||||||
case Token::LTE:
|
|
||||||
cc = le;
|
|
||||||
break;
|
|
||||||
case Token::GTE:
|
|
||||||
cc = ge;
|
|
||||||
break;
|
|
||||||
case Token::IN:
|
|
||||||
case Token::INSTANCEOF:
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
__ mov(a0, result_register());
|
__ mov(a0, result_register());
|
||||||
__ pop(a1);
|
__ pop(a1);
|
||||||
|
|
||||||
|
@ -1695,36 +1695,16 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
|
bool CompareIC::HasInlinedSmiCode(Address address) {
|
||||||
HandleScope scope;
|
// The address of the instruction following the call.
|
||||||
Handle<Code> rewritten;
|
Address andi_instruction_address =
|
||||||
State previous_state = GetState();
|
address + Assembler::kCallTargetAddressOffset;
|
||||||
State state = TargetState(previous_state, false, x, y);
|
|
||||||
if (state == GENERIC) {
|
|
||||||
CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0);
|
|
||||||
rewritten = stub.GetCode();
|
|
||||||
} else {
|
|
||||||
ICCompareStub stub(op_, state);
|
|
||||||
if (state == KNOWN_OBJECTS) {
|
|
||||||
stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
|
|
||||||
}
|
|
||||||
rewritten = stub.GetCode();
|
|
||||||
}
|
|
||||||
set_target(*rewritten);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
// If the instruction following the call is not a andi at, rx, #yyy, nothing
|
||||||
if (FLAG_trace_ic) {
|
// was inlined.
|
||||||
PrintF("[CompareIC (%s->%s)#%s]\n",
|
Instr instr = Assembler::instr_at(andi_instruction_address);
|
||||||
GetStateName(previous_state),
|
return Assembler::IsAndImmediate(instr) &&
|
||||||
GetStateName(state),
|
Assembler::GetRt(instr) == (uint32_t)zero_reg.code();
|
||||||
Token::Name(op_));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Activate inlined smi code.
|
|
||||||
if (previous_state == UNINITIALIZED) {
|
|
||||||
PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -229,7 +229,30 @@ bool LCodeGen::GenerateBody() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (emit_instructions) {
|
if (emit_instructions) {
|
||||||
Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
|
if (FLAG_code_comments) {
|
||||||
|
HValue* hydrogen = instr->hydrogen_value();
|
||||||
|
if (hydrogen != NULL) {
|
||||||
|
if (hydrogen->IsChange()) {
|
||||||
|
HValue* changed_value = HChange::cast(hydrogen)->value();
|
||||||
|
int use_id = 0;
|
||||||
|
const char* use_mnemo = "dead";
|
||||||
|
if (hydrogen->UseCount() >= 1) {
|
||||||
|
HValue* use_value = hydrogen->uses().value();
|
||||||
|
use_id = use_value->id();
|
||||||
|
use_mnemo = use_value->Mnemonic();
|
||||||
|
}
|
||||||
|
Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
|
||||||
|
current_instruction_, instr->Mnemonic(),
|
||||||
|
changed_value->id(), changed_value->Mnemonic(),
|
||||||
|
use_id, use_mnemo);
|
||||||
|
} else {
|
||||||
|
Comment(";;; @%d: %s. <#%d>", current_instruction_,
|
||||||
|
instr->Mnemonic(), hydrogen->id());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
|
||||||
|
}
|
||||||
|
}
|
||||||
instr->CompileToNative(this);
|
instr->CompileToNative(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1345,7 +1345,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
|
|||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
|
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
|
||||||
HCompareIDAndBranch* instr) {
|
HCompareIDAndBranch* instr) {
|
||||||
Representation r = instr->GetInputRepresentation();
|
Representation r = instr->representation();
|
||||||
if (r.IsInteger32()) {
|
if (r.IsInteger32()) {
|
||||||
ASSERT(instr->left()->representation().IsInteger32());
|
ASSERT(instr->left()->representation().IsInteger32());
|
||||||
ASSERT(instr->right()->representation().IsInteger32());
|
ASSERT(instr->right()->representation().IsInteger32());
|
||||||
@ -2105,7 +2105,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
|
|||||||
env->set_ast_id(instr->ast_id());
|
env->set_ast_id(instr->ast_id());
|
||||||
|
|
||||||
env->Drop(instr->pop_count());
|
env->Drop(instr->pop_count());
|
||||||
for (int i = 0; i < instr->values()->length(); ++i) {
|
for (int i = instr->values()->length() - 1; i >= 0; --i) {
|
||||||
HValue* value = instr->values()->at(i);
|
HValue* value = instr->values()->at(i);
|
||||||
if (instr->HasAssignedIndexAt(i)) {
|
if (instr->HasAssignedIndexAt(i)) {
|
||||||
env->Bind(instr->GetAssignedIndexAt(i), value);
|
env->Bind(instr->GetAssignedIndexAt(i), value);
|
||||||
|
@ -616,7 +616,7 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
|
|||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
bool is_double() const {
|
bool is_double() const {
|
||||||
return hydrogen()->GetInputRepresentation().IsDouble();
|
return hydrogen()->representation().IsDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void PrintDataTo(StringStream* stream);
|
virtual void PrintDataTo(StringStream* stream);
|
||||||
|
@ -2219,10 +2219,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
|
|||||||
set_register(HI, static_cast<int32_t>(u64hilo >> 32));
|
set_register(HI, static_cast<int32_t>(u64hilo >> 32));
|
||||||
break;
|
break;
|
||||||
case DIV:
|
case DIV:
|
||||||
// Divide by zero was not checked in the configuration step - div and
|
// Divide by zero and overflow was not checked in the configuration
|
||||||
// divu do not raise exceptions. On division by 0, the result will
|
// step - div and divu do not raise exceptions. On division by 0 and
|
||||||
// be UNPREDICTABLE.
|
// on overflow (INT_MIN/-1), the result will be UNPREDICTABLE.
|
||||||
if (rt != 0) {
|
if (rt != 0 && !(rs == INT_MIN && rt == -1)) {
|
||||||
set_register(LO, rs / rt);
|
set_register(LO, rs / rt);
|
||||||
set_register(HI, rs % rt);
|
set_register(HI, rs % rt);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user