diff options
Diffstat (limited to 'deps/v8/src/compiler/ia32')
-rw-r--r-- | deps/v8/src/compiler/ia32/code-generator-ia32.cc | 208 | ||||
-rw-r--r-- | deps/v8/src/compiler/ia32/instruction-codes-ia32.h | 711 | ||||
-rw-r--r-- | deps/v8/src/compiler/ia32/instruction-scheduler-ia32.cc | 35 | ||||
-rw-r--r-- | deps/v8/src/compiler/ia32/instruction-selector-ia32.cc | 384 |
4 files changed, 888 insertions, 450 deletions
diff --git a/deps/v8/src/compiler/ia32/code-generator-ia32.cc b/deps/v8/src/compiler/ia32/code-generator-ia32.cc index 9aef138811..9d54eaeb90 100644 --- a/deps/v8/src/compiler/ia32/code-generator-ia32.cc +++ b/deps/v8/src/compiler/ia32/code-generator-ia32.cc @@ -16,6 +16,8 @@ #include "src/ia32/assembler-ia32.h" #include "src/ia32/macro-assembler-ia32.h" #include "src/optimized-compilation-info.h" +#include "src/wasm/wasm-code-manager.h" +#include "src/wasm/wasm-objects.h" namespace v8 { namespace internal { @@ -166,6 +168,22 @@ class IA32OperandConverter : public InstructionOperandConverter { Operand MemoryOperand(size_t first_input = 0) { return MemoryOperand(&first_input); } + + Operand NextMemoryOperand(size_t offset = 0) { + AddressingMode mode = AddressingModeField::decode(instr_->opcode()); + Register base = InputRegister(NextOffset(&offset)); + const int32_t disp = 4; + if (mode == kMode_MR1) { + Register index = InputRegister(NextOffset(&offset)); + ScaleFactor scale = ScaleFor(kMode_MR1, kMode_MR1); + return Operand(base, index, scale, disp); + } else if (mode == kMode_MRI) { + Constant ctant = ToConstant(instr_->InputAt(NextOffset(&offset))); + return Operand(base, ctant.ToInt32() + disp, ctant.rmode()); + } else { + UNREACHABLE(); + } + } }; @@ -409,6 +427,23 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, __ j(not_equal, &binop); \ } while (false) +#define ASSEMBLE_I64ATOMIC_BINOP(instr1, instr2) \ + do { \ + Label binop; \ + __ bind(&binop); \ + __ mov(i.OutputRegister(0), i.MemoryOperand(2)); \ + __ mov(i.OutputRegister(1), i.NextMemoryOperand(2)); \ + __ push(i.InputRegister(0)); \ + __ push(i.InputRegister(1)); \ + __ instr1(i.InputRegister(0), i.OutputRegister(0)); \ + __ instr2(i.InputRegister(1), i.OutputRegister(1)); \ + __ lock(); \ + __ cmpxchg8b(i.MemoryOperand(2)); \ + __ pop(i.InputRegister(1)); \ + __ pop(i.InputRegister(0)); \ + __ j(not_equal, &binop); \ + } while (false); + #define ASSEMBLE_MOVX(mov_instr) \ do { \ if (instr->addressing_mode() != kMode_None) { \ @@ -1152,6 +1187,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kIA32Popcnt: __ Popcnt(i.OutputRegister(), i.InputOperand(0)); break; + case kIA32Bswap: + __ bswap(i.OutputRegister()); + break; case kArchWordPoisonOnSpeculation: DCHECK_EQ(i.OutputRegister(), i.InputRegister(0)); __ and_(i.InputRegister(0), kSpeculationPoisonRegister); @@ -3594,7 +3632,22 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kIA32StackCheck: { ExternalReference const stack_limit = ExternalReference::address_of_stack_limit(__ isolate()); - __ cmp(esp, Operand::StaticVariable(stack_limit)); + __ VerifyRootRegister(); + __ cmp(esp, tasm()->StaticVariable(stack_limit)); + break; + } + case kIA32Word32AtomicPairLoad: { + XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0)); + __ movq(tmp, i.MemoryOperand()); + __ Pextrd(i.OutputRegister(0), tmp, 0); + __ Pextrd(i.OutputRegister(1), tmp, 1); + break; + } + case kIA32Word32AtomicPairStore: { + __ mov(i.TempRegister(0), i.MemoryOperand(2)); + __ mov(i.TempRegister(1), i.NextMemoryOperand(2)); + __ lock(); + __ cmpxchg8b(i.MemoryOperand(2)); break; } case kWord32AtomicExchangeInt8: { @@ -3621,6 +3674,34 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ xchg(i.InputRegister(0), i.MemoryOperand(1)); break; } + // For the narrow Word64 operations below, i.OutputRegister(1) contains + // the high-order 32 bits for the 64bit operation. As the data exchange + // fits in one register, the i.OutputRegister(1) needs to be cleared for + // the correct return value to be propagated back. + case kIA32Word64AtomicNarrowExchangeUint8: { + __ xchg_b(i.OutputRegister(0), i.MemoryOperand(1)); + __ movzx_b(i.OutputRegister(0), i.OutputRegister(0)); + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); + break; + } + case kIA32Word64AtomicNarrowExchangeUint16: { + __ xchg_w(i.OutputRegister(0), i.MemoryOperand(1)); + __ movzx_w(i.OutputRegister(0), i.OutputRegister(0)); + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); + break; + } + case kIA32Word64AtomicNarrowExchangeUint32: { + __ xchg(i.OutputRegister(0), i.MemoryOperand(1)); + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); + break; + } + case kIA32Word32AtomicPairExchange: { + __ mov(i.OutputRegister(0), i.MemoryOperand(2)); + __ mov(i.OutputRegister(1), i.NextMemoryOperand(2)); + __ lock(); + __ cmpxchg8b(i.MemoryOperand(2)); + break; + } case kWord32AtomicCompareExchangeInt8: { __ lock(); __ cmpxchg_b(i.MemoryOperand(2), i.InputRegister(1)); @@ -3650,30 +3731,72 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ cmpxchg(i.MemoryOperand(2), i.InputRegister(1)); break; } -#define ATOMIC_BINOP_CASE(op, inst) \ - case kWord32Atomic##op##Int8: { \ - ASSEMBLE_ATOMIC_BINOP(inst, mov_b, cmpxchg_b); \ - __ movsx_b(eax, eax); \ - break; \ - } \ - case kWord32Atomic##op##Uint8: { \ - ASSEMBLE_ATOMIC_BINOP(inst, mov_b, cmpxchg_b); \ - __ movzx_b(eax, eax); \ - break; \ - } \ - case kWord32Atomic##op##Int16: { \ - ASSEMBLE_ATOMIC_BINOP(inst, mov_w, cmpxchg_w); \ - __ movsx_w(eax, eax); \ - break; \ - } \ - case kWord32Atomic##op##Uint16: { \ - ASSEMBLE_ATOMIC_BINOP(inst, mov_w, cmpxchg_w); \ - __ movzx_w(eax, eax); \ - break; \ - } \ - case kWord32Atomic##op##Word32: { \ - ASSEMBLE_ATOMIC_BINOP(inst, mov, cmpxchg); \ - break; \ + case kIA32Word64AtomicNarrowCompareExchangeUint8: { + __ lock(); + __ cmpxchg_b(i.MemoryOperand(2), i.InputRegister(1)); + __ movzx_b(i.OutputRegister(0), i.OutputRegister(0)); + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); + break; + } + case kIA32Word64AtomicNarrowCompareExchangeUint16: { + __ lock(); + __ cmpxchg_w(i.MemoryOperand(2), i.InputRegister(1)); + __ movzx_w(i.OutputRegister(0), i.OutputRegister(0)); + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); + break; + } + case kIA32Word64AtomicNarrowCompareExchangeUint32: { + __ lock(); + __ cmpxchg(i.MemoryOperand(2), i.InputRegister(1)); + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); + break; + } + case kIA32Word32AtomicPairCompareExchange: { + __ lock(); + __ cmpxchg8b(i.MemoryOperand(4)); + break; + } +#define ATOMIC_BINOP_CASE(op, inst) \ + case kWord32Atomic##op##Int8: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov_b, cmpxchg_b); \ + __ movsx_b(eax, eax); \ + break; \ + } \ + case kIA32Word64AtomicNarrow##op##Uint8: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov_b, cmpxchg_b); \ + __ movzx_b(i.OutputRegister(0), i.OutputRegister(0)); \ + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); \ + break; \ + } \ + case kWord32Atomic##op##Uint8: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov_b, cmpxchg_b); \ + __ movzx_b(eax, eax); \ + break; \ + } \ + case kWord32Atomic##op##Int16: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov_w, cmpxchg_w); \ + __ movsx_w(eax, eax); \ + break; \ + } \ + case kIA32Word64AtomicNarrow##op##Uint16: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov_w, cmpxchg_w); \ + __ movzx_w(i.OutputRegister(0), i.OutputRegister(0)); \ + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); \ + break; \ + } \ + case kWord32Atomic##op##Uint16: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov_w, cmpxchg_w); \ + __ movzx_w(eax, eax); \ + break; \ + } \ + case kIA32Word64AtomicNarrow##op##Uint32: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov, cmpxchg); \ + __ xor_(i.OutputRegister(1), i.OutputRegister(1)); \ + break; \ + } \ + case kWord32Atomic##op##Word32: { \ + ASSEMBLE_ATOMIC_BINOP(inst, mov, cmpxchg); \ + break; \ } ATOMIC_BINOP_CASE(Add, add) ATOMIC_BINOP_CASE(Sub, sub) @@ -3681,6 +3804,40 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ATOMIC_BINOP_CASE(Or, or_) ATOMIC_BINOP_CASE(Xor, xor_) #undef ATOMIC_BINOP_CASE +#define ATOMIC_BINOP_CASE(op, instr1, instr2) \ + case kIA32Word32AtomicPair##op: { \ + ASSEMBLE_I64ATOMIC_BINOP(instr1, instr2) \ + break; \ + } + ATOMIC_BINOP_CASE(Add, add, adc) + ATOMIC_BINOP_CASE(And, and_, and_) + ATOMIC_BINOP_CASE(Or, or_, or_) + ATOMIC_BINOP_CASE(Xor, xor_, xor_) +#undef ATOMIC_BINOP_CASE + case kIA32Word32AtomicPairSub: { + Label binop; + __ bind(&binop); + // Move memory operand into edx:eax + __ mov(i.OutputRegister(0), i.MemoryOperand(2)); + __ mov(i.OutputRegister(1), i.NextMemoryOperand(2)); + // Save input registers temporarily on the stack. + __ push(i.InputRegister(0)); + __ push(i.InputRegister(1)); + // Negate input in place + __ neg(i.InputRegister(0)); + __ adc(i.InputRegister(1), 0); + __ neg(i.InputRegister(1)); + // Add memory operand, negated input. + __ add(i.InputRegister(0), i.OutputRegister(0)); + __ adc(i.InputRegister(1), i.OutputRegister(1)); + __ lock(); + __ cmpxchg8b(i.MemoryOperand(2)); + // Restore input registers + __ pop(i.InputRegister(1)); + __ pop(i.InputRegister(0)); + __ j(not_equal, &binop); + break; + } case kWord32AtomicLoadInt8: case kWord32AtomicLoadUint8: case kWord32AtomicLoadInt16: @@ -4450,6 +4607,7 @@ void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { #undef ASSEMBLE_IEEE754_UNOP #undef ASSEMBLE_BINOP #undef ASSEMBLE_ATOMIC_BINOP +#undef ASSEMBLE_I64ATOMIC_BINOP #undef ASSEMBLE_MOVX #undef ASSEMBLE_SIMD_PUNPCK_SHUFFLE #undef ASSEMBLE_SIMD_IMM_SHUFFLE diff --git a/deps/v8/src/compiler/ia32/instruction-codes-ia32.h b/deps/v8/src/compiler/ia32/instruction-codes-ia32.h index 8ffc9c3819..97f3763cf5 100644 --- a/deps/v8/src/compiler/ia32/instruction-codes-ia32.h +++ b/deps/v8/src/compiler/ia32/instruction-codes-ia32.h @@ -11,346 +11,377 @@ namespace compiler { // IA32-specific opcodes that specify which assembly sequence to emit. // Most opcodes specify a single instruction. -#define TARGET_ARCH_OPCODE_LIST(V) \ - V(IA32Add) \ - V(IA32And) \ - V(IA32Cmp) \ - V(IA32Cmp16) \ - V(IA32Cmp8) \ - V(IA32Test) \ - V(IA32Test16) \ - V(IA32Test8) \ - V(IA32Or) \ - V(IA32Xor) \ - V(IA32Sub) \ - V(IA32Imul) \ - V(IA32ImulHigh) \ - V(IA32UmulHigh) \ - V(IA32Idiv) \ - V(IA32Udiv) \ - V(IA32Not) \ - V(IA32Neg) \ - V(IA32Shl) \ - V(IA32Shr) \ - V(IA32Sar) \ - V(IA32AddPair) \ - V(IA32SubPair) \ - V(IA32MulPair) \ - V(IA32ShlPair) \ - V(IA32ShrPair) \ - V(IA32SarPair) \ - V(IA32Ror) \ - V(IA32Lzcnt) \ - V(IA32Tzcnt) \ - V(IA32Popcnt) \ - V(LFence) \ - V(SSEFloat32Cmp) \ - V(SSEFloat32Add) \ - V(SSEFloat32Sub) \ - V(SSEFloat32Mul) \ - V(SSEFloat32Div) \ - V(SSEFloat32Abs) \ - V(SSEFloat32Neg) \ - V(SSEFloat32Sqrt) \ - V(SSEFloat32Round) \ - V(SSEFloat64Cmp) \ - V(SSEFloat64Add) \ - V(SSEFloat64Sub) \ - V(SSEFloat64Mul) \ - V(SSEFloat64Div) \ - V(SSEFloat64Mod) \ - V(SSEFloat32Max) \ - V(SSEFloat64Max) \ - V(SSEFloat32Min) \ - V(SSEFloat64Min) \ - V(SSEFloat64Abs) \ - V(SSEFloat64Neg) \ - V(SSEFloat64Sqrt) \ - V(SSEFloat64Round) \ - V(SSEFloat32ToFloat64) \ - V(SSEFloat64ToFloat32) \ - V(SSEFloat32ToInt32) \ - V(SSEFloat32ToUint32) \ - V(SSEFloat64ToInt32) \ - V(SSEFloat64ToUint32) \ - V(SSEInt32ToFloat32) \ - V(SSEUint32ToFloat32) \ - V(SSEInt32ToFloat64) \ - V(SSEUint32ToFloat64) \ - V(SSEFloat64ExtractLowWord32) \ - V(SSEFloat64ExtractHighWord32) \ - V(SSEFloat64InsertLowWord32) \ - V(SSEFloat64InsertHighWord32) \ - V(SSEFloat64LoadLowWord32) \ - V(SSEFloat64SilenceNaN) \ - V(AVXFloat32Add) \ - V(AVXFloat32Sub) \ - V(AVXFloat32Mul) \ - V(AVXFloat32Div) \ - V(AVXFloat64Add) \ - V(AVXFloat64Sub) \ - V(AVXFloat64Mul) \ - V(AVXFloat64Div) \ - V(AVXFloat64Abs) \ - V(AVXFloat64Neg) \ - V(AVXFloat32Abs) \ - V(AVXFloat32Neg) \ - V(IA32Movsxbl) \ - V(IA32Movzxbl) \ - V(IA32Movb) \ - V(IA32Movsxwl) \ - V(IA32Movzxwl) \ - V(IA32Movw) \ - V(IA32Movl) \ - V(IA32Movss) \ - V(IA32Movsd) \ - V(IA32Movdqu) \ - V(IA32BitcastFI) \ - V(IA32BitcastIF) \ - V(IA32Lea) \ - V(IA32Push) \ - V(IA32PushFloat32) \ - V(IA32PushFloat64) \ - V(IA32PushSimd128) \ - V(IA32Poke) \ - V(IA32Peek) \ - V(IA32StackCheck) \ - V(SSEF32x4Splat) \ - V(AVXF32x4Splat) \ - V(SSEF32x4ExtractLane) \ - V(AVXF32x4ExtractLane) \ - V(SSEF32x4ReplaceLane) \ - V(AVXF32x4ReplaceLane) \ - V(IA32F32x4SConvertI32x4) \ - V(SSEF32x4UConvertI32x4) \ - V(AVXF32x4UConvertI32x4) \ - V(SSEF32x4Abs) \ - V(AVXF32x4Abs) \ - V(SSEF32x4Neg) \ - V(AVXF32x4Neg) \ - V(IA32F32x4RecipApprox) \ - V(IA32F32x4RecipSqrtApprox) \ - V(SSEF32x4Add) \ - V(AVXF32x4Add) \ - V(SSEF32x4AddHoriz) \ - V(AVXF32x4AddHoriz) \ - V(SSEF32x4Sub) \ - V(AVXF32x4Sub) \ - V(SSEF32x4Mul) \ - V(AVXF32x4Mul) \ - V(SSEF32x4Min) \ - V(AVXF32x4Min) \ - V(SSEF32x4Max) \ - V(AVXF32x4Max) \ - V(SSEF32x4Eq) \ - V(AVXF32x4Eq) \ - V(SSEF32x4Ne) \ - V(AVXF32x4Ne) \ - V(SSEF32x4Lt) \ - V(AVXF32x4Lt) \ - V(SSEF32x4Le) \ - V(AVXF32x4Le) \ - V(IA32I32x4Splat) \ - V(IA32I32x4ExtractLane) \ - V(SSEI32x4ReplaceLane) \ - V(AVXI32x4ReplaceLane) \ - V(SSEI32x4SConvertF32x4) \ - V(AVXI32x4SConvertF32x4) \ - V(IA32I32x4SConvertI16x8Low) \ - V(IA32I32x4SConvertI16x8High) \ - V(IA32I32x4Neg) \ - V(SSEI32x4Shl) \ - V(AVXI32x4Shl) \ - V(SSEI32x4ShrS) \ - V(AVXI32x4ShrS) \ - V(SSEI32x4Add) \ - V(AVXI32x4Add) \ - V(SSEI32x4AddHoriz) \ - V(AVXI32x4AddHoriz) \ - V(SSEI32x4Sub) \ - V(AVXI32x4Sub) \ - V(SSEI32x4Mul) \ - V(AVXI32x4Mul) \ - V(SSEI32x4MinS) \ - V(AVXI32x4MinS) \ - V(SSEI32x4MaxS) \ - V(AVXI32x4MaxS) \ - V(SSEI32x4Eq) \ - V(AVXI32x4Eq) \ - V(SSEI32x4Ne) \ - V(AVXI32x4Ne) \ - V(SSEI32x4GtS) \ - V(AVXI32x4GtS) \ - V(SSEI32x4GeS) \ - V(AVXI32x4GeS) \ - V(SSEI32x4UConvertF32x4) \ - V(AVXI32x4UConvertF32x4) \ - V(IA32I32x4UConvertI16x8Low) \ - V(IA32I32x4UConvertI16x8High) \ - V(SSEI32x4ShrU) \ - V(AVXI32x4ShrU) \ - V(SSEI32x4MinU) \ - V(AVXI32x4MinU) \ - V(SSEI32x4MaxU) \ - V(AVXI32x4MaxU) \ - V(SSEI32x4GtU) \ - V(AVXI32x4GtU) \ - V(SSEI32x4GeU) \ - V(AVXI32x4GeU) \ - V(IA32I16x8Splat) \ - V(IA32I16x8ExtractLane) \ - V(SSEI16x8ReplaceLane) \ - V(AVXI16x8ReplaceLane) \ - V(IA32I16x8SConvertI8x16Low) \ - V(IA32I16x8SConvertI8x16High) \ - V(IA32I16x8Neg) \ - V(SSEI16x8Shl) \ - V(AVXI16x8Shl) \ - V(SSEI16x8ShrS) \ - V(AVXI16x8ShrS) \ - V(SSEI16x8SConvertI32x4) \ - V(AVXI16x8SConvertI32x4) \ - V(SSEI16x8Add) \ - V(AVXI16x8Add) \ - V(SSEI16x8AddSaturateS) \ - V(AVXI16x8AddSaturateS) \ - V(SSEI16x8AddHoriz) \ - V(AVXI16x8AddHoriz) \ - V(SSEI16x8Sub) \ - V(AVXI16x8Sub) \ - V(SSEI16x8SubSaturateS) \ - V(AVXI16x8SubSaturateS) \ - V(SSEI16x8Mul) \ - V(AVXI16x8Mul) \ - V(SSEI16x8MinS) \ - V(AVXI16x8MinS) \ - V(SSEI16x8MaxS) \ - V(AVXI16x8MaxS) \ - V(SSEI16x8Eq) \ - V(AVXI16x8Eq) \ - V(SSEI16x8Ne) \ - V(AVXI16x8Ne) \ - V(SSEI16x8GtS) \ - V(AVXI16x8GtS) \ - V(SSEI16x8GeS) \ - V(AVXI16x8GeS) \ - V(IA32I16x8UConvertI8x16Low) \ - V(IA32I16x8UConvertI8x16High) \ - V(SSEI16x8ShrU) \ - V(AVXI16x8ShrU) \ - V(SSEI16x8UConvertI32x4) \ - V(AVXI16x8UConvertI32x4) \ - V(SSEI16x8AddSaturateU) \ - V(AVXI16x8AddSaturateU) \ - V(SSEI16x8SubSaturateU) \ - V(AVXI16x8SubSaturateU) \ - V(SSEI16x8MinU) \ - V(AVXI16x8MinU) \ - V(SSEI16x8MaxU) \ - V(AVXI16x8MaxU) \ - V(SSEI16x8GtU) \ - V(AVXI16x8GtU) \ - V(SSEI16x8GeU) \ - V(AVXI16x8GeU) \ - V(IA32I8x16Splat) \ - V(IA32I8x16ExtractLane) \ - V(SSEI8x16ReplaceLane) \ - V(AVXI8x16ReplaceLane) \ - V(SSEI8x16SConvertI16x8) \ - V(AVXI8x16SConvertI16x8) \ - V(IA32I8x16Neg) \ - V(SSEI8x16Shl) \ - V(AVXI8x16Shl) \ - V(IA32I8x16ShrS) \ - V(SSEI8x16Add) \ - V(AVXI8x16Add) \ - V(SSEI8x16AddSaturateS) \ - V(AVXI8x16AddSaturateS) \ - V(SSEI8x16Sub) \ - V(AVXI8x16Sub) \ - V(SSEI8x16SubSaturateS) \ - V(AVXI8x16SubSaturateS) \ - V(SSEI8x16Mul) \ - V(AVXI8x16Mul) \ - V(SSEI8x16MinS) \ - V(AVXI8x16MinS) \ - V(SSEI8x16MaxS) \ - V(AVXI8x16MaxS) \ - V(SSEI8x16Eq) \ - V(AVXI8x16Eq) \ - V(SSEI8x16Ne) \ - V(AVXI8x16Ne) \ - V(SSEI8x16GtS) \ - V(AVXI8x16GtS) \ - V(SSEI8x16GeS) \ - V(AVXI8x16GeS) \ - V(SSEI8x16UConvertI16x8) \ - V(AVXI8x16UConvertI16x8) \ - V(SSEI8x16AddSaturateU) \ - V(AVXI8x16AddSaturateU) \ - V(SSEI8x16SubSaturateU) \ - V(AVXI8x16SubSaturateU) \ - V(IA32I8x16ShrU) \ - V(SSEI8x16MinU) \ - V(AVXI8x16MinU) \ - V(SSEI8x16MaxU) \ - V(AVXI8x16MaxU) \ - V(SSEI8x16GtU) \ - V(AVXI8x16GtU) \ - V(SSEI8x16GeU) \ - V(AVXI8x16GeU) \ - V(IA32S128Zero) \ - V(SSES128Not) \ - V(AVXS128Not) \ - V(SSES128And) \ - V(AVXS128And) \ - V(SSES128Or) \ - V(AVXS128Or) \ - V(SSES128Xor) \ - V(AVXS128Xor) \ - V(SSES128Select) \ - V(AVXS128Select) \ - V(IA32S8x16Shuffle) \ - V(IA32S32x4Swizzle) \ - V(IA32S32x4Shuffle) \ - V(IA32S16x8Blend) \ - V(IA32S16x8HalfShuffle1) \ - V(IA32S16x8HalfShuffle2) \ - V(IA32S8x16Alignr) \ - V(IA32S16x8Dup) \ - V(IA32S8x16Dup) \ - V(SSES16x8UnzipHigh) \ - V(AVXS16x8UnzipHigh) \ - V(SSES16x8UnzipLow) \ - V(AVXS16x8UnzipLow) \ - V(SSES8x16UnzipHigh) \ - V(AVXS8x16UnzipHigh) \ - V(SSES8x16UnzipLow) \ - V(AVXS8x16UnzipLow) \ - V(IA32S64x2UnpackHigh) \ - V(IA32S32x4UnpackHigh) \ - V(IA32S16x8UnpackHigh) \ - V(IA32S8x16UnpackHigh) \ - V(IA32S64x2UnpackLow) \ - V(IA32S32x4UnpackLow) \ - V(IA32S16x8UnpackLow) \ - V(IA32S8x16UnpackLow) \ - V(SSES8x16TransposeLow) \ - V(AVXS8x16TransposeLow) \ - V(SSES8x16TransposeHigh) \ - V(AVXS8x16TransposeHigh) \ - V(SSES8x8Reverse) \ - V(AVXS8x8Reverse) \ - V(SSES8x4Reverse) \ - V(AVXS8x4Reverse) \ - V(SSES8x2Reverse) \ - V(AVXS8x2Reverse) \ - V(IA32S1x4AnyTrue) \ - V(IA32S1x4AllTrue) \ - V(IA32S1x8AnyTrue) \ - V(IA32S1x8AllTrue) \ - V(IA32S1x16AnyTrue) \ - V(IA32S1x16AllTrue) +#define TARGET_ARCH_OPCODE_LIST(V) \ + V(IA32Add) \ + V(IA32And) \ + V(IA32Cmp) \ + V(IA32Cmp16) \ + V(IA32Cmp8) \ + V(IA32Test) \ + V(IA32Test16) \ + V(IA32Test8) \ + V(IA32Or) \ + V(IA32Xor) \ + V(IA32Sub) \ + V(IA32Imul) \ + V(IA32ImulHigh) \ + V(IA32UmulHigh) \ + V(IA32Idiv) \ + V(IA32Udiv) \ + V(IA32Not) \ + V(IA32Neg) \ + V(IA32Shl) \ + V(IA32Shr) \ + V(IA32Sar) \ + V(IA32AddPair) \ + V(IA32SubPair) \ + V(IA32MulPair) \ + V(IA32ShlPair) \ + V(IA32ShrPair) \ + V(IA32SarPair) \ + V(IA32Ror) \ + V(IA32Lzcnt) \ + V(IA32Tzcnt) \ + V(IA32Popcnt) \ + V(IA32Bswap) \ + V(LFence) \ + V(SSEFloat32Cmp) \ + V(SSEFloat32Add) \ + V(SSEFloat32Sub) \ + V(SSEFloat32Mul) \ + V(SSEFloat32Div) \ + V(SSEFloat32Abs) \ + V(SSEFloat32Neg) \ + V(SSEFloat32Sqrt) \ + V(SSEFloat32Round) \ + V(SSEFloat64Cmp) \ + V(SSEFloat64Add) \ + V(SSEFloat64Sub) \ + V(SSEFloat64Mul) \ + V(SSEFloat64Div) \ + V(SSEFloat64Mod) \ + V(SSEFloat32Max) \ + V(SSEFloat64Max) \ + V(SSEFloat32Min) \ + V(SSEFloat64Min) \ + V(SSEFloat64Abs) \ + V(SSEFloat64Neg) \ + V(SSEFloat64Sqrt) \ + V(SSEFloat64Round) \ + V(SSEFloat32ToFloat64) \ + V(SSEFloat64ToFloat32) \ + V(SSEFloat32ToInt32) \ + V(SSEFloat32ToUint32) \ + V(SSEFloat64ToInt32) \ + V(SSEFloat64ToUint32) \ + V(SSEInt32ToFloat32) \ + V(SSEUint32ToFloat32) \ + V(SSEInt32ToFloat64) \ + V(SSEUint32ToFloat64) \ + V(SSEFloat64ExtractLowWord32) \ + V(SSEFloat64ExtractHighWord32) \ + V(SSEFloat64InsertLowWord32) \ + V(SSEFloat64InsertHighWord32) \ + V(SSEFloat64LoadLowWord32) \ + V(SSEFloat64SilenceNaN) \ + V(AVXFloat32Add) \ + V(AVXFloat32Sub) \ + V(AVXFloat32Mul) \ + V(AVXFloat32Div) \ + V(AVXFloat64Add) \ + V(AVXFloat64Sub) \ + V(AVXFloat64Mul) \ + V(AVXFloat64Div) \ + V(AVXFloat64Abs) \ + V(AVXFloat64Neg) \ + V(AVXFloat32Abs) \ + V(AVXFloat32Neg) \ + V(IA32Movsxbl) \ + V(IA32Movzxbl) \ + V(IA32Movb) \ + V(IA32Movsxwl) \ + V(IA32Movzxwl) \ + V(IA32Movw) \ + V(IA32Movl) \ + V(IA32Movss) \ + V(IA32Movsd) \ + V(IA32Movdqu) \ + V(IA32BitcastFI) \ + V(IA32BitcastIF) \ + V(IA32Lea) \ + V(IA32Push) \ + V(IA32PushFloat32) \ + V(IA32PushFloat64) \ + V(IA32PushSimd128) \ + V(IA32Poke) \ + V(IA32Peek) \ + V(IA32StackCheck) \ + V(SSEF32x4Splat) \ + V(AVXF32x4Splat) \ + V(SSEF32x4ExtractLane) \ + V(AVXF32x4ExtractLane) \ + V(SSEF32x4ReplaceLane) \ + V(AVXF32x4ReplaceLane) \ + V(IA32F32x4SConvertI32x4) \ + V(SSEF32x4UConvertI32x4) \ + V(AVXF32x4UConvertI32x4) \ + V(SSEF32x4Abs) \ + V(AVXF32x4Abs) \ + V(SSEF32x4Neg) \ + V(AVXF32x4Neg) \ + V(IA32F32x4RecipApprox) \ + V(IA32F32x4RecipSqrtApprox) \ + V(SSEF32x4Add) \ + V(AVXF32x4Add) \ + V(SSEF32x4AddHoriz) \ + V(AVXF32x4AddHoriz) \ + V(SSEF32x4Sub) \ + V(AVXF32x4Sub) \ + V(SSEF32x4Mul) \ + V(AVXF32x4Mul) \ + V(SSEF32x4Min) \ + V(AVXF32x4Min) \ + V(SSEF32x4Max) \ + V(AVXF32x4Max) \ + V(SSEF32x4Eq) \ + V(AVXF32x4Eq) \ + V(SSEF32x4Ne) \ + V(AVXF32x4Ne) \ + V(SSEF32x4Lt) \ + V(AVXF32x4Lt) \ + V(SSEF32x4Le) \ + V(AVXF32x4Le) \ + V(IA32I32x4Splat) \ + V(IA32I32x4ExtractLane) \ + V(SSEI32x4ReplaceLane) \ + V(AVXI32x4ReplaceLane) \ + V(SSEI32x4SConvertF32x4) \ + V(AVXI32x4SConvertF32x4) \ + V(IA32I32x4SConvertI16x8Low) \ + V(IA32I32x4SConvertI16x8High) \ + V(IA32I32x4Neg) \ + V(SSEI32x4Shl) \ + V(AVXI32x4Shl) \ + V(SSEI32x4ShrS) \ + V(AVXI32x4ShrS) \ + V(SSEI32x4Add) \ + V(AVXI32x4Add) \ + V(SSEI32x4AddHoriz) \ + V(AVXI32x4AddHoriz) \ + V(SSEI32x4Sub) \ + V(AVXI32x4Sub) \ + V(SSEI32x4Mul) \ + V(AVXI32x4Mul) \ + V(SSEI32x4MinS) \ + V(AVXI32x4MinS) \ + V(SSEI32x4MaxS) \ + V(AVXI32x4MaxS) \ + V(SSEI32x4Eq) \ + V(AVXI32x4Eq) \ + V(SSEI32x4Ne) \ + V(AVXI32x4Ne) \ + V(SSEI32x4GtS) \ + V(AVXI32x4GtS) \ + V(SSEI32x4GeS) \ + V(AVXI32x4GeS) \ + V(SSEI32x4UConvertF32x4) \ + V(AVXI32x4UConvertF32x4) \ + V(IA32I32x4UConvertI16x8Low) \ + V(IA32I32x4UConvertI16x8High) \ + V(SSEI32x4ShrU) \ + V(AVXI32x4ShrU) \ + V(SSEI32x4MinU) \ + V(AVXI32x4MinU) \ + V(SSEI32x4MaxU) \ + V(AVXI32x4MaxU) \ + V(SSEI32x4GtU) \ + V(AVXI32x4GtU) \ + V(SSEI32x4GeU) \ + V(AVXI32x4GeU) \ + V(IA32I16x8Splat) \ + V(IA32I16x8ExtractLane) \ + V(SSEI16x8ReplaceLane) \ + V(AVXI16x8ReplaceLane) \ + V(IA32I16x8SConvertI8x16Low) \ + V(IA32I16x8SConvertI8x16High) \ + V(IA32I16x8Neg) \ + V(SSEI16x8Shl) \ + V(AVXI16x8Shl) \ + V(SSEI16x8ShrS) \ + V(AVXI16x8ShrS) \ + V(SSEI16x8SConvertI32x4) \ + V(AVXI16x8SConvertI32x4) \ + V(SSEI16x8Add) \ + V(AVXI16x8Add) \ + V(SSEI16x8AddSaturateS) \ + V(AVXI16x8AddSaturateS) \ + V(SSEI16x8AddHoriz) \ + V(AVXI16x8AddHoriz) \ + V(SSEI16x8Sub) \ + V(AVXI16x8Sub) \ + V(SSEI16x8SubSaturateS) \ + V(AVXI16x8SubSaturateS) \ + V(SSEI16x8Mul) \ + V(AVXI16x8Mul) \ + V(SSEI16x8MinS) \ + V(AVXI16x8MinS) \ + V(SSEI16x8MaxS) \ + V(AVXI16x8MaxS) \ + V(SSEI16x8Eq) \ + V(AVXI16x8Eq) \ + V(SSEI16x8Ne) \ + V(AVXI16x8Ne) \ + V(SSEI16x8GtS) \ + V(AVXI16x8GtS) \ + V(SSEI16x8GeS) \ + V(AVXI16x8GeS) \ + V(IA32I16x8UConvertI8x16Low) \ + V(IA32I16x8UConvertI8x16High) \ + V(SSEI16x8ShrU) \ + V(AVXI16x8ShrU) \ + V(SSEI16x8UConvertI32x4) \ + V(AVXI16x8UConvertI32x4) \ + V(SSEI16x8AddSaturateU) \ + V(AVXI16x8AddSaturateU) \ + V(SSEI16x8SubSaturateU) \ + V(AVXI16x8SubSaturateU) \ + V(SSEI16x8MinU) \ + V(AVXI16x8MinU) \ + V(SSEI16x8MaxU) \ + V(AVXI16x8MaxU) \ + V(SSEI16x8GtU) \ + V(AVXI16x8GtU) \ + V(SSEI16x8GeU) \ + V(AVXI16x8GeU) \ + V(IA32I8x16Splat) \ + V(IA32I8x16ExtractLane) \ + V(SSEI8x16ReplaceLane) \ + V(AVXI8x16ReplaceLane) \ + V(SSEI8x16SConvertI16x8) \ + V(AVXI8x16SConvertI16x8) \ + V(IA32I8x16Neg) \ + V(SSEI8x16Shl) \ + V(AVXI8x16Shl) \ + V(IA32I8x16ShrS) \ + V(SSEI8x16Add) \ + V(AVXI8x16Add) \ + V(SSEI8x16AddSaturateS) \ + V(AVXI8x16AddSaturateS) \ + V(SSEI8x16Sub) \ + V(AVXI8x16Sub) \ + V(SSEI8x16SubSaturateS) \ + V(AVXI8x16SubSaturateS) \ + V(SSEI8x16Mul) \ + V(AVXI8x16Mul) \ + V(SSEI8x16MinS) \ + V(AVXI8x16MinS) \ + V(SSEI8x16MaxS) \ + V(AVXI8x16MaxS) \ + V(SSEI8x16Eq) \ + V(AVXI8x16Eq) \ + V(SSEI8x16Ne) \ + V(AVXI8x16Ne) \ + V(SSEI8x16GtS) \ + V(AVXI8x16GtS) \ + V(SSEI8x16GeS) \ + V(AVXI8x16GeS) \ + V(SSEI8x16UConvertI16x8) \ + V(AVXI8x16UConvertI16x8) \ + V(SSEI8x16AddSaturateU) \ + V(AVXI8x16AddSaturateU) \ + V(SSEI8x16SubSaturateU) \ + V(AVXI8x16SubSaturateU) \ + V(IA32I8x16ShrU) \ + V(SSEI8x16MinU) \ + V(AVXI8x16MinU) \ + V(SSEI8x16MaxU) \ + V(AVXI8x16MaxU) \ + V(SSEI8x16GtU) \ + V(AVXI8x16GtU) \ + V(SSEI8x16GeU) \ + V(AVXI8x16GeU) \ + V(IA32S128Zero) \ + V(SSES128Not) \ + V(AVXS128Not) \ + V(SSES128And) \ + V(AVXS128And) \ + V(SSES128Or) \ + V(AVXS128Or) \ + V(SSES128Xor) \ + V(AVXS128Xor) \ + V(SSES128Select) \ + V(AVXS128Select) \ + V(IA32S8x16Shuffle) \ + V(IA32S32x4Swizzle) \ + V(IA32S32x4Shuffle) \ + V(IA32S16x8Blend) \ + V(IA32S16x8HalfShuffle1) \ + V(IA32S16x8HalfShuffle2) \ + V(IA32S8x16Alignr) \ + V(IA32S16x8Dup) \ + V(IA32S8x16Dup) \ + V(SSES16x8UnzipHigh) \ + V(AVXS16x8UnzipHigh) \ + V(SSES16x8UnzipLow) \ + V(AVXS16x8UnzipLow) \ + V(SSES8x16UnzipHigh) \ + V(AVXS8x16UnzipHigh) \ + V(SSES8x16UnzipLow) \ + V(AVXS8x16UnzipLow) \ + V(IA32S64x2UnpackHigh) \ + V(IA32S32x4UnpackHigh) \ + V(IA32S16x8UnpackHigh) \ + V(IA32S8x16UnpackHigh) \ + V(IA32S64x2UnpackLow) \ + V(IA32S32x4UnpackLow) \ + V(IA32S16x8UnpackLow) \ + V(IA32S8x16UnpackLow) \ + V(SSES8x16TransposeLow) \ + V(AVXS8x16TransposeLow) \ + V(SSES8x16TransposeHigh) \ + V(AVXS8x16TransposeHigh) \ + V(SSES8x8Reverse) \ + V(AVXS8x8Reverse) \ + V(SSES8x4Reverse) \ + V(AVXS8x4Reverse) \ + V(SSES8x2Reverse) \ + V(AVXS8x2Reverse) \ + V(IA32S1x4AnyTrue) \ + V(IA32S1x4AllTrue) \ + V(IA32S1x8AnyTrue) \ + V(IA32S1x8AllTrue) \ + V(IA32S1x16AnyTrue) \ + V(IA32S1x16AllTrue) \ + V(IA32Word32AtomicPairLoad) \ + V(IA32Word32AtomicPairStore) \ + V(IA32Word32AtomicPairAdd) \ + V(IA32Word32AtomicPairSub) \ + V(IA32Word32AtomicPairAnd) \ + V(IA32Word32AtomicPairOr) \ + V(IA32Word32AtomicPairXor) \ + V(IA32Word32AtomicPairExchange) \ + V(IA32Word32AtomicPairCompareExchange) \ + V(IA32Word64AtomicNarrowAddUint8) \ + V(IA32Word64AtomicNarrowAddUint16) \ + V(IA32Word64AtomicNarrowAddUint32) \ + V(IA32Word64AtomicNarrowSubUint8) \ + V(IA32Word64AtomicNarrowSubUint16) \ + V(IA32Word64AtomicNarrowSubUint32) \ + V(IA32Word64AtomicNarrowAndUint8) \ + V(IA32Word64AtomicNarrowAndUint16) \ + V(IA32Word64AtomicNarrowAndUint32) \ + V(IA32Word64AtomicNarrowOrUint8) \ + V(IA32Word64AtomicNarrowOrUint16) \ + V(IA32Word64AtomicNarrowOrUint32) \ + V(IA32Word64AtomicNarrowXorUint8) \ + V(IA32Word64AtomicNarrowXorUint16) \ + V(IA32Word64AtomicNarrowXorUint32) \ + V(IA32Word64AtomicNarrowExchangeUint8) \ + V(IA32Word64AtomicNarrowExchangeUint16) \ + V(IA32Word64AtomicNarrowExchangeUint32) \ + V(IA32Word64AtomicNarrowCompareExchangeUint8) \ + V(IA32Word64AtomicNarrowCompareExchangeUint16) \ + V(IA32Word64AtomicNarrowCompareExchangeUint32) // Addressing modes represent the "shape" of inputs to an instruction. // Many instructions support multiple addressing modes. Addressing modes diff --git a/deps/v8/src/compiler/ia32/instruction-scheduler-ia32.cc b/deps/v8/src/compiler/ia32/instruction-scheduler-ia32.cc index 82d6fb88a3..07d42bc614 100644 --- a/deps/v8/src/compiler/ia32/instruction-scheduler-ia32.cc +++ b/deps/v8/src/compiler/ia32/instruction-scheduler-ia32.cc @@ -43,6 +43,7 @@ int InstructionScheduler::GetTargetInstructionFlags( case kIA32Lzcnt: case kIA32Tzcnt: case kIA32Popcnt: + case kIA32Bswap: case kIA32Lea: case kSSEFloat32Cmp: case kSSEFloat32Add: @@ -368,6 +369,40 @@ int InstructionScheduler::GetTargetInstructionFlags( case kLFence: return kHasSideEffect; + case kIA32Word32AtomicPairLoad: + return kIsLoadOperation; + + case kIA32Word32AtomicPairStore: + case kIA32Word32AtomicPairAdd: + case kIA32Word32AtomicPairSub: + case kIA32Word32AtomicPairAnd: + case kIA32Word32AtomicPairOr: + case kIA32Word32AtomicPairXor: + case kIA32Word32AtomicPairExchange: + case kIA32Word32AtomicPairCompareExchange: + case kIA32Word64AtomicNarrowAddUint8: + case kIA32Word64AtomicNarrowAddUint16: + case kIA32Word64AtomicNarrowAddUint32: + case kIA32Word64AtomicNarrowSubUint8: + case kIA32Word64AtomicNarrowSubUint16: + case kIA32Word64AtomicNarrowSubUint32: + case kIA32Word64AtomicNarrowAndUint8: + case kIA32Word64AtomicNarrowAndUint16: + case kIA32Word64AtomicNarrowAndUint32: + case kIA32Word64AtomicNarrowOrUint8: + case kIA32Word64AtomicNarrowOrUint16: + case kIA32Word64AtomicNarrowOrUint32: + case kIA32Word64AtomicNarrowXorUint8: + case kIA32Word64AtomicNarrowXorUint16: + case kIA32Word64AtomicNarrowXorUint32: + case kIA32Word64AtomicNarrowExchangeUint8: + case kIA32Word64AtomicNarrowExchangeUint16: + case kIA32Word64AtomicNarrowExchangeUint32: + case kIA32Word64AtomicNarrowCompareExchangeUint8: + case kIA32Word64AtomicNarrowCompareExchangeUint16: + case kIA32Word64AtomicNarrowCompareExchangeUint32: + return kHasSideEffect; + #define CASE(Name) case k##Name: COMMON_ARCH_OPCODE_LIST(CASE) #undef CASE diff --git a/deps/v8/src/compiler/ia32/instruction-selector-ia32.cc b/deps/v8/src/compiler/ia32/instruction-selector-ia32.cc index 4144254285..ce2f14e97f 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) \ |