diff options
Diffstat (limited to 'deps/v8/src/compiler/ia32/instruction-selector-ia32.cc')
-rw-r--r-- | deps/v8/src/compiler/ia32/instruction-selector-ia32.cc | 384 |
1 files changed, 299 insertions, 85 deletions
diff --git a/deps/v8/src/compiler/ia32/instruction-selector-ia32.cc b/deps/v8/src/compiler/ia32/instruction-selector-ia32.cc index 41442542850..ce2f14e97f6 100644 --- a/deps/v8/src/compiler/ia32/instruction-selector-ia32.cc +++ b/deps/v8/src/compiler/ia32/instruction-selector-ia32.cc @@ -164,6 +164,17 @@ class IA32OperandGenerator final : public OperandGenerator { } } + InstructionOperand GetEffectiveIndexOperand(Node* index, + AddressingMode* mode) { + if (CanBeImmediate(index)) { + *mode = kMode_MRI; + return UseImmediate(index); + } else { + *mode = kMode_MR1; + return UseUniqueRegister(index); + } + } + bool CanBeBetterLeftOperand(Node* node) const { return !selector()->IsLive(node); } @@ -331,17 +342,10 @@ void InstructionSelector::VisitStore(Node* node) { if (write_barrier_kind != kNoWriteBarrier) { DCHECK(CanBeTaggedPointer(rep)); AddressingMode addressing_mode; - InstructionOperand inputs[3]; - size_t input_count = 0; - inputs[input_count++] = g.UseUniqueRegister(base); - if (g.CanBeImmediate(index)) { - inputs[input_count++] = g.UseImmediate(index); - addressing_mode = kMode_MRI; - } else { - inputs[input_count++] = g.UseUniqueRegister(index); - addressing_mode = kMode_MR1; - } - inputs[input_count++] = g.UseUniqueRegister(value); + InstructionOperand inputs[] = { + g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode), + g.UseUniqueRegister(value)}; RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny; switch (write_barrier_kind) { case kNoWriteBarrier: @@ -362,7 +366,7 @@ void InstructionSelector::VisitStore(Node* node) { InstructionCode code = kArchStoreWithWriteBarrier; code |= AddressingModeField::encode(addressing_mode); code |= MiscField::encode(static_cast<int>(record_write_mode)); - Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); + Emit(code, 0, nullptr, arraysize(inputs), inputs, temp_count, temps); } else { ArchOpcode opcode = kArchNop; switch (rep) { @@ -823,7 +827,10 @@ void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); } -void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord32ReverseBytes(Node* node) { + IA32OperandGenerator g(this); + Emit(kIA32Bswap, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0))); +} void InstructionSelector::VisitInt32Add(Node* node) { IA32OperandGenerator g(this); @@ -1293,30 +1300,86 @@ void VisitAtomicExchange(InstructionSelector* selector, Node* node, Node* value = node->InputAt(2); AddressingMode addressing_mode; - InstructionOperand inputs[3]; - size_t input_count = 0; - if (rep == MachineRepresentation::kWord8) { - inputs[input_count++] = g.UseFixed(value, edx); - } else { - inputs[input_count++] = g.UseUniqueRegister(value); - } - inputs[input_count++] = g.UseUniqueRegister(base); - if (g.CanBeImmediate(index)) { - inputs[input_count++] = g.UseImmediate(index); - addressing_mode = kMode_MRI; - } else { - inputs[input_count++] = g.UseUniqueRegister(index); - addressing_mode = kMode_MR1; - } - InstructionOperand outputs[1]; - if (rep == MachineRepresentation::kWord8) { - // Using DefineSameAsFirst requires the register to be unallocated. - outputs[0] = g.DefineAsFixed(node, edx); - } else { - outputs[0] = g.DefineSameAsFirst(node); - } + InstructionOperand value_operand = (rep == MachineRepresentation::kWord8) + ? g.UseFixed(value, edx) + : g.UseUniqueRegister(value); + InstructionOperand inputs[] = { + value_operand, g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = { + (rep == MachineRepresentation::kWord8) + // Using DefineSameAsFirst requires the register to be unallocated. + ? g.DefineAsFixed(node, edx) + : g.DefineSameAsFirst(node)}; + InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); + selector->Emit(code, 1, outputs, arraysize(inputs), inputs); +} + +void VisitAtomicBinOp(InstructionSelector* selector, Node* node, + ArchOpcode opcode, MachineRepresentation rep) { + AddressingMode addressing_mode; + IA32OperandGenerator g(selector); + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + Node* value = node->InputAt(2); + InstructionOperand inputs[] = { + g.UseUniqueRegister(value), g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = {g.DefineAsFixed(node, eax)}; + InstructionOperand temp[] = {(rep == MachineRepresentation::kWord8) + ? g.UseByteRegister(node) + : g.TempRegister()}; + InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); + selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs, + arraysize(temp), temp); +} + +void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node, + ArchOpcode opcode) { + IA32OperandGenerator g(selector); + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + Node* value = node->InputAt(2); + // For Word64 operations, the value input is split into the a high node, + // and a low node in the int64-lowering phase. + Node* value_high = node->InputAt(3); + + // Wasm lives in 32-bit address space, so we do not need to worry about + // base/index lowering. This will need to be fixed for Wasm64. + AddressingMode addressing_mode; + InstructionOperand inputs[] = { + g.UseFixed(value, ebx), g.UseFixed(value_high, ecx), + g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = { + g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax), + g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)}; + InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); + selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs); +} + +void VisitNarrowAtomicBinOp(InstructionSelector* selector, Node* node, + ArchOpcode opcode, MachineType type) { + IA32OperandGenerator g(selector); + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + Node* value = node->InputAt(2); + + // Wasm lives in 32-bit address space, so we do not need to worry about + // base/index lowering. This will need to be fixed for Wasm64. + AddressingMode addressing_mode; + InstructionOperand inputs[] = { + g.UseUniqueRegister(value), g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = { + g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax), + g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)}; + InstructionOperand temp[] = {(type == MachineType::Uint8()) + ? g.UseByteRegister(node) + : g.TempRegister()}; InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); - selector->Emit(code, 1, outputs, input_count, inputs); + selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs, + arraysize(temp), temp); } } // namespace @@ -1608,7 +1671,7 @@ void InstructionSelector::VisitWord32AtomicStore(Node* node) { void InstructionSelector::VisitWord32AtomicExchange(Node* node) { IA32OperandGenerator g(this); - MachineType type = AtomicOpRepresentationOf(node->op()); + MachineType type = AtomicOpType(node->op()); ArchOpcode opcode = kArchNop; if (type == MachineType::Int8()) { opcode = kWord32AtomicExchangeInt8; @@ -1634,7 +1697,7 @@ void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) { Node* old_value = node->InputAt(2); Node* new_value = node->InputAt(3); - MachineType type = AtomicOpRepresentationOf(node->op()); + MachineType type = AtomicOpType(node->op()); ArchOpcode opcode = kArchNop; if (type == MachineType::Int8()) { opcode = kWord32AtomicCompareExchangeInt8; @@ -1650,38 +1713,23 @@ void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) { UNREACHABLE(); return; } - InstructionOperand outputs[1]; AddressingMode addressing_mode; - InstructionOperand inputs[4]; - size_t input_count = 0; - inputs[input_count++] = g.UseFixed(old_value, eax); - if (type == MachineType::Int8() || type == MachineType::Uint8()) { - inputs[input_count++] = g.UseByteRegister(new_value); - } else { - inputs[input_count++] = g.UseUniqueRegister(new_value); - } - inputs[input_count++] = g.UseUniqueRegister(base); - if (g.CanBeImmediate(index)) { - inputs[input_count++] = g.UseImmediate(index); - addressing_mode = kMode_MRI; - } else { - inputs[input_count++] = g.UseUniqueRegister(index); - addressing_mode = kMode_MR1; - } - outputs[0] = g.DefineAsFixed(node, eax); + InstructionOperand new_val_operand = + (type.representation() == MachineRepresentation::kWord8) + ? g.UseByteRegister(new_value) + : g.UseUniqueRegister(new_value); + InstructionOperand inputs[] = { + g.UseFixed(old_value, eax), new_val_operand, g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = {g.DefineAsFixed(node, eax)}; InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); - Emit(code, 1, outputs, input_count, inputs); + Emit(code, 1, outputs, arraysize(inputs), inputs); } void InstructionSelector::VisitWord32AtomicBinaryOperation( Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op, ArchOpcode uint16_op, ArchOpcode word32_op) { - IA32OperandGenerator g(this); - Node* base = node->InputAt(0); - Node* index = node->InputAt(1); - Node* value = node->InputAt(2); - - MachineType type = AtomicOpRepresentationOf(node->op()); + MachineType type = AtomicOpType(node->op()); ArchOpcode opcode = kArchNop; if (type == MachineType::Int8()) { opcode = int8_op; @@ -1697,28 +1745,7 @@ void InstructionSelector::VisitWord32AtomicBinaryOperation( UNREACHABLE(); return; } - InstructionOperand outputs[1]; - AddressingMode addressing_mode; - InstructionOperand inputs[3]; - size_t input_count = 0; - inputs[input_count++] = g.UseUniqueRegister(value); - inputs[input_count++] = g.UseUniqueRegister(base); - if (g.CanBeImmediate(index)) { - inputs[input_count++] = g.UseImmediate(index); - addressing_mode = kMode_MRI; - } else { - inputs[input_count++] = g.UseUniqueRegister(index); - addressing_mode = kMode_MR1; - } - outputs[0] = g.DefineAsFixed(node, eax); - InstructionOperand temp[1]; - if (type == MachineType::Int8() || type == MachineType::Uint8()) { - temp[0] = g.UseByteRegister(node); - } else { - temp[0] = g.TempRegister(); - } - InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); - Emit(code, 1, outputs, input_count, inputs, 1, temp); + VisitAtomicBinOp(this, node, opcode, type.representation()); } #define VISIT_ATOMIC_BINOP(op) \ @@ -1735,6 +1762,193 @@ VISIT_ATOMIC_BINOP(Or) VISIT_ATOMIC_BINOP(Xor) #undef VISIT_ATOMIC_BINOP +void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) { + IA32OperandGenerator g(this); + AddressingMode mode; + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + InstructionOperand inputs[] = {g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &mode)}; + InstructionOperand temps[] = {g.TempDoubleRegister()}; + InstructionOperand outputs[] = { + g.DefineAsRegister(NodeProperties::FindProjection(node, 0)), + g.DefineAsRegister(NodeProperties::FindProjection(node, 1))}; + InstructionCode code = + kIA32Word32AtomicPairLoad | AddressingModeField::encode(mode); + Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs, + arraysize(temps), temps); +} + +void InstructionSelector::VisitWord32AtomicPairStore(Node* node) { + IA32OperandGenerator g(this); + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + Node* value = node->InputAt(2); + Node* value_high = node->InputAt(3); + + AddressingMode addressing_mode; + InstructionOperand inputs[] = { + g.UseFixed(value, ebx), g.UseFixed(value_high, ecx), + g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + // Allocating temp registers here as stores are performed using an atomic + // exchange, the output of which is stored in edx:eax, which should be saved + // and restored at the end of the instruction. + InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)}; + InstructionCode code = + kIA32Word32AtomicPairStore | AddressingModeField::encode(addressing_mode); + Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps); +} + +void InstructionSelector::VisitWord32AtomicPairAdd(Node* node) { + VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairAdd); +} + +void InstructionSelector::VisitWord32AtomicPairSub(Node* node) { + VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairSub); +} + +void InstructionSelector::VisitWord32AtomicPairAnd(Node* node) { + VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairAnd); +} + +void InstructionSelector::VisitWord32AtomicPairOr(Node* node) { + VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairOr); +} + +void InstructionSelector::VisitWord32AtomicPairXor(Node* node) { + VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairXor); +} + +void InstructionSelector::VisitWord32AtomicPairExchange(Node* node) { + VisitPairAtomicBinOp(this, node, kIA32Word32AtomicPairExchange); +} + +void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) { + IA32OperandGenerator g(this); + Node* index = node->InputAt(1); + AddressingMode addressing_mode; + InstructionOperand inputs[] = { + // High, Low values of old value + g.UseFixed(node->InputAt(2), eax), g.UseFixed(node->InputAt(3), edx), + // High, Low values of new value + g.UseFixed(node->InputAt(4), ebx), g.UseFixed(node->InputAt(5), ecx), + // InputAt(0) => base + g.UseUniqueRegister(node->InputAt(0)), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = { + g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax), + g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)}; + InstructionCode code = kIA32Word32AtomicPairCompareExchange | + AddressingModeField::encode(addressing_mode); + Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs); +} + +void InstructionSelector::VisitWord64AtomicNarrowBinop(Node* node, + ArchOpcode uint8_op, + ArchOpcode uint16_op, + ArchOpcode uint32_op) { + MachineType type = AtomicOpType(node->op()); + DCHECK(type != MachineType::Uint64()); + ArchOpcode opcode = kArchNop; + if (type == MachineType::Uint32()) { + opcode = uint32_op; + } else if (type == MachineType::Uint16()) { + opcode = uint16_op; + } else if (type == MachineType::Uint8()) { + opcode = uint8_op; + } else { + UNREACHABLE(); + return; + } + VisitNarrowAtomicBinOp(this, node, opcode, type); +} + +#define VISIT_ATOMIC_BINOP(op) \ + void InstructionSelector::VisitWord64AtomicNarrow##op(Node* node) { \ + VisitWord64AtomicNarrowBinop(node, kIA32Word64AtomicNarrow##op##Uint8, \ + kIA32Word64AtomicNarrow##op##Uint16, \ + kIA32Word64AtomicNarrow##op##Uint32); \ + } +VISIT_ATOMIC_BINOP(Add) +VISIT_ATOMIC_BINOP(Sub) +VISIT_ATOMIC_BINOP(And) +VISIT_ATOMIC_BINOP(Or) +VISIT_ATOMIC_BINOP(Xor) +#undef VISIT_ATOMIC_BINOP + +void InstructionSelector::VisitWord64AtomicNarrowExchange(Node* node) { + MachineType type = AtomicOpType(node->op()); + DCHECK(type != MachineType::Uint64()); + ArchOpcode opcode = kArchNop; + if (type == MachineType::Uint32()) { + opcode = kIA32Word64AtomicNarrowExchangeUint32; + } else if (type == MachineType::Uint16()) { + opcode = kIA32Word64AtomicNarrowExchangeUint16; + } else if (type == MachineType::Uint8()) { + opcode = kIA32Word64AtomicNarrowExchangeUint8; + } else { + UNREACHABLE(); + return; + } + IA32OperandGenerator g(this); + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + Node* value = node->InputAt(2); + AddressingMode addressing_mode; + InstructionOperand value_operand = + (type.representation() == MachineRepresentation::kWord8) + ? g.UseFixed(value, edx) + : g.UseUniqueRegister(value); + InstructionOperand inputs[] = { + value_operand, g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[2]; + if (type.representation() == MachineRepresentation::kWord8) { + // Using DefineSameAsFirst requires the register to be unallocated. + outputs[0] = g.DefineAsFixed(NodeProperties::FindProjection(node, 0), edx); + } else { + outputs[0] = g.DefineSameAsFirst(NodeProperties::FindProjection(node, 0)); + } + outputs[1] = g.DefineAsRegister(NodeProperties::FindProjection(node, 1)); + InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); + Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs); +} + +void InstructionSelector::VisitWord64AtomicNarrowCompareExchange(Node* node) { + MachineType type = AtomicOpType(node->op()); + DCHECK(type != MachineType::Uint64()); + ArchOpcode opcode = kArchNop; + if (type == MachineType::Uint32()) { + opcode = kIA32Word64AtomicNarrowCompareExchangeUint32; + } else if (type == MachineType::Uint16()) { + opcode = kIA32Word64AtomicNarrowCompareExchangeUint16; + } else if (type == MachineType::Uint8()) { + opcode = kIA32Word64AtomicNarrowCompareExchangeUint8; + } else { + UNREACHABLE(); + return; + } + IA32OperandGenerator g(this); + Node* base = node->InputAt(0); + Node* index = node->InputAt(1); + Node* old_value = node->InputAt(2); + Node* new_value = node->InputAt(3); + AddressingMode addressing_mode; + InstructionOperand new_value_operand = + (type.representation() == MachineRepresentation::kWord8) + ? g.UseByteRegister(new_value) + : g.UseUniqueRegister(new_value); + InstructionOperand inputs[] = { + g.UseFixed(old_value, eax), new_value_operand, g.UseUniqueRegister(base), + g.GetEffectiveIndexOperand(index, &addressing_mode)}; + InstructionOperand outputs[] = { + g.DefineAsFixed(NodeProperties::FindProjection(node, 0), eax), + g.DefineAsRegister(NodeProperties::FindProjection(node, 1))}; + InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); + Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs); +} + #define SIMD_INT_TYPES(V) \ V(I32x4) \ V(I16x8) \ |