Commit 39ed137e authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

ARM: Improve register allocation and constraints (try 2).

Gives ~20% boost for Crypto benchmark on A9.

BUG=none
TEST=added to mjsunit/div-mod.js

Review URL: http://codereview.chromium.org//7276034
Patch from Martyn Capewell <m.m.capewell@googlemail.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8459 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6f666643
......@@ -167,13 +167,14 @@ struct SwVfpRegister {
// Double word VFP register.
struct DwVfpRegister {
// d0 has been excluded from allocation. This is following ia32
// where xmm0 is excluded. This should be revisited.
// Currently d0 is used as a scratch register.
// d1 has also been excluded from allocation to be used as a scratch
// register as well.
static const int kNumRegisters = 16;
static const int kNumAllocatableRegisters = 15;
// A few double registers are reserved: one as a scratch register and one to
// hold 0.0, that does not fit in the immediate field of vmov instructions.
// d14: 0.0
// d15: scratch register.
static const int kNumReservedRegisters = 2;
static const int kNumAllocatableRegisters = kNumRegisters -
kNumReservedRegisters;
static int ToAllocationIndex(DwVfpRegister reg) {
ASSERT(reg.code() != 0);
......@@ -188,6 +189,7 @@ struct DwVfpRegister {
static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = {
"d0",
"d1",
"d2",
"d3",
......@@ -200,9 +202,7 @@ struct DwVfpRegister {
"d10",
"d11",
"d12",
"d13",
"d14",
"d15"
"d13"
};
return names[index];
}
......@@ -306,6 +306,7 @@ const DwVfpRegister d15 = { 15 };
// Aliases for double registers.
const DwVfpRegister kFirstCalleeSavedDoubleReg = d8;
const DwVfpRegister kLastCalleeSavedDoubleReg = d15;
const DwVfpRegister kDoubleRegZero = d14;
// Coprocessor register
......
......@@ -3540,6 +3540,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
CpuFeatures::Scope scope(VFP3);
// Save callee-saved vfp registers.
__ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
// Set up the reserved register for 0.0.
__ vmov(kDoubleRegZero, 0.0);
}
// Get address of argv, see stm above.
......
......@@ -822,7 +822,7 @@ LInstruction* LChunkBuilder::DoBit(Token::Value op,
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
return DefineSameAsFirst(new LBitI(op, left, right));
return DefineAsRegister(new LBitI(op, left, right));
} else {
ASSERT(instr->representation().IsTagged());
ASSERT(instr->left()->representation().IsTagged());
......@@ -861,7 +861,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
right = chunk_->DefineConstantOperand(constant);
constant_value = constant->Integer32Value() & 0x1f;
} else {
right = UseRegister(right_value);
right = UseRegisterAtStart(right_value);
}
// Shift operations can only deoptimize if we do a logical shift
......@@ -878,7 +878,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
}
LInstruction* result =
DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
DefineAsRegister(new LShiftI(op, left, right, does_deopt));
return does_deopt ? AssignEnvironment(result) : result;
}
......@@ -892,7 +892,7 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
LArithmeticD* result = new LArithmeticD(op, left, right);
return DefineSameAsFirst(result);
return DefineAsRegister(result);
}
......@@ -1233,15 +1233,15 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
switch (op) {
case kMathAbs:
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
case kMathFloor:
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
case kMathSqrt:
return DefineSameAsFirst(result);
return DefineAsRegister(result);
case kMathRound:
return AssignEnvironment(DefineAsRegister(result));
case kMathPowHalf:
return DefineSameAsFirst(result);
return DefineAsRegister(result);
default:
UNREACHABLE();
return NULL;
......@@ -1319,7 +1319,7 @@ LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
ASSERT(instr->value()->representation().IsInteger32());
ASSERT(instr->representation().IsInteger32());
return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value())));
return DefineAsRegister(new LBitNotI(UseRegisterAtStart(instr->value())));
}
......@@ -1364,15 +1364,20 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
mod = new LModI(value, UseOrConstant(instr->right()));
} else {
LOperand* dividend = UseRegister(instr->left());
LOperand* divisor = UseRegisterAtStart(instr->right());
LOperand* divisor = UseRegister(instr->right());
mod = new LModI(dividend,
divisor,
TempRegister(),
FixedTemp(d1),
FixedTemp(d2));
FixedTemp(d10),
FixedTemp(d11));
}
return AssignEnvironment(DefineSameAsFirst(mod));
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
instr->CheckFlag(HValue::kCanBeDivByZero)) {
return AssignEnvironment(DefineAsRegister(mod));
} else {
return DefineAsRegister(mod);
}
} else if (instr->representation().IsTagged()) {
return DoArithmeticT(Token::MOD, instr);
} else {
......@@ -1392,15 +1397,18 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
if (instr->representation().IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
LOperand* left;
LOperand* right = UseOrConstant(instr->MostConstantOperand());
LOperand* temp = NULL;
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
(instr->CheckFlag(HValue::kCanOverflow) ||
!right->IsConstantOperand())) {
left = UseRegister(instr->LeastConstantOperand());
temp = TempRegister();
} else {
left = UseRegisterAtStart(instr->LeastConstantOperand());
}
return AssignEnvironment(DefineSameAsFirst(new LMulI(left, right, temp)));
return AssignEnvironment(DefineAsRegister(new LMulI(left, right, temp)));
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MUL, instr);
......@@ -1418,7 +1426,7 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
LSubI* sub = new LSubI(left, right);
LInstruction* result = DefineSameAsFirst(sub);
LInstruction* result = DefineAsRegister(sub);
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
......@@ -1438,7 +1446,7 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
LAddI* add = new LAddI(left, right);
LInstruction* result = DefineSameAsFirst(add);
LInstruction* result = DefineAsRegister(add);
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
......@@ -1604,7 +1612,7 @@ LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister());
return AssignEnvironment(DefineSameAsFirst(result));
return AssignEnvironment(DefineAsRegister(result));
}
......@@ -1659,7 +1667,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
: NULL;
LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d3)
LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d11)
: NULL;
res = DefineSameAsFirst(new LTaggedToI(value, temp1, temp2, temp3));
res = AssignEnvironment(res);
......@@ -1753,14 +1761,14 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
Representation input_rep = value->representation();
LOperand* reg = UseRegister(value);
if (input_rep.IsDouble()) {
return DefineAsRegister(new LClampDToUint8(reg, FixedTemp(d1)));
return DefineAsRegister(new LClampDToUint8(reg, FixedTemp(d11)));
} else if (input_rep.IsInteger32()) {
return DefineAsRegister(new LClampIToUint8(reg));
} else {
ASSERT(input_rep.IsTagged());
// Register allocator doesn't (yet) support allocation of double
// temps. Reserve d1 explicitly.
LClampTToUint8* result = new LClampTToUint8(reg, FixedTemp(d1));
LClampTToUint8* result = new LClampTToUint8(reg, FixedTemp(d11));
return AssignEnvironment(DefineAsRegister(result));
}
}
......@@ -1784,7 +1792,7 @@ LInstruction* LChunkBuilder::DoToInt32(HToInt32* instr) {
ASSERT(input_rep.IsTagged());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* temp3 = FixedTemp(d3);
LOperand* temp3 = FixedTemp(d11);
LTaggedToI* res = new LTaggedToI(reg, temp1, temp2, temp3);
return AssignEnvironment(DefineSameAsFirst(res));
}
......@@ -1922,7 +1930,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
return AssignEnvironment(DefineSameAsFirst(result));
return AssignEnvironment(DefineAsRegister(result));
}
......
This diff is collapsed.
......@@ -148,7 +148,7 @@ class LCodeGen BASE_EMBEDDED {
HGraph* graph() const { return chunk_->graph(); }
Register scratch0() { return r9; }
DwVfpRegister double_scratch0() { return d0; }
DwVfpRegister double_scratch0() { return d15; }
int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction();
......
......@@ -309,9 +309,9 @@ void MacroAssembler::Move(Register dst, Handle<Object> value) {
}
void MacroAssembler::Move(Register dst, Register src) {
void MacroAssembler::Move(Register dst, Register src, Condition cond) {
if (!dst.is(src)) {
mov(dst, src);
mov(dst, src, LeaveCC, cond);
}
}
......@@ -755,6 +755,23 @@ void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
vmrs(fpscr_flags, cond);
}
void MacroAssembler::Vmov(const DwVfpRegister dst,
const double imm,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
static const DoubleRepresentation minus_zero(-0.0);
static const DoubleRepresentation zero(0.0);
DoubleRepresentation value(imm);
// Handle special values first.
if (value.bits == zero.bits) {
vmov(dst, kDoubleRegZero, cond);
} else if (value.bits == minus_zero.bits) {
vneg(dst, kDoubleRegZero, cond);
} else {
vmov(dst, imm, cond);
}
}
void MacroAssembler::EnterFrame(StackFrame::Type type) {
// r0-r3: preserved
......@@ -3101,7 +3118,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
Label done;
Label in_bounds;
vmov(temp_double_reg, 0.0);
Vmov(temp_double_reg, 0.0);
VFPCompareAndSetFlags(input_reg, temp_double_reg);
b(gt, &above_zero);
......@@ -3111,7 +3128,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
// Double value is >= 255, return 255.
bind(&above_zero);
vmov(temp_double_reg, 255.0);
Vmov(temp_double_reg, 255.0);
VFPCompareAndSetFlags(input_reg, temp_double_reg);
b(le, &in_bounds);
mov(result_reg, Operand(255));
......@@ -3119,7 +3136,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
// In 0-255 range, round and truncate.
bind(&in_bounds);
vmov(temp_double_reg, 0.5);
Vmov(temp_double_reg, 0.5);
vadd(temp_double_reg, input_reg, temp_double_reg);
vcvt_u32_f64(s0, temp_double_reg);
vmov(result_reg, s0);
......
......@@ -143,7 +143,7 @@ class MacroAssembler: public Assembler {
// Register move. May do nothing if the registers are identical.
void Move(Register dst, Handle<Object> value);
void Move(Register dst, Register src);
void Move(Register dst, Register src, Condition cond = al);
void Move(DoubleRegister dst, DoubleRegister src);
// Load an object from the root table.
......@@ -312,6 +312,10 @@ class MacroAssembler: public Assembler {
const Register fpscr_flags,
const Condition cond = al);
void Vmov(const DwVfpRegister dst,
const double imm,
const Condition cond = al);
// ---------------------------------------------------------------------------
// Activation frames
......
......@@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Test fast div and mod.
function divmod(div_func, mod_func, x, y) {
......@@ -190,3 +192,113 @@ function negative_zero_modulus_test() {
}
negative_zero_modulus_test();
function lithium_integer_mod() {
var left_operands = [
0,
305419896, // 0x12345678
];
// Test the standard lithium code for modulo opeartions.
var mod_func;
for (var i = 0; i < left_operands.length; i++) {
for (var j = 0; j < divisors.length; j++) {
mod_func = this.eval("(function(left) { return left % " + divisors[j]+ "; })");
assertEquals((mod_func)(left_operands[i]), left_operands[i] % divisors[j]);
assertEquals((mod_func)(-left_operands[i]), -left_operands[i] % divisors[j]);
}
}
var results_powers_of_two = [
// 0
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
// 305419896 == 0x12345678
[0, 0, 0, 8, 24, 56, 120, 120, 120, 632, 1656, 1656, 5752, 5752, 22136, 22136, 22136, 22136, 284280, 284280, 1332856, 3430008, 3430008, 3430008, 3430008, 36984440, 36984440, 36984440, 305419896, 305419896, 305419896],
];
// Test the lithium code for modulo operations with a variable power of two
// right hand side operand.
for (var i = 0; i < left_operands.length; i++) {
for (var j = 0; j < 31; j++) {
assertEquals(results_powers_of_two[i][j], left_operands[i] % (2 << j));
assertEquals(results_powers_of_two[i][j], left_operands[i] % -(2 << j));
assertEquals(-results_powers_of_two[i][j], -left_operands[i] % (2 << j));
assertEquals(-results_powers_of_two[i][j], -left_operands[i] % -(2 << j));
}
}
// Test the lithium code for modulo operations with a constant power of two
// right hand side operand.
for (var i = 0; i < left_operands.length; i++) {
// With positive left hand side operand.
assertEquals(results_powers_of_two[i][0], left_operands[i] % -(2 << 0));
assertEquals(results_powers_of_two[i][1], left_operands[i] % (2 << 1));
assertEquals(results_powers_of_two[i][2], left_operands[i] % -(2 << 2));
assertEquals(results_powers_of_two[i][3], left_operands[i] % (2 << 3));
assertEquals(results_powers_of_two[i][4], left_operands[i] % -(2 << 4));
assertEquals(results_powers_of_two[i][5], left_operands[i] % (2 << 5));
assertEquals(results_powers_of_two[i][6], left_operands[i] % -(2 << 6));
assertEquals(results_powers_of_two[i][7], left_operands[i] % (2 << 7));
assertEquals(results_powers_of_two[i][8], left_operands[i] % -(2 << 8));
assertEquals(results_powers_of_two[i][9], left_operands[i] % (2 << 9));
assertEquals(results_powers_of_two[i][10], left_operands[i] % -(2 << 10));
assertEquals(results_powers_of_two[i][11], left_operands[i] % (2 << 11));
assertEquals(results_powers_of_two[i][12], left_operands[i] % -(2 << 12));
assertEquals(results_powers_of_two[i][13], left_operands[i] % (2 << 13));
assertEquals(results_powers_of_two[i][14], left_operands[i] % -(2 << 14));
assertEquals(results_powers_of_two[i][15], left_operands[i] % (2 << 15));
assertEquals(results_powers_of_two[i][16], left_operands[i] % -(2 << 16));
assertEquals(results_powers_of_two[i][17], left_operands[i] % (2 << 17));
assertEquals(results_powers_of_two[i][18], left_operands[i] % -(2 << 18));
assertEquals(results_powers_of_two[i][19], left_operands[i] % (2 << 19));
assertEquals(results_powers_of_two[i][20], left_operands[i] % -(2 << 20));
assertEquals(results_powers_of_two[i][21], left_operands[i] % (2 << 21));
assertEquals(results_powers_of_two[i][22], left_operands[i] % -(2 << 22));
assertEquals(results_powers_of_two[i][23], left_operands[i] % (2 << 23));
assertEquals(results_powers_of_two[i][24], left_operands[i] % -(2 << 24));
assertEquals(results_powers_of_two[i][25], left_operands[i] % (2 << 25));
assertEquals(results_powers_of_two[i][26], left_operands[i] % -(2 << 26));
assertEquals(results_powers_of_two[i][27], left_operands[i] % (2 << 27));
assertEquals(results_powers_of_two[i][28], left_operands[i] % -(2 << 28));
assertEquals(results_powers_of_two[i][29], left_operands[i] % (2 << 29));
assertEquals(results_powers_of_two[i][30], left_operands[i] % -(2 << 30));
// With negative left hand side operand.
assertEquals(-results_powers_of_two[i][0], -left_operands[i] % -(2 << 0));
assertEquals(-results_powers_of_two[i][1], -left_operands[i] % (2 << 1));
assertEquals(-results_powers_of_two[i][2], -left_operands[i] % -(2 << 2));
assertEquals(-results_powers_of_two[i][3], -left_operands[i] % (2 << 3));
assertEquals(-results_powers_of_two[i][4], -left_operands[i] % -(2 << 4));
assertEquals(-results_powers_of_two[i][5], -left_operands[i] % (2 << 5));
assertEquals(-results_powers_of_two[i][6], -left_operands[i] % -(2 << 6));
assertEquals(-results_powers_of_two[i][7], -left_operands[i] % (2 << 7));
assertEquals(-results_powers_of_two[i][8], -left_operands[i] % -(2 << 8));
assertEquals(-results_powers_of_two[i][9], -left_operands[i] % (2 << 9));
assertEquals(-results_powers_of_two[i][10], -left_operands[i] % -(2 << 10));
assertEquals(-results_powers_of_two[i][11], -left_operands[i] % (2 << 11));
assertEquals(-results_powers_of_two[i][12], -left_operands[i] % -(2 << 12));
assertEquals(-results_powers_of_two[i][13], -left_operands[i] % (2 << 13));
assertEquals(-results_powers_of_two[i][14], -left_operands[i] % -(2 << 14));
assertEquals(-results_powers_of_two[i][15], -left_operands[i] % (2 << 15));
assertEquals(-results_powers_of_two[i][16], -left_operands[i] % -(2 << 16));
assertEquals(-results_powers_of_two[i][17], -left_operands[i] % (2 << 17));
assertEquals(-results_powers_of_two[i][18], -left_operands[i] % -(2 << 18));
assertEquals(-results_powers_of_two[i][19], -left_operands[i] % (2 << 19));
assertEquals(-results_powers_of_two[i][20], -left_operands[i] % -(2 << 20));
assertEquals(-results_powers_of_two[i][21], -left_operands[i] % (2 << 21));
assertEquals(-results_powers_of_two[i][22], -left_operands[i] % -(2 << 22));
assertEquals(-results_powers_of_two[i][23], -left_operands[i] % (2 << 23));
assertEquals(-results_powers_of_two[i][24], -left_operands[i] % -(2 << 24));
assertEquals(-results_powers_of_two[i][25], -left_operands[i] % (2 << 25));
assertEquals(-results_powers_of_two[i][26], -left_operands[i] % -(2 << 26));
assertEquals(-results_powers_of_two[i][27], -left_operands[i] % (2 << 27));
assertEquals(-results_powers_of_two[i][28], -left_operands[i] % -(2 << 28));
assertEquals(-results_powers_of_two[i][29], -left_operands[i] % (2 << 29));
assertEquals(-results_powers_of_two[i][30], -left_operands[i] % -(2 << 30));
}
}
lithium_integer_mod();
%OptimizeFunctionOnNextCall(lithium_integer_mod)
lithium_integer_mod();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment