Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (194541 => 194542)
--- trunk/Source/_javascript_Core/ChangeLog 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,3 +1,112 @@
+2016-01-04 Filip Pizlo <fpi...@apple.com>
+
+ B3 patchpoints should allow requesting scratch registers
+ https://bugs.webkit.org/show_bug.cgi?id=152669
+
+ Reviewed by Benjamin Poulain.
+
+ Scratch registers are something that we often need in many patchpoint use cases. In LLVM's
+ patchpoints, we didn't have a good way to request scratch registers. So, our current FTL code
+ often does crazy scratch register allocation madness even when it would be better to just ask
+ the backend for some registers. This patch adds a mechanism for requesting scratch registers
+ in B3, and wires it all the way to all of our register allocation and liveness
+ infrastructure.
+
+ From the standpoint of a patchpoint, a "scratch register" is an instruction argument that
+ only admits Tmp and is defined early (like an early clobber register) and is used late (like
+ what we previously called LateUse, except that this time it's also a warm use). We already
+ had the beginning of support for early def's because of early clobbers, and we already
+ supported late uses albeit cold ones. I really only needed to add one new role: "Scratch",
+ which means both early def and late use in much the same way as "UseDef" means both early
+ use and late def. But, it feels better to complete the set of roles, so I added LateColdUse
+ to differentiate from LateUse (which is now a warm use) and EarlyDef to differentiate from
+ Def (which is, and always has been, a late def). Forcing the code to deal with the full
+ matrix of possibilities resulted in what is probably a progression in how we handle defs in
+ the register and stack allocators. The new Inst::forEachDef(Inst*, Inst*, callback) fully
+ recognizes that a "def" is something that can come from either the preceding instruction or
+ the succeeding one.
+
+ This doesn't add any new functionality to FTL B3 yet, but the new scratch register mechanism
+ is covered by new testb3 tests.
+
+ * b3/B3CheckSpecial.cpp:
+ (JSC::B3::CheckSpecial::isValid):
+ (JSC::B3::CheckSpecial::admitsStack):
+ (JSC::B3::CheckSpecial::generate):
+ * b3/B3LowerToAir.cpp:
+ (JSC::B3::Air::LowerToAir::lower):
+ * b3/B3PatchpointSpecial.cpp:
+ (JSC::B3::PatchpointSpecial::forEachArg):
+ (JSC::B3::PatchpointSpecial::isValid):
+ (JSC::B3::PatchpointSpecial::admitsStack):
+ (JSC::B3::PatchpointSpecial::generate):
+ * b3/B3PatchpointValue.cpp:
+ (JSC::B3::PatchpointValue::dumpMeta):
+ (JSC::B3::PatchpointValue::PatchpointValue):
+ * b3/B3PatchpointValue.h:
+ * b3/B3StackmapGenerationParams.cpp:
+ (JSC::B3::StackmapGenerationParams::unavailableRegisters):
+ * b3/B3StackmapGenerationParams.h:
+ (JSC::B3::StackmapGenerationParams::gpScratch):
+ (JSC::B3::StackmapGenerationParams::fpScratch):
+ * b3/B3StackmapSpecial.cpp:
+ (JSC::B3::StackmapSpecial::forEachArgImpl):
+ (JSC::B3::StackmapSpecial::isValidImpl):
+ (JSC::B3::StackmapSpecial::admitsStackImpl):
+ (JSC::B3::StackmapSpecial::repsImpl):
+ (JSC::B3::StackmapSpecial::isArgValidForValue):
+ (JSC::B3::StackmapSpecial::appendRepsImpl): Deleted.
+ * b3/B3StackmapSpecial.h:
+ * b3/air/AirAllocateStack.cpp:
+ (JSC::B3::Air::allocateStack):
+ * b3/air/AirArg.cpp:
+ (WTF::printInternal):
+ * b3/air/AirArg.h:
+ (JSC::B3::Air::Arg::isAnyUse):
+ (JSC::B3::Air::Arg::isColdUse):
+ (JSC::B3::Air::Arg::isEarlyUse):
+ (JSC::B3::Air::Arg::isLateUse):
+ (JSC::B3::Air::Arg::isAnyDef):
+ (JSC::B3::Air::Arg::isEarlyDef):
+ (JSC::B3::Air::Arg::isLateDef):
+ (JSC::B3::Air::Arg::isZDef):
+ (JSC::B3::Air::Arg::Arg):
+ (JSC::B3::Air::Arg::imm):
+ (JSC::B3::Air::Arg::isDef): Deleted.
+ * b3/air/AirBasicBlock.h:
+ (JSC::B3::Air::BasicBlock::at):
+ (JSC::B3::Air::BasicBlock::get):
+ (JSC::B3::Air::BasicBlock::last):
+ * b3/air/AirEliminateDeadCode.cpp:
+ (JSC::B3::Air::eliminateDeadCode):
+ * b3/air/AirFixPartialRegisterStalls.cpp:
+ (JSC::B3::Air::fixPartialRegisterStalls):
+ * b3/air/AirInst.cpp:
+ (JSC::B3::Air::Inst::hasArgEffects):
+ * b3/air/AirInst.h:
+ * b3/air/AirInstInlines.h:
+ (JSC::B3::Air::Inst::extraEarlyClobberedRegs):
+ (JSC::B3::Air::Inst::forEachDef):
+ (JSC::B3::Air::Inst::forEachDefWithExtraClobberedRegs):
+ (JSC::B3::Air::Inst::reportUsedRegisters):
+ (JSC::B3::Air::Inst::forEachTmpWithExtraClobberedRegs): Deleted.
+ * b3/air/AirIteratedRegisterCoalescing.cpp:
+ * b3/air/AirLiveness.h:
+ (JSC::B3::Air::AbstractLiveness::AbstractLiveness):
+ (JSC::B3::Air::AbstractLiveness::LocalCalc::execute):
+ * b3/air/AirSpillEverything.cpp:
+ (JSC::B3::Air::spillEverything):
+ * b3/air/AirTmpWidth.cpp:
+ (JSC::B3::Air::TmpWidth::recompute):
+ * b3/air/AirUseCounts.h:
+ (JSC::B3::Air::UseCounts::UseCounts):
+ * b3/testb3.cpp:
+ (JSC::B3::testPatchpointAny):
+ (JSC::B3::testPatchpointGPScratch):
+ (JSC::B3::testPatchpointFPScratch):
+ (JSC::B3::testPatchpointLotsOfLateAnys):
+ (JSC::B3::run):
+
2016-01-04 Csaba Osztrogonác <o...@webkit.org>
Fix the !ENABLE(INTL) build after r193493
Modified: trunk/Source/_javascript_Core/b3/B3CheckSpecial.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3CheckSpecial.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3CheckSpecial.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -124,7 +124,8 @@
bool CheckSpecial::isValid(Inst& inst)
{
return hiddenBranch(inst).isValidForm()
- && isValidImpl(numB3Args(inst), m_numCheckArgs + 1, inst);
+ && isValidImpl(numB3Args(inst), m_numCheckArgs + 1, inst)
+ && inst.args.size() - m_numCheckArgs - 1 == inst.origin->numChildren() - numB3Args(inst);
}
bool CheckSpecial::admitsStack(Inst& inst, unsigned argIndex)
@@ -142,8 +143,7 @@
StackmapValue* value = inst.origin->as<StackmapValue>();
ASSERT(value);
- Vector<ValueRep> reps;
- appendRepsImpl(context, m_numCheckArgs + 1, inst, reps);
+ Vector<ValueRep> reps = repsImpl(context, numB3Args(inst), m_numCheckArgs + 1, inst);
// Set aside the args that are relevant to undoing the operation. This is because we don't want to
// capture all of inst in the closure below.
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -2007,6 +2007,11 @@
}
fillStackmap(inst, patchpointValue, 0);
+
+ for (unsigned i = patchpointValue->numGPScratchRegisters; i--;)
+ inst.args.append(m_code.newTmp(Arg::GP));
+ for (unsigned i = patchpointValue->numFPScratchRegisters; i--;)
+ inst.args.append(m_code.newTmp(Arg::FP));
m_insts.last().append(WTFMove(inst));
m_insts.last().appendVector(after);
Modified: trunk/Source/_javascript_Core/b3/B3PatchpointSpecial.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3PatchpointSpecial.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3PatchpointSpecial.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -46,32 +46,56 @@
void PatchpointSpecial::forEachArg(Inst& inst, const ScopedLambda<Inst::EachArgCallback>& callback)
{
- // FIXME: Allow B3 Patchpoints to specify LateUse.
- // https://bugs.webkit.org/show_bug.cgi?id=151335
-
- if (inst.origin->type() == Void) {
- forEachArgImpl(0, 1, inst, SameAsRep, callback);
- return;
- }
+ unsigned argIndex = 1;
- callback(inst.args[1], Arg::Def, inst.origin->airType(), inst.origin->airWidth());
- forEachArgImpl(0, 2, inst, SameAsRep, callback);
+ if (inst.origin->type() != Void)
+ callback(inst.args[argIndex++], Arg::Def, inst.origin->airType(), inst.origin->airWidth());
+
+ forEachArgImpl(0, argIndex, inst, SameAsRep, callback);
+ argIndex += inst.origin->numChildren();
+
+ for (unsigned i = inst.origin->as<PatchpointValue>()->numGPScratchRegisters; i--;)
+ callback(inst.args[argIndex++], Arg::Scratch, Arg::GP, Arg::conservativeWidth(Arg::GP));
+ for (unsigned i = inst.origin->as<PatchpointValue>()->numFPScratchRegisters; i--;)
+ callback(inst.args[argIndex++], Arg::Scratch, Arg::FP, Arg::conservativeWidth(Arg::FP));
}
bool PatchpointSpecial::isValid(Inst& inst)
{
- if (inst.origin->type() == Void)
- return isValidImpl(0, 1, inst);
+ PatchpointValue* patchpoint = inst.origin->as<PatchpointValue>();
+ unsigned argIndex = 1;
- if (inst.args.size() < 2)
+ if (inst.origin->type() != Void) {
+ if (argIndex >= inst.args.size())
+ return false;
+
+ if (!isArgValidForValue(inst.args[argIndex], patchpoint))
+ return false;
+ if (!isArgValidForRep(code(), inst.args[argIndex], patchpoint->resultConstraint))
+ return false;
+ argIndex++;
+ }
+
+ if (!isValidImpl(0, argIndex, inst))
return false;
- PatchpointValue* patchpoint = inst.origin->as<PatchpointValue>();
- if (!isArgValidForValue(inst.args[1], patchpoint))
+ argIndex += patchpoint->numChildren();
+
+ if (argIndex + patchpoint->numGPScratchRegisters + patchpoint->numFPScratchRegisters
+ != inst.args.size())
return false;
- if (!isArgValidForRep(code(), inst.args[1], patchpoint->resultConstraint))
- return false;
- return isValidImpl(0, 2, inst);
+ for (unsigned i = patchpoint->numGPScratchRegisters; i--;) {
+ Arg arg = inst.args[argIndex++];
+ if (!arg.isGPTmp())
+ return false;
+ }
+ for (unsigned i = patchpoint->numFPScratchRegisters; i--;) {
+ Arg arg = inst.args[argIndex++];
+ if (!arg.isFPTmp())
+ return false;
+ }
+
+ return true;
}
bool PatchpointSpecial::admitsStack(Inst& inst, unsigned argIndex)
@@ -99,16 +123,24 @@
CCallHelpers::Jump PatchpointSpecial::generate(
Inst& inst, CCallHelpers& jit, GenerationContext& context)
{
- StackmapValue* value = inst.origin->as<StackmapValue>();
+ PatchpointValue* value = inst.origin->as<PatchpointValue>();
ASSERT(value);
Vector<ValueRep> reps;
unsigned offset = 1;
if (inst.origin->type() != Void)
reps.append(repForArg(*context.code, inst.args[offset++]));
- appendRepsImpl(context, offset, inst, reps);
+ reps.appendVector(repsImpl(context, 0, offset, inst));
+ offset += value->numChildren();
+
+ StackmapGenerationParams params(value, reps, context);
+
+ for (unsigned i = value->numGPScratchRegisters; i--;)
+ params.m_gpScratch.append(inst.args[offset++].gpr());
+ for (unsigned i = value->numFPScratchRegisters; i--;)
+ params.m_fpScratch.append(inst.args[offset++].fpr());
- value->m_generator->run(jit, StackmapGenerationParams(value, reps, context));
+ value->m_generator->run(jit, params);
return CCallHelpers::Jump();
}
Modified: trunk/Source/_javascript_Core/b3/B3PatchpointValue.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3PatchpointValue.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3PatchpointValue.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -38,6 +38,10 @@
{
Base::dumpMeta(comma, out);
out.print(comma, "resultConstraint = ", resultConstraint);
+ if (numGPScratchRegisters)
+ out.print(comma, "numGPScratchRegisters = ", numGPScratchRegisters);
+ if (numFPScratchRegisters)
+ out.print(comma, "numFPScratchRegisters = ", numFPScratchRegisters);
}
PatchpointValue::PatchpointValue(unsigned index, Type type, Origin origin)
Modified: trunk/Source/_javascript_Core/b3/B3PatchpointValue.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3PatchpointValue.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3PatchpointValue.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -56,6 +56,12 @@
// is Void. Otherwise you can set this to any input constraint.
ValueRep resultConstraint;
+ // The number of scratch registers that this patchpoint gets. The scratch register is guaranteed
+ // to be different from any input register and the destination register. It's also guaranteed not
+ // to be clobbered either early or late. These are 0 by default.
+ uint8_t numGPScratchRegisters { 0 };
+ uint8_t numFPScratchRegisters { 0 };
+
protected:
void dumpMeta(CommaPrinter&, PrintStream&) const override;
Modified: trunk/Source/_javascript_Core/b3/B3StackmapGenerationParams.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3StackmapGenerationParams.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3StackmapGenerationParams.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -50,6 +50,12 @@
unsavedCalleeSaves.clear(regAtOffset.reg());
result.merge(unsavedCalleeSaves);
+
+ for (GPRReg gpr : m_gpScratch)
+ result.clear(gpr);
+ for (FPRReg fpr : m_fpScratch)
+ result.clear(fpr);
+
return result;
}
Modified: trunk/Source/_javascript_Core/b3/B3StackmapGenerationParams.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3StackmapGenerationParams.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3StackmapGenerationParams.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -59,13 +59,28 @@
// This tells you the registers that were used.
const RegisterSet& usedRegisters() const;
- // This is a useful helper if you want to do register allocation inside of a patchpoint. You
- // can only use callee-save registers if they were saved in the prologue. This gives you the
- // used register set that's useful for such settings by returning:
+ // This is a useful helper if you want to do register allocation inside of a patchpoint. The
+ // usedRegisters() set is not directly useful for this purpose because:
//
- // usedRegisters() | (RegisterSet::calleeSaveRegisters() - proc.calleeSaveRegisters())
- RegisterSet unavailableRegisters() const;
+ // - You can only use callee-save registers for scratch if they were saved in the prologue. So,
+ // if a register is callee-save, it's not enough that it's not in usedRegisters().
+ //
+ // - Scratch registers are going to be in usedRegisters() at the patchpoint. So, if you want to
+ // find one of your requested scratch registers using usedRegisters(), you'll have a bad time.
+ //
+ // This gives you the used register set that's useful for allocating scratch registers. This set
+ // is defined as:
+ //
+ // (usedRegisters() | (RegisterSet::calleeSaveRegisters() - proc.calleeSaveRegisters()))
+ // - gpScratchRegisters - fpScratchRegisters
+ //
+ // I.e. it is like usedRegisters() but also includes unsaved callee-saves and excludes scratch
+ // registers.
+ JS_EXPORT_PRIVATE RegisterSet unavailableRegisters() const;
+ GPRReg gpScratch(unsigned index) const { return m_gpScratch[index]; }
+ FPRReg fpScratch(unsigned index) const { return m_fpScratch[index]; }
+
// This is provided for convenience; it means that you don't have to capture it if you don't want to.
Procedure& proc() const;
@@ -90,6 +105,8 @@
StackmapValue* m_value;
Vector<ValueRep> m_reps;
+ Vector<GPRReg> m_gpScratch;
+ Vector<FPRReg> m_fpScratch;
Air::GenerationContext& m_context;
};
Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -81,9 +81,9 @@
// Check that insane things have not happened.
ASSERT(inst.args.size() >= numIgnoredAirArgs);
ASSERT(value->children().size() >= numIgnoredB3Args);
- ASSERT(inst.args.size() - numIgnoredAirArgs == value->children().size() - numIgnoredB3Args);
+ ASSERT(inst.args.size() - numIgnoredAirArgs >= value->children().size() - numIgnoredB3Args);
- for (unsigned i = 0; i < inst.args.size() - numIgnoredAirArgs; ++i) {
+ for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
Arg& arg = inst.args[i + numIgnoredAirArgs];
ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args);
@@ -103,12 +103,12 @@
role = Arg::ColdUse;
break;
case ValueRep::LateColdAny:
- role = Arg::LateUse;
+ role = Arg::LateColdUse;
break;
}
break;
case ForceLateUse:
- role = Arg::LateUse;
+ role = Arg::LateColdUse;
break;
}
@@ -129,13 +129,13 @@
ASSERT(value->children().size() >= numIgnoredB3Args);
// For the Inst to be valid, it needs to have the right number of arguments.
- if (inst.args.size() - numIgnoredAirArgs != value->children().size() - numIgnoredB3Args)
+ if (inst.args.size() - numIgnoredAirArgs < value->children().size() - numIgnoredB3Args)
return false;
// Regardless of constraints, stackmaps have some basic requirements for their arguments. For
// example, you can't have a non-FP-offset address. This verifies those conditions as well as the
// argument types.
- for (unsigned i = 0; i < inst.args.size() - numIgnoredAirArgs; ++i) {
+ for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
Value* child = value->child(i + numIgnoredB3Args);
Arg& arg = inst.args[i + numIgnoredAirArgs];
@@ -167,6 +167,11 @@
unsigned stackmapArgIndex = argIndex - numIgnoredAirArgs + numIgnoredB3Args;
+ if (stackmapArgIndex >= value->numChildren()) {
+ // It's not a stackmap argument, so as far as we are concerned, it doesn't admit stack.
+ return false;
+ }
+
if (stackmapArgIndex >= value->m_reps.size()) {
// This means that there was no constraint.
return true;
@@ -180,11 +185,13 @@
return false;
}
-void StackmapSpecial::appendRepsImpl(
- GenerationContext& context, unsigned numIgnoredArgs, Inst& inst, Vector<ValueRep>& result)
+Vector<ValueRep> StackmapSpecial::repsImpl(
+ GenerationContext& context, unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Inst& inst)
{
- for (unsigned i = numIgnoredArgs; i < inst.args.size(); ++i)
- result.append(repForArg(*context.code, inst.args[i]));
+ Vector<ValueRep> result;
+ for (unsigned i = 0; i < inst.origin->numChildren() - numIgnoredB3Args; ++i)
+ result.append(repForArg(*context.code, inst.args[i + numIgnoredAirArgs]));
+ return result;
}
bool StackmapSpecial::isArgValidForValue(const Air::Arg& arg, Value* value)
Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -69,7 +69,8 @@
Air::Inst&, unsigned argIndex);
// Appends the reps for the Inst's args, starting with numIgnoredArgs, to the given vector.
- void appendRepsImpl(Air::GenerationContext&, unsigned numIgnoredArgs, Air::Inst&, Vector<ValueRep>&);
+ Vector<ValueRep> repsImpl(
+ Air::GenerationContext&, unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs, Air::Inst&);
static bool isArgValidForValue(const Air::Arg&, Value*);
static bool isArgValidForRep(Air::Code&, const Air::Arg&, const ValueRep&);
Modified: trunk/Source/_javascript_Core/b3/air/AirAllocateStack.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirAllocateStack.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirAllocateStack.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -143,14 +143,13 @@
for (BasicBlock* block : code) {
StackSlotLiveness::LocalCalc localCalc(liveness, block);
- auto interfere = [&] (Inst& inst) {
+ auto interfere = [&] (unsigned instIndex) {
if (verbose)
dataLog("Interfering: ", WTF::pointerListDump(localCalc.live()), "\n");
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
- if (!Arg::isDef(role))
- return;
+ Inst::forEachDef<Arg>(
+ block->get(instIndex), block->get(instIndex + 1),
+ [&] (Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
if (!arg.isStack())
return;
StackSlot* slot = arg.stackSlot();
@@ -167,12 +166,10 @@
for (unsigned instIndex = block->size(); instIndex--;) {
if (verbose)
dataLog("Analyzing: ", block->at(instIndex), "\n");
- Inst& inst = block->at(instIndex);
- interfere(inst);
+ interfere(instIndex);
localCalc.execute(instIndex);
}
- Inst nop;
- interfere(nop);
+ interfere(-1);
}
if (verbose) {
Modified: trunk/Source/_javascript_Core/b3/air/AirArg.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirArg.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -193,6 +193,15 @@
case Arg::LateUse:
out.print("LateUse");
return;
+ case Arg::LateColdUse:
+ out.print("LateColdUse");
+ return;
+ case Arg::EarlyDef:
+ out.print("EarlyDef");
+ return;
+ case Arg::Scratch:
+ out.print("Scratch");
+ return;
}
RELEASE_ASSERT_NOT_REACHED();
Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirArg.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -92,10 +92,14 @@
ColdUse,
// LateUse means that the Inst will read from this value after doing its Def's. Note that LateUse
- // on an Addr or Index still means Use on the internal temporaries. LateUse also currently also
- // implies ColdUse.
+ // on an Addr or Index still means Use on the internal temporaries. Note that specifying the
+ // same Tmp once as Def and once as LateUse has undefined behavior: the use may happen before
+ // the def, or it may happen after it.
LateUse,
+ // Combination of LateUse and ColdUse.
+ LateColdUse,
+
// Def means that the Inst will write to this value after doing everything else.
//
// For Tmp: The Inst will write to this Tmp.
@@ -127,6 +131,16 @@
// This is a combined Use and ZDef. It means that both things happen.
UseZDef,
+ // This is like Def, but implies that the assignment occurs before the start of the Inst's
+ // execution rather than after. Note that specifying the same Tmp once as EarlyDef and once
+ // as Use has undefined behavior: the use may happen before the def, or it may happen after
+ // it.
+ EarlyDef,
+
+ // Some instructions need a scratch register. We model this by saying that the temporary is
+ // defined early and used late. This role implies that.
+ Scratch,
+
// This is a special kind of use that is only valid for addresses. It means that the
// instruction will evaluate the address _expression_ and consume the effective address, but it
// will neither load nor store. This is an escaping use, because now the address may be
@@ -171,10 +185,13 @@
case UseDef:
case UseZDef:
case LateUse:
+ case LateColdUse:
+ case Scratch:
return true;
case Def:
case ZDef:
case UseAddr:
+ case EarlyDef:
return false;
}
}
@@ -183,14 +200,17 @@
{
switch (role) {
case ColdUse:
- case LateUse:
+ case LateColdUse:
return true;
case Use:
case UseDef:
case UseZDef:
+ case LateUse:
case Def:
case ZDef:
case UseAddr:
+ case Scratch:
+ case EarlyDef:
return false;
}
}
@@ -213,6 +233,9 @@
case ZDef:
case UseAddr:
case LateUse:
+ case LateColdUse:
+ case Scratch:
+ case EarlyDef:
return false;
}
}
@@ -220,26 +243,83 @@
// Returns true if the Role implies that the Inst will Use the Arg after doing everything else.
static bool isLateUse(Role role)
{
- return role == LateUse;
+ switch (role) {
+ case LateUse:
+ case LateColdUse:
+ case Scratch:
+ return true;
+ case ColdUse:
+ case Use:
+ case UseDef:
+ case UseZDef:
+ case Def:
+ case ZDef:
+ case UseAddr:
+ case EarlyDef:
+ return false;
+ }
}
// Returns true if the Role implies that the Inst will Def the Arg.
- static bool isDef(Role role)
+ static bool isAnyDef(Role role)
{
switch (role) {
case Use:
case ColdUse:
case UseAddr:
case LateUse:
+ case LateColdUse:
return false;
case Def:
case UseDef:
case ZDef:
case UseZDef:
+ case EarlyDef:
+ case Scratch:
return true;
}
}
+ // Returns true if the Role implies that the Inst will Def the Arg before start of execution.
+ static bool isEarlyDef(Role role)
+ {
+ switch (role) {
+ case Use:
+ case ColdUse:
+ case UseAddr:
+ case LateUse:
+ case Def:
+ case UseDef:
+ case ZDef:
+ case UseZDef:
+ case LateColdUse:
+ return false;
+ case EarlyDef:
+ case Scratch:
+ return true;
+ }
+ }
+
+ // Returns true if the Role implies that the Inst will Def the Arg after the end of execution.
+ static bool isLateDef(Role role)
+ {
+ switch (role) {
+ case Use:
+ case ColdUse:
+ case UseAddr:
+ case LateUse:
+ case EarlyDef:
+ case Scratch:
+ case LateColdUse:
+ return false;
+ case Def:
+ case UseDef:
+ case ZDef:
+ case UseZDef:
+ return true;
+ }
+ }
+
// Returns true if the Role implies that the Inst will ZDef the Arg.
static bool isZDef(Role role)
{
@@ -250,6 +330,9 @@
case LateUse:
case Def:
case UseDef:
+ case EarlyDef:
+ case Scratch:
+ case LateColdUse:
return false;
case ZDef:
case UseZDef:
@@ -331,6 +414,11 @@
{
}
+ Arg(Reg reg)
+ : Arg(Air::Tmp(reg))
+ {
+ }
+
static Arg imm(int64_t value)
{
Arg result;
@@ -845,7 +933,7 @@
case CallArg:
return isValidAddrForm(offset());
case Index:
- return isValidIndexForm(offset(), scale(), width);
+ return isValidIndexForm(scale(), offset(), width);
case RelCond:
case ResCond:
case DoubleCond:
@@ -882,7 +970,7 @@
{
switch (m_kind) {
case Tmp:
- ASSERT(isAnyUse(argRole) || isDef(argRole));
+ ASSERT(isAnyUse(argRole) || isAnyDef(argRole));
functor(m_base, argRole, argType, argWidth);
break;
case Addr:
Modified: trunk/Source/_javascript_Core/b3/air/AirBasicBlock.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirBasicBlock.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirBasicBlock.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -64,6 +64,11 @@
const Inst& at(unsigned index) const { return m_insts[index]; }
Inst& at(unsigned index) { return m_insts[index]; }
+ Inst* get(unsigned index)
+ {
+ return index < size() ? &at(index) : nullptr;
+ }
+
const Inst& last() const { return m_insts.last(); }
Inst& last() { return m_insts.last(); }
Modified: trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -81,8 +81,10 @@
bool storesToLive = false;
inst.forEachArg(
[&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
- if (!Arg::isDef(role))
+ if (!Arg::isAnyDef(role))
return;
+ if (role == Arg::Scratch)
+ return;
storesToLive |= isArgLive(arg);
});
return storesToLive;
Modified: trunk/Source/_javascript_Core/b3/air/AirFixPartialRegisterStalls.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirFixPartialRegisterStalls.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirFixPartialRegisterStalls.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -116,7 +116,7 @@
inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
ASSERT_WITH_MESSAGE(tmp.isReg(), "This phase must be run after register allocation.");
- if (tmp.isFPR() && Arg::isDef(role))
+ if (tmp.isFPR() && Arg::isAnyDef(role))
localDistance.add(tmp.fpr(), distanceToBlockEnd);
});
}
@@ -205,7 +205,7 @@
RegisterSet uses;
inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
if (tmp.isFPR()) {
- if (Arg::isDef(role))
+ if (Arg::isAnyDef(role))
defs.set(tmp.fpr());
if (Arg::isAnyUse(role))
uses.set(tmp.fpr());
Modified: trunk/Source/_javascript_Core/b3/air/AirInst.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirInst.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirInst.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,7 +39,7 @@
bool result = false;
forEachArg(
[&] (Arg&, Arg::Role role, Arg::Type, Arg::Width) {
- if (Arg::isDef(role))
+ if (Arg::isAnyDef(role))
result = true;
});
return result;
Modified: trunk/Source/_javascript_Core/b3/air/AirInst.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirInst.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirInst.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -115,7 +115,7 @@
});
}
- // Thing can be either Arg or Tmp.
+ // Thing can be either Arg, Tmp, or StackSlot*.
template<typename Thing, typename Functor>
void forEach(const Functor&);
@@ -127,11 +127,19 @@
const RegisterSet& extraClobberedRegs();
const RegisterSet& extraEarlyClobberedRegs();
- // Iterate over the Defs and the extra clobbered registers. You must supply the next instruction if
- // there is one.
- template<typename Functor>
- void forEachTmpWithExtraClobberedRegs(Inst* nextInst, const Functor& functor);
+ // Iterate over all Def's that happen at the end of an instruction. You supply a pair
+ // instructions. The instructions must appear next to each other, in that order, in some basic
+ // block. You can pass null for the first instruction when analyzing what happens at the top of
+ // a basic block. You can pass null for the second instruction when analyzing what happens at the
+ // bottom of a basic block.
+ template<typename Thing, typename Functor>
+ static void forEachDef(Inst* prevInst, Inst* nextInst, const Functor&);
+ // Iterate over all Def's that happen at the end of this instruction, including extra clobbered
+ // registers. Note that Thing can only be Arg or Tmp when you use this functor.
+ template<typename Thing, typename Functor>
+ static void forEachDefWithExtraClobberedRegs(Inst* prevInst, Inst* nextInst, const Functor&);
+
// Use this to report which registers are live. This should be done just before codegen. Note
// that for efficiency, reportUsedRegisters() only works if hasSpecial() returns true.
void reportUsedRegisters(const RegisterSet&);
Modified: trunk/Source/_javascript_Core/b3/air/AirInstInlines.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirInstInlines.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirInstInlines.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -95,24 +95,48 @@
return args[0].special()->extraEarlyClobberedRegs(*this);
}
-template<typename Functor>
-inline void Inst::forEachTmpWithExtraClobberedRegs(Inst* nextInst, const Functor& functor)
+template<typename Thing, typename Functor>
+inline void Inst::forEachDef(Inst* prevInst, Inst* nextInst, const Functor& functor)
{
- forEachTmp(
- [&] (Tmp& tmpArg, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
- functor(tmpArg, role, argType, argWidth);
- });
+ if (prevInst) {
+ prevInst->forEach<Thing>(
+ [&] (Thing& thing, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
+ if (Arg::isLateDef(role))
+ functor(thing, role, argType, argWidth);
+ });
+ }
+ if (nextInst) {
+ nextInst->forEach<Thing>(
+ [&] (Thing& thing, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
+ if (Arg::isEarlyDef(role))
+ functor(thing, role, argType, argWidth);
+ });
+ }
+}
+
+template<typename Thing, typename Functor>
+inline void Inst::forEachDefWithExtraClobberedRegs(
+ Inst* prevInst, Inst* nextInst, const Functor& functor)
+{
+ forEachDef<Thing>(prevInst, nextInst, functor);
+
+ Arg::Role regDefRole;
+
auto reportReg = [&] (Reg reg) {
Arg::Type type = reg.isGPR() ? Arg::GP : Arg::FP;
- functor(Tmp(reg), Arg::Def, type, Arg::conservativeWidth(type));
+ functor(Thing(reg), regDefRole, type, Arg::conservativeWidth(type));
};
- if (hasSpecial())
- extraClobberedRegs().forEach(reportReg);
+ if (prevInst && prevInst->hasSpecial()) {
+ regDefRole = Arg::Def;
+ prevInst->extraClobberedRegs().forEach(reportReg);
+ }
- if (nextInst && nextInst->hasSpecial())
+ if (nextInst && nextInst->hasSpecial()) {
+ regDefRole = Arg::EarlyDef;
nextInst->extraEarlyClobberedRegs().forEach(reportReg);
+ }
}
inline void Inst::reportUsedRegisters(const RegisterSet& usedRegisters)
Modified: trunk/Source/_javascript_Core/b3/air/AirIteratedRegisterCoalescing.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirIteratedRegisterCoalescing.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirIteratedRegisterCoalescing.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -770,40 +770,43 @@
typename TmpLiveness<type>::LocalCalc localCalc(liveness, block);
for (unsigned instIndex = block->size(); instIndex--;) {
Inst& inst = block->at(instIndex);
- Inst* nextInst = instIndex + 1 < block->size() ? &block->at(instIndex + 1) : nullptr;
- build(inst, nextInst, localCalc);
+ Inst* nextInst = block->get(instIndex + 1);
+ build(&inst, nextInst, localCalc);
localCalc.execute(instIndex);
}
+ build(nullptr, &block->at(0), localCalc);
}
}
- void build(Inst& inst, Inst* nextInst, const typename TmpLiveness<type>::LocalCalc& localCalc)
+ void build(Inst* prevInst, Inst* nextInst, const typename TmpLiveness<type>::LocalCalc& localCalc)
{
- inst.forEachTmpWithExtraClobberedRegs(
- nextInst,
- [&] (const Tmp& arg, Arg::Role role, Arg::Type argType, Arg::Width) {
- if (!Arg::isDef(role) || argType != type)
+ Inst::forEachDefWithExtraClobberedRegs<Tmp>(
+ prevInst, nextInst,
+ [&] (const Tmp& arg, Arg::Role, Arg::Type argType, Arg::Width) {
+ if (argType != type)
return;
// All the Def()s interfere with each other and with all the extra clobbered Tmps.
- // We should not use forEachDefAndExtraClobberedTmp() here since colored Tmps
+ // We should not use forEachDefWithExtraClobberedRegs() here since colored Tmps
// do not need interference edges in our implementation.
- inst.forEachTmp([&] (Tmp& otherArg, Arg::Role role, Arg::Type argType, Arg::Width) {
- if (!Arg::isDef(role) || argType != type)
- return;
-
- addEdge(arg, otherArg);
- });
+ Inst::forEachDef<Tmp>(
+ prevInst, nextInst,
+ [&] (Tmp& otherArg, Arg::Role, Arg::Type argType, Arg::Width) {
+ if (argType != type)
+ return;
+
+ addEdge(arg, otherArg);
+ });
});
- if (mayBeCoalescable(inst)) {
+ if (prevInst && mayBeCoalescable(*prevInst)) {
// We do not want the Use() of this move to interfere with the Def(), even if it is live
// after the Move. If we were to add the interference edge, it would be impossible to
// coalesce the Move even if the two Tmp never interfere anywhere.
Tmp defTmp;
Tmp useTmp;
- inst.forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type, Arg::Width) {
- if (Arg::isDef(role))
+ prevInst->forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type, Arg::Width) {
+ if (Arg::isLateDef(role))
defTmp = argTmp;
else {
ASSERT(Arg::isEarlyUse(role));
@@ -822,7 +825,7 @@
ASSERT(nextMoveIndex <= m_activeMoves.size());
m_activeMoves.ensureSize(nextMoveIndex + 1);
- for (const Arg& arg : inst.args) {
+ for (const Arg& arg : prevInst->args) {
auto& list = m_moveList[AbsoluteTmpMapper<type>::absoluteIndex(arg.tmp())];
list.add(nextMoveIndex);
}
@@ -832,26 +835,20 @@
addEdge(defTmp, liveTmp);
}
- // The next instruction could have early clobbers. We need to consider those now.
- if (nextInst && nextInst->hasSpecial()) {
- nextInst->extraEarlyClobberedRegs().forEach([&] (Reg reg) {
- if (reg.isGPR() == (type == Arg::GP)) {
- for (const Tmp& liveTmp : localCalc.live())
- addEdge(Tmp(reg), liveTmp);
- }
- });
- }
+ // The next instruction could have early clobbers or early def's. We need to consider
+ // those now.
+ addEdges(nullptr, nextInst, localCalc.live());
} else
- addEdges(inst, nextInst, localCalc.live());
+ addEdges(prevInst, nextInst, localCalc.live());
}
- void addEdges(Inst& inst, Inst* nextInst, typename TmpLiveness<type>::LocalCalc::Iterable liveTmps)
+ void addEdges(Inst* prevInst, Inst* nextInst, typename TmpLiveness<type>::LocalCalc::Iterable liveTmps)
{
// All the Def()s interfere with everthing live.
- inst.forEachTmpWithExtraClobberedRegs(
- nextInst,
- [&] (const Tmp& arg, Arg::Role role, Arg::Type argType, Arg::Width) {
- if (!Arg::isDef(role) || argType != type)
+ Inst::forEachDefWithExtraClobberedRegs<Tmp>(
+ prevInst, nextInst,
+ [&] (const Tmp& arg, Arg::Role, Arg::Type argType, Arg::Width) {
+ if (argType != type)
return;
for (const Tmp& liveTmp : liveTmps) {
@@ -1082,6 +1079,12 @@
void iteratedRegisterCoalescingOnType()
{
HashSet<unsigned> unspillableTmps;
+
+ // FIXME: If a Tmp is used only from a Scratch role and that argument is !admitsStack, then
+ // we should add the Tmp to unspillableTmps. That will help avoid relooping only to turn the
+ // Tmp into an unspillable Tmp.
+ // https://bugs.webkit.org/show_bug.cgi?id=152699
+
while (true) {
++m_numIterations;
@@ -1242,15 +1245,12 @@
break;
}
- if (Arg::isAnyUse(role)) {
- Tmp newTmp = m_code.newTmp(type);
- insertionSet.insert(instIndex, move, inst.origin, arg, newTmp);
- tmp = newTmp;
+ tmp = m_code.newTmp(type);
+ unspillableTmps.add(AbsoluteTmpMapper<type>::absoluteIndex(tmp));
- // Any new Fill() should never be spilled.
- unspillableTmps.add(AbsoluteTmpMapper<type>::absoluteIndex(tmp));
- }
- if (Arg::isDef(role))
+ if (Arg::isAnyUse(role) && role != Arg::Scratch)
+ insertionSet.insert(instIndex, move, inst.origin, arg, tmp);
+ if (Arg::isAnyDef(role))
insertionSet.insert(instIndex + 1, move, inst.origin, tmp, arg);
});
}
Modified: trunk/Source/_javascript_Core/b3/air/AirLiveness.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirLiveness.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirLiveness.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -118,6 +118,13 @@
for (size_t instIndex = block->size(); instIndex--;)
localCalc.execute(instIndex);
+ // Handle the early def's of the first instruction.
+ block->at(0).forEach<typename Adapter::Thing>(
+ [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
+ if (Arg::isEarlyDef(role) && Adapter::acceptsType(type))
+ m_workset.remove(Adapter::valueToIndex(thing));
+ });
+
Vector<unsigned>& liveAtHead = m_liveAtHead[block];
// We only care about Tmps that were discovered in this iteration. It is impossible
@@ -213,10 +220,21 @@
{
Inst& inst = m_block->at(instIndex);
auto& workset = m_liveness.m_workset;
- // First handle def's.
+
+ // First handle the early def's of the next instruction.
+ if (instIndex + 1 < m_block->size()) {
+ Inst& nextInst = m_block->at(instIndex + 1);
+ nextInst.forEach<typename Adapter::Thing>(
+ [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
+ if (Arg::isEarlyDef(role) && Adapter::acceptsType(type))
+ workset.remove(Adapter::valueToIndex(thing));
+ });
+ }
+
+ // Then handle def's.
inst.forEach<typename Adapter::Thing>(
[&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isDef(role) && Adapter::acceptsType(type))
+ if (Arg::isLateDef(role) && Adapter::acceptsType(type))
workset.remove(Adapter::valueToIndex(thing));
});
Modified: trunk/Source/_javascript_Core/b3/air/AirSpillEverything.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirSpillEverything.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirSpillEverything.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,7 +53,7 @@
usedRegisters[block].resize(block->size() + 1);
- auto setUsedRegisters = [&] (unsigned index, Inst& inst) {
+ auto setUsedRegisters = [&] (unsigned index) {
RegisterSet& registerSet = usedRegisters[block][index];
for (Tmp tmp : gpLocalCalc.live()) {
if (tmp.isReg())
@@ -66,23 +66,20 @@
// Gotta account for dead assignments to registers. These may happen because the input
// code is suboptimal.
- inst.forEachTmpWithExtraClobberedRegs(
- index < block->size() ? &block->at(index) : nullptr,
- [®isterSet] (const Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
- if (tmp.isReg() && Arg::isDef(role))
+ Inst::forEachDefWithExtraClobberedRegs<Tmp>(
+ block->get(index - 1), block->get(index),
+ [&] (const Tmp& tmp, Arg::Role, Arg::Type, Arg::Width) {
+ if (tmp.isReg())
registerSet.set(tmp.reg());
});
};
for (unsigned instIndex = block->size(); instIndex--;) {
- Inst& inst = block->at(instIndex);
- setUsedRegisters(instIndex + 1, inst);
+ setUsedRegisters(instIndex + 1);
gpLocalCalc.execute(instIndex);
fpLocalCalc.execute(instIndex);
}
-
- Inst nop;
- setUsedRegisters(0, nop);
+ setUsedRegisters(0);
}
// Allocate a stack slot for each tmp.
@@ -133,6 +130,7 @@
switch (role) {
case Arg::Use:
case Arg::ColdUse:
+ case Arg::EarlyDef:
for (Reg reg : regsInPriorityOrder(type)) {
if (!setBefore.get(reg)) {
setBefore.set(reg);
@@ -154,6 +152,8 @@
case Arg::UseDef:
case Arg::UseZDef:
case Arg::LateUse:
+ case Arg::LateColdUse:
+ case Arg::Scratch:
for (Reg reg : regsInPriorityOrder(type)) {
if (!setBefore.get(reg) && !setAfter.get(reg)) {
setAfter.set(reg);
@@ -174,14 +174,10 @@
Opcode move = type == Arg::GP ? Move : MoveDouble;
- if (Arg::isAnyUse(role)) {
- insertionSet.insert(
- instIndex, move, inst.origin, arg, tmp);
- }
- if (Arg::isDef(role)) {
- insertionSet.insert(
- instIndex + 1, move, inst.origin, tmp, arg);
- }
+ if (Arg::isAnyUse(role) && role != Arg::Scratch)
+ insertionSet.insert(instIndex, move, inst.origin, arg, tmp);
+ if (Arg::isAnyDef(role))
+ insertionSet.insert(instIndex + 1, move, inst.origin, tmp, arg);
});
}
insertionSet.execute(block);
Modified: trunk/Source/_javascript_Core/b3/air/AirTmpWidth.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirTmpWidth.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirTmpWidth.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -119,7 +119,7 @@
if (Arg::isZDef(role))
widths.def = std::max(widths.def, width);
- else if (Arg::isDef(role))
+ else if (Arg::isAnyDef(role))
widths.def = Arg::conservativeWidth(type);
});
}
Modified: trunk/Source/_javascript_Core/b3/air/AirUseCounts.h (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/air/AirUseCounts.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/air/AirUseCounts.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -84,7 +84,7 @@
counts.numWarmUses += frequency;
if (Arg::isColdUse(role))
counts.numColdUses += frequency;
- if (Arg::isDef(role))
+ if (Arg::isAnyDef(role))
counts.numDefs += frequency;
});
}
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (194541 => 194542)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2016-01-04 19:33:35 UTC (rev 194542)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -6157,6 +6157,72 @@
CHECK(compileAndRun<int>(proc, 1, 2) == 3);
}
+void testPatchpointGPScratch()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+ PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
+ patchpoint->append(arg1, ValueRep::SomeRegister);
+ patchpoint->append(arg2, ValueRep::SomeRegister);
+ patchpoint->numGPScratchRegisters = 2;
+ patchpoint->setGenerator(
+ [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ AllowMacroScratchRegisterUsage allowScratch(jit);
+ // We shouldn't have spilled the inputs, so we assert that they're in registers.
+ CHECK(params.size() == 3);
+ CHECK(params[0].isGPR());
+ CHECK(params[1].isGPR());
+ CHECK(params[2].isGPR());
+ CHECK(params.gpScratch(0) != InvalidGPRReg);
+ CHECK(params.gpScratch(0) != params[0].gpr());
+ CHECK(params.gpScratch(0) != params[1].gpr());
+ CHECK(params.gpScratch(0) != params[2].gpr());
+ CHECK(params.gpScratch(1) != InvalidGPRReg);
+ CHECK(params.gpScratch(1) != params.gpScratch(0));
+ CHECK(params.gpScratch(1) != params[0].gpr());
+ CHECK(params.gpScratch(1) != params[1].gpr());
+ CHECK(params.gpScratch(1) != params[2].gpr());
+ CHECK(!params.unavailableRegisters().get(params.gpScratch(0)));
+ CHECK(!params.unavailableRegisters().get(params.gpScratch(1)));
+ add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr());
+ });
+ root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+ CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
+void testPatchpointFPScratch()
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+ PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
+ patchpoint->append(arg1, ValueRep::SomeRegister);
+ patchpoint->append(arg2, ValueRep::SomeRegister);
+ patchpoint->numFPScratchRegisters = 2;
+ patchpoint->setGenerator(
+ [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ AllowMacroScratchRegisterUsage allowScratch(jit);
+ // We shouldn't have spilled the inputs, so we assert that they're in registers.
+ CHECK(params.size() == 3);
+ CHECK(params[0].isGPR());
+ CHECK(params[1].isGPR());
+ CHECK(params[2].isGPR());
+ CHECK(params.fpScratch(0) != InvalidFPRReg);
+ CHECK(params.fpScratch(1) != InvalidFPRReg);
+ CHECK(params.fpScratch(1) != params.fpScratch(0));
+ CHECK(!params.unavailableRegisters().get(params.fpScratch(0)));
+ CHECK(!params.unavailableRegisters().get(params.fpScratch(1)));
+ add32(jit, params[1].gpr(), params[2].gpr(), params[0].gpr());
+ });
+ root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint);
+
+ CHECK(compileAndRun<int>(proc, 1, 2) == 3);
+}
+
void testPatchpointLotsOfLateAnys()
{
Procedure proc;
@@ -9598,6 +9664,8 @@
RUN(testPatchpointFixedRegister());
RUN(testPatchpointAny(ValueRep::WarmAny));
RUN(testPatchpointAny(ValueRep::ColdAny));
+ RUN(testPatchpointGPScratch());
+ RUN(testPatchpointFPScratch());
RUN(testPatchpointLotsOfLateAnys());
RUN(testPatchpointAnyImm(ValueRep::WarmAny));
RUN(testPatchpointAnyImm(ValueRep::ColdAny));
Modified: trunk/Source/_javascript_Core/dfg/DFGCommon.h (194541 => 194542)
--- trunk/Source/_javascript_Core/dfg/DFGCommon.h 2016-01-04 19:27:43 UTC (rev 194541)
+++ trunk/Source/_javascript_Core/dfg/DFGCommon.h 2016-01-04 19:33:35 UTC (rev 194542)
@@ -38,7 +38,7 @@
// We are in the middle of an experimental transition from LLVM to B3 as the backend for the FTL. We don't
// yet know how it will turn out. For now, this flag will control whether FTL uses B3. Remember to set this
// to 0 before committing!
-#define FTL_USES_B3 0
+#define FTL_USES_B3 1
struct Node;