Commit 55b01ccb authored by bbudge's avatar bbudge Committed by Commit bot

[Turbofan] Revert FP register aliasing support on Arm.

- Changes register allocation to only use even numbered registers on Arm.
- Turns on float32 testing in test-gap-resolver.cc.

This is effectively a revert of:
https://codereview.chromium.org/2086653003/

LOG=N
BUG=V8:4124, V8:5202

Review-Url: https://codereview.chromium.org/2176173003
Cr-Commit-Position: refs/heads/master@{#38151}
parent c07c675e
This diff is collapsed.
...@@ -65,14 +65,7 @@ FlagsCondition CommuteFlagsCondition(FlagsCondition condition) { ...@@ -65,14 +65,7 @@ FlagsCondition CommuteFlagsCondition(FlagsCondition condition) {
} }
bool InstructionOperand::InterferesWith(const InstructionOperand& that) const { bool InstructionOperand::InterferesWith(const InstructionOperand& that) const {
if (!IsFPRegister() || !that.IsFPRegister() || kSimpleFPAliasing) return EqualsCanonicalized(that);
return EqualsCanonicalized(that);
// Both operands are fp registers and aliasing is non-simple.
const LocationOperand& loc1 = *LocationOperand::cast(this);
const LocationOperand& loc2 = LocationOperand::cast(that);
return GetRegConfig()->AreAliases(loc1.representation(), loc1.register_code(),
loc2.representation(),
loc2.register_code());
} }
void InstructionOperand::Print(const RegisterConfiguration* config) const { void InstructionOperand::Print(const RegisterConfiguration* config) const {
......
...@@ -607,14 +607,8 @@ uint64_t InstructionOperand::GetCanonicalizedValue() const { ...@@ -607,14 +607,8 @@ uint64_t InstructionOperand::GetCanonicalizedValue() const {
if (IsAllocated() || IsExplicit()) { if (IsAllocated() || IsExplicit()) {
MachineRepresentation canonical = MachineRepresentation::kNone; MachineRepresentation canonical = MachineRepresentation::kNone;
if (IsFPRegister()) { if (IsFPRegister()) {
if (kSimpleFPAliasing) { // We treat all FP register operands the same for simple aliasing.
// We treat all FP register operands the same for simple aliasing. canonical = MachineRepresentation::kFloat64;
canonical = MachineRepresentation::kFloat64;
} else {
// We need to distinguish FP register operands of different reps when
// aliasing is not simple (e.g. ARM).
canonical = LocationOperand::cast(this)->representation();
}
} }
return InstructionOperand::KindField::update( return InstructionOperand::KindField::update(
LocationOperand::RepresentationField::update(this->value_, canonical), LocationOperand::RepresentationField::update(this->value_, canonical),
......
...@@ -28,48 +28,20 @@ typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap; ...@@ -28,48 +28,20 @@ typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap;
typedef ZoneSet<InstructionOperand, CompareOperandModuloType> OperandSet; typedef ZoneSet<InstructionOperand, CompareOperandModuloType> OperandSet;
bool Blocks(const OperandSet& set, const InstructionOperand& operand) { bool Blocks(const OperandSet& set, const InstructionOperand& operand) {
if (set.find(operand) != set.end()) return true; if (!operand.IsFPRegister()) return set.find(operand) != set.end();
// Only FP registers on archs with non-simple aliasing need extra checks.
if (!operand.IsFPRegister() || kSimpleFPAliasing) return false;
// Check operand against operands of other FP types for interference.
const LocationOperand& loc = LocationOperand::cast(operand); const LocationOperand& loc = LocationOperand::cast(operand);
MachineRepresentation rep = loc.representation(); if (loc.representation() == MachineRepresentation::kFloat64) {
MachineRepresentation other_rep1, other_rep2; return set.find(operand) != set.end() ||
switch (rep) { set.find(LocationOperand(loc.kind(), loc.location_kind(),
case MachineRepresentation::kFloat32: MachineRepresentation::kFloat32,
other_rep1 = MachineRepresentation::kFloat64; loc.register_code())) != set.end();
other_rep2 = MachineRepresentation::kSimd128; }
break; DCHECK_EQ(MachineRepresentation::kFloat32, loc.representation());
case MachineRepresentation::kFloat64: return set.find(operand) != set.end() ||
other_rep1 = MachineRepresentation::kFloat32; set.find(LocationOperand(loc.kind(), loc.location_kind(),
other_rep2 = MachineRepresentation::kSimd128; MachineRepresentation::kFloat64,
break; loc.register_code())) != set.end();
case MachineRepresentation::kSimd128:
other_rep1 = MachineRepresentation::kFloat32;
other_rep2 = MachineRepresentation::kFloat64;
break;
default:
UNREACHABLE();
break;
}
const RegisterConfiguration* config = RegisterConfiguration::Turbofan();
int base = -1;
int aliases = config->GetAliases(rep, loc.register_code(), other_rep1, &base);
DCHECK(aliases > 0 || (aliases == 0 && base == -1));
while (aliases--) {
if (set.find(LocationOperand(loc.kind(), loc.location_kind(), other_rep1,
base + aliases)) != set.end())
return true;
}
aliases = config->GetAliases(rep, loc.register_code(), other_rep2, &base);
DCHECK(aliases > 0 || (aliases == 0 && base == -1));
while (aliases--) {
if (set.find(LocationOperand(loc.kind(), loc.location_kind(), other_rep2,
base + aliases)) != set.end())
return true;
}
return false;
} }
int FindFirstNonEmptySlot(const Instruction* instr) { int FindFirstNonEmptySlot(const Instruction* instr) {
......
This diff is collapsed.
...@@ -766,24 +766,12 @@ class RegisterAllocationData final : public ZoneObject { ...@@ -766,24 +766,12 @@ class RegisterAllocationData final : public ZoneObject {
ZoneVector<TopLevelLiveRange*>& fixed_live_ranges() { ZoneVector<TopLevelLiveRange*>& fixed_live_ranges() {
return fixed_live_ranges_; return fixed_live_ranges_;
} }
ZoneVector<TopLevelLiveRange*>& fixed_float_live_ranges() {
return fixed_float_live_ranges_;
}
const ZoneVector<TopLevelLiveRange*>& fixed_float_live_ranges() const {
return fixed_float_live_ranges_;
}
ZoneVector<TopLevelLiveRange*>& fixed_double_live_ranges() { ZoneVector<TopLevelLiveRange*>& fixed_double_live_ranges() {
return fixed_double_live_ranges_; return fixed_double_live_ranges_;
} }
const ZoneVector<TopLevelLiveRange*>& fixed_double_live_ranges() const { const ZoneVector<TopLevelLiveRange*>& fixed_double_live_ranges() const {
return fixed_double_live_ranges_; return fixed_double_live_ranges_;
} }
ZoneVector<TopLevelLiveRange*>& fixed_simd128_live_ranges() {
return fixed_simd128_live_ranges_;
}
const ZoneVector<TopLevelLiveRange*>& fixed_simd128_live_ranges() const {
return fixed_simd128_live_ranges_;
}
ZoneVector<BitVector*>& live_in_sets() { return live_in_sets_; } ZoneVector<BitVector*>& live_in_sets() { return live_in_sets_; }
ZoneVector<BitVector*>& live_out_sets() { return live_out_sets_; } ZoneVector<BitVector*>& live_out_sets() { return live_out_sets_; }
ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; } ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
...@@ -845,9 +833,7 @@ class RegisterAllocationData final : public ZoneObject { ...@@ -845,9 +833,7 @@ class RegisterAllocationData final : public ZoneObject {
ZoneVector<BitVector*> live_out_sets_; ZoneVector<BitVector*> live_out_sets_;
ZoneVector<TopLevelLiveRange*> live_ranges_; ZoneVector<TopLevelLiveRange*> live_ranges_;
ZoneVector<TopLevelLiveRange*> fixed_live_ranges_; ZoneVector<TopLevelLiveRange*> fixed_live_ranges_;
ZoneVector<TopLevelLiveRange*> fixed_float_live_ranges_;
ZoneVector<TopLevelLiveRange*> fixed_double_live_ranges_; ZoneVector<TopLevelLiveRange*> fixed_double_live_ranges_;
ZoneVector<TopLevelLiveRange*> fixed_simd128_live_ranges_;
ZoneVector<SpillRange*> spill_ranges_; ZoneVector<SpillRange*> spill_ranges_;
DelayedReferences delayed_references_; DelayedReferences delayed_references_;
BitVector* assigned_registers_; BitVector* assigned_registers_;
......
...@@ -177,17 +177,6 @@ struct Allocator { ...@@ -177,17 +177,6 @@ struct Allocator {
// Allocate a floating point register/stack location. // Allocate a floating point register/stack location.
if (fp_offset < fp_count) { if (fp_offset < fp_count) {
DoubleRegister reg = fp_regs[fp_offset++]; DoubleRegister reg = fp_regs[fp_offset++];
#if V8_TARGET_ARCH_ARM
// Allocate floats using a double register, but modify the code to
// reflect how ARM FP registers alias.
// TODO(bbudge) Modify wasm linkage to allow use of all float regs.
if (type == kAstF32) {
int float_reg_code = reg.code() * 2;
DCHECK(float_reg_code < RegisterConfiguration::kMaxFPRegisters);
return regloc(DoubleRegister::from_code(float_reg_code),
MachineTypeFor(type));
}
#endif
return regloc(reg, MachineTypeFor(type)); return regloc(reg, MachineTypeFor(type));
} else { } else {
int offset = -1 - stack_offset; int offset = -1 - stack_offset;
......
...@@ -70,12 +70,15 @@ class ArchDefaultRegisterConfiguration : public RegisterConfiguration { ...@@ -70,12 +70,15 @@ class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
#if V8_TARGET_ARCH_IA32 #if V8_TARGET_ARCH_IA32
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_X87 #elif V8_TARGET_ARCH_X87
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
compiler == TURBOFAN ? 1 : kMaxAllocatableDoubleRegisterCount, compiler == TURBOFAN ? 1 : kMaxAllocatableDoubleRegisterCount,
compiler == TURBOFAN ? 1 : kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_X64 #elif V8_TARGET_ARCH_X64
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_ARM #elif V8_TARGET_ARCH_ARM
FLAG_enable_embedded_constant_pool FLAG_enable_embedded_constant_pool
? (kMaxAllocatableGeneralRegisterCount - 1) ? (kMaxAllocatableGeneralRegisterCount - 1)
...@@ -83,21 +86,27 @@ class ArchDefaultRegisterConfiguration : public RegisterConfiguration { ...@@ -83,21 +86,27 @@ class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
CpuFeatures::IsSupported(VFP32DREGS) CpuFeatures::IsSupported(VFP32DREGS)
? kMaxAllocatableDoubleRegisterCount ? kMaxAllocatableDoubleRegisterCount
: (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0), : (ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0),
ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(REGISTER_COUNT) 0,
#elif V8_TARGET_ARCH_ARM64 #elif V8_TARGET_ARCH_ARM64
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_MIPS #elif V8_TARGET_ARCH_MIPS
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_MIPS64 #elif V8_TARGET_ARCH_MIPS64
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_PPC #elif V8_TARGET_ARCH_PPC
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#elif V8_TARGET_ARCH_S390 #elif V8_TARGET_ARCH_S390
kMaxAllocatableGeneralRegisterCount, kMaxAllocatableGeneralRegisterCount,
kMaxAllocatableDoubleRegisterCount, kMaxAllocatableDoubleRegisterCount,
kMaxAllocatableDoubleRegisterCount,
#else #else
#error Unsupported target architecture. #error Unsupported target architecture.
#endif #endif
...@@ -136,6 +145,7 @@ const RegisterConfiguration* RegisterConfiguration::Turbofan() { ...@@ -136,6 +145,7 @@ const RegisterConfiguration* RegisterConfiguration::Turbofan() {
RegisterConfiguration::RegisterConfiguration( RegisterConfiguration::RegisterConfiguration(
int num_general_registers, int num_double_registers, int num_general_registers, int num_double_registers,
int num_allocatable_general_registers, int num_allocatable_double_registers, int num_allocatable_general_registers, int num_allocatable_double_registers,
int num_allocatable_aliased_double_registers,
const int* allocatable_general_codes, const int* allocatable_double_codes, const int* allocatable_general_codes, const int* allocatable_double_codes,
AliasingKind fp_aliasing_kind, const char* const* general_register_names, AliasingKind fp_aliasing_kind, const char* const* general_register_names,
const char* const* float_register_names, const char* const* float_register_names,
...@@ -148,6 +158,8 @@ RegisterConfiguration::RegisterConfiguration( ...@@ -148,6 +158,8 @@ RegisterConfiguration::RegisterConfiguration(
num_allocatable_general_registers_(num_allocatable_general_registers), num_allocatable_general_registers_(num_allocatable_general_registers),
num_allocatable_float_registers_(0), num_allocatable_float_registers_(0),
num_allocatable_double_registers_(num_allocatable_double_registers), num_allocatable_double_registers_(num_allocatable_double_registers),
num_allocatable_aliased_double_registers_(
num_allocatable_aliased_double_registers),
num_allocatable_simd128_registers_(0), num_allocatable_simd128_registers_(0),
allocatable_general_codes_mask_(0), allocatable_general_codes_mask_(0),
allocatable_float_codes_mask_(0), allocatable_float_codes_mask_(0),
......
...@@ -35,6 +35,7 @@ class RegisterConfiguration { ...@@ -35,6 +35,7 @@ class RegisterConfiguration {
RegisterConfiguration(int num_general_registers, int num_double_registers, RegisterConfiguration(int num_general_registers, int num_double_registers,
int num_allocatable_general_registers, int num_allocatable_general_registers,
int num_allocatable_double_registers, int num_allocatable_double_registers,
int num_allocatable_aliased_double_registers,
const int* allocatable_general_codes, const int* allocatable_general_codes,
const int* allocatable_double_codes, const int* allocatable_double_codes,
AliasingKind fp_aliasing_kind, AliasingKind fp_aliasing_kind,
...@@ -56,6 +57,12 @@ class RegisterConfiguration { ...@@ -56,6 +57,12 @@ class RegisterConfiguration {
int num_allocatable_double_registers() const { int num_allocatable_double_registers() const {
return num_allocatable_double_registers_; return num_allocatable_double_registers_;
} }
// TODO(bbudge): This is a temporary work-around required because our
// register allocator does not yet support the aliasing of single/double
// registers on ARM.
int num_allocatable_aliased_double_registers() const {
return num_allocatable_aliased_double_registers_;
}
int num_allocatable_simd128_registers() const { int num_allocatable_simd128_registers() const {
return num_allocatable_simd128_registers_; return num_allocatable_simd128_registers_;
} }
...@@ -135,6 +142,7 @@ class RegisterConfiguration { ...@@ -135,6 +142,7 @@ class RegisterConfiguration {
int num_allocatable_general_registers_; int num_allocatable_general_registers_;
int num_allocatable_float_registers_; int num_allocatable_float_registers_;
int num_allocatable_double_registers_; int num_allocatable_double_registers_;
int num_allocatable_aliased_double_registers_;
int num_allocatable_simd128_registers_; int num_allocatable_simd128_registers_;
int32_t allocatable_general_codes_mask_; int32_t allocatable_general_codes_mask_;
int32_t allocatable_float_codes_mask_; int32_t allocatable_float_codes_mask_;
......
...@@ -83,8 +83,7 @@ class InterpreterState { ...@@ -83,8 +83,7 @@ class InterpreterState {
const LocationOperand& loc_op = LocationOperand::cast(op); const LocationOperand& loc_op = LocationOperand::cast(op);
if (loc_op.IsAnyRegister()) { if (loc_op.IsAnyRegister()) {
if (loc_op.IsFPRegister()) { if (loc_op.IsFPRegister()) {
rep = kSimpleFPAliasing ? MachineRepresentation::kFloat64 rep = MachineRepresentation::kFloat64;
: loc_op.representation();
} }
index = loc_op.register_code(); index = loc_op.register_code();
} else { } else {
...@@ -186,10 +185,7 @@ class ParallelMoveCreator : public HandleAndZoneScope { ...@@ -186,10 +185,7 @@ class ParallelMoveCreator : public HandleAndZoneScope {
case 1: case 1:
return MachineRepresentation::kWord64; return MachineRepresentation::kWord64;
case 2: case 2:
// TODO(bbudge) Re-enable float operands when GapResolver correctly return MachineRepresentation::kFloat32;
// handles FP aliasing.
return kSimpleFPAliasing ? MachineRepresentation::kFloat32
: MachineRepresentation::kFloat64;
case 3: case 3:
return MachineRepresentation::kFloat64; return MachineRepresentation::kFloat64;
case 4: case 4:
...@@ -205,13 +201,18 @@ class ParallelMoveCreator : public HandleAndZoneScope { ...@@ -205,13 +201,18 @@ class ParallelMoveCreator : public HandleAndZoneScope {
auto GetRegisterCode = [&conf](MachineRepresentation rep, int index) { auto GetRegisterCode = [&conf](MachineRepresentation rep, int index) {
switch (rep) { switch (rep) {
case MachineRepresentation::kFloat32: case MachineRepresentation::kFloat32:
#if V8_TARGET_ARCH_ARM
// Only even number float registers are used on Arm.
// TODO(bbudge) Eliminate this when FP register aliasing works.
return conf->RegisterConfiguration::GetAllocatableDoubleCode(index) *
2;
#endif
// Fall through on non-Arm targets.
case MachineRepresentation::kFloat64: case MachineRepresentation::kFloat64:
return conf->RegisterConfiguration::GetAllocatableDoubleCode(index); return conf->RegisterConfiguration::GetAllocatableDoubleCode(index);
break;
default: default:
return conf->RegisterConfiguration::GetAllocatableGeneralCode(index); return conf->RegisterConfiguration::GetAllocatableGeneralCode(index);
break;
} }
UNREACHABLE(); UNREACHABLE();
return static_cast<int>(Register::kCode_no_reg); return static_cast<int>(Register::kCode_no_reg);
......
...@@ -87,16 +87,8 @@ class RegisterPairs : public Pairs { ...@@ -87,16 +87,8 @@ class RegisterPairs : public Pairs {
class Float32RegisterPairs : public Pairs { class Float32RegisterPairs : public Pairs {
public: public:
Float32RegisterPairs() Float32RegisterPairs()
: Pairs( : Pairs(100, GetRegConfig()->num_allocatable_aliased_double_registers(),
100, GetRegConfig()->allocatable_double_codes()) {}
#if V8_TARGET_ARCH_ARM
// TODO(bbudge) Modify wasm linkage to allow use of all float regs.
GetRegConfig()->num_allocatable_double_registers() / 2 - 2,
#else
GetRegConfig()->num_allocatable_double_registers(),
#endif
GetRegConfig()->allocatable_double_codes()) {
}
}; };
...@@ -135,10 +127,6 @@ struct Allocator { ...@@ -135,10 +127,6 @@ struct Allocator {
// Allocate a floating point register/stack location. // Allocate a floating point register/stack location.
if (fp_offset < fp_count) { if (fp_offset < fp_count) {
int code = fp_regs[fp_offset++]; int code = fp_regs[fp_offset++];
#if V8_TARGET_ARCH_ARM
// TODO(bbudge) Modify wasm linkage to allow use of all float regs.
if (type.representation() == MachineRepresentation::kFloat32) code *= 2;
#endif
return LinkageLocation::ForRegister(code, type); return LinkageLocation::ForRegister(code, type);
} else { } else {
int offset = -1 - stack_offset; int offset = -1 - stack_offset;
......
...@@ -67,7 +67,8 @@ RegisterConfiguration* InstructionSequenceTest::config() { ...@@ -67,7 +67,8 @@ RegisterConfiguration* InstructionSequenceTest::config() {
if (!config_) { if (!config_) {
config_.reset(new RegisterConfiguration( config_.reset(new RegisterConfiguration(
num_general_registers_, num_double_registers_, num_general_registers_, num_general_registers_, num_double_registers_, num_general_registers_,
num_double_registers_, allocatable_codes, allocatable_double_codes, num_double_registers_, num_double_registers_, allocatable_codes,
allocatable_double_codes,
kSimpleFPAliasing ? RegisterConfiguration::OVERLAP kSimpleFPAliasing ? RegisterConfiguration::OVERLAP
: RegisterConfiguration::COMBINE, : RegisterConfiguration::COMBINE,
general_register_names_, general_register_names_,
......
...@@ -30,8 +30,9 @@ TEST_F(RegisterConfigurationUnitTest, BasicProperties) { ...@@ -30,8 +30,9 @@ TEST_F(RegisterConfigurationUnitTest, BasicProperties) {
RegisterConfiguration test( RegisterConfiguration test(
kNumGeneralRegs, kNumDoubleRegs, kNumAllocatableGeneralRegs, kNumGeneralRegs, kNumDoubleRegs, kNumAllocatableGeneralRegs,
kNumAllocatableDoubleRegs, general_codes, double_codes, kNumAllocatableDoubleRegs, kNumAllocatableDoubleRegs, general_codes,
RegisterConfiguration::OVERLAP, nullptr, nullptr, nullptr, nullptr); double_codes, RegisterConfiguration::OVERLAP, nullptr, nullptr, nullptr,
nullptr);
EXPECT_EQ(test.num_general_registers(), kNumGeneralRegs); EXPECT_EQ(test.num_general_registers(), kNumGeneralRegs);
EXPECT_EQ(test.num_double_registers(), kNumDoubleRegs); EXPECT_EQ(test.num_double_registers(), kNumDoubleRegs);
...@@ -66,8 +67,9 @@ TEST_F(RegisterConfigurationUnitTest, CombineAliasing) { ...@@ -66,8 +67,9 @@ TEST_F(RegisterConfigurationUnitTest, CombineAliasing) {
RegisterConfiguration test( RegisterConfiguration test(
kNumGeneralRegs, kNumDoubleRegs, kNumAllocatableGeneralRegs, kNumGeneralRegs, kNumDoubleRegs, kNumAllocatableGeneralRegs,
kNumAllocatableDoubleRegs, general_codes, double_codes, kNumAllocatableDoubleRegs, kNumAllocatableDoubleRegs, general_codes,
RegisterConfiguration::COMBINE, nullptr, nullptr, nullptr, nullptr); double_codes, RegisterConfiguration::COMBINE, nullptr, nullptr, nullptr,
nullptr);
// There are 3 allocatable double regs, but only 2 can alias float regs. // There are 3 allocatable double regs, but only 2 can alias float regs.
EXPECT_EQ(test.num_allocatable_float_registers(), 4); EXPECT_EQ(test.num_allocatable_float_registers(), 4);
......
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