X64 Crankshaft: Add bit operations and shifts to x64 crankshaft.
Review URL: http://codereview.chromium.org/6246099 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6632 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8d4e0bb39c
commit
c5de2c95fa
@ -894,6 +894,10 @@ class Assembler : public Malloced {
|
||||
arithmetic_op(0x0B, dst, src);
|
||||
}
|
||||
|
||||
void orl(Register dst, const Operand& src) {
|
||||
arithmetic_op_32(0x0B, dst, src);
|
||||
}
|
||||
|
||||
void or_(const Operand& dst, Register src) {
|
||||
arithmetic_op(0x09, src, dst);
|
||||
}
|
||||
@ -1057,6 +1061,18 @@ class Assembler : public Malloced {
|
||||
arithmetic_op_32(0x33, dst, src);
|
||||
}
|
||||
|
||||
void xorl(Register dst, const Operand& src) {
|
||||
arithmetic_op_32(0x33, dst, src);
|
||||
}
|
||||
|
||||
void xorl(Register dst, Immediate src) {
|
||||
immediate_arithmetic_op_32(0x6, dst, src);
|
||||
}
|
||||
|
||||
void xorl(const Operand& dst, Immediate src) {
|
||||
immediate_arithmetic_op_32(0x6, dst, src);
|
||||
}
|
||||
|
||||
void xor_(Register dst, const Operand& src) {
|
||||
arithmetic_op(0x33, dst, src);
|
||||
}
|
||||
|
@ -605,11 +605,115 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoBitI(LBitI* instr) {
|
||||
Abort("Unimplemented: %s", "DoBitI");}
|
||||
LOperand* left = instr->InputAt(0);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
ASSERT(left->IsRegister());
|
||||
|
||||
if (right->IsConstantOperand()) {
|
||||
int right_operand = ToInteger32(LConstantOperand::cast(right));
|
||||
switch (instr->op()) {
|
||||
case Token::BIT_AND:
|
||||
__ andl(ToRegister(left), Immediate(right_operand));
|
||||
break;
|
||||
case Token::BIT_OR:
|
||||
__ orl(ToRegister(left), Immediate(right_operand));
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ xorl(ToRegister(left), Immediate(right_operand));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} else if (right->IsStackSlot()) {
|
||||
switch (instr->op()) {
|
||||
case Token::BIT_AND:
|
||||
__ andl(ToRegister(left), ToOperand(right));
|
||||
break;
|
||||
case Token::BIT_OR:
|
||||
__ orl(ToRegister(left), ToOperand(right));
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ xorl(ToRegister(left), ToOperand(right));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ASSERT(right->IsRegister());
|
||||
switch (instr->op()) {
|
||||
case Token::BIT_AND:
|
||||
__ andl(ToRegister(left), ToRegister(right));
|
||||
break;
|
||||
case Token::BIT_OR:
|
||||
__ orl(ToRegister(left), ToRegister(right));
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ xorl(ToRegister(left), ToRegister(right));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoShiftI(LShiftI* instr) {
|
||||
Abort("Unimplemented: %s", "DoShiftI");
|
||||
LOperand* left = instr->InputAt(0);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
ASSERT(left->IsRegister());
|
||||
if (right->IsRegister()) {
|
||||
ASSERT(ToRegister(right).is(rcx));
|
||||
|
||||
switch (instr->op()) {
|
||||
case Token::SAR:
|
||||
__ sarl_cl(ToRegister(left));
|
||||
break;
|
||||
case Token::SHR:
|
||||
__ shrl_cl(ToRegister(left));
|
||||
if (instr->can_deopt()) {
|
||||
__ testl(ToRegister(left), ToRegister(left));
|
||||
DeoptimizeIf(negative, instr->environment());
|
||||
}
|
||||
break;
|
||||
case Token::SHL:
|
||||
__ shll_cl(ToRegister(left));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int value = ToInteger32(LConstantOperand::cast(right));
|
||||
uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
|
||||
switch (instr->op()) {
|
||||
case Token::SAR:
|
||||
if (shift_count != 0) {
|
||||
__ sarl(ToRegister(left), Immediate(shift_count));
|
||||
}
|
||||
break;
|
||||
case Token::SHR:
|
||||
if (shift_count == 0 && instr->can_deopt()) {
|
||||
__ testl(ToRegister(left), ToRegister(left));
|
||||
DeoptimizeIf(negative, instr->environment());
|
||||
} else {
|
||||
__ shrl(ToRegister(left), Immediate(shift_count));
|
||||
}
|
||||
break;
|
||||
case Token::SHL:
|
||||
if (shift_count != 0) {
|
||||
__ shll(ToRegister(left), Immediate(shift_count));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -663,7 +767,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoConstantT(LConstantT* instr) {
|
||||
ASSERT(instr->result()->IsRegister());
|
||||
ASSERT(instr->result()->IsRegister());
|
||||
__ Move(ToRegister(instr->result()), instr->value());
|
||||
}
|
||||
|
||||
@ -686,7 +790,9 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
||||
Abort("Unimplemented: %s", "DoBitNotI");
|
||||
LOperand* input = instr->InputAt(0);
|
||||
ASSERT(input->Equals(instr->result()));
|
||||
__ not_(ToRegister(input));
|
||||
}
|
||||
|
||||
|
||||
@ -1201,7 +1307,7 @@ void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
|
||||
|
||||
void LCodeGen::DoHasCachedArrayIndexAndBranch(
|
||||
LHasCachedArrayIndexAndBranch* instr) {
|
||||
Register input = ToRegister(instr->InputAt(0));
|
||||
Register input = ToRegister(instr->InputAt(0));
|
||||
|
||||
int true_block = chunk_->LookupDestination(instr->true_block_id());
|
||||
int false_block = chunk_->LookupDestination(instr->false_block_id());
|
||||
|
@ -162,6 +162,12 @@ const char* LArithmeticT::Mnemonic() const {
|
||||
case Token::MUL: return "mul-t";
|
||||
case Token::MOD: return "mod-t";
|
||||
case Token::DIV: return "div-t";
|
||||
case Token::BIT_AND: return "bit-and-t";
|
||||
case Token::BIT_OR: return "bit-or-t";
|
||||
case Token::BIT_XOR: return "bit-xor-t";
|
||||
case Token::SHL: return "sal-t";
|
||||
case Token::SAR: return "sar-t";
|
||||
case Token::SHR: return "shr-t";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
@ -319,7 +325,7 @@ int LChunk::GetNextSpillIndex(bool is_double) {
|
||||
}
|
||||
|
||||
|
||||
LOperand* LChunk::GetNextSpillSlot(bool is_double) {
|
||||
LOperand* LChunk::GetNextSpillSlot(bool is_double) {
|
||||
// All stack slots are Double stack slots on x64.
|
||||
// Alternatively, at some point, start using half-size
|
||||
// stack slots for int32 values.
|
||||
@ -741,8 +747,72 @@ LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
|
||||
|
||||
LInstruction* LChunkBuilder::DoBit(Token::Value op,
|
||||
HBitwiseBinaryOperation* instr) {
|
||||
Abort("Unimplemented: %s", "DoBit");
|
||||
return NULL;
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
return DefineSameAsFirst(new LBitI(op, left, right));
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
ASSERT(instr->left()->representation().IsTagged());
|
||||
ASSERT(instr->right()->representation().IsTagged());
|
||||
|
||||
LOperand* left = UseFixed(instr->left(), rdx);
|
||||
LOperand* right = UseFixed(instr->right(), rax);
|
||||
LArithmeticT* result = new LArithmeticT(op, left, right);
|
||||
return MarkAsCall(DefineFixed(result, rax), instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoShift(Token::Value op,
|
||||
HBitwiseBinaryOperation* instr) {
|
||||
if (instr->representation().IsTagged()) {
|
||||
ASSERT(instr->left()->representation().IsTagged());
|
||||
ASSERT(instr->right()->representation().IsTagged());
|
||||
|
||||
LOperand* left = UseFixed(instr->left(), rdx);
|
||||
LOperand* right = UseFixed(instr->right(), rax);
|
||||
LArithmeticT* result = new LArithmeticT(op, left, right);
|
||||
return MarkAsCall(DefineFixed(result, rax), instr);
|
||||
}
|
||||
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
ASSERT(instr->OperandAt(0)->representation().IsInteger32());
|
||||
ASSERT(instr->OperandAt(1)->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
|
||||
|
||||
HValue* right_value = instr->OperandAt(1);
|
||||
LOperand* right = NULL;
|
||||
int constant_value = 0;
|
||||
if (right_value->IsConstant()) {
|
||||
HConstant* constant = HConstant::cast(right_value);
|
||||
right = chunk_->DefineConstantOperand(constant);
|
||||
constant_value = constant->Integer32Value() & 0x1f;
|
||||
} else {
|
||||
right = UseFixed(right_value, rcx);
|
||||
}
|
||||
|
||||
// Shift operations can only deoptimize if we do a logical shift
|
||||
// by 0 and the result cannot be truncated to int32.
|
||||
bool can_deopt = (op == Token::SHR && constant_value == 0);
|
||||
if (can_deopt) {
|
||||
bool can_truncate = true;
|
||||
for (int i = 0; i < instr->uses()->length(); i++) {
|
||||
if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
|
||||
can_truncate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
can_deopt = !can_truncate;
|
||||
}
|
||||
|
||||
LShiftI* result = new LShiftI(op, left, right, can_deopt);
|
||||
return can_deopt
|
||||
? AssignEnvironment(DefineSameAsFirst(result))
|
||||
: DefineSameAsFirst(result);
|
||||
}
|
||||
|
||||
|
||||
@ -1131,44 +1201,41 @@ LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
|
||||
Abort("Unimplemented: %s", "DoShr");
|
||||
return NULL;
|
||||
return DoShift(Token::SHR, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
|
||||
Abort("Unimplemented: %s", "DoSar");
|
||||
return NULL;
|
||||
return DoShift(Token::SAR, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
|
||||
Abort("Unimplemented: %s", "DoShl");
|
||||
return NULL;
|
||||
return DoShift(Token::SHL, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
|
||||
Abort("Unimplemented: %s", "DoBitAnd");
|
||||
return NULL;
|
||||
return DoBit(Token::BIT_AND, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
|
||||
Abort("Unimplemented: %s", "DoBitNot");
|
||||
return NULL;
|
||||
ASSERT(instr->value()->representation().IsInteger32());
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
LOperand* input = UseRegisterAtStart(instr->value());
|
||||
LBitNotI* result = new LBitNotI(input);
|
||||
return DefineSameAsFirst(result);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
|
||||
Abort("Unimplemented: %s", "DoBitOr");
|
||||
return NULL;
|
||||
return DoBit(Token::BIT_OR, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
|
||||
Abort("Unimplemented: %s", "DoBitXor");
|
||||
return NULL;
|
||||
return DoBit(Token::BIT_XOR, instr);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user