8298088: RISC-V: Make Address a discriminated union internally

Reviewed-by: fjiang, yadongwang, shade
This commit is contained in:
Fei Yang 2022-12-16 08:45:52 +00:00
parent fa322e40b6
commit 226e579c30
2 changed files with 130 additions and 49 deletions

View File

@ -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))
{}

View File

@ -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 <type_traits>
#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<typename T, ENABLE_IF(std::is_integral<T>::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<Literal>::value, "must be");
static_assert(std::is_trivially_destructible<Nonliteral>::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