From 226e579c3004a37a09f3329a8ef09c0933126bd6 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Fri, 16 Dec 2022 08:45:52 +0000 Subject: [PATCH] 8298088: RISC-V: Make Address a discriminated union internally Reviewed-by: fjiang, yadongwang, shade --- src/hotspot/cpu/riscv/assembler_riscv.cpp | 45 +++++--- src/hotspot/cpu/riscv/assembler_riscv.hpp | 134 ++++++++++++++++------ 2 files changed, 130 insertions(+), 49 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp index 2fb75c802cf..6a581a4d081 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp @@ -40,8 +40,20 @@ int AbstractAssembler::code_fill_byte() { return 0; } -Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _offset(0), _mode(literal) { - _target = target; +#ifdef ASSERT + +void Address::assert_is_literal() const { + assert(_mode == literal, "addressing mode is non-literal: %d", _mode); +} + +void Address::assert_is_nonliteral() const { + assert(_mode != literal, "unexpected literal addressing mode"); + assert(_mode != no_mode, "unexpected no_mode addressing mode"); +} + +#endif // ASSERT + +static RelocationHolder address_relocation(address target, relocInfo::relocType rtype) { switch (rtype) { case relocInfo::oop_type: case relocInfo::metadata_type: @@ -49,30 +61,29 @@ Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _of // but in cases like icBuffer they are literals in the code stream that // we don't have a section for. We use none so that we get a literal address // which is always patchable. - break; + return RelocationHolder::none; case relocInfo::external_word_type: - _rspec = external_word_Relocation::spec(target); - break; + return external_word_Relocation::spec(target); case relocInfo::internal_word_type: - _rspec = internal_word_Relocation::spec(target); - break; + return internal_word_Relocation::spec(target); case relocInfo::opt_virtual_call_type: - _rspec = opt_virtual_call_Relocation::spec(); - break; + return opt_virtual_call_Relocation::spec(); case relocInfo::static_call_type: - _rspec = static_call_Relocation::spec(); - break; + return static_call_Relocation::spec(); case relocInfo::runtime_call_type: - _rspec = runtime_call_Relocation::spec(); - break; + return runtime_call_Relocation::spec(); case relocInfo::poll_type: case relocInfo::poll_return_type: - _rspec = Relocation::spec_simple(rtype); - break; + return Relocation::spec_simple(rtype); case relocInfo::none: - _rspec = RelocationHolder::none; - break; + return RelocationHolder::none; default: ShouldNotReachHere(); + return RelocationHolder::none; } } + +Address::Address(address target, relocInfo::relocType rtype) : + _mode(literal), + _literal(target, address_relocation(target, rtype)) +{} diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index debc809d5ae..62a81bd1551 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -30,6 +30,10 @@ #include "asm/register.hpp" #include "assembler_riscv.inline.hpp" #include "metaprogramming/enableIf.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#include #define XLEN 64 @@ -153,62 +157,128 @@ const FloatRegister g_FPArgReg[Argument::n_float_register_parameters_c] = { class Address { public: - enum mode { no_mode, base_plus_offset, pcrel, literal }; + enum mode { no_mode, base_plus_offset, literal }; private: - Register _base; - Register _index; - int64_t _offset; + struct Nonliteral { + Nonliteral(Register base, Register index, int64_t offset) + : _base(base), _index(index), _offset(offset) {} + Register _base; + Register _index; + int64_t _offset; + }; + + struct Literal { + Literal(address target, const RelocationHolder& rspec) + : _target(target), _rspec(rspec) {} + // If the target is far we'll need to load the ea of this to a + // register to reach it. Otherwise if near we can do PC-relative + // addressing. + address _target; + + RelocationHolder _rspec; + }; + + void assert_is_nonliteral() const NOT_DEBUG_RETURN; + void assert_is_literal() const NOT_DEBUG_RETURN; + + // Discriminated union, based on _mode. + // - no_mode: uses dummy _nonliteral, for ease of copying. + // - literal: only _literal is used. + // - others: only _nonliteral is used. enum mode _mode; + union { + Nonliteral _nonliteral; + Literal _literal; + }; - RelocationHolder _rspec; - - // If the target is far we'll need to load the ea of this to a - // register to reach it. Otherwise if near we can do PC-relative - // addressing. - address _target; + // Helper for copy constructor and assignment operator. + // Copy mode-relevant part of a into this. + void copy_data(const Address& a) { + assert(_mode == a._mode, "precondition"); + if (_mode == literal) { + new (&_literal) Literal(a._literal); + } else { + // non-literal mode or no_mode. + new (&_nonliteral) Nonliteral(a._nonliteral); + } + } public: - Address() - : _base(noreg), _index(noreg), _offset(0), _mode(no_mode), _target(NULL) { } + // no_mode initializes _nonliteral for ease of copying. + Address() : + _mode(no_mode), + _nonliteral(noreg, noreg, 0) + {} - Address(Register r) - : _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(NULL) { } + Address(Register r) : + _mode(base_plus_offset), + _nonliteral(r, noreg, 0) + {} template::value)> - Address(Register r, T o) - : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(NULL) {} + Address(Register r, T o) : + _mode(base_plus_offset), + _nonliteral(r, noreg, o) + {} - Address(Register r, ByteSize disp) - : Address(r, in_bytes(disp)) {} + Address(Register r, ByteSize disp) : Address(r, in_bytes(disp)) {} - Address(address target, RelocationHolder const& rspec) - : _base(noreg), - _index(noreg), - _offset(0), - _mode(literal), - _rspec(rspec), - _target(target) { } + Address(address target, const RelocationHolder& rspec) : + _mode(literal), + _literal(target, rspec) + {} Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type); + Address(const Address& a) : _mode(a._mode) { copy_data(a); } + + // Verify the value is trivially destructible regardless of mode, so our + // destructor can also be trivial, and so our assignment operator doesn't + // need to destruct the old value before copying over it. + static_assert(std::is_trivially_destructible::value, "must be"); + static_assert(std::is_trivially_destructible::value, "must be"); + + Address& operator=(const Address& a) { + _mode = a._mode; + copy_data(a); + return *this; + } + + ~Address() = default; + const Register base() const { - guarantee((_mode == base_plus_offset | _mode == pcrel | _mode == literal), "wrong mode"); - return _base; + assert_is_nonliteral(); + return _nonliteral._base; } + long offset() const { - return _offset; + assert_is_nonliteral(); + return _nonliteral._offset; } + Register index() const { - return _index; + assert_is_nonliteral(); + return _nonliteral._index; } + mode getMode() const { return _mode; } - bool uses(Register reg) const { return _base == reg; } - const address target() const { return _target; } - const RelocationHolder& rspec() const { return _rspec; } + bool uses(Register reg) const { + return base() == reg; + } + + const address target() const { + assert_is_literal(); + return _literal._target; + } + + const RelocationHolder& rspec() const { + assert_is_literal(); + return _literal._rspec; + } }; // Convenience classes