Bug 1019831: SIMD x86-x64: Align stack top on 16 bytes boundaries if SIMD instructions are present; r=sunfish

--HG--
extra : rebase_source : 28a14e3c7251e86d181cdee0db424b74ad24ea1d
This commit is contained in:
Benjamin Bouvier 2014-08-07 17:57:44 +02:00
parent 416eea5b85
commit e3b29c20e7
8 changed files with 83 additions and 18 deletions

View File

@ -2228,7 +2228,7 @@ LIRGenerator::visitInterruptCheck(MInterruptCheck *ins)
bool
LIRGenerator::visitAsmJSInterruptCheck(MAsmJSInterruptCheck *ins)
{
gen->setPerformsAsmJSCall();
gen->setPerformsCall();
LAsmJSInterruptCheck *lir = new(alloc()) LAsmJSInterruptCheck(temp(),
ins->interruptExit(),
@ -3556,7 +3556,7 @@ LIRGenerator::visitAsmJSPassStackArg(MAsmJSPassStackArg *ins)
bool
LIRGenerator::visitAsmJSCall(MAsmJSCall *ins)
{
gen->setPerformsAsmJSCall();
gen->setPerformsCall();
LAllocation *args = gen->allocate<LAllocation>(ins->numOperands());
if (!args)

View File

@ -127,18 +127,9 @@ class MIRGenerator
bool performsCall() const {
return performsCall_;
}
void setNeedsInitialStackAlignment() {
needsInitialStackAlignment_ = true;
}
bool needsInitialStackAlignment() const {
JS_ASSERT(compilingAsmJS());
return needsInitialStackAlignment_;
}
void setPerformsAsmJSCall() {
JS_ASSERT(compilingAsmJS());
setPerformsCall();
setNeedsInitialStackAlignment();
}
// Traverses the graph to find if there's any SIMD instruction. Costful but
// the value is cached, so don't worry about calling it several times.
bool usesSimd();
void noteMinAsmJSHeapLength(uint32_t len) {
minAsmJSHeapLength_ = len;
}
@ -167,7 +158,8 @@ class MIRGenerator
uint32_t maxAsmJSStackArgBytes_;
bool performsCall_;
bool needsInitialStackAlignment_;
bool usesSimd_;
bool usesSimdCached_;
uint32_t minAsmJSHeapLength_;
// Keep track of whether frame arguments are modified during execution.

View File

@ -30,12 +30,44 @@ MIRGenerator::MIRGenerator(CompileCompartment *compartment, const JitCompileOpti
cancelBuild_(false),
maxAsmJSStackArgBytes_(0),
performsCall_(false),
needsInitialStackAlignment_(false),
usesSimd_(false),
usesSimdCached_(false),
minAsmJSHeapLength_(AsmJSAllocationGranularity),
modifiesFrameArguments_(false),
options(options)
{ }
bool
MIRGenerator::usesSimd()
{
if (usesSimdCached_)
return usesSimd_;
usesSimdCached_ = true;
for (ReversePostorderIterator block = graph_->rpoBegin(),
end = graph_->rpoEnd();
block != end;
block++)
{
// It's fine to use MInstructionIterator here because we don't have to
// worry about Phis, since any reachable phi (or phi cycle) will have at
// least one instruction as an input.
for (MInstructionIterator inst = block->begin(); inst != block->end(); inst++) {
// Instructions that have SIMD inputs but not a SIMD type are fine
// to ignore, as their inputs are also reached at some point. By
// induction, at least one instruction with a SIMD type is reached
// at some point.
if (IsSimdType(inst->type())) {
JS_ASSERT(SupportsSimd);
usesSimd_ = true;
return true;
}
}
}
usesSimd_ = false;
return false;
}
bool
MIRGenerator::abortFmt(const char *message, va_list ap)
{

View File

@ -150,6 +150,7 @@ static const bool StackKeptAligned = true;
// here such that it is accessible from the entire codebase. Once full support
// for SIMD is reached on all tier-1 platforms, this constant can be deleted.
static const bool SupportsSimd = false;
static const uint32_t SimdStackAlignment = 8;
static const Scale ScalePointer = TimesFour;

View File

@ -68,10 +68,14 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
// An MAsmJSCall does not align the stack pointer at calls sites but instead
// relies on the a priori stack adjustment (in the prologue) on platforms
// (like x64) which require the stack to be aligned.
if (StackKeptAligned || gen->needsInitialStackAlignment()) {
if (StackKeptAligned || gen->performsCall() || gen->usesSimd()) {
unsigned alignmentAtCall = sizeof(AsmJSFrame) + frameDepth_;
unsigned firstFixup = 0;
if (unsigned rem = alignmentAtCall % StackAlignment)
frameDepth_ += StackAlignment - rem;
frameDepth_ += (firstFixup = StackAlignment - rem);
if (gen->usesSimd())
setupSimdAlignment(firstFixup);
}
// FrameSizeClass is only used for bailing, which cannot happen in
@ -82,6 +86,38 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
}
}
void
CodeGeneratorShared::setupSimdAlignment(unsigned fixup)
{
JS_STATIC_ASSERT(SimdStackAlignment % StackAlignment == 0);
// At this point, we have:
// (frameDepth_ + sizeof(AsmJSFrame)) % StackAlignment == 0
// which means we can add as many SimdStackAlignment as needed.
// The next constraint is to have all stack slots
// aligned for SIMD. That's done by having the first stack slot
// aligned. We need an offset such that:
// (frameDepth_ - offset) % SimdStackAlignment == 0
frameInitialAdjustment_ = frameDepth_ % SimdStackAlignment;
// We need to ensure that the first stack slot is actually
// located in this frame and not beforehand, when taking this
// offset into account, i.e.:
// frameDepth_ - initial adjustment >= frameDepth_ - fixup
// <=> fixup >= initial adjustment
//
// For instance, on x86 with gcc, if the initial frameDepth
// % 16 is 8, then the fixup is 0, although the initial
// adjustment is 8. The first stack slot would be located at
// frameDepth - 8 in this case, which is obviously before
// frameDepth.
//
// If that's not the case, we add SimdStackAlignment to the
// fixup, which will keep on satisfying other constraints.
if (frameInitialAdjustment_ > int32_t(fixup))
frameDepth_ += SimdStackAlignment;
}
bool
CodeGeneratorShared::generateOutOfLineCode()
{

View File

@ -458,6 +458,8 @@ class CodeGeneratorShared : public LInstructionVisitor
private:
void generateInvalidateEpilogue();
void setupSimdAlignment(unsigned fixup);
public:
CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);

View File

@ -194,6 +194,7 @@ static const uint32_t CodeAlignment = 8;
// here such that it is accessible from the entire codebase. Once full support
// for SIMD is reached on all tier-1 platforms, this constant can be deleted.
static const bool SupportsSimd = true;
static const uint32_t SimdStackAlignment = 16;
static const Scale ScalePointer = TimesEight;

View File

@ -122,6 +122,7 @@ static const uint32_t CodeAlignment = 8;
// here such that it is accessible from the entire codebase. Once full support
// for SIMD is reached on all tier-1 platforms, this constant can be deleted.
static const bool SupportsSimd = true;
static const uint32_t SimdStackAlignment = 16;
struct ImmTag : public Imm32
{