1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_x86_shared_CodeGenerator_x86_shared_h 8 #define jit_x86_shared_CodeGenerator_x86_shared_h 9 10 #include "jit/shared/CodeGenerator-shared.h" 11 12 namespace js { 13 namespace jit { 14 15 class CodeGeneratorX86Shared; 16 class OutOfLineBailout; 17 class OutOfLineUndoALUOperation; 18 class OutOfLineLoadTypedArrayOutOfBounds; 19 class MulNegativeZeroCheck; 20 class ModOverflowCheck; 21 class ReturnZero; 22 class OutOfLineTableSwitch; 23 24 using OutOfLineWasmTruncateCheck = 25 OutOfLineWasmTruncateCheckBase<CodeGeneratorX86Shared>; 26 27 class CodeGeneratorX86Shared : public CodeGeneratorShared { 28 friend class MoveResolverX86; 29 thisFromCtor()30 CodeGeneratorX86Shared* thisFromCtor() { return this; } 31 32 template <typename T> 33 void bailout(const T& t, LSnapshot* snapshot); 34 35 protected: 36 // Load a NaN or zero into a register for an out of bounds AsmJS or static 37 // typed array load. 38 class OutOfLineLoadTypedArrayOutOfBounds 39 : public OutOfLineCodeBase<CodeGeneratorX86Shared> { 40 AnyRegister dest_; 41 Scalar::Type viewType_; 42 43 public: OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest,Scalar::Type viewType)44 OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest, Scalar::Type viewType) 45 : dest_(dest), viewType_(viewType) {} 46 dest()47 AnyRegister dest() const { return dest_; } viewType()48 Scalar::Type viewType() const { return viewType_; } accept(CodeGeneratorX86Shared * codegen)49 void accept(CodeGeneratorX86Shared* codegen) override { 50 codegen->visitOutOfLineLoadTypedArrayOutOfBounds(this); 51 } 52 }; 53 54 // Additional bounds check for vector Float to Int conversion, when the 55 // undefined pattern is seen. Might imply a bailout. 56 class OutOfLineSimdFloatToIntCheck 57 : public OutOfLineCodeBase<CodeGeneratorX86Shared> { 58 Register temp_; 59 FloatRegister input_; 60 LInstruction* ins_; 61 wasm::BytecodeOffset bytecodeOffset_; 62 63 public: OutOfLineSimdFloatToIntCheck(Register temp,FloatRegister input,LInstruction * ins,wasm::BytecodeOffset bytecodeOffset)64 OutOfLineSimdFloatToIntCheck(Register temp, FloatRegister input, 65 LInstruction* ins, 66 wasm::BytecodeOffset bytecodeOffset) 67 : temp_(temp), 68 input_(input), 69 ins_(ins), 70 bytecodeOffset_(bytecodeOffset) {} 71 temp()72 Register temp() const { return temp_; } input()73 FloatRegister input() const { return input_; } ins()74 LInstruction* ins() const { return ins_; } bytecodeOffset()75 wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } 76 accept(CodeGeneratorX86Shared * codegen)77 void accept(CodeGeneratorX86Shared* codegen) override { 78 codegen->visitOutOfLineSimdFloatToIntCheck(this); 79 } 80 }; 81 82 public: 83 NonAssertingLabel deoptLabel_; 84 85 Operand ToOperand(const LAllocation& a); 86 Operand ToOperand(const LAllocation* a); 87 Operand ToOperand(const LDefinition* def); 88 89 #ifdef JS_PUNBOX64 90 Operand ToOperandOrRegister64(const LInt64Allocation input); 91 #else 92 Register64 ToOperandOrRegister64(const LInt64Allocation input); 93 #endif 94 95 MoveOperand toMoveOperand(LAllocation a) const; 96 97 void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot); 98 void bailoutIf(Assembler::DoubleCondition condition, LSnapshot* snapshot); 99 void bailoutFrom(Label* label, LSnapshot* snapshot); 100 void bailout(LSnapshot* snapshot); 101 102 template <typename T1, typename T2> bailoutCmpPtr(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)103 void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, 104 LSnapshot* snapshot) { 105 masm.cmpPtr(lhs, rhs); 106 bailoutIf(c, snapshot); 107 } bailoutTestPtr(Assembler::Condition c,Register lhs,Register rhs,LSnapshot * snapshot)108 void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, 109 LSnapshot* snapshot) { 110 masm.testPtr(lhs, rhs); 111 bailoutIf(c, snapshot); 112 } 113 template <typename T1, typename T2> bailoutCmp32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)114 void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, 115 LSnapshot* snapshot) { 116 masm.cmp32(lhs, rhs); 117 bailoutIf(c, snapshot); 118 } 119 template <typename T1, typename T2> bailoutTest32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)120 void bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, 121 LSnapshot* snapshot) { 122 masm.test32(lhs, rhs); 123 bailoutIf(c, snapshot); 124 } bailoutIfFalseBool(Register reg,LSnapshot * snapshot)125 void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) { 126 masm.test32(reg, Imm32(0xFF)); 127 bailoutIf(Assembler::Zero, snapshot); 128 } bailoutCvttsd2si(FloatRegister src,Register dest,LSnapshot * snapshot)129 void bailoutCvttsd2si(FloatRegister src, Register dest, LSnapshot* snapshot) { 130 // vcvttsd2si returns 0x80000000 on failure. Test for it by 131 // subtracting 1 and testing overflow. The other possibility is to test 132 // equality for INT_MIN after a comparison, but 1 costs fewer bytes to 133 // materialize. 134 masm.vcvttsd2si(src, dest); 135 masm.cmp32(dest, Imm32(1)); 136 bailoutIf(Assembler::Overflow, snapshot); 137 } bailoutCvttss2si(FloatRegister src,Register dest,LSnapshot * snapshot)138 void bailoutCvttss2si(FloatRegister src, Register dest, LSnapshot* snapshot) { 139 // Same trick as explained in the above comment. 140 masm.vcvttss2si(src, dest); 141 masm.cmp32(dest, Imm32(1)); 142 bailoutIf(Assembler::Overflow, snapshot); 143 } 144 145 protected: 146 bool generateOutOfLineCode(); 147 148 void emitCompare(MCompare::CompareType type, const LAllocation* left, 149 const LAllocation* right); 150 151 // Emits a branch that directs control flow to the true block if |cond| is 152 // true, and the false block if |cond| is false. 153 void emitBranch(Assembler::Condition cond, MBasicBlock* ifTrue, 154 MBasicBlock* ifFalse, 155 Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond); 156 void emitBranch(Assembler::DoubleCondition cond, MBasicBlock* ifTrue, 157 MBasicBlock* ifFalse); 158 testNullEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)159 void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value, 160 MBasicBlock* ifTrue, MBasicBlock* ifFalse) { 161 cond = masm.testNull(cond, value); 162 emitBranch(cond, ifTrue, ifFalse); 163 } testUndefinedEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)164 void testUndefinedEmitBranch(Assembler::Condition cond, 165 const ValueOperand& value, MBasicBlock* ifTrue, 166 MBasicBlock* ifFalse) { 167 cond = masm.testUndefined(cond, value); 168 emitBranch(cond, ifTrue, ifFalse); 169 } testObjectEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)170 void testObjectEmitBranch(Assembler::Condition cond, 171 const ValueOperand& value, MBasicBlock* ifTrue, 172 MBasicBlock* ifFalse) { 173 cond = masm.testObject(cond, value); 174 emitBranch(cond, ifTrue, ifFalse); 175 } 176 testZeroEmitBranch(Assembler::Condition cond,Register reg,MBasicBlock * ifTrue,MBasicBlock * ifFalse)177 void testZeroEmitBranch(Assembler::Condition cond, Register reg, 178 MBasicBlock* ifTrue, MBasicBlock* ifFalse) { 179 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); 180 masm.cmpPtr(reg, ImmWord(0)); 181 emitBranch(cond, ifTrue, ifFalse); 182 } 183 184 void emitTableSwitchDispatch(MTableSwitch* mir, Register index, 185 Register base); 186 187 void emitSimdExtractLane8x16(FloatRegister input, Register output, 188 unsigned lane, SimdSign signedness); 189 void emitSimdExtractLane16x8(FloatRegister input, Register output, 190 unsigned lane, SimdSign signedness); 191 void emitSimdExtractLane32x4(FloatRegister input, Register output, 192 unsigned lane); 193 194 public: 195 CodeGeneratorX86Shared(MIRGenerator* gen, LIRGraph* graph, 196 MacroAssembler* masm); 197 198 public: 199 // Instruction visitors. 200 void visitDouble(LDouble* ins); 201 void visitFloat32(LFloat32* ins); 202 void visitMinMaxD(LMinMaxD* ins); 203 void visitMinMaxF(LMinMaxF* ins); 204 void visitAbsD(LAbsD* ins); 205 void visitAbsF(LAbsF* ins); 206 void visitClzI(LClzI* ins); 207 void visitCtzI(LCtzI* ins); 208 void visitPopcntI(LPopcntI* ins); 209 void visitPopcntI64(LPopcntI64* lir); 210 void visitSqrtD(LSqrtD* ins); 211 void visitSqrtF(LSqrtF* ins); 212 void visitPowHalfD(LPowHalfD* ins); 213 void visitAddI(LAddI* ins); 214 void visitAddI64(LAddI64* ins); 215 void visitSubI(LSubI* ins); 216 void visitSubI64(LSubI64* ins); 217 void visitMulI(LMulI* ins); 218 void visitMulI64(LMulI64* ins); 219 void visitDivI(LDivI* ins); 220 void visitDivPowTwoI(LDivPowTwoI* ins); 221 void visitDivOrModConstantI(LDivOrModConstantI* ins); 222 void visitModI(LModI* ins); 223 void visitModPowTwoI(LModPowTwoI* ins); 224 void visitBitNotI(LBitNotI* ins); 225 void visitBitOpI(LBitOpI* ins); 226 void visitBitOpI64(LBitOpI64* ins); 227 void visitShiftI(LShiftI* ins); 228 void visitShiftI64(LShiftI64* ins); 229 void visitUrshD(LUrshD* ins); 230 void visitTestIAndBranch(LTestIAndBranch* test); 231 void visitTestDAndBranch(LTestDAndBranch* test); 232 void visitTestFAndBranch(LTestFAndBranch* test); 233 void visitCompare(LCompare* comp); 234 void visitCompareAndBranch(LCompareAndBranch* comp); 235 void visitCompareD(LCompareD* comp); 236 void visitCompareDAndBranch(LCompareDAndBranch* comp); 237 void visitCompareF(LCompareF* comp); 238 void visitCompareFAndBranch(LCompareFAndBranch* comp); 239 void visitBitAndAndBranch(LBitAndAndBranch* baab); 240 void visitNotI(LNotI* comp); 241 void visitNotD(LNotD* comp); 242 void visitNotF(LNotF* comp); 243 void visitMathD(LMathD* math); 244 void visitMathF(LMathF* math); 245 void visitFloor(LFloor* lir); 246 void visitFloorF(LFloorF* lir); 247 void visitCeil(LCeil* lir); 248 void visitCeilF(LCeilF* lir); 249 void visitRound(LRound* lir); 250 void visitRoundF(LRoundF* lir); 251 void visitNearbyInt(LNearbyInt* lir); 252 void visitNearbyIntF(LNearbyIntF* lir); 253 void visitEffectiveAddress(LEffectiveAddress* ins); 254 void visitUDivOrMod(LUDivOrMod* ins); 255 void visitUDivOrModConstant(LUDivOrModConstant* ins); 256 void visitWasmStackArg(LWasmStackArg* ins); 257 void visitWasmStackArgI64(LWasmStackArgI64* ins); 258 void visitWasmSelect(LWasmSelect* ins); 259 void visitWasmReinterpret(LWasmReinterpret* lir); 260 void visitMemoryBarrier(LMemoryBarrier* ins); 261 void visitWasmAddOffset(LWasmAddOffset* lir); 262 void visitWasmTruncateToInt32(LWasmTruncateToInt32* lir); 263 void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir); 264 void visitAtomicTypedArrayElementBinopForEffect( 265 LAtomicTypedArrayElementBinopForEffect* lir); 266 void visitCompareExchangeTypedArrayElement( 267 LCompareExchangeTypedArrayElement* lir); 268 void visitAtomicExchangeTypedArrayElement( 269 LAtomicExchangeTypedArrayElement* lir); 270 void visitCopySignD(LCopySignD* lir); 271 void visitCopySignF(LCopySignF* lir); 272 void visitRotateI64(LRotateI64* lir); 273 274 void visitOutOfLineLoadTypedArrayOutOfBounds( 275 OutOfLineLoadTypedArrayOutOfBounds* ool); 276 277 void visitNegI(LNegI* lir); 278 void visitNegD(LNegD* lir); 279 void visitNegF(LNegF* lir); 280 281 void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool); 282 283 // SIMD operators 284 void visitSimdValueInt32x4(LSimdValueInt32x4* lir); 285 void visitSimdValueFloat32x4(LSimdValueFloat32x4* lir); 286 void visitSimdSplatX16(LSimdSplatX16* lir); 287 void visitSimdSplatX8(LSimdSplatX8* lir); 288 void visitSimdSplatX4(LSimdSplatX4* lir); 289 void visitSimd128Int(LSimd128Int* ins); 290 void visitSimd128Float(LSimd128Float* ins); 291 void visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4* ins); 292 void visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4* ins); 293 void visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins); 294 void visitSimdReinterpretCast(LSimdReinterpretCast* lir); 295 void visitSimdExtractElementB(LSimdExtractElementB* lir); 296 void visitSimdExtractElementI(LSimdExtractElementI* lir); 297 void visitSimdExtractElementU2D(LSimdExtractElementU2D* lir); 298 void visitSimdExtractElementF(LSimdExtractElementF* lir); 299 void visitSimdInsertElementI(LSimdInsertElementI* lir); 300 void visitSimdInsertElementF(LSimdInsertElementF* lir); 301 void visitSimdSwizzleI(LSimdSwizzleI* lir); 302 void visitSimdSwizzleF(LSimdSwizzleF* lir); 303 void visitSimdShuffleX4(LSimdShuffleX4* lir); 304 void visitSimdShuffle(LSimdShuffle* lir); 305 void visitSimdUnaryArithIx16(LSimdUnaryArithIx16* lir); 306 void visitSimdUnaryArithIx8(LSimdUnaryArithIx8* lir); 307 void visitSimdUnaryArithIx4(LSimdUnaryArithIx4* lir); 308 void visitSimdUnaryArithFx4(LSimdUnaryArithFx4* lir); 309 void visitSimdBinaryCompIx16(LSimdBinaryCompIx16* lir); 310 void visitSimdBinaryCompIx8(LSimdBinaryCompIx8* lir); 311 void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir); 312 void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir); 313 void visitSimdBinaryArithIx16(LSimdBinaryArithIx16* lir); 314 void visitSimdBinaryArithIx8(LSimdBinaryArithIx8* lir); 315 void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir); 316 void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir); 317 void visitSimdBinarySaturating(LSimdBinarySaturating* lir); 318 void visitSimdBinaryBitwise(LSimdBinaryBitwise* lir); 319 void visitSimdShift(LSimdShift* lir); 320 void visitSimdSelect(LSimdSelect* ins); 321 void visitSimdAllTrue(LSimdAllTrue* ins); 322 void visitSimdAnyTrue(LSimdAnyTrue* ins); 323 324 template <class T, class Reg> 325 void visitSimdGeneralShuffle(LSimdGeneralShuffleBase* lir, Reg temp); 326 void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir); 327 void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir); 328 329 // Out of line visitors. 330 void visitOutOfLineBailout(OutOfLineBailout* ool); 331 void visitOutOfLineUndoALUOperation(OutOfLineUndoALUOperation* ool); 332 void visitMulNegativeZeroCheck(MulNegativeZeroCheck* ool); 333 void visitModOverflowCheck(ModOverflowCheck* ool); 334 void visitReturnZero(ReturnZero* ool); 335 void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); 336 void visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIntCheck* ool); 337 void generateInvalidateEpilogue(); 338 339 void setReturnDoubleRegs(LiveRegisterSet* regs); 340 341 void canonicalizeIfDeterministic(Scalar::Type type, const LAllocation* value); 342 }; 343 344 // An out-of-line bailout thunk. 345 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorX86Shared> { 346 LSnapshot* snapshot_; 347 348 public: OutOfLineBailout(LSnapshot * snapshot)349 explicit OutOfLineBailout(LSnapshot* snapshot) : snapshot_(snapshot) {} 350 351 void accept(CodeGeneratorX86Shared* codegen) override; 352 snapshot()353 LSnapshot* snapshot() const { return snapshot_; } 354 }; 355 356 } // namespace jit 357 } // namespace js 358 359 #endif /* jit_x86_shared_CodeGenerator_x86_shared_h */ 360