From 548fb463318eee44cbc8c55146c44f25bdb4df35 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Fri, 24 Oct 2014 09:36:40 +0000 Subject: [PATCH] [x86] Fix register constraints for multiply-high. TEST=mjsunit/compiler,unittests R=titzer@chromium.org Review URL: https://codereview.chromium.org/671393002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24862 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler/ia32/instruction-selector-ia32.cc | 5 ++-- src/compiler/instruction.h | 2 +- src/compiler/x64/instruction-selector-x64.cc | 5 ++-- .../mjsunit/compiler/regress-register-allocator.js | 33 ++++++++++++++++++++++ .../ia32/instruction-selector-ia32-unittest.cc | 3 ++ .../compiler/instruction-selector-unittest.cc | 18 ++++++++++++ .../compiler/instruction-selector-unittest.h | 3 ++ .../x64/instruction-selector-x64-unittest.cc | 3 ++ 8 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 test/mjsunit/compiler/regress-register-allocator.js diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index b56230f..894794b 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -469,10 +469,9 @@ void InstructionSelector::VisitInt32Mul(Node* node) { void InstructionSelector::VisitInt32MulHigh(Node* node) { IA32OperandGenerator g(this); InstructionOperand* temps[] = {g.TempRegister(eax)}; - size_t temp_count = arraysize(temps); Emit(kIA32ImulHigh, g.DefineAsFixed(node, edx), - g.UseFixed(node->InputAt(0), eax), g.UseRegister(node->InputAt(1)), - temp_count, temps); + g.UseFixed(node->InputAt(0), eax), g.UseUniqueRegister(node->InputAt(1)), + arraysize(temps), temps); } diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h index d3b8a2c..3a82c11 100644 --- a/src/compiler/instruction.h +++ b/src/compiler/instruction.h @@ -257,7 +257,7 @@ class UnallocatedOperand : public InstructionOperand { } // [lifetime]: Only for non-FIXED_SLOT. - bool IsUsedAtStart() { + bool IsUsedAtStart() const { DCHECK(basic_policy() == EXTENDED_POLICY); return LifetimeField::decode(value_) == USED_AT_START; } diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index 230e000..03240c2 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -560,10 +560,9 @@ void InstructionSelector::VisitInt64Mul(Node* node) { void InstructionSelector::VisitInt32MulHigh(Node* node) { X64OperandGenerator g(this); InstructionOperand* temps[] = {g.TempRegister(rax)}; - size_t temp_count = arraysize(temps); Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx), - g.UseFixed(node->InputAt(0), rax), g.UseRegister(node->InputAt(1)), - temp_count, temps); + g.UseFixed(node->InputAt(0), rax), g.UseUniqueRegister(node->InputAt(1)), + arraysize(temps), temps); } diff --git a/test/mjsunit/compiler/regress-register-allocator.js b/test/mjsunit/compiler/regress-register-allocator.js new file mode 100644 index 0000000..08877ee --- /dev/null +++ b/test/mjsunit/compiler/regress-register-allocator.js @@ -0,0 +1,33 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function Module(stdlib, foreign, buffer) { + "use asm"; + var HEAP32 = new stdlib.Int32Array(buffer); + function g(a) { + HEAP32[a] = 9982 * 100; + return a; + } + function f(i1) { + i1 = i1 | 0; + var i2 = HEAP32[i1 >> 2] | 0; + g(i1); + L2909: { + L2: { + if (0) { + if (0) break L2; + g(i2); + break L2909; + } + } + var r = (HEAP32[1] | 0) / 100 | 0; + g(r); + return r; + } + } + return {f: f}; +} + +var f = Module(this, {}, new ArrayBuffer(64 * 1024)).f; +assertEquals(9982, f(1)); diff --git a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc index 2ce7bca..d1a1726 100644 --- a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -593,9 +593,12 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) { EXPECT_EQ(kIA32ImulHigh, s[0]->arch_opcode()); ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), eax)); EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); ASSERT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), edx)); } } // namespace compiler diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc index 0b58dc0..defc953 100644 --- a/test/unittests/compiler/instruction-selector-unittest.cc +++ b/test/unittests/compiler/instruction-selector-unittest.cc @@ -129,6 +129,24 @@ int InstructionSelectorTest::Stream::ToVreg(const Node* node) const { } +bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand, + Register reg) const { + if (!operand->IsUnallocated()) return false; + const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand); + if (!unallocated->HasFixedRegisterPolicy()) return false; + const int index = Register::ToAllocationIndex(reg); + return unallocated->fixed_register_index() == index; +} + + +bool InstructionSelectorTest::Stream::IsUsedAtStart( + const InstructionOperand* operand) const { + if (!operand->IsUnallocated()) return false; + const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand); + return unallocated->IsUsedAtStart(); +} + + // ----------------------------------------------------------------------------- // Return. diff --git a/test/unittests/compiler/instruction-selector-unittest.h b/test/unittests/compiler/instruction-selector-unittest.h index ee5f610..4e49862 100644 --- a/test/unittests/compiler/instruction-selector-unittest.h +++ b/test/unittests/compiler/instruction-selector-unittest.h @@ -170,6 +170,9 @@ class InstructionSelectorTest : public TestWithContext, public TestWithZone { int ToVreg(const Node* node) const; + bool IsFixed(const InstructionOperand* operand, Register reg) const; + bool IsUsedAtStart(const InstructionOperand* operand) const; + FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) { EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount()); return deoptimization_entries_[deoptimization_id]; diff --git a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index 8470818..dddb70c 100644 --- a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -510,9 +510,12 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) { EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode()); ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax)); EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); ASSERT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx)); } } // namespace compiler -- 2.7.4