author | Nicolas B. Pierron <nicolas.b.pierron@mozilla.com> |
Mon, 17 Aug 2015 11:32:15 +0200 | |
changeset 258026 | 011f8d81a9ae1e11e09bd46916cdca9c433cb779 |
parent 258025 | 28c84f5978dae7e26dad0fee66b96646241d928d |
child 258027 | 939b1402b1f57adb5b77ddf33bbf061692cf1c4d |
push id | 29241 |
push user | kwierso@gmail.com |
push date | Tue, 18 Aug 2015 00:00:46 +0000 |
treeherder | mozilla-central@6ae3e9ff53b2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | h4writer |
bugs | 1184959 |
milestone | 43.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -10982,16 +10982,21 @@ GenerateEntry(ModuleCompiler& m, unsigne for (ABIArgTypeIter iter(func.sig().args()); !iter.done(); iter++) { unsigned argOffset = iter.index() * sizeof(AsmJSModule::EntryArg); Address src(argv, argOffset); MIRType type = iter.mirType(); switch (iter->kind()) { case ABIArg::GPR: masm.load32(src, iter->gpr()); break; +#ifdef JS_CODEGEN_REGISTER_PAIR + case ABIArg::GPR_PAIR: + MOZ_CRASH("AsmJS uses hardfp for function calls."); + break; +#endif case ABIArg::FPU: { static_assert(sizeof(AsmJSModule::EntryArg) >= jit::Simd128DataSize, "EntryArg must be big enough to store SIMD values"); switch (type) { case MIRType_Int32x4: masm.loadUnalignedInt32x4(src, iter->fpu()); break; case MIRType_Float32x4: @@ -11094,16 +11099,21 @@ FillArgumentArray(ModuleCompiler& m, con MacroAssembler& masm = m.masm(); for (ABIArgTypeIter i(argTypes); !i.done(); i++) { Address dstAddr(masm.getStackPointer(), offsetToArgs + i.index() * sizeof(Value)); switch (i->kind()) { case ABIArg::GPR: masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr); break; +#ifdef JS_CODEGEN_REGISTER_PAIR + case ABIArg::GPR_PAIR: + MOZ_CRASH("AsmJS uses hardfp for function calls."); + break; +#endif case ABIArg::FPU: masm.canonicalizeDouble(i->fpu()); masm.storeDouble(i->fpu(), dstAddr); break; case ABIArg::Stack: if (i.mirType() == MIRType_Int32) { Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase()); #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
--- a/js/src/jit/RegisterSets.h +++ b/js/src/jit/RegisterSets.h @@ -1215,34 +1215,69 @@ class AnyRegisterIterator return AnyRegister(*geniter_); return AnyRegister(*floatiter_); } }; class ABIArg { public: - enum Kind { GPR, FPU, Stack }; + enum Kind { + GPR, +#ifdef JS_CODEGEN_REGISTER_PAIR + GPR_PAIR, +#endif + FPU, + Stack + }; private: Kind kind_; union { Register::Code gpr_; FloatRegister::Code fpu_; uint32_t offset_; } u; public: ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; } explicit ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); } + explicit ABIArg(Register gprLow, Register gprHigh) + { +#if defined(JS_CODEGEN_REGISTER_PAIR) + kind_ = GPR_PAIR; +#else + MOZ_CRASH("Unsupported type of ABI argument."); +#endif + u.gpr_ = gprLow.code(); + MOZ_ASSERT(u.gpr_ % 2 == 0); + MOZ_ASSERT(u.gpr_ + 1 == gprHigh.code()); + } explicit ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); } explicit ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; } Kind kind() const { return kind_; } - Register gpr() const { MOZ_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); } +#ifdef JS_CODEGEN_REGISTER_PAIR + bool isGeneralRegPair() const { return kind_ == GPR_PAIR; } +#else + bool isGeneralRegPair() const { return false; } +#endif + + Register gpr() const { + MOZ_ASSERT(kind() == GPR); + return Register::FromCode(u.gpr_); + } + Register evenGpr() const { + MOZ_ASSERT(isGeneralRegPair()); + return Register::FromCode(u.gpr_); + } + Register oddGpr() const { + MOZ_ASSERT(isGeneralRegPair()); + return Register::FromCode(u.gpr_ + 1); + } FloatRegister fpu() const { MOZ_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); } uint32_t offsetFromArgBase() const { MOZ_ASSERT(kind() == Stack); return u.offset_; } bool argInRegister() const { return kind() != Stack; } AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); } }; // Get the set of registers which should be saved by a block of code which
--- a/js/src/jit/arm/Architecture-arm.h +++ b/js/src/jit/arm/Architecture-arm.h @@ -634,16 +634,20 @@ static inline bool UseHardFpABI() #if defined(JS_CODEGEN_ARM_HARDFP) return true; #else return false; #endif } #endif +// In order to handle SoftFp ABI calls, we need to be able to express that we +// have ABIArg which are represented by pair of general purpose registers. +#define JS_CODEGEN_REGISTER_PAIR 1 + // See the comments above AsmJSMappedSize in AsmJSValidate.h for more info. // TODO: Implement this for ARM. Note that it requires Codegen to respect the // offset field of AsmJSHeapAccess. static const size_t AsmJSCheckedImmediateRange = 0; static const size_t AsmJSImmediateRange = 0; } // namespace jit } // namespace js
--- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -19,27 +19,77 @@ using namespace js; using namespace js::jit; using mozilla::CountLeadingZeroes32; void dbg_break() {} -// Note this is used for inter-AsmJS calls and may pass arguments and results in -// floating point registers even if the system ABI does not. +// The ABIArgGenerator is used for making system ABI calls and for inter-AsmJS +// calls. The system ABI can either be SoftFp or HardFp, and inter-AsmJS calls +// are always HardFp calls. The initialization defaults to HardFp, and the ABI +// choice is made before any system ABI calls with the method "setUseHardFp". ABIArgGenerator::ABIArgGenerator() : intRegIndex_(0), floatRegIndex_(0), stackOffset_(0), - current_() + current_(), + useHardFp_(true) { } +// See the "Parameter Passing" section of the "Procedure Call Standard for the +// ARM Architecture" documentation. +ABIArg +ABIArgGenerator::softNext(MIRType type) +{ + switch (type) { + case MIRType_Int32: + case MIRType_Pointer: + if (intRegIndex_ == NumIntArgRegs) { + current_ = ABIArg(stackOffset_); + stackOffset_ += sizeof(uint32_t); + break; + } + current_ = ABIArg(Register::FromCode(intRegIndex_)); + intRegIndex_++; + break; + case MIRType_Float32: + if (intRegIndex_ == NumIntArgRegs) { + current_ = ABIArg(stackOffset_); + stackOffset_ += sizeof(uint32_t); + break; + } + current_ = ABIArg(Register::FromCode(intRegIndex_)); + intRegIndex_++; + break; + case MIRType_Double: + // Make sure to use an even register index. Increase to next even number + // when odd. + intRegIndex_ = (intRegIndex_ + 1) & ~1; + if (intRegIndex_ == NumIntArgRegs) { + // Align the stack on 8 bytes. + static const int align = sizeof(double) - 1; + stackOffset_ = (stackOffset_ + align) & ~align; + current_ = ABIArg(stackOffset_); + stackOffset_ += sizeof(double); + break; + } + current_ = ABIArg(Register::FromCode(intRegIndex_), Register::FromCode(intRegIndex_ + 1)); + intRegIndex_ += 2; + break; + default: + MOZ_CRASH("Unexpected argument type"); + } + + return current_; +} + ABIArg -ABIArgGenerator::next(MIRType type) +ABIArgGenerator::hardNext(MIRType type) { switch (type) { case MIRType_Int32: case MIRType_Pointer: if (intRegIndex_ == NumIntArgRegs) { current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint32_t); break; @@ -54,35 +104,45 @@ ABIArgGenerator::next(MIRType type) current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); break; } current_ = ABIArg(VFPRegister(floatRegIndex_, VFPRegister::Single)); floatRegIndex_++; break; case MIRType_Double: - // Bump the number of used registers up to the next multiple of two. + // Double register are composed of 2 float registers, thus we have to + // skip any float register which cannot be used in a pair of float + // registers in which a double value can be stored. floatRegIndex_ = (floatRegIndex_ + 1) & ~1; if (floatRegIndex_ == NumFloatArgRegs) { static const int align = sizeof(double) - 1; stackOffset_ = (stackOffset_ + align) & ~align; current_ = ABIArg(stackOffset_); stackOffset_ += sizeof(uint64_t); break; } current_ = ABIArg(VFPRegister(floatRegIndex_ >> 1, VFPRegister::Double)); - floatRegIndex_+=2; + floatRegIndex_ += 2; break; default: MOZ_CRASH("Unexpected argument type"); } return current_; } +ABIArg +ABIArgGenerator::next(MIRType type) +{ + if (useHardFp_) + return hardNext(type); + return softNext(type); +} + const Register ABIArgGenerator::NonArgReturnReg0 = r4; const Register ABIArgGenerator::NonArgReturnReg1 = r5; const Register ABIArgGenerator::NonReturn_VolatileReg0 = r2; const Register ABIArgGenerator::NonReturn_VolatileReg1 = r3; // Encode a standard register when it is being used as src1, the dest, and an // extra register. These should never be called with an InvalidReg. uint32_t
--- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -67,19 +67,33 @@ static const uint32_t NumCallTempNonArgR class ABIArgGenerator { unsigned intRegIndex_; unsigned floatRegIndex_; uint32_t stackOffset_; ABIArg current_; + // ARM can either use HardFp (use float registers for float arguments), or + // SoftFp (use general registers for float arguments) ABI. We keep this + // switch as a runtime switch because AsmJS always use the HardFp back-end + // while the calls to native functions have to use the one provided by the + // system. + bool useHardFp_; + + ABIArg softNext(MIRType argType); + ABIArg hardNext(MIRType argType); + public: ABIArgGenerator(); + void setUseHardFp(bool useHardFp) { + MOZ_ASSERT(intRegIndex_ == 0 && floatRegIndex_ == 0); + useHardFp_ = useHardFp; + } ABIArg next(MIRType argType); ABIArg& current() { return current_; } uint32_t stackBytesConsumedSoFar() const { return stackOffset_; } static const Register NonArgReturnReg0; static const Register NonArgReturnReg1; static const Register NonReturn_VolatileReg0; static const Register NonReturn_VolatileReg1;