Commit c5de2c95 authored by whesse@chromium.org's avatar whesse@chromium.org

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
parent 8d4e0bb3
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment