Commit 944858e7 authored by dcarney@chromium.org's avatar dcarney@chromium.org

[turbofan] support all shift operands on x64

R=bmeurer@chromium.org

BUG=

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24388 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e9fcaa4b
......@@ -184,13 +184,21 @@ static bool HasImmediateInput(Instruction* instr, int index) {
} while (0)
#define ASSEMBLE_SHIFT(asm_instr, width) \
do { \
if (HasImmediateInput(instr, 1)) { \
__ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
} else { \
__ asm_instr##_cl(i.OutputRegister()); \
} \
#define ASSEMBLE_SHIFT(asm_instr, width) \
do { \
if (HasImmediateInput(instr, 1)) { \
if (instr->Output()->IsRegister()) { \
__ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
} else { \
__ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1))); \
} \
} else { \
if (instr->Output()->IsRegister()) { \
__ asm_instr##_cl(i.OutputRegister()); \
} else { \
__ asm_instr##_cl(i.OutputOperand()); \
} \
} \
} while (0)
......
......@@ -21,8 +21,6 @@ class X64OperandGenerator FINAL : public OperandGenerator {
Register::ToAllocationIndex(reg));
}
InstructionOperand* UseImmediate64(Node* node) { return UseImmediate(node); }
bool CanBeImmediate(Node* node) {
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
......@@ -32,23 +30,6 @@ class X64OperandGenerator FINAL : public OperandGenerator {
}
}
bool CanBeImmediate64(Node* node) {
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
return true;
case IrOpcode::kNumberConstant:
return true;
case IrOpcode::kHeapConstant: {
// Constants in new space cannot be used as immediates in V8 because
// the GC does not scan code objects when collecting the new generation.
Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
return !isolate()->heap()->InNewSpace(*value.handle());
}
default:
return false;
}
}
bool CanBeBetterLeftOperand(Node* node) const {
return !selector()->IsLive(node);
}
......@@ -350,9 +331,8 @@ static void VisitWord32Shift(InstructionSelector* selector, Node* node,
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
// TODO(turbofan): assembler only supports some addressing modes for shifts.
if (g.CanBeImmediate(right)) {
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(left),
g.UseImmediate(right));
} else {
Int32BinopMatcher m(node);
......@@ -362,7 +342,7 @@ static void VisitWord32Shift(InstructionSelector* selector, Node* node,
right = mright.left().node();
}
}
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(left),
g.UseFixed(right, rcx));
}
}
......@@ -376,9 +356,8 @@ static void VisitWord64Shift(InstructionSelector* selector, Node* node,
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
// TODO(turbofan): assembler only supports some addressing modes for shifts.
if (g.CanBeImmediate(right)) {
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(left),
g.UseImmediate(right));
} else {
Int64BinopMatcher m(node);
......@@ -388,7 +367,7 @@ static void VisitWord64Shift(InstructionSelector* selector, Node* node,
right = mright.left().node();
}
}
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(left),
g.UseFixed(right, rcx));
}
}
......
......@@ -617,6 +617,24 @@ void Assembler::shift(Register dst,
}
void Assembler::shift(Operand dst, Immediate shift_amount, int subcode,
int size) {
EnsureSpace ensure_space(this);
DCHECK(size == kInt64Size ? is_uint6(shift_amount.value_)
: is_uint5(shift_amount.value_));
if (shift_amount.value_ == 1) {
emit_rex(dst, size);
emit(0xD1);
emit_operand(subcode, dst);
} else {
emit_rex(dst, size);
emit(0xC1);
emit_operand(subcode, dst);
emit(shift_amount.value_);
}
}
void Assembler::shift(Register dst, int subcode, int size) {
EnsureSpace ensure_space(this);
emit_rex(dst, size);
......@@ -625,6 +643,14 @@ void Assembler::shift(Register dst, int subcode, int size) {
}
void Assembler::shift(Operand dst, int subcode, int size) {
EnsureSpace ensure_space(this);
emit_rex(dst, size);
emit(0xD3);
emit_operand(subcode, dst);
}
void Assembler::bt(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
emit_rex_64(src, dst);
......
......@@ -813,30 +813,42 @@ class Assembler : public AssemblerBase {
// Multiply rax by src, put the result in rdx:rax.
void mul(Register src);
#define DECLARE_SHIFT_INSTRUCTION(instruction, subcode) \
void instruction##p(Register dst, Immediate imm8) { \
shift(dst, imm8, subcode, kPointerSize); \
} \
\
void instruction##l(Register dst, Immediate imm8) { \
shift(dst, imm8, subcode, kInt32Size); \
} \
\
void instruction##q(Register dst, Immediate imm8) { \
shift(dst, imm8, subcode, kInt64Size); \
} \
\
void instruction##p_cl(Register dst) { \
shift(dst, subcode, kPointerSize); \
} \
\
void instruction##l_cl(Register dst) { \
shift(dst, subcode, kInt32Size); \
} \
\
void instruction##q_cl(Register dst) { \
shift(dst, subcode, kInt64Size); \
}
#define DECLARE_SHIFT_INSTRUCTION(instruction, subcode) \
void instruction##p(Register dst, Immediate imm8) { \
shift(dst, imm8, subcode, kPointerSize); \
} \
\
void instruction##l(Register dst, Immediate imm8) { \
shift(dst, imm8, subcode, kInt32Size); \
} \
\
void instruction##q(Register dst, Immediate imm8) { \
shift(dst, imm8, subcode, kInt64Size); \
} \
\
void instruction##p(Operand dst, Immediate imm8) { \
shift(dst, imm8, subcode, kPointerSize); \
} \
\
void instruction##l(Operand dst, Immediate imm8) { \
shift(dst, imm8, subcode, kInt32Size); \
} \
\
void instruction##q(Operand dst, Immediate imm8) { \
shift(dst, imm8, subcode, kInt64Size); \
} \
\
void instruction##p_cl(Register dst) { shift(dst, subcode, kPointerSize); } \
\
void instruction##l_cl(Register dst) { shift(dst, subcode, kInt32Size); } \
\
void instruction##q_cl(Register dst) { shift(dst, subcode, kInt64Size); } \
\
void instruction##p_cl(Operand dst) { shift(dst, subcode, kPointerSize); } \
\
void instruction##l_cl(Operand dst) { shift(dst, subcode, kInt32Size); } \
\
void instruction##q_cl(Operand dst) { shift(dst, subcode, kInt64Size); }
SHIFT_INSTRUCTION_LIST(DECLARE_SHIFT_INSTRUCTION)
#undef DECLARE_SHIFT_INSTRUCTION
......@@ -1365,9 +1377,11 @@ class Assembler : public AssemblerBase {
int size);
// Emit machine code for a shift operation.
void shift(Operand dst, Immediate shift_amount, int subcode, int size);
void shift(Register dst, Immediate shift_amount, int subcode, int size);
// Shift dst by cl % 64 bits.
void shift(Register dst, int subcode, int size);
void shift(Operand dst, int subcode, int size);
void emit_farith(int b1, int b2, int i);
......
......@@ -709,65 +709,62 @@ int DisassemblerX64::F6F7Instruction(byte* data) {
int DisassemblerX64::ShiftInstruction(byte* data) {
byte op = *data & (~1);
int count = 1;
if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
UnimplementedInstruction();
return 1;
return count;
}
byte modrm = *(data + 1);
int mod, regop, rm;
get_modrm(modrm, &mod, &regop, &rm);
regop &= 0x7; // The REX.R bit does not affect the operation.
int imm8 = -1;
int num_bytes = 2;
if (mod != 3) {
UnimplementedInstruction();
return num_bytes;
}
const char* mnem = NULL;
switch (regop) {
case 0:
mnem = "rol";
break;
case 1:
mnem = "ror";
break;
case 2:
mnem = "rcl";
break;
case 3:
mnem = "rcr";
break;
case 4:
mnem = "shl";
break;
case 5:
mnem = "shr";
break;
case 7:
mnem = "sar";
break;
default:
UnimplementedInstruction();
return num_bytes;
}
DCHECK_NE(NULL, mnem);
if (op == 0xD0) {
imm8 = 1;
} else if (op == 0xC0) {
imm8 = *(data + 2);
num_bytes = 3;
// Print mneumonic.
{
byte modrm = *(data + count);
int mod, regop, rm;
get_modrm(modrm, &mod, &regop, &rm);
regop &= 0x7; // The REX.R bit does not affect the operation.
const char* mnem = NULL;
switch (regop) {
case 0:
mnem = "rol";
break;
case 1:
mnem = "ror";
break;
case 2:
mnem = "rcl";
break;
case 3:
mnem = "rcr";
break;
case 4:
mnem = "shl";
break;
case 5:
mnem = "shr";
break;
case 7:
mnem = "sar";
break;
default:
UnimplementedInstruction();
return count + 1;
}
DCHECK_NE(NULL, mnem);
AppendToBuffer("%s%c ", mnem, operand_size_code());
}
AppendToBuffer("%s%c %s,",
mnem,
operand_size_code(),
byte_size_operand_ ? NameOfByteCPURegister(rm)
: NameOfCPURegister(rm));
count += PrintRightOperand(data + count);
if (op == 0xD2) {
AppendToBuffer("cl");
AppendToBuffer(", cl");
} else {
AppendToBuffer("%d", imm8);
int imm8 = -1;
if (op == 0xD0) {
imm8 = 1;
} else {
DCHECK_EQ(0xC0, op);
imm8 = *(data + count);
count++;
}
AppendToBuffer(", %d", imm8);
}
return num_bytes;
return count;
}
......
......@@ -117,6 +117,26 @@ TEST(DisasmX64) {
__ imulq(rdx, rcx);
__ shld(rdx, rcx);
__ shrd(rdx, rcx);
__ shlq(Operand(rdi, rax, times_4, 100), Immediate(1));
__ shlq(Operand(rdi, rax, times_4, 100), Immediate(6));
__ shlq(Operand(r15, 0), Immediate(1));
__ shlq(Operand(r15, 0), Immediate(6));
__ shlq_cl(Operand(r15, 0));
__ shlq_cl(Operand(r15, 0));
__ shlq_cl(Operand(rdi, rax, times_4, 100));
__ shlq_cl(Operand(rdi, rax, times_4, 100));
__ shlq(rdx, Immediate(1));
__ shlq(rdx, Immediate(6));
__ shll(Operand(rdi, rax, times_4, 100), Immediate(1));
__ shll(Operand(rdi, rax, times_4, 100), Immediate(6));
__ shll(Operand(r15, 0), Immediate(1));
__ shll(Operand(r15, 0), Immediate(6));
__ shll_cl(Operand(r15, 0));
__ shll_cl(Operand(r15, 0));
__ shll_cl(Operand(rdi, rax, times_4, 100));
__ shll_cl(Operand(rdi, rax, times_4, 100));
__ shll(rdx, Immediate(1));
__ shll(rdx, Immediate(6));
__ bts(Operand(rdx, 0), rcx);
__ bts(Operand(rbx, rcx, times_4, 0), rcx);
__ nop();
......
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