diff --git a/.gitignore b/.gitignore index cea9c8e..1ef4d88 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ -/qtwebengine-everywhere-src-*.tar.xz /pulseaudio-12.2-headers.tar.gz +/qtwebengine-everywhere-src-5.15.8-clean.tar.xz +/python2.7-2.7.18-19.el9.1.src.rpm +/python2.7-2.7.18-19.el9.1.aarch64.rpm +/python2.7-2.7.18-19.el9.1.x86_64.rpm diff --git a/clean_qtwebengine.sh b/clean_qtwebengine.sh index 628fe44..17f77fa 100755 --- a/clean_qtwebengine.sh +++ b/clean_qtwebengine.sh @@ -21,7 +21,7 @@ if [ -z "$1" ] ; then echo "usage: ./clean_qtwebengine.sh VERSION" - echo "e.g.: ./clean_qtwebengine.sh 5.15.16" + echo "e.g.: ./clean_qtwebengine.sh 5.15.8" exit 1 fi diff --git a/fix_build_pdf_extension_util.patch b/fix_build_pdf_extension_util.patch deleted file mode 100644 index 0b4c754..0000000 --- a/fix_build_pdf_extension_util.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- ./src/3rdparty/chromium/qtwebengine/browser/pdf/BUILD.gn.orig 2024-07-03 13:49:13.812285886 +0100 -+++ ./src/3rdparty/chromium/qtwebengine/browser/pdf/BUILD.gn 2024-07-03 13:51:45.789966941 +0100 -@@ -6,6 +6,7 @@ source_set("pdf") { - ] - - deps = [ -+ "//chrome/app:generated_resources", - "//content/public/browser", - ] - } diff --git a/python3.12-six.patch b/python3.12-six.patch deleted file mode 100644 index bfc0438..0000000 --- a/python3.12-six.patch +++ /dev/null @@ -1,58 +0,0 @@ -Patch-Source: https://sources.debian.org/data/main/q/qtwebengine-opensource-src/5.15.16+dfsg-3/debian/patches/python3.12-six.patch --- -Description: implement find_spec() for _SixMetaPathImporter -Origin: upstream, https://github.com/benjaminp/six/commit/25916292d96f5f09 -Last-Update: 2024-03-17 - ---- a/src/3rdparty/chromium/third_party/protobuf/third_party/six/six.py -+++ b/src/3rdparty/chromium/third_party/protobuf/third_party/six/six.py -@@ -71,6 +71,11 @@ else: - MAXSIZE = int((1 << 63) - 1) - del X - -+if PY34: -+ from importlib.util import spec_from_loader -+else: -+ spec_from_loader = None -+ - - def _add_doc(func, doc): - """Add documentation to a function.""" -@@ -186,6 +191,11 @@ class _SixMetaPathImporter(object): - return self - return None - -+ def find_spec(self, fullname, path, target=None): -+ if fullname in self.known_modules: -+ return spec_from_loader(fullname, self) -+ return None -+ - def __get_module(self, fullname): - try: - return self.known_modules[fullname] ---- a/src/3rdparty/chromium/tools/grit/third_party/six/__init__.py -+++ b/src/3rdparty/chromium/tools/grit/third_party/six/__init__.py -@@ -71,6 +71,11 @@ else: - MAXSIZE = int((1 << 63) - 1) - del X - -+if PY34: -+ from importlib.util import spec_from_loader -+else: -+ spec_from_loader = None -+ - - def _add_doc(func, doc): - """Add documentation to a function.""" -@@ -186,6 +191,11 @@ class _SixMetaPathImporter(object): - return self - return None - -+ def find_spec(self, fullname, path, target=None): -+ if fullname in self.known_modules: -+ return spec_from_loader(fullname, self) -+ return None -+ - def __get_module(self, fullname): - try: - return self.known_modules[fullname] diff --git a/python3.13-pipes.patch b/python3.13-pipes.patch deleted file mode 100644 index b04f6a4..0000000 --- a/python3.13-pipes.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/src/3rdparty/chromium/build/android/gyp/util/build_utils.py b/src/3rdparty/chromium/build/android/gyp/util/build_utils.py -index 022980517..e3f82704a 100644 ---- a/src/3rdparty/chromium/build/android/gyp/util/build_utils.py -+++ b/src/3rdparty/chromium/build/android/gyp/util/build_utils.py -@@ -12,7 +12,6 @@ import fnmatch - import json - import logging - import os --import pipes - import re - import shutil - import stat -@@ -198,7 +197,7 @@ class CalledProcessError(Exception): - # A user should be able to simply copy and paste the command that failed - # into their shell. - copyable_command = '( cd {}; {} )'.format(os.path.abspath(self.cwd), -- ' '.join(map(pipes.quote, self.args))) -+ printed_cmd) - return 'Command failed: {}\n{}'.format(copyable_command, self.output) - - diff --git a/qt5-qtwebengine-c99.patch b/qt5-qtwebengine-c99.patch deleted file mode 100644 index bf34288..0000000 --- a/qt5-qtwebengine-c99.patch +++ /dev/null @@ -1,45 +0,0 @@ -Avoid calls to the undeclared strlcpy function in libsync. This -prevents a build failure with future compilers. - -Submitted upstream: - -diff -up qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/BUILD.gn.c99 qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/BUILD.gn ---- qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/BUILD.gn.c99 2023-02-23 10:54:15.909380015 +0100 -+++ qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/BUILD.gn 2023-02-23 11:00:32.019601795 +0100 -@@ -21,24 +21,15 @@ if (!use_system_libsync) { - ] - } - -- config("libsync_private_config") { -- # To suppress the warning caused by strlcpy. -- cflags = [ "-Wno-implicit-function-declaration" ] -- } -- - source_set("libsync") { - sources = [ - "src/include/sync/sync.h", - "src/sw_sync.h", - "src/sync.c", -- "strlcpy.c", - ] - - configs -= [ "//build/config/compiler:chromium_code" ] -- configs += [ -- "//build/config/compiler:no_chromium_code", -- ":libsync_private_config", -- ] -+ configs += [ "//build/config/compiler:no_chromium_code" ] - - public_configs = [ ":libsync_config" ] - } -diff -up qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/src/sync.c.c99 qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/src/sync.c ---- qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/src/sync.c.c99 2023-02-23 10:54:30.650231820 +0100 -+++ qtwebengine-everywhere-src-5.15.12/src/3rdparty/chromium/third_party/libsync/src/sync.c 2023-02-23 10:54:50.116036131 +0100 -@@ -29,6 +29,7 @@ - - #include - -+#include "../strlcpy.c" - - struct sw_sync_create_fence_data { - __u32 value; diff --git a/qt5-qtwebengine-ffmpeg7.patch b/qt5-qtwebengine-ffmpeg7.patch deleted file mode 100644 index 182239f..0000000 --- a/qt5-qtwebengine-ffmpeg7.patch +++ /dev/null @@ -1,493 +0,0 @@ -From 6e554a30893150793c2638e3689cf208ffc8e375 Mon Sep 17 00:00:00 2001 -From: Dale Curtis -Date: Sat, 2 Apr 2022 05:13:53 +0000 -Subject: [PATCH] Roll src/third_party/ffmpeg/ 574c39cce..32b2d1d526 (1125 - commits) - -https://chromium.googlesource.com/chromium/third_party/ffmpeg.git/+log/574c39cce323..32b2d1d526 - -Created with: - roll-dep src/third_party/ffmpeg - -Fixed: 1293918 -Cq-Include-Trybots: luci.chromium.try:mac_chromium_asan_rel_ng,linux_chromium_asan_rel_ng,linux_chromium_chromeos_asan_rel_ng -Change-Id: I41945d0f963e3d1f65940067bac22f63b68e37d2 -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3565647 -Auto-Submit: Dale Curtis -Reviewed-by: Dan Sanders -Commit-Queue: Dale Curtis -Cr-Commit-Position: refs/heads/main@{#988253} ---- - .../clear_key_cdm/ffmpeg_cdm_audio_decoder.cc | 29 ++++++++++--------- - media/ffmpeg/ffmpeg_common.cc | 11 +++---- - media/filters/audio_file_reader.cc | 9 +++--- - media/filters/audio_file_reader_unittest.cc | 6 ++-- - .../filters/audio_video_metadata_extractor.cc | 11 +++++-- - .../filters/ffmpeg_aac_bitstream_converter.cc | 7 +++-- - ...ffmpeg_aac_bitstream_converter_unittest.cc | 2 +- - media/filters/ffmpeg_audio_decoder.cc | 13 +++++---- - 8 files changed, 51 insertions(+), 37 deletions(-) - -diff --git a/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc b/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc -index a043005..9ae2ca9 100644 ---- a/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc -+++ b/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc -@@ -73,7 +73,7 @@ void CdmAudioDecoderConfigToAVCodecContext( - codec_context->sample_fmt = AV_SAMPLE_FMT_NONE; - } - -- codec_context->channels = config.channel_count; -+ codec_context->ch_layout.nb_channels = config.channel_count; - codec_context->sample_rate = config.samples_per_second; - - if (config.extra_data) { -@@ -123,8 +123,8 @@ void CopySamples(cdm::AudioFormat cdm_format, - case cdm::kAudioFormatPlanarS16: - case cdm::kAudioFormatPlanarF32: { - const int decoded_size_per_channel = -- decoded_audio_size / av_frame.channels; -- for (int i = 0; i < av_frame.channels; ++i) { -+ decoded_audio_size / av_frame.ch_layout.nb_channels; -+ for (int i = 0; i < av_frame.ch_layout.nb_channels; ++i) { - memcpy(output_buffer, av_frame.extended_data[i], - decoded_size_per_channel); - output_buffer += decoded_size_per_channel; -@@ -184,13 +184,14 @@ bool FFmpegCdmAudioDecoder::Initialize( - // Success! - decoding_loop_.reset(new FFmpegDecodingLoop(codec_context_.get())); - samples_per_second_ = config.samples_per_second; -- bytes_per_frame_ = codec_context_->channels * config.bits_per_channel / 8; -+ bytes_per_frame_ = -+ codec_context_->ch_layout.nb_channels * config.bits_per_channel / 8; - output_timestamp_helper_.reset( - new AudioTimestampHelper(config.samples_per_second)); - is_initialized_ = true; - - // Store initial values to guard against midstream configuration changes. -- channels_ = codec_context_->channels; -+ channels_ = codec_context_->ch_layout.nb_channels; - av_sample_format_ = codec_context_->sample_fmt; - - return true; -@@ -290,17 +291,18 @@ cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( - for (auto& frame : audio_frames) { - int decoded_audio_size = 0; - if (frame->sample_rate != samples_per_second_ || -- frame->channels != channels_ || frame->format != av_sample_format_) { -+ frame->ch_layout.nb_channels != channels_ || -+ frame->format != av_sample_format_) { - DLOG(ERROR) << "Unsupported midstream configuration change!" - << " Sample Rate: " << frame->sample_rate << " vs " -- << samples_per_second_ << ", Channels: " << frame->channels -+ << samples_per_second_ << ", Channels: " << frame->ch_layout.nb_channels - << " vs " << channels_ << ", Sample Format: " << frame->format - << " vs " << av_sample_format_; - return cdm::kDecodeError; - } - - decoded_audio_size = av_samples_get_buffer_size( -- nullptr, codec_context_->channels, frame->nb_samples, -+ nullptr, codec_context_->ch_layout.nb_channels, frame->nb_samples, - codec_context_->sample_fmt, 1); - if (!decoded_audio_size) - continue; -@@ -319,7 +321,7 @@ bool FFmpegCdmAudioDecoder::OnNewFrame( - size_t* total_size, - std::vector>* audio_frames, - AVFrame* frame) { -- *total_size += av_samples_get_buffer_size(nullptr, codec_context_->channels, -+ *total_size += av_samples_get_buffer_size(nullptr, codec_context_->ch_layout.nb_channels, - frame->nb_samples, - codec_context_->sample_fmt, 1); - audio_frames->emplace_back(av_frame_clone(frame)); -diff --git a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc -index c17dd9f..0448cb5 100644 ---- a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc -+++ b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc -@@ -341,10 +341,11 @@ bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context, - codec_context->sample_fmt, codec_context->codec_id); - - ChannelLayout channel_layout = -- codec_context->channels > 8 -+ codec_context->ch_layout.nb_channels > 8 - ? CHANNEL_LAYOUT_DISCRETE -- : ChannelLayoutToChromeChannelLayout(codec_context->channel_layout, -- codec_context->channels); -+ : ChannelLayoutToChromeChannelLayout( -+ codec_context->ch_layout.u.mask, -+ codec_context->ch_layout.nb_channels); - - int sample_rate = codec_context->sample_rate; - switch (codec) { -@@ -397,7 +398,7 @@ bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context, - extra_data, encryption_scheme, seek_preroll, - codec_context->delay); - if (channel_layout == CHANNEL_LAYOUT_DISCRETE) -- config->SetChannelsForDiscrete(codec_context->channels); -+ config->SetChannelsForDiscrete(codec_context->ch_layout.nb_channels); - - #if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO) - // These are bitstream formats unknown to ffmpeg, so they don't have -@@ -462,7 +463,7 @@ void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config, - - // TODO(scherkus): should we set |channel_layout|? I'm not sure if FFmpeg uses - // said information to decode. -- codec_context->channels = config.channels(); -+ codec_context->ch_layout.nb_channels = config.channels(); - codec_context->sample_rate = config.samples_per_second(); - - if (config.extra_data().empty()) { -diff --git a/src/3rdparty/chromium/media/filters/audio_file_reader.cc b/src/3rdparty/chromium/media/filters/audio_file_reader.cc -index bd73908..745c4c7 100644 ---- a/src/3rdparty/chromium/media/filters/audio_file_reader.cc -+++ b/src/3rdparty/chromium/media/filters/audio_file_reader.cc -@@ -112,14 +112,15 @@ bool AudioFileReader::OpenDecoder() { - - // Verify the channel layout is supported by Chrome. Acts as a sanity check - // against invalid files. See http://crbug.com/171962 -- if (ChannelLayoutToChromeChannelLayout(codec_context_->channel_layout, -- codec_context_->channels) == -+ if (ChannelLayoutToChromeChannelLayout( -+ codec_context_->ch_layout.u.mask, -+ codec_context_->ch_layout.nb_channels) == - CHANNEL_LAYOUT_UNSUPPORTED) { - return false; - } - - // Store initial values to guard against midstream configuration changes. -- channels_ = codec_context_->channels; -+ channels_ = codec_context_->ch_layout.nb_channels; - audio_codec_ = CodecIDToAudioCodec(codec_context_->codec_id); - sample_rate_ = codec_context_->sample_rate; - av_sample_format_ = codec_context_->sample_fmt; -@@ -222,7 +223,7 @@ bool AudioFileReader::OnNewFrame( - if (frames_read < 0) - return false; - -- const int channels = frame->channels; -+ const int channels = frame->ch_layout.nb_channels; - if (frame->sample_rate != sample_rate_ || channels != channels_ || - frame->format != av_sample_format_) { - DLOG(ERROR) << "Unsupported midstream configuration change!" -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter.cc b/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter.cc -index 6f231c8..ca5e5fb 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter.cc -@@ -195,14 +195,15 @@ bool FFmpegAACBitstreamConverter::ConvertPacket(AVPacket* packet) { - if (!header_generated_ || codec_ != stream_codec_parameters_->codec_id || - audio_profile_ != stream_codec_parameters_->profile || - sample_rate_index_ != sample_rate_index || -- channel_configuration_ != stream_codec_parameters_->channels || -+ channel_configuration_ != -+ stream_codec_parameters_->ch_layout.nb_channels || - frame_length_ != header_plus_packet_size) { - header_generated_ = - GenerateAdtsHeader(stream_codec_parameters_->codec_id, - 0, // layer - stream_codec_parameters_->profile, sample_rate_index, - 0, // private stream -- stream_codec_parameters_->channels, -+ stream_codec_parameters_->ch_layout.nb_channels, - 0, // originality - 0, // home - 0, // copyrighted_stream -@@ -214,7 +215,7 @@ bool FFmpegAACBitstreamConverter::ConvertPacket(AVPacket* packet) { - codec_ = stream_codec_parameters_->codec_id; - audio_profile_ = stream_codec_parameters_->profile; - sample_rate_index_ = sample_rate_index; -- channel_configuration_ = stream_codec_parameters_->channels; -+ channel_configuration_ = stream_codec_parameters_->ch_layout.nb_channels; - frame_length_ = header_plus_packet_size; - } - -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc b/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc -index ac8bb13..3e4e3f6 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_aac_bitstream_converter_unittest.cc -@@ -29,7 +29,7 @@ class FFmpegAACBitstreamConverterTest : public testing::Test { - memset(&test_parameters_, 0, sizeof(AVCodecParameters)); - test_parameters_.codec_id = AV_CODEC_ID_AAC; - test_parameters_.profile = FF_PROFILE_AAC_MAIN; -- test_parameters_.channels = 2; -+ test_parameters_.ch_layout.nb_channels = 2; - test_parameters_.extradata = extradata_header_; - test_parameters_.extradata_size = sizeof(extradata_header_); - } -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc b/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc -index 72fac61..ab49fd5 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc -@@ -27,7 +27,7 @@ namespace media { - - // Return the number of channels from the data in |frame|. - static inline int DetermineChannels(AVFrame* frame) { -- return frame->channels; -+ return frame->ch_layout.nb_channels; - } - - // Called by FFmpeg's allocation routine to allocate a buffer. Uses -@@ -227,7 +227,7 @@ bool FFmpegAudioDecoder::OnNewFrame(const DecoderBuffer& buffer, - // Translate unsupported into discrete layouts for discrete configurations; - // ffmpeg does not have a labeled discrete configuration internally. - ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout( -- codec_context_->channel_layout, codec_context_->channels); -+ codec_context_->ch_layout.u.mask, codec_context_->ch_layout.nb_channels); - if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED && - config_.channel_layout() == CHANNEL_LAYOUT_DISCRETE) { - channel_layout = CHANNEL_LAYOUT_DISCRETE; -@@ -344,11 +344,11 @@ bool FFmpegAudioDecoder::ConfigureDecoder(const AudioDecoderConfig& config) { - // Success! - av_sample_format_ = codec_context_->sample_fmt; - -- if (codec_context_->channels != config.channels()) { -+ if (codec_context_->ch_layout.nb_channels != config.channels()) { - MEDIA_LOG(ERROR, media_log_) - << "Audio configuration specified " << config.channels() - << " channels, but FFmpeg thinks the file contains " -- << codec_context_->channels << " channels"; -+ << codec_context_->ch_layout.nb_channels << " channels"; - ReleaseFFmpegResources(); - state_ = kUninitialized; - return false; -@@ -398,7 +398,7 @@ int FFmpegAudioDecoder::GetAudioBuffer(struct AVCodecContext* s, - if (frame->nb_samples <= 0) - return AVERROR(EINVAL); - -- if (s->channels != channels) { -+ if (s->ch_layout.nb_channels != channels) { - DLOG(ERROR) << "AVCodecContext and AVFrame disagree on channel count."; - return AVERROR(EINVAL); - } -@@ -431,7 +431,8 @@ int FFmpegAudioDecoder::GetAudioBuffer(struct AVCodecContext* s, - ChannelLayout channel_layout = - config_.channel_layout() == CHANNEL_LAYOUT_DISCRETE - ? CHANNEL_LAYOUT_DISCRETE -- : ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels); -+ : ChannelLayoutToChromeChannelLayout(s->ch_layout.u.mask, -+ s->ch_layout.nb_channels); - - if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { - DLOG(ERROR) << "Unsupported channel layout."; -commit 62274859104bd828373ae406aa9309e610449ac5 -Author: Ted Meyer -Date: Fri Mar 22 19:56:55 2024 +0000 - - Replace deprecated use of AVCodecContext::reordered_opaque - - We can use the AV_CODEC_FLAG_COPY_OPAQUE flag on the codec context - now to trigger timestamp propagation. - - Bug: 330573128 - Change-Id: I6bc57241a35ab5283742aad8d42acb4dc5e85858 - Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5384308 - Commit-Queue: Ted (Chromium) Meyer - Reviewed-by: Dan Sanders - Cr-Commit-Position: refs/heads/main@{#1277051} - -diff --git a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc -index 0448cb5..89e9cf9 100644 ---- a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc -+++ b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc -@@ -414,7 +414,9 @@ bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context, - #if BUILDFLAG(USE_PROPRIETARY_CODECS) - // TODO(dalecurtis): Just use the profile from the codec context if ffmpeg - // ever starts supporting xHE-AAC. -- if (codec == kCodecAAC && codec_context->profile == FF_PROFILE_UNKNOWN) { -+ constexpr uint8_t kXHEAAc = 41; -+ if (codec == kCodecAAC && codec_context->profile == FF_PROFILE_UNKNOWN || -+ codec_context->profile == kXHEAAc) { - // Errors aren't fatal here, so just drop any MediaLog messages. - NullMediaLog media_log; - mp4::AAC aac_parser; -diff --git a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_regression_tests.cc b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_regression_tests.cc -index ebd1bab..04d5ecc 100644 ---- a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_regression_tests.cc -+++ b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_regression_tests.cc -@@ -86,16 +86,16 @@ FFMPEG_TEST_CASE(Cr47761, "crbug47761.ogg", PIPELINE_OK, PIPELINE_OK); - FFMPEG_TEST_CASE(Cr50045, "crbug50045.mp4", PIPELINE_OK, PIPELINE_OK); - FFMPEG_TEST_CASE(Cr62127, "crbug62127.webm", PIPELINE_OK, PIPELINE_OK); - FFMPEG_TEST_CASE(Cr93620, "security/93620.ogg", PIPELINE_OK, PIPELINE_OK); --FFMPEG_TEST_CASE(Cr100492, -- "security/100492.webm", -- DECODER_ERROR_NOT_SUPPORTED, -- DECODER_ERROR_NOT_SUPPORTED); -+FFMPEG_TEST_CASE(Cr100492, "security/100492.webm", PIPELINE_OK, PIPELINE_OK); - FFMPEG_TEST_CASE(Cr100543, "security/100543.webm", PIPELINE_OK, PIPELINE_OK); - FFMPEG_TEST_CASE(Cr101458, - "security/101458.webm", - PIPELINE_ERROR_DECODE, - PIPELINE_ERROR_DECODE); --FFMPEG_TEST_CASE(Cr108416, "security/108416.webm", PIPELINE_OK, PIPELINE_OK); -+FFMPEG_TEST_CASE(Cr108416, -+ "security/108416.webm", -+ PIPELINE_ERROR_DECODE, -+ PIPELINE_ERROR_DECODE); - FFMPEG_TEST_CASE(Cr110849, - "security/110849.mkv", - DEMUXER_ERROR_COULD_NOT_OPEN, -@@ -150,7 +150,10 @@ FFMPEG_TEST_CASE(Cr234630b, - "security/234630b.mov", - DEMUXER_ERROR_NO_SUPPORTED_STREAMS, - DEMUXER_ERROR_NO_SUPPORTED_STREAMS); --FFMPEG_TEST_CASE(Cr242786, "security/242786.webm", PIPELINE_OK, PIPELINE_OK); -+FFMPEG_TEST_CASE(Cr242786, -+ "security/242786.webm", -+ PIPELINE_OK, -+ PIPELINE_ERROR_DECODE); - // Test for out-of-bounds access with slightly corrupt file (detection logic - // thinks it's a MONO file, but actually contains STEREO audio). - FFMPEG_TEST_CASE(Cr275590, -@@ -371,8 +374,8 @@ FFMPEG_TEST_CASE(WEBM_2, - DEMUXER_ERROR_NO_SUPPORTED_STREAMS); - FFMPEG_TEST_CASE(WEBM_4, - "security/out.webm.68798.1929", -- DECODER_ERROR_NOT_SUPPORTED, -- DECODER_ERROR_NOT_SUPPORTED); -+ PIPELINE_OK, -+ PIPELINE_OK); - FFMPEG_TEST_CASE(WEBM_5, "frame_size_change.webm", PIPELINE_OK, PIPELINE_OK); - - // General MKV test cases. -diff --git a/src/3rdparty/chromium/media/filters/audio_file_reader.cc b/src/3rdparty/chromium/media/filters/audio_file_reader.cc -index 745c4c7..2b3abba 100644 ---- a/src/3rdparty/chromium/media/filters/audio_file_reader.cc -+++ b/src/3rdparty/chromium/media/filters/audio_file_reader.cc -@@ -242,10 +242,10 @@ bool AudioFileReader::OnNewFrame( - // silence from being output. In the case where we are also discarding some - // portion of the packet (as indicated by a negative pts), we further want to - // adjust the duration downward by however much exists before zero. -- if (audio_codec_ == kCodecAAC && frame->pkt_duration) { -+ if (audio_codec_ == kCodecAAC && frame->duration) { - const base::TimeDelta pkt_duration = ConvertFromTimeBase( - glue_->format_context()->streams[stream_index_]->time_base, -- frame->pkt_duration + std::min(static_cast(0), frame->pts)); -+ frame->duration + std::min(static_cast(0), frame->pts)); - const base::TimeDelta frame_duration = base::TimeDelta::FromSecondsD( - frames_read / static_cast(sample_rate_)); - -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc -index 7996606..a15aafc 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc -@@ -86,7 +86,7 @@ bool FFmpegVideoDecoder::IsCodecSupported(VideoCodec codec) { - } - - FFmpegVideoDecoder::FFmpegVideoDecoder(MediaLog* media_log) -- : media_log_(media_log), state_(kUninitialized), decode_nalus_(false) { -+ : media_log_(media_log), state_(kUninitialized), decode_nalus_(false), timestamp_map_(128) { - DVLOG(1) << __func__; - thread_checker_.DetachFromThread(); - } -@@ -183,7 +183,6 @@ int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context, - frame->width = coded_size.width(); - frame->height = coded_size.height(); - frame->format = codec_context->pix_fmt; -- frame->reordered_opaque = codec_context->reordered_opaque; - - // Now create an AVBufferRef for the data just allocated. It will own the - // reference to the VideoFrame object. -@@ -318,8 +317,10 @@ bool FFmpegVideoDecoder::FFmpegDecode(const DecoderBuffer& buffer) { - DCHECK(packet.data); - DCHECK_GT(packet.size, 0); - -- // Let FFmpeg handle presentation timestamp reordering. -- codec_context_->reordered_opaque = buffer.timestamp().InMicroseconds(); -+ const int64_t timestamp = buffer.timestamp().InMicroseconds(); -+ const TimestampId timestamp_id = timestamp_id_generator_.GenerateNextId(); -+ timestamp_map_.Put(timestamp_id, timestamp); -+ packet.opaque = reinterpret_cast(timestamp_id.GetUnsafeValue()); - } - - switch (decoding_loop_->DecodePacket( -@@ -358,8 +359,13 @@ bool FFmpegVideoDecoder::OnNewFrame(AVFrame* frame) { - - scoped_refptr video_frame = - reinterpret_cast(av_buffer_get_opaque(frame->buf[0])); -+ const auto ts_id = TimestampId(reinterpret_cast(frame->opaque)); -+ const auto ts_lookup = timestamp_map_.Get(ts_id); -+ if (ts_lookup == timestamp_map_.end()) { -+ return false; -+ } - video_frame->set_timestamp( -- base::TimeDelta::FromMicroseconds(frame->reordered_opaque)); -+ base::TimeDelta::FromMicroseconds(std::get<1>(*ts_lookup))); - video_frame->metadata()->power_efficient = false; - output_cb_.Run(video_frame); - return true; -@@ -385,8 +391,10 @@ bool FFmpegVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config, - codec_context_->thread_count = GetFFmpegVideoDecoderThreadCount(config); - codec_context_->thread_type = - FF_THREAD_SLICE | (low_delay ? 0 : FF_THREAD_FRAME); -+ - codec_context_->opaque = this; - codec_context_->get_buffer2 = GetVideoBufferImpl; -+ codec_context_->flags |= AV_CODEC_FLAG_COPY_OPAQUE; - - if (decode_nalus_) - codec_context_->flags2 |= AV_CODEC_FLAG2_CHUNKS; -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.h b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.h -index f13ce41..ee2444b 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.h -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.h -@@ -8,6 +8,8 @@ - #include - #include - -+#include "base/containers/mru_cache.h" -+#include "base/util/type_safety/id_type.h" - #include "base/callback.h" - #include "base/macros.h" - #include "base/memory/ref_counted.h" -@@ -85,6 +87,20 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { - // FFmpeg structures owned by this object. - std::unique_ptr codec_context_; - -+ // The gist here is that timestamps need to be 64 bits to store microsecond -+ // precision. A 32 bit integer would overflow at ~35 minutes at this level of -+ // precision. We can't cast the timestamp to the void ptr object used by the -+ // opaque field in ffmpeg then, because it would lose data on a 32 bit build. -+ // However, we don't actually have 2^31 timestamped frames in a single -+ // playback, so it's fine to use the 32 bit value as a key in a map which -+ // contains the actual timestamps. Additionally, we've in the past set 128 -+ // outstanding frames for re-ordering as a limit for cross-thread decoding -+ // tasks, so we'll do that here too with the LRU cache. -+ using TimestampId = util::IdType; -+ -+ TimestampId::Generator timestamp_id_generator_; -+ base::MRUCache timestamp_map_; -+ - VideoDecoderConfig config_; - - VideoFramePool frame_pool_; -diff --git a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc -index d12fade..8abfbbf 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc -+++ b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc -@@ -114,7 +114,6 @@ int H264DecoderImpl::AVGetBuffer2(AVCodecContext* context, - int total_size = y_size + 2 * uv_size; - - av_frame->format = context->pix_fmt; -- av_frame->reordered_opaque = context->reordered_opaque; - - // Set |av_frame| members as required by FFmpeg. - av_frame->data[kYPlaneIndex] = frame_buffer->MutableDataY(); -@@ -273,8 +272,6 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, - return WEBRTC_VIDEO_CODEC_ERROR; - } - packet.size = static_cast(input_image.size()); -- int64_t frame_timestamp_us = input_image.ntp_time_ms_ * 1000; // ms -> μs -- av_context_->reordered_opaque = frame_timestamp_us; - - int result = avcodec_send_packet(av_context_.get(), &packet); - if (result < 0) { -@@ -290,10 +287,6 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, - return WEBRTC_VIDEO_CODEC_ERROR; - } - -- // We don't expect reordering. Decoded frame tamestamp should match -- // the input one. -- RTC_DCHECK_EQ(av_frame_->reordered_opaque, frame_timestamp_us); -- - absl::optional qp; - // TODO(sakal): Maybe it is possible to get QP directly from FFmpeg. - h264_bitstream_parser_.ParseBitstream(input_image.data(), input_image.size()); diff --git a/qt5-qtwebengine-ffmpeg8.patch b/qt5-qtwebengine-ffmpeg8.patch deleted file mode 100644 index 5b7073f..0000000 --- a/qt5-qtwebengine-ffmpeg8.patch +++ /dev/null @@ -1,113 +0,0 @@ -diff -up qtwebengine-everywhere-src-5.15.18/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc.ffmpeg8 qtwebengine-everywhere-src-5.15.18/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc ---- qtwebengine-everywhere-src-5.15.18/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc.ffmpeg8 2025-11-02 21:41:06.931797956 +0000 -+++ qtwebengine-everywhere-src-5.15.18/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc 2025-11-02 23:06:28.874349338 +0000 -@@ -237,22 +237,22 @@ AVCodecID VideoCodecToCodecID(VideoCodec - static VideoCodecProfile ProfileIDToVideoCodecProfile(int profile) { - // Clear out the CONSTRAINED & INTRA flags which are strict subsets of the - // corresponding profiles with which they're used. -- profile &= ~FF_PROFILE_H264_CONSTRAINED; -- profile &= ~FF_PROFILE_H264_INTRA; -+ profile &= ~AV_PROFILE_H264_CONSTRAINED; -+ profile &= ~AV_PROFILE_H264_INTRA; - switch (profile) { -- case FF_PROFILE_H264_BASELINE: -+ case AV_PROFILE_H264_BASELINE: - return H264PROFILE_BASELINE; -- case FF_PROFILE_H264_MAIN: -+ case AV_PROFILE_H264_MAIN: - return H264PROFILE_MAIN; -- case FF_PROFILE_H264_EXTENDED: -+ case AV_PROFILE_H264_EXTENDED: - return H264PROFILE_EXTENDED; -- case FF_PROFILE_H264_HIGH: -+ case AV_PROFILE_H264_HIGH: - return H264PROFILE_HIGH; -- case FF_PROFILE_H264_HIGH_10: -+ case AV_PROFILE_H264_HIGH_10: - return H264PROFILE_HIGH10PROFILE; -- case FF_PROFILE_H264_HIGH_422: -+ case AV_PROFILE_H264_HIGH_422: - return H264PROFILE_HIGH422PROFILE; -- case FF_PROFILE_H264_HIGH_444_PREDICTIVE: -+ case AV_PROFILE_H264_HIGH_444_PREDICTIVE: - return H264PROFILE_HIGH444PREDICTIVEPROFILE; - default: - DVLOG(1) << "Unknown profile id: " << profile; -@@ -263,23 +263,23 @@ static VideoCodecProfile ProfileIDToVide - static int VideoCodecProfileToProfileID(VideoCodecProfile profile) { - switch (profile) { - case H264PROFILE_BASELINE: -- return FF_PROFILE_H264_BASELINE; -+ return AV_PROFILE_H264_BASELINE; - case H264PROFILE_MAIN: -- return FF_PROFILE_H264_MAIN; -+ return AV_PROFILE_H264_MAIN; - case H264PROFILE_EXTENDED: -- return FF_PROFILE_H264_EXTENDED; -+ return AV_PROFILE_H264_EXTENDED; - case H264PROFILE_HIGH: -- return FF_PROFILE_H264_HIGH; -+ return AV_PROFILE_H264_HIGH; - case H264PROFILE_HIGH10PROFILE: -- return FF_PROFILE_H264_HIGH_10; -+ return AV_PROFILE_H264_HIGH_10; - case H264PROFILE_HIGH422PROFILE: -- return FF_PROFILE_H264_HIGH_422; -+ return AV_PROFILE_H264_HIGH_422; - case H264PROFILE_HIGH444PREDICTIVEPROFILE: -- return FF_PROFILE_H264_HIGH_444_PREDICTIVE; -+ return AV_PROFILE_H264_HIGH_444_PREDICTIVE; - default: - DVLOG(1) << "Unknown VideoCodecProfile: " << profile; - } -- return FF_PROFILE_UNKNOWN; -+ return AV_PROFILE_UNKNOWN; - } - - SampleFormat AVSampleFormatToSampleFormat(AVSampleFormat sample_format, -@@ -415,7 +415,7 @@ bool AVCodecContextToAudioDecoderConfig( - // TODO(dalecurtis): Just use the profile from the codec context if ffmpeg - // ever starts supporting xHE-AAC. - constexpr uint8_t kXHEAAc = 41; -- if (codec == kCodecAAC && codec_context->profile == FF_PROFILE_UNKNOWN || -+ if (codec == kCodecAAC && codec_context->profile == AV_PROFILE_UNKNOWN || - codec_context->profile == kXHEAAc) { - // Errors aren't fatal here, so just drop any MediaLog messages. - NullMediaLog media_log; -@@ -537,16 +537,16 @@ bool AVStreamToVideoDecoderConfig(const - break; - case kCodecVP9: - switch (codec_context->profile) { -- case FF_PROFILE_VP9_0: -+ case AV_PROFILE_VP9_0: - profile = VP9PROFILE_PROFILE0; - break; -- case FF_PROFILE_VP9_1: -+ case AV_PROFILE_VP9_1: - profile = VP9PROFILE_PROFILE1; - break; -- case FF_PROFILE_VP9_2: -+ case AV_PROFILE_VP9_2: - profile = VP9PROFILE_PROFILE2; - break; -- case FF_PROFILE_VP9_3: -+ case AV_PROFILE_VP9_3: - profile = VP9PROFILE_PROFILE3; - break; - default: -@@ -645,9 +645,15 @@ bool AVStreamToVideoDecoderConfig(const - coded_size, visible_rect, natural_size, extra_data, - GetEncryptionScheme(stream)); - -+#if (LIBAVFORMAT_VERSION_MAJOR < 62) - if (stream->nb_side_data) { - for (int i = 0; i < stream->nb_side_data; ++i) { - AVPacketSideData side_data = stream->side_data[i]; -+#else -+ if (stream->codecpar->nb_coded_side_data) { -+ for (int i = 0; i < stream->codecpar->nb_coded_side_data; ++i) { -+ const auto& side_data = stream->codecpar->coded_side_data[i]; -+#endif - if (side_data.type != AV_PKT_DATA_MASTERING_DISPLAY_METADATA) - continue; - diff --git a/qt5-qtwebengine.spec b/qt5-qtwebengine.spec index f46dd9c..d789055 100644 --- a/qt5-qtwebengine.spec +++ b/qt5-qtwebengine.spec @@ -5,12 +5,26 @@ # package-notes causes FTBFS (#2043178) %undefine _package_note_file +# define to build docs, may need to undef this for bootstrapping +# where qt5-qttools (qt5-doctools) builds are not yet available +%global docs 0 + %if 0%{?fedora} # need libvpx >= 1.8.0 (need commit 297dfd869609d7c3c5cd5faa3ebc7b43a394434e) %global use_system_libvpx 1 # For screen sharing on Wayland, currently Fedora only thing - no epel #global pipewire 1 %endif +%if 0%{?fedora} > 30 || 0%{?epel} > 7 +# need libwebp >= 0.6.0 +%global use_system_libwebp 1 +%global use_system_jsoncpp 1 +%if 0%{?rhel} && 0%{?rhel} == 9 +%global use_system_re2 0 +%else +%global use_system_re2 1 +%endif +%endif %if 0%{?fedora} > 32 # need libicu >= 65, only currently available on f33+ @@ -47,14 +61,13 @@ Summary: Qt5 - QtWebEngine components Name: qt5-qtwebengine -Version: 5.15.19 -Release: 5%{?dist} +Version: 5.15.8 +Release: 5%{?dist}.1 # See LICENSE.GPL LICENSE.LGPL LGPL_EXCEPTION.txt, for details # See also http://qt-project.org/doc/qt-5.0/qtdoc/licensing.html # The other licenses are from Chromium and the code it bundles -# Automatically converted from old format: (LGPLv2 with exceptions or GPLv3 with exceptions) and BSD and LGPLv2+ and ASL 2.0 and IJG and MIT and GPLv2+ and ISC and OpenSSL and (MPLv1.1 or GPLv2 or LGPLv2) - review is highly recommended. -License: (LGPL-2.0-or-later WITH FLTK-exception OR LicenseRef-Callaway-GPLv3-with-exceptions) AND LicenseRef-Callaway-BSD AND LicenseRef-Callaway-LGPLv2+ AND Apache-2.0 AND IJG AND LicenseRef-Callaway-MIT AND GPL-2.0-or-later AND ISC AND OpenSSL AND (LicenseRef-Callaway-MPLv1.1 OR GPL-2.0-only OR LicenseRef-Callaway-LGPLv2) +License: (LGPLv2 with exceptions or GPLv3 with exceptions) and BSD and LGPLv2+ and ASL 2.0 and IJG and MIT and GPLv2+ and ISC and OpenSSL and (MPLv1.1 or GPLv2 or LGPLv2) URL: http://www.qt.io # cleaned tarball with patent-encumbered codecs removed from the bundled FFmpeg # ./qtwebengine-release.sh @@ -72,6 +85,18 @@ Source10: macros.qt5-qtwebengine # pulseaudio headers Source20: pulseaudio-12.2-headers.tar.gz +## Python2 Sources +## src.rpm is Fedora spec with tests and tkinter turned off +## binary rpms have been built on epel9 +Source100: python2.7-2.7.18-19.el9.1.src.rpm +Source101: python2.7-2.7.18-19.el9.1.aarch64.rpm +Source102: python2.7-2.7.18-19.el9.1.x86_64.rpm + +# quick hack to avoid checking for the nonexistent icudtl.dat and silence the +# resulting warnings - not upstreamable as is because it removes the fallback +# mechanism for the ICU data directory (which is not used in our builds because +# we use the system ICU, which embeds the data statically) completely +Patch1: qtwebengine-everywhere-src-5.15.0-no-icudtl-dat.patch # fix extractCFlag to also look in QMAKE_CFLAGS_RELEASE, needed to detect the # ARM flags with our %%qmake_qt5 macro, including for the next patch Patch2: qtwebengine-opensource-src-5.12.4-fix-extractcflag.patch @@ -88,39 +113,20 @@ Patch7: chromium-hunspell-nullptr.patch Patch8: qtwebengine-everywhere-5.15.8-libpipewire-0.3.patch # Fix/workaround FTBFS on aarch64 with newer glibc Patch24: qtwebengine-everywhere-src-5.11.3-aarch64-new-stat.patch -Patch32: qtwebengine-skia-missing-includes.patch -Patch34: qtwebengine-fix-build.patch -Patch35: qt5-qtwebengine-c99.patch -Patch36: qtwebengine-chromium-141-glibc-2.42-SYS_SECCOMP.patch - -# Working with ffmpeg -Patch60: qtwebengine-ffmpeg5.patch -# Adapt for ffmpeg7 (from openSUSE) -Patch61: qt5-qtwebengine-ffmpeg7.patch -# Adapt for ffmpeg8 -Patch62: qt5-qtwebengine-ffmpeg8.patch - -# Fix build -Patch70: qtwebengine-5.15.13_p20240322-ninja1.12.patch -Patch71: fix_build_pdf_extension_util.patch -Patch73: python3.12-six.patch - -# Fix building with ICU 75 -# https://gitlab.archlinux.org/archlinux/packaging/packages/qt5-webengine/-/blob/97c4d298f/qt5-webengine-icu-75.patch -Patch80: qtwebengine-icu75.patch - -# riscv64 support patches taken from Opensuse: -# https://build.opensuse.org/package/show/openSUSE:Factory:RISCV/libqt5-qtwebengine?rev=110 -Patch100: riscv-v8.patch -Patch101: riscv.patch -Patch102: riscv-breakpad.patch -Patch103: riscv-crashpad.patch -Patch104: riscv-sandbox.patch +# Use Python2 +Patch26: qtwebengine-everywhere-5.15.5-use-python2.patch +# FTBFS TRUE/FALSE undeclared +Patch31: qtwebengine-everywhere-src-5.15.5-TRUE.patch ## Upstream patches: +## epel8 patches +Patch101: qtwebengine-everywhere-5.15.8-gcc-aarch64-hack.patch.patch + +%if 0%{?fedora} || 0%{?epel} > 7 # handled by qt5-srpm-macros, which defines %%qt5_qtwebengine_arches ExclusiveArch: %{qt5_qtwebengine_arches} +%endif BuildRequires: make BuildRequires: qt5-qtbase-devel @@ -151,6 +157,9 @@ BuildRequires: libicu-devel >= 65 %endif BuildRequires: libjpeg-devel BuildRequires: nodejs +%if 0%{?use_system_re2} +BuildRequires: re2-devel +%endif %if 0%{?pipewire} BuildRequires: pkgconfig(libpipewire-0.3) %endif @@ -162,18 +171,26 @@ BuildRequires: pkgconfig(fontconfig) BuildRequires: pkgconfig(freetype2) BuildRequires: pkgconfig(gl) BuildRequires: pkgconfig(egl) +%if 0%{?use_system_jsoncpp} BuildRequires: pkgconfig(jsoncpp) +%endif BuildRequires: pkgconfig(libpng) BuildRequires: pkgconfig(libudev) +%if 0%{?use_system_libwebp} BuildRequires: pkgconfig(libwebp) >= 0.6.0 +%endif BuildRequires: pkgconfig(harfbuzz) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(opus) BuildRequires: pkgconfig(libevent) BuildRequires: pkgconfig(poppler-cpp) BuildRequires: pkgconfig(zlib) +%if 0%{?fedora} && 0%{?fedora} < 30 +BuildRequires: pkgconfig(minizip) +%else BuildConflicts: minizip-devel Provides: bundled(minizip) = 1.2 +%endif BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(xi) BuildRequires: pkgconfig(xcursor) @@ -198,8 +215,19 @@ BuildRequires: pkgconfig(xkbfile) ## requires libxml2 built with icu support #BuildRequires: pkgconfig(libxslt) pkgconfig(libxml-2.0) BuildRequires: perl-interpreter +# fesco exception to allow python2 use: https://pagure.io/fesco/issue/2208 +# per https://fedoraproject.org/wiki/Changes/RetirePython2#FESCo_exceptions +# Only the interpreter is needed +%if 0%{?fedora} > 29 || 0%{?rhel} > 8 +%if 0%{?rhel} && 0%{?rhel} == 9 BuildRequires: %{__python3} -BuildRequires: python3-html5lib +%else +BuildRequires: %{__python2} +%endif +%else +BuildRequires: python2 +BuildRequires: python2-rpm-macros +%endif %if 0%{?use_system_libvpx} BuildRequires: pkgconfig(vpx) >= 1.8.0 %endif @@ -208,11 +236,6 @@ BuildRequires: libtirpc BuildRequires: libnsl2 BuildRequires: python-rpm-macros -# For ffmpeg libraries -BuildRequires: pkgconfig(libavcodec) -BuildRequires: pkgconfig(libavformat) -BuildRequires: pkgconfig(libavutil) - # extra (non-upstream) functions needed, see # src/3rdparty/chromium/third_party/sqlite/README.chromium for details #BuildRequires: pkgconfig(sqlite3) @@ -271,6 +294,9 @@ Provides: bundled(libsrtp) = 2.2.0 %if !0%{?use_system_libvpx} Provides: bundled(libvpx) = 1.8.2 %endif +%if !0%{?use_system_libwebp} +Provides: bundled(libwebp) = 1.1.0-28-g55a080e5 +%endif # bundled as "libxml" # see src/3rdparty/chromium/third_party/libxml/linux/include/libxml/xmlversion.h # post 2.9.9 snapshot?, 2.9.9-0b3c64d9f2f3e9ce1a98d8f19ee7a763c87e27d5 @@ -338,6 +364,10 @@ Provides: bundled(fdlibm) = 5.3 Conflicts: qt5-qtwebengine-freeworld < 5.15.2-2 %endif +%if 0%{?rhel} == 7 +BuildRequires: devtoolset-7-toolchain +%endif + %description %{summary}. @@ -364,6 +394,22 @@ Summary: Example files for %{name} %{summary}. +%if 0%{?docs} +%package doc +Summary: API documentation for %{name} +BuildRequires: qt5-qdoc +BuildRequires: qt5-qhelpgenerator +BuildRequires: qt5-qtbase-doc +Requires: qt5-qtbase-doc +BuildRequires: qt5-qtxmlpatterns-doc +Requires: qt5-qtxmlpatterns-doc +BuildRequires: qt5-qtdeclarative-doc +Requires: qt5-qtdeclarative-doc +BuildArch: noarch +%description doc +%{summary}. +%endif + %prep %setup -q -n %{qt_module}-everywhere-src-%{version}%{?prerelease:-%{prerelease}} -a20 @@ -373,49 +419,72 @@ mv pulse src/3rdparty/chromium/ pushd src/3rdparty/chromium popd -%patch -P2 -p1 -b .fix-extractcflag -%if !0%{?arm_neon} -%patch -P3 -p1 -b .no-neon +%if 0%{?rhel} && 0%{?rhel} == 9 +# Install python2 from rpms +mkdir python2 +pushd python2 +%ifarch aarch64 +rpm2cpio %{SOURCE101} | cpio -idm %endif -%patch -P4 -p1 -b .SIOCGSTAMP -%patch -P5 -p1 -b .QT_DEPRECATED_VERSION -%patch -P6 -p1 -b .angle_nullptr -%patch -P7 -p1 -b .hunspell_nullptr +%ifarch x86_64 +rpm2cpio %{SOURCE102} | cpio -idm +%endif +popd +%endif + +%if 0%{?use_system_libicu} +%patch1 -p1 -b .no-icudtl-dat +%endif +%patch2 -p1 -b .fix-extractcflag +%if !0%{?arm_neon} +%patch3 -p1 -b .no-neon +%endif +%patch4 -p1 -b .SIOCGSTAMP +%patch5 -p1 -b .QT_DEPRECATED_VERSION +%patch6 -p1 -b .angle_nullptr +%patch7 -p1 -b .hunspell_nullptr #if 0%{?pipewire} -%patch -P8 -p1 -b .libpipewire-0.3 +%patch8 -p1 -b .libpipewire-0.3 #endif ## upstream patches -%patch -P24 -p1 -b .aarch64-new-stat -%patch -P32 -p1 -b .skia-missing-includes -%patch -P34 -p1 -b .fix-build -%patch -P35 -p1 -b .c99 +%patch24 -p1 -b .aarch64-new-stat +%patch26 -p1 -b .use-python2 +%patch31 -p1 -b .TRUE -%if 0%{?fedora} > 43 -%patch -P36 -p1 -b .chromium-141-glibc-2.42-SYS_SECCOMP -%endif - -%patch -P60 -p1 -%patch -P61 -p1 -%patch -P62 -p1 -b .ffmpeg8 -%patch -P70 -p1 -%patch -P71 -p1 -%patch -P73 -p1 - -%patch -P80 -p1 - -# RISC-V support patches -%patch -P100 -p1 -b .riscv64-v8 -%patch -P101 -p1 -b .riscv64 -%patch -P102 -p1 -b .riscv64-breakpad -%patch -P103 -p1 -b .riscv64-crashpad -%patch -P104 -p1 -b .riscv64-sandbox +## epel8 patches +%patch101 -p1 -b .fix-aarch64 # delete all "toolprefix = " lines from build/toolchain/linux/BUILD.gn, as we # never cross-compile in native Fedora RPMs, fixes ARM and aarch64 FTBFS sed -i -e '/toolprefix = /d' -e 's/\${toolprefix}//g' \ src/3rdparty/chromium/build/toolchain/linux/BUILD.gn +%if 0%{?use_system_re2} +# http://bugzilla.redhat.com/1337585 +# can't just delete, but we'll overwrite with system headers to be on the safe side +cp -bv /usr/include/re2/*.h src/3rdparty/chromium/third_party/re2/src/re2/ +%endif + +%if 0 +#ifarch x86_64 +# enable this to force -g2 on x86_64 (most arches run out of memory with -g2) +# DISABLED BECAUSE OF: +# /usr/lib/rpm/find-debuginfo.sh: line 188: 3619 Segmentation fault +# (core dumped) eu-strip --remove-comment $r $g -f "$1" "$2" +sed -i -e 's/symbol_level=1/symbol_level=2/g' src/core/config/common.pri +%endif + +%if 0%{?docs} +# generate qtwebengine-3rdparty.qdoc, it is missing from the tarball +pushd src/3rdparty +%{__python3} chromium/tools/licenses.py \ + --file-template ../../tools/about_credits.tmpl \ + --entry-template ../../tools/about_credits_entry.tmpl \ + credits >../webengine/doc/src/qtwebengine-3rdparty.qdoc +popd +%endif + # copy the Chromium license so it is installed with the appropriate name cp -p src/3rdparty/chromium/LICENSE LICENSE.Chromium @@ -431,25 +500,40 @@ test -f "./include/QtWebEngineCore/qtwebenginecoreglobal.h" %build +%if 0%{?rhel} == 7 +. /opt/rh/devtoolset-7/enable +%endif + +# python2 path +export PATH=$(pwd)/python2/usr/bin:$PATH +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/python2/usr/lib64 + export STRIP=strip export NINJAFLAGS="%{__ninja_common_opts}" export NINJA_PATH=%{__ninja} %{qmake_qt5} \ %{?debug_config:CONFIG+="%{debug_config}}" \ - CONFIG+="link_pulseaudio" \ - QMAKE_EXTRA_ARGS+="-system-webengine-ffmpeg -system-webengine-webp -system-webengine-opus" \ - QMAKE_EXTRA_ARGS+="-webengine-kerberos -webengine-python-version python3" \ + CONFIG+="link_pulseaudio use_gold_linker" \ %{?use_system_libicu:QMAKE_EXTRA_ARGS+="-system-webengine-icu"} \ + QMAKE_EXTRA_ARGS+="-webengine-kerberos" \ %{?pipewire:QMAKE_EXTRA_ARGS+="-webengine-webrtc-pipewire"} \ . # avoid %%make_build for now, the -O flag buffers output from intermediate build steps done via ninja make %{?_smp_mflags} +%if 0%{?docs} +%make_build docs +%endif + %install make install INSTALL_ROOT=%{buildroot} +%if 0%{?docs} +make install_docs INSTALL_ROOT=%{buildroot} +%endif + # rpm macros install -p -m644 -D %{SOURCE10} \ %{buildroot}%{rpm_macros_dir}/macros.qt5-qtwebengine @@ -485,11 +569,7 @@ sed -i -e "s|%{version} \${_Qt5WebEngine|%{lesser_version} \${_Qt5WebEngine|" \ %ldconfig_scriptlets -%if 0%{?fedora} > 35 || 0%{?epel} > 9 -%filetriggerin -- %{_datadir}/hunspell -%else %filetriggerin -- %{_datadir}/myspell -%endif while read filename ; do case "$filename" in *.dic) @@ -501,10 +581,14 @@ done %files %license LICENSE.* +%if 0%{?docs} +%license src/webengine/doc/src/qtwebengine-3rdparty.qdoc +%endif %{_qt5_libdir}/libQt5*.so.* %{_qt5_bindir}/qwebengine_convert_dict %{_qt5_libdir}/qt5/qml/* %{_qt5_libdir}/qt5/libexec/QtWebEngineProcess +%{_qt5_plugindir}/designer/libqwebengineview.so %{_qt5_plugindir}/imageformats/libqpdf.so %dir %{_qt5_datadir}/resources/ %if ! 0%{?use_system_libicu} @@ -577,7 +661,6 @@ done %{_qt5_libdir}/cmake/Qt5*/ %{_qt5_libdir}/pkgconfig/Qt5*.pc %{_qt5_archdatadir}/mkspecs/modules/*.pri -%{_qt5_plugindir}/designer/libqwebengineview.so %files devtools %{_qt5_datadir}/resources/qtwebengine_devtools_resources.pak @@ -585,168 +668,15 @@ done %files examples %{_qt5_examplesdir}/ +%if 0%{?docs} +%files doc +%{_qt5_docdir}/* +%endif + + %changelog -* Thu Nov 27 2025 Marcin Juszkiewicz - 5.15.19-5 -- Update RISC-V patches - -* Wed Nov 05 2025 Dominik Mierzejewski - 5.15.19-4 -- Rebuilt for Qt5 5.15.18 - -* Wed Nov 05 2025 Dominik Mierzejewski - 5.15.19-3 -- Fixed build with FFmpeg 8 - -* Tue Nov 04 2025 Jan Grulich - 5.15.19-2 -- Rebuild (qt5) - -* Mon Nov 03 2025 Jan Grulich - 5.15.19-1 -- 5.15.19 - -* Wed Aug 06 2025 František Zatloukal - 5.15.18-6 -- Rebuilt for icu 77.1 - -* Fri Jul 25 2025 Fedora Release Engineering - 5.15.18-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Mon May 26 2025 Jan Grulich - 5.15.18-4 -- Rebuild (qt5) - -* Wed Feb 26 2025 Jan Grulich - 5.15.18-3 -- Switch to ld.bfd - -* Sat Jan 18 2025 Fedora Release Engineering - 5.15.18-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Thu Jan 09 2025 Zephyr Lykos - 5.15.18-1 -- 5.15.18 - -* Mon Sep 23 2024 Fabio Valentini - 5.15.17-11 -- Rebuild for ffmpeg 7 - -* Wed Sep 04 2024 Miroslav Suchý - 5.15.17-10 -- convert license to SPDX - -* Wed Sep 04 2024 Jan Grulich - 5.15.17-9 -- Rebuild (qt5) - -* Tue Aug 20 2024 Jan Grulich - 5.15.17-8 -- Use Python 3 and bundled re2 - -* Thu Aug 15 2024 Denis Arnaud - 5.15.17-7 -- Back to python2 macro, even though it is failing currently on Rawhide - -* Thu Aug 15 2024 Denis Arnaud - 5.15.17-6 -- [Rawhide] python2 -> python2.7, as the python2 macro no longer seems to - work on Rawhide - -* Thu Aug 15 2024 Denis Arnaud - 5.15.17-5 -- [WIP] The python2 RPM macro seems no longer valid on Rawhide - -* Thu Aug 08 2024 Neal Gompa - 5.15.17-4 -- Fix comment for ffmpeg7 patch - -* Thu Aug 08 2024 Neal Gompa - 5.15.17-3 -- Backport Chromium support for ffmpeg 6.1/7.0 - -* Fri Jul 19 2024 Fedora Release Engineering - 5.15.17-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Mon Jun 24 2024 Sérgio Basto - 5.15.17-1 -- 5.15.17 -- BR: binutils-gold to build on rawhide - -* Thu May 30 2024 Jan Grulich - 5.15.16-6 -- Rebuild (qt5) - -* Wed Mar 20 2024 Liu Yang - 5.15.16-5 -- Add riscv64 support patch from Arch Linux - -* Thu Mar 14 2024 Jan Grulich - 5.15.16-4 -- Rebuild (qt5) - -* Sat Feb 24 2024 Paul Wouters - 5.15.16-3 -- Rebuilt for libre2.so.11 bump - -* Thu Feb 08 2024 Pete Walter - 5.15.16-2 -- Rebuild for libvpx 1.14.x - -* Thu Feb 01 2024 Jan Grulich - 5.15.16-1 -- 5.15.16 - -* Fri Jan 26 2024 Fedora Release Engineering - 5.15.12-12 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Mon Jan 22 2024 Fedora Release Engineering - 5.15.12-11 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Wed Jan 03 2024 Jan Grulich - 5.15.12-10 -- Rebuild (qt5) - -* Sun Oct 08 2023 Jan Grulich - 5.15.12-9 -- Rebuild (qt5) - -* Fri Jul 21 2023 Fedora Release Engineering - 5.15.12-8 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Tue Jul 11 2023 František Zatloukal - 5.15.12-7 -- Rebuilt for ICU 73.2 - -* Tue Jun 13 2023 Jan Grulich - 5.15.12-6 -- Rebuild (qt5) - -* Tue Apr 11 2023 Jan Grulich - 5.15.12-5 -- Rebuild (qt5) - -* Thu Feb 23 2023 Florian Weimer - 5.15.12-4 -- Port bundled libsync to C99 (#2155642) - -* Wed Feb 15 2023 Tom Callaway - 5.15.12-3 -- rebuild for libvpx - -* Fri Jan 20 2023 Fedora Release Engineering - 5.15.12-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Mon Jan 16 2023 Jan Grulich - 5.15.12-1 -- 5.15.12 - -* Fri Jan 06 2023 Jan Grulich - 5.15.10-6 -- Rebuild (qt5) - -* Sat Dec 31 2022 Pete Walter - 5.15.10-5 -- Rebuild for ICU 72 - -* Sun Nov 20 2022 Neal Gompa - 5.15.10-4 -- Add patch to backport support for 16k pages on AArch64 (#2144200) - -* Mon Oct 31 2022 Jan Grulich - 5.15.10-3 -- Rebuild (qt5) - -* Wed Sep 21 2022 Jan Grulich - 5.15.10-2 -- Rebuild (qt5) - -* Mon Aug 29 2022 Ankur Sinha - 5.15.10-1 -- Update to 5.15.10 - -* Tue Aug 02 2022 Frantisek Zatloukal - 5.15.9-5 -- Rebuilt for ICU 71.1 - -* Sat Jul 23 2022 Fedora Release Engineering - 5.15.9-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Wed Jul 20 2022 Kevin Kofler - 5.15.9-3 -- Drop obsolete no-icudtl-dat patch, code has been fixed upstream since 5.11.0 - -* Thu Jul 14 2022 Jan Grulich - 5.15.9-2 -- Rebuild (Qt 5.15.5) - -* Wed Jun 01 2022 Rex Dieter - 5.15.9-1 -- 5.15.9 - -* Tue May 17 2022 Jan Grulich - 5.15.8-7 -- Rebuild (Qt 5.15.4) - -* Tue Mar 29 2022 Parag Nemade - 5.15.8-6 -- Update hunspell dictionary path by adding conditional support - F36 Change https://fedoraproject.org/wiki/Changes/Hunspell_dictionary_dir_change +* Thu May 12 2022 Troy Dawson - 5.15.8-5.1 +- Fix aarch64 build failures on epel8-next * Wed Mar 09 2022 Jan Grulich - 5.15.8-5 - Rebuild (qt5) @@ -1415,5 +1345,3 @@ done * Thu Jun 25 2015 Helio Chissini de Castro - 5.5.0-0.2.rc - Update for official RC1 released packages - - diff --git a/qtwebengine-5.15.13_p20240322-ninja1.12.patch b/qtwebengine-5.15.13_p20240322-ninja1.12.patch deleted file mode 100644 index 0fdf13e..0000000 --- a/qtwebengine-5.15.13_p20240322-ninja1.12.patch +++ /dev/null @@ -1,27 +0,0 @@ -Quoting the description from qtwebengine-6.7.0-ninja1.12.patch: -""" -Patch status: pending being looked at upstream - -Issue[1][2][3] also exist in chromium itself[4], and unclear -why this started happening only with ninja-1.12.0 at the moment. - -Just a quickfix, likely not fully correct and seems there may -be further unresolved race issues. - -[1] https://bugs.gentoo.org/930107 -[2] https://bugreports.qt.io/browse/QTBUG-124375 -[3] https://github.com/ninja-build/ninja/issues/2417 -[4] https://bugs.gentoo.org/930112 -""" - -This has a hunk removed but is otherwise the same. ---- ./src/3rdparty/chromium/content/browser/BUILD.gn.orig 2024-03-26 14:47:34.000000000 +0000 -+++ ./src/3rdparty/chromium/content/browser/BUILD.gn 2024-06-24 04:57:25.108720935 +0100 -@@ -196,6 +196,7 @@ jumbo_static_library("browser") { - "//content/common", - "//content/common:buildflags", - "//content/common:mojo_bindings", -+ "//components/spellcheck:buildflags", - "//content/public/browser:proto", - "//content/public/common:common_sources", - "//content/public/common:content_descriptor_keys", diff --git a/qtwebengine-chromium-141-glibc-2.42-SYS_SECCOMP.patch b/qtwebengine-chromium-141-glibc-2.42-SYS_SECCOMP.patch deleted file mode 100644 index 6c827bc..0000000 --- a/qtwebengine-chromium-141-glibc-2.42-SYS_SECCOMP.patch +++ /dev/null @@ -1,29 +0,0 @@ -Fix FTBFS - -/usr/include/bits/siginfo-consts.h:219:3: error: expected identifier - 219 | SYS_SECCOMP = 1, /* Seccomp triggered. */ - | ^ -../../sandbox/linux/system_headers/linux_seccomp.h:220:39: note: expanded from macro 'SYS_SECCOMP' - 220 | #define SYS_SECCOMP 1 - | ^ -../../sandbox/linux/seccomp-bpf/trap.cc:159:46: error: use of undeclared identifier 'SYS_SECCOMP' - 159 | if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx || - | ^~~~~~~~~~~ -/usr/include/bits/siginfo-consts.h:220:23: note: expanded from macro 'SYS_SECCOMP' - 220 | # define SYS_SECCOMP SYS_SECCOMP - -diff -up chromium-141.0.7390.122/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h.me chromium-141.0.7390.122/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h ---- chromium-141.0.7390.122/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h.me 2025-10-28 10:05:44.970248151 +0100 -+++ chromium-141.0.7390.122/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h 2025-10-28 10:05:52.291345772 +0100 -@@ -214,8 +214,11 @@ struct seccomp_notif_addfd { - #define SECCOMP_RET_INVALID 0x00010000U // Illegal return value - #endif - -+// check glibc version < 2.42 -+#if (__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 42) - #ifndef SYS_SECCOMP - #define SYS_SECCOMP 1 - #endif -+#endif - - #endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_ diff --git a/qtwebengine-everywhere-5.15.5-use-python2.patch b/qtwebengine-everywhere-5.15.5-use-python2.patch new file mode 100644 index 0000000..9626d27 --- /dev/null +++ b/qtwebengine-everywhere-5.15.5-use-python2.patch @@ -0,0 +1,35 @@ +diff --git a/src/3rdparty/chromium/third_party/catapult/common/py_vulcanize/py_vulcanize/generate.py b/src/3rdparty/chromium/third_party/catapult/common/py_vulcanize/py_vulcanize/generate.py +index 8af373102..b551c0fe2 100644 +--- a/src/3rdparty/chromium/third_party/catapult/common/py_vulcanize/py_vulcanize/generate.py ++++ b/src/3rdparty/chromium/third_party/catapult/common/py_vulcanize/py_vulcanize/generate.py +@@ -83,7 +83,7 @@ def _MinifyJS(input_js): + + with tempfile.NamedTemporaryFile() as _: + args = [ +- 'python', ++ 'python2', + rjsmin_path + ] + p = subprocess.Popen(args, +@@ -203,7 +203,7 @@ def _MinifyCSS(css_text): + os.path.join(py_vulcanize_path, 'third_party', 'rcssmin', 'rcssmin.py')) + + with tempfile.NamedTemporaryFile() as _: +- rcssmin_args = ['python', rcssmin_path] ++ rcssmin_args = ['python2', rcssmin_path] + p = subprocess.Popen(rcssmin_args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, +diff --git a/src/webengine/module.pro b/src/webengine/module.pro +index 49a1086b2..afc89d49e 100644 +--- a/src/webengine/module.pro ++++ b/src/webengine/module.pro +@@ -76,7 +76,7 @@ qtConfig(webengine-testsupport) { + python = $$pythonPathForShell() + chromium_attributions.commands = \ + cd $$shell_quote($$shell_path($$PWD/../3rdparty)) && \ +- $$python chromium/tools/licenses.py \ ++ python2 chromium/tools/licenses.py \ + --file-template ../../tools/about_credits.tmpl \ + --entry-template ../../tools/about_credits_entry.tmpl credits \ + $$shell_quote($$shell_path($$OUT_PWD/chromium_attributions.qdoc)) diff --git a/qtwebengine-everywhere-5.15.8-gcc-aarch64-hack.patch.patch b/qtwebengine-everywhere-5.15.8-gcc-aarch64-hack.patch.patch new file mode 100644 index 0000000..73c20d9 --- /dev/null +++ b/qtwebengine-everywhere-5.15.8-gcc-aarch64-hack.patch.patch @@ -0,0 +1,48 @@ +From 14242d039503d5b79cb1867f06a5682cfde167f3 Mon Sep 17 00:00:00 2001 +From: Troy Dawson +Date: Thu, 12 May 2022 13:17:26 -0700 +Subject: [PATCH] gcc-aarch64-hack.patch + +--- + .../skia/third_party/skcms/src/Transform_inl.h | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/src/3rdparty/chromium/third_party/skia/third_party/skcms/src/Transform_inl.h b/src/3rdparty/chromium/third_party/skia/third_party/skcms/src/Transform_inl.h +index 2dcf717..02514ef 100644 +--- a/src/3rdparty/chromium/third_party/skia/third_party/skcms/src/Transform_inl.h ++++ b/src/3rdparty/chromium/third_party/skia/third_party/skcms/src/Transform_inl.h +@@ -117,6 +117,22 @@ SI D cast(const S& v) { + #endif + } + ++// This is a hack to work around GCC PR95726 ++template ++SI D cast2(const S& v) { ++#if N == 1 ++ return (D)v; ++#elif defined(__clang__) ++ return __builtin_convertvector(v, D); ++#else ++ D d; ++ for (int i = 0; i < N; i++) { ++ d[i] = v[i]; ++ } ++ return d; ++#endif ++} ++ + template + SI D bit_pun(const S& v) { + static_assert(sizeof(D) == sizeof(v), ""); +@@ -618,7 +634,7 @@ SI F F_from_U16_BE(U16 v) { + // MSVC catches the "loss" of data here in the portable path, so we also make sure to mask. + U16 lo = (v >> 8), + hi = (v << 8) & 0xffff; +- return cast(lo|hi) * (1/65535.0f); ++ return cast2(lo|hi) * (1/65535.0f); + } + + SI U16 U16_from_F(F v) { +-- +2.36.1 + diff --git a/qtwebengine-everywhere-src-5.15.0-no-icudtl-dat.patch b/qtwebengine-everywhere-src-5.15.0-no-icudtl-dat.patch new file mode 100644 index 0000000..a83367e --- /dev/null +++ b/qtwebengine-everywhere-src-5.15.0-no-icudtl-dat.patch @@ -0,0 +1,33 @@ +diff -up qtwebengine-everywhere-src-5.15.5/src/core/web_engine_library_info.cpp.no-icudtl-dat qtwebengine-everywhere-src-5.15.5/src/core/web_engine_library_info.cpp +--- qtwebengine-everywhere-src-5.15.5/src/core/web_engine_library_info.cpp.no-icudtl-dat 2021-06-24 07:26:58.976486102 -0500 ++++ qtwebengine-everywhere-src-5.15.5/src/core/web_engine_library_info.cpp 2021-06-24 07:32:19.272863523 -0500 +@@ -273,7 +273,6 @@ QString dictionariesPath() + + QString resourcesDataPath() + { +- static bool initialized = false; + static QString potentialResourcesPath = + #if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) + getResourcesPath(frameworkBundle()); +@@ -282,21 +281,6 @@ QString resourcesDataPath() + #else + QLibraryInfo::location(QLibraryInfo::DataPath) % QLatin1String("/resources"); + #endif +- if (!initialized) { +- initialized = true; +- if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { +- qWarning("Qt WebEngine resources not found at %s. Trying parent directory...", qPrintable(potentialResourcesPath)); +- potentialResourcesPath = QLibraryInfo::location(QLibraryInfo::DataPath); +- } +- if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { +- qWarning("Qt WebEngine resources not found at %s. Trying application directory...", qPrintable(potentialResourcesPath)); +- potentialResourcesPath = QCoreApplication::applicationDirPath(); +- } +- if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { +- qWarning("Qt WebEngine resources not found at %s. Trying fallback directory... The application MAY NOT work.", qPrintable(potentialResourcesPath)); +- potentialResourcesPath = fallbackDir(); +- } +- } + + return potentialResourcesPath; + } diff --git a/qtwebengine-everywhere-src-5.15.5-TRUE.patch b/qtwebengine-everywhere-src-5.15.5-TRUE.patch new file mode 100644 index 0000000..b61c923 --- /dev/null +++ b/qtwebengine-everywhere-src-5.15.5-TRUE.patch @@ -0,0 +1,12 @@ +diff -up qtwebengine-everywhere-src-5.15.5/src/3rdparty/chromium/third_party/libxml/src/encoding.c.TRUE qtwebengine-everywhere-src-5.15.5/src/3rdparty/chromium/third_party/libxml/src/encoding.c +--- qtwebengine-everywhere-src-5.15.5/src/3rdparty/chromium/third_party/libxml/src/encoding.c.TRUE 2021-05-28 07:05:45.000000000 -0500 ++++ qtwebengine-everywhere-src-5.15.5/src/3rdparty/chromium/third_party/libxml/src/encoding.c 2021-06-24 09:44:41.592468805 -0500 +@@ -2004,7 +2004,7 @@ xmlEncOutputChunk(xmlCharEncodingHandler + #ifdef LIBXML_ICU_ENABLED + else if (handler->uconv_out != NULL) { + ret = xmlUconvWrapper(handler->uconv_out, 0, out, outlen, in, inlen, +- TRUE); ++ 1); + } + #endif /* LIBXML_ICU_ENABLED */ + else { diff --git a/qtwebengine-ffmpeg5.patch b/qtwebengine-ffmpeg5.patch deleted file mode 100644 index 87f259e..0000000 --- a/qtwebengine-ffmpeg5.patch +++ /dev/null @@ -1,154 +0,0 @@ -Allow building qtwebengine using ffmpeg 5 -Origin: ArchLinux, https://github.com/archlinux/svntogit-packages/tree/packages/qt5-webengine/trunk - -diff --git a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h -index 2734a48..70b1877 100644 ---- a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h -+++ b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h -@@ -29,6 +29,7 @@ extern "C" { - #include - #include - #include -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/media/filters/audio_file_reader.cc b/src/3rdparty/chromium/media/filters/audio_file_reader.cc -index cb81d92..bd73908 100644 ---- a/src/3rdparty/chromium/media/filters/audio_file_reader.cc -+++ b/src/3rdparty/chromium/media/filters/audio_file_reader.cc -@@ -85,7 +85,7 @@ bool AudioFileReader::OpenDemuxer() { - } - - bool AudioFileReader::OpenDecoder() { -- AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); -+ const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); - if (codec) { - // MP3 decodes to S16P which we don't support, tell it to use S16 instead. - if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P) -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc b/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc -index 0d825ed..72fac61 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc -@@ -329,7 +329,7 @@ bool FFmpegAudioDecoder::ConfigureDecoder(const AudioDecoderConfig& config) { - } - } - -- AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); -+ const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); - if (!codec || - avcodec_open2(codec_context_.get(), codec, &codec_options) < 0) { - DLOG(ERROR) << "Could not initialize audio decoder: " -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_demuxer.cc b/src/3rdparty/chromium/media/filters/ffmpeg_demuxer.cc -index d34db63..427565b 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_demuxer.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_demuxer.cc -@@ -98,12 +98,12 @@ static base::TimeDelta ExtractStartTime(AVStream* stream) { - - // Next try to use the first DTS value, for codecs where we know PTS == DTS - // (excludes all H26x codecs). The start time must be returned in PTS. -- if (stream->first_dts != kNoFFmpegTimestamp && -+ if (av_stream_get_first_dts(stream) != kNoFFmpegTimestamp && - stream->codecpar->codec_id != AV_CODEC_ID_HEVC && - stream->codecpar->codec_id != AV_CODEC_ID_H264 && - stream->codecpar->codec_id != AV_CODEC_ID_MPEG4) { - const base::TimeDelta first_pts = -- ConvertFromTimeBase(stream->time_base, stream->first_dts); -+ ConvertFromTimeBase(stream->time_base, av_stream_get_first_dts(stream)); - if (first_pts < start_time) - start_time = first_pts; - } -@@ -408,11 +408,11 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { - scoped_refptr buffer; - - if (type() == DemuxerStream::TEXT) { -- int id_size = 0; -+ size_t id_size = 0; - uint8_t* id_data = av_packet_get_side_data( - packet.get(), AV_PKT_DATA_WEBVTT_IDENTIFIER, &id_size); - -- int settings_size = 0; -+ size_t settings_size = 0; - uint8_t* settings_data = av_packet_get_side_data( - packet.get(), AV_PKT_DATA_WEBVTT_SETTINGS, &settings_size); - -@@ -424,7 +424,7 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { - buffer = DecoderBuffer::CopyFrom(packet->data, packet->size, - side_data.data(), side_data.size()); - } else { -- int side_data_size = 0; -+ size_t side_data_size = 0; - uint8_t* side_data = av_packet_get_side_data( - packet.get(), AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, &side_data_size); - -@@ -485,7 +485,7 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { - packet->size - data_offset); - } - -- int skip_samples_size = 0; -+ size_t skip_samples_size = 0; - const uint32_t* skip_samples_ptr = - reinterpret_cast(av_packet_get_side_data( - packet.get(), AV_PKT_DATA_SKIP_SAMPLES, &skip_samples_size)); -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc b/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc -index 0ef3521..8483ecc 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc -@@ -59,7 +59,6 @@ static int64_t AVIOSeekOperation(void* opaque, int64_t offset, int whence) { - } - - void FFmpegGlue::InitializeFFmpeg() { -- av_register_all(); - } - - static void LogContainer(bool is_local_file, -@@ -95,9 +94,6 @@ FFmpegGlue::FFmpegGlue(FFmpegURLProtocol* protocol) { - // Enable fast, but inaccurate seeks for MP3. - format_context_->flags |= AVFMT_FLAG_FAST_SEEK; - -- // Ensures we can read out various metadata bits like vp8 alpha. -- format_context_->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; -- - // Ensures format parsing errors will bail out. From an audit on 11/2017, all - // instances were real failures. Solves bugs like http://crbug.com/710791. - format_context_->error_recognition |= AV_EF_EXPLODE; -diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc -index ef12477..7996606 100644 ---- a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc -+++ b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc -@@ -391,7 +391,7 @@ bool FFmpegVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config, - if (decode_nalus_) - codec_context_->flags2 |= AV_CODEC_FLAG2_CHUNKS; - -- AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); -+ const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); - if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { - ReleaseFFmpegResources(); - return false; -diff --git a/src/3rdparty/chromium/media/filters/media_file_checker.cc b/src/3rdparty/chromium/media/filters/media_file_checker.cc -index 59c2a2f..1a9872c 100644 ---- a/src/3rdparty/chromium/media/filters/media_file_checker.cc -+++ b/src/3rdparty/chromium/media/filters/media_file_checker.cc -@@ -68,7 +68,7 @@ bool MediaFileChecker::Start(base::TimeDelta check_time) { - auto context = AVStreamToAVCodecContext(format_context->streams[i]); - if (!context) - continue; -- AVCodec* codec = avcodec_find_decoder(cp->codec_id); -+ const AVCodec* codec = avcodec_find_decoder(cp->codec_id); - if (codec && avcodec_open2(context.get(), codec, nullptr) >= 0) { - auto loop = std::make_unique(context.get()); - stream_contexts[i] = {std::move(context), std::move(loop)}; -diff --git a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc -index 9002b87..d12fade 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc -+++ b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc -@@ -203,7 +203,7 @@ int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings, - // a pointer |this|. - av_context_->opaque = this; - -- AVCodec* codec = avcodec_find_decoder(av_context_->codec_id); -+ const AVCodec* codec = avcodec_find_decoder(av_context_->codec_id); - if (!codec) { - // This is an indication that FFmpeg has not been initialized or it has not - // been compiled/initialized with the correct set of codecs. - diff --git a/qtwebengine-fix-build.patch b/qtwebengine-fix-build.patch deleted file mode 100644 index 42b877e..0000000 --- a/qtwebengine-fix-build.patch +++ /dev/null @@ -1,431 +0,0 @@ -diff --git a/src/3rdparty/chromium/base/debug/profiler.h b/src/3rdparty/chromium/base/debug/profiler.h -index be6e272e0..b27f5f690 100644 ---- a/src/3rdparty/chromium/base/debug/profiler.h -+++ b/src/3rdparty/chromium/base/debug/profiler.h -@@ -5,6 +5,7 @@ - #ifndef BASE_DEBUG_PROFILER_H_ - #define BASE_DEBUG_PROFILER_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/cc/trees/target_property.cc b/src/3rdparty/chromium/cc/trees/target_property.cc -index 00595fda0..ebd8c605a 100644 ---- a/src/3rdparty/chromium/cc/trees/target_property.cc -+++ b/src/3rdparty/chromium/cc/trees/target_property.cc -@@ -6,6 +6,10 @@ - - #include "cc/trees/target_property.h" - -+#include -+ -+#include -+ - namespace cc { - - static_assert(TargetProperty::LAST_TARGET_PROPERTY < kMaxTargetPropertyIndex, -diff --git a/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc b/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc -index 98266a16c..7676e6097 100644 ---- a/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc -+++ b/src/3rdparty/chromium/device/base/synchronization/one_writer_seqlock.cc -@@ -6,6 +6,8 @@ - - #include "device/base/synchronization/one_writer_seqlock.h" - -+#include -+ - namespace device { - - OneWriterSeqLock::OneWriterSeqLock() : sequence_(0) {} -diff --git a/src/3rdparty/chromium/extensions/common/constants.h b/src/3rdparty/chromium/extensions/common/constants.h -index e6183dc11..5a12758ac 100644 ---- a/src/3rdparty/chromium/extensions/common/constants.h -+++ b/src/3rdparty/chromium/extensions/common/constants.h -@@ -13,6 +13,8 @@ - #include "components/version_info/channel.h" - #include "ui/base/layout.h" - -+#include -+ - namespace extensions { - - // Scheme we serve extension content from. -diff --git a/src/3rdparty/chromium/gpu/config/gpu_preferences.h b/src/3rdparty/chromium/gpu/config/gpu_preferences.h -index 57bda1f99..7a5ef9b3a 100644 ---- a/src/3rdparty/chromium/gpu/config/gpu_preferences.h -+++ b/src/3rdparty/chromium/gpu/config/gpu_preferences.h -@@ -5,6 +5,7 @@ - #ifndef GPU_CONFIG_GPU_PREFERENCES_H_ - #define GPU_CONFIG_GPU_PREFERENCES_H_ - -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/net/base/parse_number.h b/src/3rdparty/chromium/net/base/parse_number.h -index 301d14ac8..378058a23 100644 ---- a/src/3rdparty/chromium/net/base/parse_number.h -+++ b/src/3rdparty/chromium/net/base/parse_number.h -@@ -11,6 +11,8 @@ - #include "base/strings/string_piece.h" - #include "net/base/net_export.h" - -+#include -+ - // This file contains utility functions for parsing numbers, in the context of - // network protocols. - // -diff --git a/src/3rdparty/chromium/pdf/document_attachment_info.h b/src/3rdparty/chromium/pdf/document_attachment_info.h -index fd78cb729..f9330a0db 100644 ---- a/src/3rdparty/chromium/pdf/document_attachment_info.h -+++ b/src/3rdparty/chromium/pdf/document_attachment_info.h -@@ -9,6 +9,8 @@ - - #include "base/strings/string16.h" - -+#include -+ - namespace chrome_pdf { - - struct DocumentAttachmentInfo { -diff --git a/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h b/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h -index ac0b31a75..5d1c421d0 100644 ---- a/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h -+++ b/src/3rdparty/chromium/ppapi/utility/completion_callback_factory_thread_traits.h -@@ -38,6 +38,10 @@ namespace pp { - /// As a further optimization, we can add support for this later. - class ThreadSafeThreadTraits { - public: -+ -+ typedef pp::Lock Lock; -+ typedef pp::AutoLock AutoLock; -+ - class RefCount { - public: - /// Default constructor. In debug mode, this checks that the object is being -@@ -67,8 +71,6 @@ class ThreadSafeThreadTraits { - int32_t ref_; - }; - -- typedef pp::Lock Lock; -- typedef pp::AutoLock AutoLock; - }; - - /// The non-thread-safe version of thread traits. Using this class as the -diff --git a/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h b/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h -index fb9a44225..f9330f313 100644 ---- a/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h -+++ b/src/3rdparty/chromium/third_party/angle/src/common/angleutils.h -@@ -15,6 +15,7 @@ - # include "absl/container/flat_hash_map.h" - #endif // defined(ANGLE_USE_ABSEIL) - -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc b/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc -index 4e8788bc4..a5d35b31b 100644 ---- a/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc -+++ b/src/3rdparty/chromium/third_party/libgav1/src/src/utils/threadpool.cc -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h -index 098433c47..0820bb220 100644 ---- a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h -+++ b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/proto/proto_importer_module.h -@@ -23,6 +23,8 @@ - #include "perfetto/trace_processor/status.h" - #include "src/trace_processor/trace_blob_view.h" - -+#include -+ - namespace perfetto { - - namespace protos { -diff --git a/src/3rdparty/chromium/ui/events/gesture_event_details.h b/src/3rdparty/chromium/ui/events/gesture_event_details.h -index d20416738..8dadab3d0 100644 ---- a/src/3rdparty/chromium/ui/events/gesture_event_details.h -+++ b/src/3rdparty/chromium/ui/events/gesture_event_details.h -@@ -5,6 +5,7 @@ - #ifndef UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_ - #define UI_EVENTS_GESTURE_DETECTION_GESTURE_EVENT_DETAILS_H_ - -+#include - #include - - #include "base/check_op.h" -diff --git a/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc b/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc -index 1d5527691..ef9d5ce13 100644 ---- a/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc -+++ b/src/3rdparty/chromium/ui/gl/gl_surface_glx.cc -@@ -4,6 +4,7 @@ - - #include "ui/gl/gl_surface_glx.h" - -+#include - #include - - #include "base/bind.h" -diff --git a/src/3rdparty/chromium/ui/gl/gl_surface_glx.h b/src/3rdparty/chromium/ui/gl/gl_surface_glx.h -index ab612cd87..2178d8514 100644 ---- a/src/3rdparty/chromium/ui/gl/gl_surface_glx.h -+++ b/src/3rdparty/chromium/ui/gl/gl_surface_glx.h -@@ -5,6 +5,7 @@ - #ifndef UI_GL_GL_SURFACE_GLX_H_ - #define UI_GL_GL_SURFACE_GLX_H_ - -+#include - #include - - #include -diff --git a/src/3rdparty/chromium/v8/src/base/logging.h b/src/3rdparty/chromium/v8/src/base/logging.h -index 7c774ed30..1c44cf72a 100644 ---- a/src/3rdparty/chromium/v8/src/base/logging.h -+++ b/src/3rdparty/chromium/v8/src/base/logging.h -@@ -5,6 +5,7 @@ - #ifndef V8_BASE_LOGGING_H_ - #define V8_BASE_LOGGING_H_ - -+#include - #include - #include - #include -diff --git a/src/core/browsing_data_remover_delegate_qt.h b/src/core/browsing_data_remover_delegate_qt.h -index 5adfbbe7e..4e5c59e33 100644 ---- a/src/core/browsing_data_remover_delegate_qt.h -+++ b/src/core/browsing_data_remover_delegate_qt.h -@@ -44,6 +44,8 @@ - - #include "content/public/browser/browsing_data_remover_delegate.h" - -+#include -+ - namespace QtWebEngineCore { - - class BrowsingDataRemoverDelegateQt : public content::BrowsingDataRemoverDelegate { -diff --git a/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h b/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h -index 90b1efd31..63526a738 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h -+++ b/src/3rdparty/chromium/third_party/webrtc/api/task_queue/task_queue_base.h -@@ -10,6 +10,7 @@ - #ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_ - #define API_TASK_QUEUE_TASK_QUEUE_BASE_H_ - -+#include - #include - - #include "api/task_queue/queued_task.h" -diff --git a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc -index 8a30c7f32..4934432cc 100644 ---- a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc -+++ b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.cc -@@ -20,6 +20,8 @@ - #include "perfetto/base/build_config.h" - #include "perfetto/base/compiler.h" - -+#include -+ - #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB) - #include - #else -diff --git a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h -index 624363ff6..6d717fba4 100644 ---- a/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h -+++ b/src/3rdparty/chromium/third_party/perfetto/src/trace_processor/importers/gzip/gzip_utils.h -@@ -17,6 +17,7 @@ - #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_UTILS_H_ - #define SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_UTILS_H_ - -+#include - #include - - struct z_stream_s; -diff --git a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h -index 4ce66fdea..3f3932b22 100644 ---- a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h -+++ b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/tracing/core/slice.h -@@ -20,6 +20,7 @@ - #include - #include - -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc b/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc -index 0dea150c1..c3def1683 100644 ---- a/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc -+++ b/src/3rdparty/chromium/third_party/perfetto/src/tracing/core/trace_packet.cc -@@ -19,6 +19,8 @@ - #include "perfetto/base/logging.h" - #include "perfetto/protozero/proto_utils.h" - -+#include -+ - namespace perfetto { - - TracePacket::TracePacket() = default; -diff --git a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h -index 67b0d2eb5..3c2462de5 100644 ---- a/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h -+++ b/src/3rdparty/chromium/third_party/perfetto/include/perfetto/tracing/tracing_backend.h -@@ -17,6 +17,7 @@ - #ifndef INCLUDE_PERFETTO_TRACING_TRACING_BACKEND_H_ - #define INCLUDE_PERFETTO_TRACING_TRACING_BACKEND_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/base/task/thread_pool.h b/src/3rdparty/chromium/base/task/thread_pool.h -index 085c249ba..afc674ca7 100644 ---- a/src/3rdparty/chromium/base/task/thread_pool.h -+++ b/src/3rdparty/chromium/base/task/thread_pool.h -@@ -5,6 +5,7 @@ - #ifndef BASE_TASK_THREAD_POOL_H_ - #define BASE_TASK_THREAD_POOL_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h b/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h -index fe70260f9..eac6a7fc2 100644 ---- a/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h -+++ b/src/3rdparty/chromium/net/tools/huffman_trie/trie_entry.h -@@ -5,6 +5,7 @@ - #ifndef NET_TOOLS_HUFFMAN_TRIE_TRIE_ENTRY_H_ - #define NET_TOOLS_HUFFMAN_TRIE_TRIE_ENTRY_H_ - -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h b/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h -index 3e5f7bb21..87777a53f 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h -+++ b/src/3rdparty/chromium/third_party/webrtc/api/fec_controller.h -@@ -11,6 +11,7 @@ - #ifndef API_FEC_CONTROLLER_H_ - #define API_FEC_CONTROLLER_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h -index c85666c9a..dfb90e447 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h -+++ b/src/3rdparty/chromium/third_party/webrtc/modules/video_coding/timestamp_map.h -@@ -11,6 +11,7 @@ - #ifndef MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_ - #define MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_ - -+#include - #include - - namespace webrtc { -diff --git a/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h b/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h -index 9cf5ab6f0..2d165baa5 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h -+++ b/src/3rdparty/chromium/third_party/webrtc/api/network_state_predictor.h -@@ -11,6 +11,7 @@ - #ifndef API_NETWORK_STATE_PREDICTOR_H_ - #define API_NETWORK_STATE_PREDICTOR_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h b/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h -index 6508d79a1..a9f9528f1 100644 ---- a/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h -+++ b/src/3rdparty/chromium/gpu/command_buffer/common/skia_utils.h -@@ -5,6 +5,7 @@ - #ifndef GPU_COMMAND_BUFFER_COMMON_SKIA_UTILS_H_ - #define GPU_COMMAND_BUFFER_COMMON_SKIA_UTILS_H_ - -+#include - #include - - #include "base/optional.h" -diff --git a/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h b/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h -index ee50d6fdd..576f6e3bc 100644 ---- a/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h -+++ b/src/3rdparty/chromium/gpu/command_buffer/service/gpu_fence_manager.h -@@ -5,6 +5,7 @@ - #ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_FENCE_MANAGER_H_ - #define GPU_COMMAND_BUFFER_SERVICE_GPU_FENCE_MANAGER_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h b/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h -index fd68b6b49..dc7c015d5 100644 ---- a/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h -+++ b/src/3rdparty/chromium/third_party/pdfium/core/fpdfapi/page/cpdf_function.h -@@ -7,6 +7,7 @@ - #ifndef CORE_FPDFAPI_PAGE_CPDF_FUNCTION_H_ - #define CORE_FPDFAPI_PAGE_CPDF_FUNCTION_H_ - -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h b/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h -index 9bcdd371e..5921794f1 100644 ---- a/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h -+++ b/src/3rdparty/chromium/third_party/pdfium/core/fxcodec/jbig2/JBig2_DocumentContext.h -@@ -7,6 +7,7 @@ - #ifndef CORE_FXCODEC_JBIG2_JBIG2_DOCUMENTCONTEXT_H_ - #define CORE_FXCODEC_JBIG2_JBIG2_DOCUMENTCONTEXT_H_ - -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h b/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h -index bb07f43a0..0b7daf775 100644 ---- a/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h -+++ b/src/3rdparty/chromium/third_party/pdfium/third_party/base/span.h -@@ -9,6 +9,7 @@ - - #include - #include -+#include - #include - #include - #include -diff --git a/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h b/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h -index fb6017f41..ed5530ca0 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h -+++ b/src/3rdparty/chromium/third_party/webrtc/video/stats_counter.h -@@ -11,6 +11,7 @@ - #ifndef VIDEO_STATS_COUNTER_H_ - #define VIDEO_STATS_COUNTER_H_ - -+#include - #include - #include - -diff --git a/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h b/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h -index c325f67be..5c4dc4d18 100644 ---- a/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h -+++ b/src/3rdparty/chromium/third_party/woff2/include/woff2/output.h -@@ -10,6 +10,7 @@ - #define WOFF2_WOFF2_OUT_H_ - - #include -+#include - #include - #include - #include diff --git a/qtwebengine-icu75.patch b/qtwebengine-icu75.patch deleted file mode 100644 index 7193ace..0000000 --- a/qtwebengine-icu75.patch +++ /dev/null @@ -1,99 +0,0 @@ -diff --git a/src/3rdparty/chromium/build/config/compiler/BUILD.gn b/src/3rdparty/chromium/build/config/compiler/BUILD.gn -index b511a58c5a8..abd78a74ead 100644 ---- a/src/3rdparty/chromium/build/config/compiler/BUILD.gn -+++ b/src/3rdparty/chromium/build/config/compiler/BUILD.gn -@@ -566,7 +566,7 @@ config("compiler") { - # Override Chromium's default for projects that wish to stay on C++11. - cflags_cc += [ "-std=${standard_prefix}++11" ] - } else { -- cflags_cc += [ "-std=${standard_prefix}++14" ] -+ cflags_cc += [ "-std=${standard_prefix}++17" ] - } - } else if (!is_win && !is_nacl) { - if (target_os == "android") { -diff --git a/src/3rdparty/chromium/base/allocator/partition_allocator/partition_alloc_constants.h b/src/3rdparty/chromium/base/allocator/partition_allocator/partition_alloc_constants.h -index f03ba1e4ab4..b1495f7ae74 100644 ---- a/src/3rdparty/chromium/base/allocator/partition_allocator/partition_alloc_constants.h -+++ b/src/3rdparty/chromium/base/allocator/partition_allocator/partition_alloc_constants.h -@@ -195,7 +195,7 @@ NumPartitionPagesPerSuperPage() { - // - // __STDCPP_DEFAULT_NEW_ALIGNMENT__ is C++17. As such, it is not defined on all - // platforms, as Chrome's requirement is C++14 as of 2020. --#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) -+#if 0 - static constexpr size_t kAlignment = - std::max(alignof(std::max_align_t), __STDCPP_DEFAULT_NEW_ALIGNMENT__); - #else -diff --git a/src/3rdparty/chromium/third_party/webrtc/common_video/h264/sps_parser.h b/src/3rdparty/chromium/third_party/webrtc/common_video/h264/sps_parser.h -index 76e627d27a3..942435f44a0 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/common_video/h264/sps_parser.h -+++ b/src/3rdparty/chromium/third_party/webrtc/common_video/h264/sps_parser.h -@@ -12,6 +12,7 @@ - #define COMMON_VIDEO_H264_SPS_PARSER_H_ - - #include "absl/types/optional.h" -+#include - - namespace rtc { - class BitBuffer; -diff --git a/src/3rdparty/chromium/third_party/webrtc/common_video/h264/pps_parser.h b/src/3rdparty/chromium/third_party/webrtc/common_video/h264/pps_parser.h -index d6c31b06887..d8852dfd186 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/common_video/h264/pps_parser.h -+++ b/src/3rdparty/chromium/third_party/webrtc/common_video/h264/pps_parser.h -@@ -12,6 +12,7 @@ - #define COMMON_VIDEO_H264_PPS_PARSER_H_ - - #include "absl/types/optional.h" -+#include - - namespace rtc { - class BitBuffer; -diff --git a/src/3rdparty/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h b/src/3rdparty/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h -index 3b9971abae1..d4458038527 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h -+++ b/src/3rdparty/chromium/third_party/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h -@@ -13,6 +13,7 @@ - - #include - #include -+#include - - #include "absl/types/optional.h" - #include "api/array_view.h" -diff --git a/src/3rdparty/chromium/third_party/webrtc/modules/include/module_common_types_public.h b/src/3rdparty/chromium/third_party/webrtc/modules/include/module_common_types_public.h -index 345e45ce127..e686e5d691a 100644 ---- a/src/3rdparty/chromium/third_party/webrtc/modules/include/module_common_types_public.h -+++ b/src/3rdparty/chromium/third_party/webrtc/modules/include/module_common_types_public.h -@@ -12,6 +12,7 @@ - #define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_ - - #include -+#include - - #include "absl/types/optional.h" - -diff --git a/src/3rdparty/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/src/3rdparty/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc -index 8fcc799b795..bc69ddcf18c 100644 ---- a/src/3rdparty/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc -+++ b/src/3rdparty/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc -@@ -15,6 +15,7 @@ - #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h" - #include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h" - #include "third_party/blink/renderer/platform/text/text_boundaries.h" -+#include "absl/base/attributes.h" - - namespace blink { - -diff --git a/src/3rdparty/chromium/third_party/abseil-cpp/absl/base/options.h b/src/3rdparty/chromium/third_party/abseil-cpp/absl/base/options.h -index df506f0fae6..1de105fed4a 100644 ---- a/src/3rdparty/chromium/third_party/abseil-cpp/absl/base/options.h -+++ b/src/3rdparty/chromium/third_party/abseil-cpp/absl/base/options.h -@@ -180,7 +180,7 @@ - // absl::variant is a typedef of std::variant, use the feature macro - // ABSL_USES_STD_VARIANT. - --#define ABSL_OPTION_USE_STD_VARIANT 2 -+#define ABSL_OPTION_USE_STD_VARIANT 0 - - - // ABSL_OPTION_USE_INLINE_NAMESPACE diff --git a/qtwebengine-release.sh b/qtwebengine-release.sh index 4e599c5..a05c100 100755 --- a/qtwebengine-release.sh +++ b/qtwebengine-release.sh @@ -1,6 +1,6 @@ #!/bin/sh set -x -VERSION=5.15.19 +VERSION=5.15.8 CHROMIUMHASH=`wget https://code.qt.io/cgit/qt/qtwebengine.git/tree/src/3rdparty?h=$VERSION -q --content-on-error -O - | grep "Bad object name: " | sed 's/^.*Bad object name: \([0-9a-f]\{40\}\).*$/\1/g'` rm -rf qtwebengine-$VERSION qtwebengine-$VERSION.tar.gz qtwebengine-chromium-$CHROMIUMHASH qtwebengine-chromium-$CHROMIUMHASH.tar.gz qtwebengine-everywhere-src-$VERSION wget https://github.com/qt/qtwebengine/archive/$VERSION.tar.gz -O qtwebengine-$VERSION.tar.gz || exit $? diff --git a/qtwebengine-skia-missing-includes.patch b/qtwebengine-skia-missing-includes.patch deleted file mode 100644 index 729d07e..0000000 --- a/qtwebengine-skia-missing-includes.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/src/3rdparty/chromium/third_party/skia/src/utils/SkParseColor.cpp b/src/3rdparty/chromium/third_party/skia/src/utils/SkParseColor.cpp -index 0dc349706..0bfee6da4 100644 ---- a/src/3rdparty/chromium/third_party/skia/src/utils/SkParseColor.cpp -+++ b/src/3rdparty/chromium/third_party/skia/src/utils/SkParseColor.cpp -@@ -11,6 +11,10 @@ - #include // std::lower_bound - #include - -+#include -+#include -+#include -+ - static constexpr const char* gColorNames[] = { - "aliceblue", - "antiquewhite", diff --git a/riscv-breakpad.patch b/riscv-breakpad.patch deleted file mode 100644 index 8cdcfc7..0000000 --- a/riscv-breakpad.patch +++ /dev/null @@ -1,540 +0,0 @@ -riscv64 support patch taken from Opensuse: -https://build.opensuse.org/package/show/openSUSE:Factory:RISCV/libqt5-qtwebengine?rev=110 - -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h -@@ -44,6 +44,8 @@ typedef MDRawContextARM RawContextCPU; - typedef MDRawContextARM64_Old RawContextCPU; - #elif defined(__mips__) - typedef MDRawContextMIPS RawContextCPU; -+#elif defined(__riscv) -+typedef MDRawContextRISCV64 RawContextCPU; - #else - #error "This code has not been ported to your platform yet." - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/thread_info.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/thread_info.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/thread_info.cc -@@ -270,7 +270,23 @@ void ThreadInfo::FillCPUContext(RawConte - out->float_save.fir = mcontext.fpc_eir; - #endif - } --#endif // __mips__ -+#elif defined(__riscv) -+ -+uintptr_t ThreadInfo::GetInstructionPointer() const { -+ return mcontext.__gregs[REG_PC]; -+} -+ -+void ThreadInfo::FillCPUContext(RawContextCPU* out) const { -+ out->context_flags = MD_CONTEXT_RISCV64_FULL; -+ -+ my_memcpy (out->iregs, mcontext.__gregs, MD_CONTEXT_RISCV64_GPR_COUNT * 8); -+ -+ out->float_save.fcsr = mcontext.__fpregs.__d.__fcsr; -+ my_memcpy(&out->float_save.regs, &mcontext.__fpregs.__d.__f, -+ MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT * 8); -+} -+ -+#endif // __riscv - - void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { - assert(gp_regs || size); -@@ -279,6 +295,11 @@ void ThreadInfo::GetGeneralPurposeRegist - *gp_regs = mcontext.gregs; - if (size) - *size = sizeof(mcontext.gregs); -+#elif defined(__riscv) -+ if (gp_regs) -+ *gp_regs = mcontext.__gregs; -+ if (size) -+ *size = sizeof(mcontext.__gregs); - #else - if (gp_regs) - *gp_regs = ®s; -@@ -294,6 +315,11 @@ void ThreadInfo::GetFloatingPointRegiste - *fp_regs = &mcontext.fpregs; - if (size) - *size = sizeof(mcontext.fpregs); -+#elif defined(__riscv) -+ if (fp_regs) -+ *fp_regs = &mcontext.__fpregs; -+ if (size) -+ *size = sizeof(mcontext.__fpregs); - #else - if (fp_regs) - *fp_regs = &fpregs; -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/thread_info.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/thread_info.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/dump_writer_common/thread_info.h -@@ -68,7 +68,7 @@ struct ThreadInfo { - // Use the structures defined in - struct user_regs_struct regs; - struct user_fpsimd_struct fpregs; --#elif defined(__mips__) -+#elif defined(__mips__) || defined(__riscv) - // Use the structure defined in . - mcontext_t mcontext; - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.cc -@@ -461,7 +461,7 @@ bool ExceptionHandler::HandleSignal(int - memcpy(&g_crash_context_.float_state, fp_ptr, - sizeof(g_crash_context_.float_state)); - } --#elif !defined(__ARM_EABI__) && !defined(__mips__) -+#elif !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - // FP state is not part of user ABI on ARM Linux. - // In case of MIPS Linux FP state is already part of ucontext_t - // and 'float_state' is not a member of CrashContext. -@@ -701,7 +701,7 @@ bool ExceptionHandler::WriteMinidump() { - } - #endif - --#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) && !defined(__riscv) - // FPU state is not part of ARM EABI ucontext_t. - memcpy(&context.float_state, context.context.uc_mcontext.fpregs, - sizeof(context.float_state)); -@@ -726,6 +726,9 @@ bool ExceptionHandler::WriteMinidump() { - #elif defined(__mips__) - context.siginfo.si_addr = - reinterpret_cast(context.context.uc_mcontext.pc); -+#elif defined(__riscv) -+ context.siginfo.si_addr = -+ reinterpret_cast(context.context.uc_mcontext.__gregs[REG_PC]); - #else - #error "This code has not been ported to your platform yet." - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.h -@@ -192,7 +192,7 @@ class ExceptionHandler { - siginfo_t siginfo; - pid_t tid; // the crashing thread. - ucontext_t context; --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - // #ifdef this out because FP state is not part of user ABI for Linux ARM. - // In case of MIPS Linux FP state is already part of ucontext_t so - // 'float_state' is not required. -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/microdump_writer/microdump_writer.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/microdump_writer/microdump_writer.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/microdump_writer/microdump_writer.cc -@@ -138,7 +138,7 @@ class MicrodumpWriter { - const MicrodumpExtraInfo& microdump_extra_info, - LinuxDumper* dumper) - : ucontext_(context ? &context->context : NULL), --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - float_state_(context ? &context->float_state : NULL), - #endif - dumper_(dumper), -@@ -337,6 +337,12 @@ class MicrodumpWriter { - # else - # error "This mips ABI is currently not supported (n32)" - #endif -+#elif defined(__riscv) -+# if __riscv_xlen == 64 -+ const char kArch[] = "riscv64"; -+# else -+# error "This RISC-V ABI is currently not supported" -+#endif - #else - #error "This code has not been ported to your platform yet" - #endif -@@ -409,7 +415,7 @@ class MicrodumpWriter { - void DumpCPUState() { - RawContextCPU cpu; - my_memset(&cpu, 0, sizeof(RawContextCPU)); --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - UContextReader::FillCPUContext(&cpu, ucontext_, float_state_); - #else - UContextReader::FillCPUContext(&cpu, ucontext_); -@@ -605,7 +611,7 @@ class MicrodumpWriter { - void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } - - const ucontext_t* const ucontext_; --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - const google_breakpad::fpstate_t* const float_state_; - #endif - LinuxDumper* dumper_; -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc -@@ -112,6 +112,9 @@ bool LinuxCoreDumper::GetThreadInfoByInd - #elif defined(__mips__) - stack_pointer = - reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); -+#elif defined(__riscv) -+ stack_pointer = -+ reinterpret_cast(info->mcontext.__gregs[MD_CONTEXT_RISCV64_REG_SP]); - #else - #error "This code hasn't been ported to your platform yet." - #endif -@@ -208,6 +211,8 @@ bool LinuxCoreDumper::EnumerateThreads() - info.mcontext.mdlo = status->pr_reg[EF_LO]; - info.mcontext.mdhi = status->pr_reg[EF_HI]; - info.mcontext.pc = status->pr_reg[EF_CP0_EPC]; -+#elif defined(__riscv) -+ memcpy(info.mcontext.__gregs, status->pr_reg, sizeof(info.mcontext.__gregs)); - #else // __mips__ - memcpy(&info.regs, status->pr_reg, sizeof(info.regs)); - #endif // __mips__ -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_dumper.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_dumper.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_dumper.h -@@ -63,7 +63,8 @@ namespace google_breakpad { - (defined(__mips__) && _MIPS_SIM == _ABIO32) - typedef Elf32_auxv_t elf_aux_entry; - #elif defined(__x86_64) || defined(__aarch64__) || \ -- (defined(__mips__) && _MIPS_SIM != _ABIO32) -+ (defined(__mips__) && _MIPS_SIM != _ABIO32) || \ -+ (defined(__riscv) && __riscv_xlen == 64) - typedef Elf64_auxv_t elf_aux_entry; - #endif - -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc -@@ -298,6 +298,9 @@ bool LinuxPtraceDumper::GetThreadInfoByI - #elif defined(__mips__) - stack_pointer = - reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); -+#elif defined(__riscv) -+ stack_pointer = -+ reinterpret_cast(info->mcontext.__gregs[MD_CONTEXT_RISCV64_REG_SP]); - #else - #error "This code hasn't been ported to your platform yet." - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.cc -@@ -136,7 +136,7 @@ class MinidumpWriter { - : fd_(minidump_fd), - path_(minidump_path), - ucontext_(context ? &context->context : NULL), --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - float_state_(context ? &context->float_state : NULL), - #endif - dumper_(dumper), -@@ -468,7 +468,7 @@ class MinidumpWriter { - if (!cpu.Allocate()) - return false; - my_memset(cpu.get(), 0, sizeof(RawContextCPU)); --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); - #else - UContextReader::FillCPUContext(cpu.get(), ucontext_); -@@ -897,7 +897,7 @@ class MinidumpWriter { - dirent->location.rva = 0; - } - --#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) -+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || defined(__riscv) - bool WriteCPUInformation(MDRawSystemInfo* sys_info) { - char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; - static const char vendor_id_name[] = "vendor_id"; -@@ -925,6 +925,12 @@ class MinidumpWriter { - # else - # error "This mips ABI is currently not supported (n32)" - #endif -+#elif defined(__riscv) -+# if __riscv_xlen == 64 -+ MD_CPU_ARCHITECTURE_RISCV64; -+# else -+# error "This RISC-V ABI is currently not supported" -+# endif - #elif defined(__i386__) - MD_CPU_ARCHITECTURE_X86; - #else -@@ -1333,7 +1339,7 @@ class MinidumpWriter { - const char* path_; // Path to the file where the minidum should be written. - - const ucontext_t* const ucontext_; // also from the signal handler --#if !defined(__ARM_EABI__) && !defined(__mips__) -+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - const google_breakpad::fpstate_t* const float_state_; // ditto - #endif - LinuxDumper* dumper_; -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.h -@@ -48,7 +48,7 @@ class ExceptionHandler; - - #if defined(__aarch64__) - typedef struct fpsimd_context fpstate_t; --#elif !defined(__ARM_EABI__) && !defined(__mips__) -+#elif !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) - typedef std::remove_pointer::type fpstate_t; - #endif - -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/breakpad_getcontext.S -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/breakpad_getcontext.S -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/breakpad_getcontext.S -@@ -481,6 +481,68 @@ breakpad_getcontext: - .cfi_endproc - .size breakpad_getcontext, . - breakpad_getcontext - -+#elif defined(__riscv) && __riscv_xlen == 64 -+ -+#define __NR_rt_sigprocmask 135 -+#define _NSIG8 64 / 8 -+#define SIG_BLOCK 0 -+ -+ .text -+ .global breakpad_getcontext -+ .hidden breakpad_getcontext -+ .type breakpad_getcontext, @function -+ .align 2 -+breakpad_getcontext: -+ sd ra, MCONTEXT_GREGS_OFFSET + 0*8(a0) -+ sd ra, MCONTEXT_GREGS_OFFSET + 1*8(a0) -+ sd sp, MCONTEXT_GREGS_OFFSET + 2*8(a0) -+ sd s0, MCONTEXT_GREGS_OFFSET + 8*8(a0) -+ sd s1, MCONTEXT_GREGS_OFFSET + 9*8(a0) -+ sd x0, MCONTEXT_GREGS_OFFSET + 10*8(a0) /* return 0 by overwriting a0. */ -+ sd s2, MCONTEXT_GREGS_OFFSET + 18*8(a0) -+ sd s3, MCONTEXT_GREGS_OFFSET + 19*8(a0) -+ sd s4, MCONTEXT_GREGS_OFFSET + 20*8(a0) -+ sd s5, MCONTEXT_GREGS_OFFSET + 21*8(a0) -+ sd s6, MCONTEXT_GREGS_OFFSET + 22*8(a0) -+ sd s7, MCONTEXT_GREGS_OFFSET + 23*8(a0) -+ sd s8, MCONTEXT_GREGS_OFFSET + 24*8(a0) -+ sd s9, MCONTEXT_GREGS_OFFSET + 25*8(a0) -+ sd s10, MCONTEXT_GREGS_OFFSET + 26*8(a0) -+ sd s11, MCONTEXT_GREGS_OFFSET + 27*8(a0) -+ -+#ifndef __riscv_float_abi_soft -+ frsr a1 -+ -+ fsd fs0, MCONTEXT_FPREGS_OFFSET + 8*8(a0) -+ fsd fs1, MCONTEXT_FPREGS_OFFSET + 9*8(a0) -+ fsd fs2, MCONTEXT_FPREGS_OFFSET + 18*8(a0) -+ fsd fs3, MCONTEXT_FPREGS_OFFSET + 19*8(a0) -+ fsd fs4, MCONTEXT_FPREGS_OFFSET + 20*8(a0) -+ fsd fs5, MCONTEXT_FPREGS_OFFSET + 21*8(a0) -+ fsd fs6, MCONTEXT_FPREGS_OFFSET + 22*8(a0) -+ fsd fs7, MCONTEXT_FPREGS_OFFSET + 23*8(a0) -+ fsd fs8, MCONTEXT_FPREGS_OFFSET + 24*8(a0) -+ fsd fs9, MCONTEXT_FPREGS_OFFSET + 25*8(a0) -+ fsd fs10, MCONTEXT_FPREGS_OFFSET + 26*8(a0) -+ fsd fs11, MCONTEXT_FPREGS_OFFSET + 27*8(a0) -+ -+ sw a1, MCONTEXT_FSR_OFFSET(a0) -+#endif /* __riscv_float_abi_soft */ -+ -+/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG / 8) */ -+ li a3, _NSIG8 -+ add a2, a0, UCONTEXT_SIGMASK_OFFSET -+ mv a1, zero -+ li a0, SIG_BLOCK -+ -+ li a7, __NR_rt_sigprocmask -+ scall -+ -+ /* Always return 0 for success, even if sigprocmask failed. */ -+ mv a0, zero -+ ret -+ .size breakpad_getcontext, . - breakpad_getcontext -+ - #else - #error "This file has not been ported for your CPU!" - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/memory_mapped_file.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/memory_mapped_file.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/memory_mapped_file.cc -@@ -65,7 +65,8 @@ bool MemoryMappedFile::Map(const char* p - } - - #if defined(__x86_64__) || defined(__aarch64__) || \ -- (defined(__mips__) && _MIPS_SIM == _ABI64) -+ (defined(__mips__) && _MIPS_SIM == _ABI64) || \ -+ (defined(__riscv) && __riscv_xlen == 64) - - struct kernel_stat st; - if (sys_fstat(fd, &st) == -1 || st.st_size < 0) { -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/ucontext_constants.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/ucontext_constants.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/common/linux/ucontext_constants.h -@@ -146,6 +146,14 @@ - #endif - #define FPREGS_OFFSET_MXCSR 24 - -+#elif defined(__riscv) -+ -+#define UCONTEXT_SIGMASK_OFFSET 40 -+ -+#define MCONTEXT_GREGS_OFFSET 176 -+#define MCONTEXT_FPREGS_OFFSET 432 -+#define MCONTEXT_FSR_OFFSET (MCONTEXT_FPREGS_OFFSET + 32*8) -+ - #else - #error "This header has not been ported for your CPU" - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/google_breakpad/common/minidump_cpu_riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/google_breakpad/common/minidump_cpu_riscv64.h -@@ -0,0 +1,121 @@ -+/* Copyright 2013 Google Inc. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are -+ * met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * * Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following disclaimer -+ * in the documentation and/or other materials provided with the -+ * distribution. -+ * * Neither the name of Google Inc. nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -+ -+/* minidump_format.h: A cross-platform reimplementation of minidump-related -+ * portions of DbgHelp.h from the Windows Platform SDK. -+ * -+ * (This is C99 source, please don't corrupt it with C++.) -+ * -+ * This file contains the necessary definitions to read minidump files -+ * produced on ARM. These files may be read on any platform provided -+ * that the alignments of these structures on the processing system are -+ * identical to the alignments of these structures on the producing system. -+ * For this reason, precise-sized types are used. The structures defined -+ * by this file have been laid out to minimize alignment problems by -+ * ensuring that all members are aligned on their natural boundaries. -+ * In some cases, tail-padding may be significant when different ABIs specify -+ * different tail-padding behaviors. To avoid problems when reading or -+ * writing affected structures, MD_*_SIZE macros are provided where needed, -+ * containing the useful size of the structures without padding. -+ * -+ * Structures that are defined by Microsoft to contain a zero-length array -+ * are instead defined here to contain an array with one element, as -+ * zero-length arrays are forbidden by standard C and C++. In these cases, -+ * *_minsize constants are provided to be used in place of sizeof. For a -+ * cleaner interface to these sizes when using C++, see minidump_size.h. -+ * -+ * These structures are also sufficient to populate minidump files. -+ * -+ * Because precise data type sizes are crucial for this implementation to -+ * function properly and portably, a set of primitive types with known sizes -+ * are used as the basis of each structure defined by this file. -+ * -+ * Author: Colin Blundell -+ */ -+ -+/* -+ * RISCV64 support -+ */ -+ -+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV64_H__ -+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV64_H__ -+ -+#include "google_breakpad/common/breakpad_types.h" -+ -+#define MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT 32 -+#define MD_CONTEXT_RISCV64_GPR_COUNT 32 -+ -+typedef struct { -+ /* 32 64-bit floating point registers, f0 .. f31. */ -+ uint64_t regs[MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT]; -+ -+ uint32_t fcsr; /* FPU control and status register */ -+} MDFloatingSaveAreaRISCV64; -+ -+/* For (MDRawContextRISCV64).context_flags. These values indicate the type of -+ * context stored in the structure. */ -+#define MD_CONTEXT_RISCV64 0x00400000 -+#define MD_CONTEXT_RISCV64_CONTROL (MD_CONTEXT_RISCV64 | 0x00000001) -+#define MD_CONTEXT_RISCV64_INTEGER (MD_CONTEXT_RISCV64 | 0x00000002) -+#define MD_CONTEXT_RISCV64_FLOATING_POINT (MD_CONTEXT_RISCV64 | 0x00000004) -+#define MD_CONTEXT_RISCV64_DEBUG (MD_CONTEXT_RISCV64 | 0x00000008) -+#define MD_CONTEXT_RISCV64_FULL (MD_CONTEXT_RISCV64_CONTROL | \ -+ MD_CONTEXT_RISCV64_INTEGER | \ -+ MD_CONTEXT_RISCV64_FLOATING_POINT) -+#define MD_CONTEXT_RISCV64_ALL (MD_CONTEXT_RISCV64_FULL | MD_CONTEXT_RISCV64_DEBUG) -+ -+typedef struct { -+ /* Determines which fields of this struct are populated */ -+ uint32_t context_flags; -+ -+ /* 32 64-bit integer registers, x1 .. x31 + the PC -+ * Note the following fixed uses: -+ * x8 is the frame pointer -+ * x1 is the link register -+ * x2 is the stack pointer -+ * The PC is effectively x0. -+ */ -+ uint64_t iregs[MD_CONTEXT_RISCV64_GPR_COUNT]; -+ -+ /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */ -+ MDFloatingSaveAreaRISCV64 float_save; -+ -+} MDRawContextRISCV64; -+ -+/* Indices into iregs for registers with a dedicated or conventional -+ * purpose. -+ */ -+enum MDRISCV64RegisterNumbers { -+ MD_CONTEXT_RISCV64_REG_FP = 8, -+ MD_CONTEXT_RISCV64_REG_RA = 1, -+ MD_CONTEXT_RISCV64_REG_SP = 2, -+ MD_CONTEXT_RISCV64_REG_PC = 0 -+}; -+ -+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV64_H__ */ -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/google_breakpad/common/minidump_format.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/breakpad/breakpad/src/google_breakpad/common/minidump_format.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/breakpad/breakpad/src/google_breakpad/common/minidump_format.h -@@ -118,6 +118,7 @@ typedef struct { - #include "minidump_cpu_mips.h" - #include "minidump_cpu_ppc.h" - #include "minidump_cpu_ppc64.h" -+#include "minidump_cpu_riscv64.h" - #include "minidump_cpu_sparc.h" - #include "minidump_cpu_x86.h" - -@@ -660,6 +661,7 @@ typedef enum { - MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ - MD_CPU_ARCHITECTURE_ARM64_OLD = 0x8003, /* Breakpad-defined value for ARM64 */ - MD_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */ -+ MD_CPU_ARCHITECTURE_RISCV64 = 0x8005, /* Breakpad-defined value for RISCV64 */ - MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ - } MDCPUArchitecture; - diff --git a/riscv-crashpad.patch b/riscv-crashpad.patch deleted file mode 100644 index eed13ca..0000000 --- a/riscv-crashpad.patch +++ /dev/null @@ -1,809 +0,0 @@ -riscv64 support patch taken from Opensuse: -https://build.opensuse.org/package/show/openSUSE:Factory:RISCV/libqt5-qtwebengine?rev=110 - -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context.h -@@ -592,6 +592,41 @@ struct MinidumpContextMIPS64 { - uint64_t fir; - }; - -+//! \brief 64bit RISC-V-specifc flags for MinidumpContextRISCV64::context_flags. -+//! Based on minidump_cpu_riscv64.h from breakpad -+enum MinidumpContextRISCV64Flags : uint32_t { -+ //! \brief Identifies the context structure as RISCV64. -+ kMinidumpContextRISCV64 = 0x00080000, -+ -+ //! \brief Indicates the validity of integer registers. -+ //! -+ //! Registers `x1`-`x31` and pc are valid. -+ kMinidumpContextRISCV64Integer = kMinidumpContextRISCV64 | 0x00000002, -+ -+ //! \brief Indicates the validity of floating point registers. -+ //! -+ //! Floating point registers `f0`-`f31`, and `fcsr` are valid -+ kMinidumpContextRISCV64FloatingPoint = kMinidumpContextRISCV64 | 0x00000004, -+ -+ //! \brief Indicates the validity of all registers. -+ kMinidumpContextRISCV64All = kMinidumpContextRISCV64Integer | -+ kMinidumpContextRISCV64FloatingPoint, -+}; -+ -+//! \brief A 64bit RISCV CPU context (register state) carried in a minidump file. -+struct MinidumpContextRISCV64 { -+ uint64_t context_flags; -+ -+ //! \brief General purpose registers. -+ uint64_t regs[32]; -+ -+ //! \brief FPU registers. -+ uint64_t fpregs[32]; -+ -+ //! \brief FPU status register. -+ uint64_t fcsr; -+}; -+ - } // namespace crashpad - - #endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_ -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc -@@ -101,6 +101,13 @@ MinidumpContextWriter::CreateFromSnapsho - break; - } - -+ case kCPUArchitectureRISCV64: { -+ context = std::make_unique(); -+ reinterpret_cast(context.get()) -+ ->InitializeFromSnapshot(context_snapshot->riscv64); -+ break; -+ } -+ - default: { - LOG(ERROR) << "unknown context architecture " - << context_snapshot->architecture; -@@ -452,5 +459,42 @@ size_t MinidumpContextMIPS64Writer::Cont - DCHECK_GE(state(), kStateFrozen); - return sizeof(context_); - } -+ -+MinidumpContextRISCV64Writer::MinidumpContextRISCV64Writer() -+ : MinidumpContextWriter(), context_() { -+ context_.context_flags = kMinidumpContextRISCV64; -+} -+ -+MinidumpContextRISCV64Writer::~MinidumpContextRISCV64Writer() = default; -+ -+void MinidumpContextRISCV64Writer::InitializeFromSnapshot( -+ const CPUContextRISCV64* context_snapshot) { -+ DCHECK_EQ(state(), kStateMutable); -+ DCHECK_EQ(context_.context_flags, kMinidumpContextRISCV64); -+ -+ context_.context_flags = kMinidumpContextRISCV64All; -+ -+ static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs), -+ "GPRs size mismatch"); -+ memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs)); -+ -+ static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs), -+ "FPRs size mismatch"); -+ memcpy(context_.fpregs, -+ context_snapshot->fpregs, -+ sizeof(context_.fpregs)); -+ context_.fcsr = context_snapshot->fcsr; -+} -+ -+bool MinidumpContextRISCV64Writer::WriteObject( -+ FileWriterInterface* file_writer) { -+ DCHECK_EQ(state(), kStateWritable); -+ return file_writer->Write(&context_, sizeof(context_)); -+} -+ -+size_t MinidumpContextRISCV64Writer::ContextSize() const { -+ DCHECK_GE(state(), kStateFrozen); -+ return sizeof(context_); -+} - - } // namespace crashpad -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context_writer.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context_writer.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_context_writer.h -@@ -315,6 +315,46 @@ class MinidumpContextMIPS64Writer final - DISALLOW_COPY_AND_ASSIGN(MinidumpContextMIPS64Writer); - }; - -+//! \brief The writer for a MinidumpContextRISCV64 structure in a minidump file. -+class MinidumpContextRISCV64Writer final : public MinidumpContextWriter { -+ public: -+ MinidumpContextRISCV64Writer(); -+ ~MinidumpContextRISCV64Writer() override; -+ -+ //! \brief Initializes the MinidumpContextRISCV based on \a context_snapshot. -+ //! -+ //! \param[in] context_snapshot The context snapshot to use as source data. -+ //! -+ //! \note Valid in #kStateMutable. No mutation of context() may be done before -+ //! calling this method, and it is not normally necessary to alter -+ //! context() after calling this method. -+ void InitializeFromSnapshot(const CPUContextRISCV64* context_snapshot); -+ -+ //! \brief Returns a pointer to the context structure that this object will -+ //! write. -+ //! -+ //! \attention This returns a non-`const` pointer to this object’s private -+ //! data so that a caller can populate the context structure directly. -+ //! This is done because providing setter interfaces to each field in the -+ //! context structure would be unwieldy and cumbersome. Care must be taken -+ //! to populate the context structure correctly. The context structure -+ //! must only be modified while this object is in the #kStateMutable -+ //! state. -+ MinidumpContextRISCV64* context() { return &context_; } -+ -+ protected: -+ // MinidumpWritable: -+ bool WriteObject(FileWriterInterface* file_writer) override; -+ -+ // MinidumpContextWriter: -+ size_t ContextSize() const override; -+ -+ private: -+ MinidumpContextRISCV64 context_; -+ -+ DISALLOW_COPY_AND_ASSIGN(MinidumpContextRISCV64Writer); -+}; -+ - } // namespace crashpad - - #endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc -@@ -135,6 +135,10 @@ std::string MinidumpMiscInfoDebugBuildSt - static constexpr char kCPU[] = "mips"; - #elif defined(ARCH_CPU_MIPS64EL) - static constexpr char kCPU[] = "mips64"; -+#elif defined(ARCH_CPU_RISCV) -+ static constexpr char kCPU[] = "riscv"; -+#elif defined(ARCH_CPU_RISCV64) -+ static constexpr char kCPU[] = "riscv64"; - #else - #error define kCPU for this CPU - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/capture_memory.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/capture_memory.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/capture_memory.cc -@@ -112,6 +112,16 @@ void CaptureMemory::PointedToByContext(c - for (size_t i = 0; i < base::size(context.mipsel->regs); ++i) { - MaybeCaptureMemoryAround(delegate, context.mipsel->regs[i]); - } -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ if (context.architecture == kCPUArchitectureRISCV) { -+ for (size_t i = 0; i < base::size(context.riscv->regs); ++i) { -+ MaybeCaptureMemoryAround(delegate, context.riscv->regs[i]); -+ } -+ } else { -+ for (size_t i = 0; i < base::size(context.riscv64->regs); ++i) { -+ MaybeCaptureMemoryAround(delegate, context.riscv64->regs[i]); -+ } -+ } - #else - #error Port. - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_architecture.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_architecture.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_architecture.h -@@ -43,7 +43,13 @@ enum CPUArchitecture { - kCPUArchitectureMIPSEL, - - //! \brief 64-bit MIPSEL. -- kCPUArchitectureMIPS64EL -+ kCPUArchitectureMIPS64EL, -+ -+ //! \brief 32-bit RISCV. -+ kCPUArchitectureRISCV, -+ -+ //! \brief 64-bit RISCV. -+ kCPUArchitectureRISCV64 - }; - - } // namespace crashpad -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_context.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_context.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_context.cc -@@ -196,10 +196,12 @@ bool CPUContext::Is64Bit() const { - case kCPUArchitectureX86_64: - case kCPUArchitectureARM64: - case kCPUArchitectureMIPS64EL: -+ case kCPUArchitectureRISCV64: - return true; - case kCPUArchitectureX86: - case kCPUArchitectureARM: - case kCPUArchitectureMIPSEL: -+ case kCPUArchitectureRISCV: - return false; - default: - NOTREACHED(); -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_context.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_context.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/cpu_context.h -@@ -352,6 +352,20 @@ struct CPUContextMIPS64 { - uint64_t fir; - }; - -+//! \brief A context structure carrying RISC CPU state. -+struct CPUContextRISCV { -+ uint32_t regs[32]; -+ uint64_t fpregs[32]; -+ uint32_t fcsr; -+}; -+ -+//! \brief A context structure carrying RISC64 CPU state. -+struct CPUContextRISCV64 { -+ uint64_t regs[32]; -+ uint64_t fpregs[32]; -+ uint32_t fcsr; -+}; -+ - //! \brief A context structure capable of carrying the context of any supported - //! CPU architecture. - struct CPUContext { -@@ -382,6 +396,8 @@ struct CPUContext { - CPUContextARM64* arm64; - CPUContextMIPS* mipsel; - CPUContextMIPS64* mips64; -+ CPUContextRISCV* riscv; -+ CPUContextRISCV64* riscv64; - }; - }; - -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc -@@ -266,6 +266,30 @@ void InitializeCPUContextARM64_OnlyFPSIM - context->fpcr = float_context.fpcr; - } - -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ -+template -+void InitializeCPUContextRISCV( -+ const typename Traits::SignalThreadContext& thread_context, -+ const typename Traits::SignalFloatContext& float_context, -+ typename Traits::CPUContext* context) { -+ static_assert(sizeof(context->regs) == sizeof(thread_context), -+ "registers size mismatch"); -+ static_assert(sizeof(context->fpregs) == sizeof(float_context.f), -+ "fp registers size mismatch"); -+ memcpy(&context->regs, &thread_context, sizeof(context->regs)); -+ memcpy(&context->fpregs, &float_context, sizeof(context->fpregs)); -+ context->fcsr = float_context.fcsr; -+} -+template void InitializeCPUContextRISCV( -+ const ContextTraits32::SignalThreadContext& thread_context, -+ const ContextTraits32::SignalFloatContext& float_context, -+ ContextTraits32::CPUContext* context); -+template void InitializeCPUContextRISCV( -+ const ContextTraits64::SignalThreadContext& thread_context, -+ const ContextTraits64::SignalFloatContext& float_context, -+ ContextTraits64::CPUContext* context); -+ - #endif // ARCH_CPU_X86_FAMILY - - } // namespace internal -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h -@@ -174,6 +174,22 @@ void InitializeCPUContextMIPS( - - #endif // ARCH_CPU_MIPS_FAMILY || DOXYGEN - -+#if defined(ARCH_CPU_RISCV_FAMILY) || DOXYGEN -+ -+//! \brief Initializes a CPUContextRISCV structure from native context -+//! structures on Linux. -+//! -+//! \param[in] thread_context The native thread context. -+//! \param[in] float_context The native float context. -+//! \param[out] context The CPUContextRISCV structure to initialize. -+template -+void InitializeCPUContextRISCV( -+ const typename Traits::SignalThreadContext& thread_context, -+ const typename Traits::SignalFloatContext& float_context, -+ typename Traits::CPUContext* context); -+ -+#endif // ARCH_CPU_RISCV_FAMILY || DOXYGEN -+ - } // namespace internal - } // namespace crashpad - -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc -@@ -323,6 +323,61 @@ bool ExceptionSnapshotLinux::ReadContext - reader, context_address, context_.mips64); - } - -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ -+template -+static bool ReadContext(ProcessReaderLinux* reader, -+ LinuxVMAddress context_address, -+ typename Traits::CPUContext* dest_context) { -+ const ProcessMemory* memory = reader->Memory(); -+ -+ LinuxVMAddress gregs_address = context_address + -+ offsetof(UContext, mcontext) + -+ offsetof(typename Traits::MContext, gregs); -+ -+ typename Traits::SignalThreadContext thread_context; -+ if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) { -+ LOG(ERROR) << "Couldn't read gregs"; -+ return false; -+ } -+ -+ LinuxVMAddress fpregs_address = context_address + -+ offsetof(UContext, mcontext) + -+ offsetof(typename Traits::MContext, fpregs); -+ -+ typename Traits::SignalFloatContext fp_context; -+ if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) { -+ LOG(ERROR) << "Couldn't read fpregs"; -+ return false; -+ } -+ -+ InitializeCPUContextRISCV(thread_context, fp_context, dest_context); -+ -+ return true; -+} -+ -+template <> -+bool ExceptionSnapshotLinux::ReadContext( -+ ProcessReaderLinux* reader, -+ LinuxVMAddress context_address) { -+ context_.architecture = kCPUArchitectureRISCV; -+ context_.riscv = &context_union_.riscv; -+ -+ return internal::ReadContext( -+ reader, context_address, context_.riscv); -+} -+ -+template <> -+bool ExceptionSnapshotLinux::ReadContext( -+ ProcessReaderLinux* reader, -+ LinuxVMAddress context_address) { -+ context_.architecture = kCPUArchitectureRISCV64; -+ context_.riscv64 = &context_union_.riscv64; -+ -+ return internal::ReadContext( -+ reader, context_address, context_.riscv64); -+} -+ - #endif // ARCH_CPU_X86_FAMILY - - bool ExceptionSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h -@@ -84,6 +84,9 @@ class ExceptionSnapshotLinux final : pub - #elif defined(ARCH_CPU_MIPS_FAMILY) - CPUContextMIPS mipsel; - CPUContextMIPS64 mips64; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ CPUContextRISCV riscv; -+ CPUContextRISCV64 riscv64; - #endif - } context_union_; - CPUContext context_; -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc -@@ -108,6 +108,9 @@ void ProcessReaderLinux::Thread::Initial - #elif defined(ARCH_CPU_MIPS_FAMILY) - stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.regs[29] - : thread_info.thread_context.t32.regs[29]; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.sp -+ : thread_info.thread_context.t32.sp; - #else - #error Port. - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/signal_context.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/signal_context.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/signal_context.h -@@ -422,6 +422,67 @@ static_assert(offsetof(UContext -+struct UContext { -+ typename Traits::ULong flags; -+ typename Traits::Address link; -+ SignalStack stack; -+ Sigset sigmask; -+ char padding[128 - sizeof(sigmask)]; -+ typename Traits::Char_64Only padding2[8]; -+ typename Traits::MContext mcontext; -+}; -+ -+#if defined(ARCH_CPU_RISCV) -+static_assert(offsetof(UContext, mcontext) == -+ offsetof(ucontext_t, uc_mcontext), -+ "context offset mismatch"); -+static_assert(offsetof(UContext, mcontext.gregs) == -+ offsetof(ucontext_t, uc_mcontext.__gregs), -+ "context offset mismatch"); -+static_assert(offsetof(UContext, mcontext.fpregs) == -+ offsetof(ucontext_t, uc_mcontext.__fpregs), -+ "context offset mismatch"); -+#elif defined(ARCH_CPU_RISCV64) -+static_assert(offsetof(UContext, mcontext) == -+ offsetof(ucontext_t, uc_mcontext), -+ "context offset mismatch"); -+static_assert(offsetof(UContext, mcontext.gregs) == -+ offsetof(ucontext_t, uc_mcontext.__gregs), -+ "context offset mismatch"); -+static_assert(offsetof(UContext, mcontext.fpregs) == -+ offsetof(ucontext_t, uc_mcontext.__fpregs), -+ "context offset mismatch"); -+#endif -+ - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc -@@ -204,6 +204,9 @@ CPUArchitecture SystemSnapshotLinux::Get - #elif defined(ARCH_CPU_MIPS_FAMILY) - return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL - : kCPUArchitectureMIPSEL; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ return process_reader_->Is64Bit() ? kCPUArchitectureRISCV64 -+ : kCPUArchitectureRISCV; - #else - #error port to your architecture - #endif -@@ -219,6 +222,9 @@ uint32_t SystemSnapshotLinux::CPURevisio - #elif defined(ARCH_CPU_MIPS_FAMILY) - // Not implementable on MIPS - return 0; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ // Not implementable on RISCV -+ return 0; - #else - #error port to your architecture - #endif -@@ -239,6 +245,9 @@ std::string SystemSnapshotLinux::CPUVend - #elif defined(ARCH_CPU_MIPS_FAMILY) - // Not implementable on MIPS - return std::string(); -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ // Not implementable on RISCV -+ return std::string(); - #else - #error port to your architecture - #endif -@@ -372,6 +381,9 @@ bool SystemSnapshotLinux::NXEnabled() co - #elif defined(ARCH_CPU_MIPS_FAMILY) - // Not implementable on MIPS - return false; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ // Not implementable on RISCV -+ return false; - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc -@@ -186,6 +186,22 @@ bool ThreadSnapshotLinux::Initialize(Pro - thread.thread_info.float_context.f32, - context_.mipsel); - } -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ if (process_reader->Is64Bit()) { -+ context_.architecture = kCPUArchitectureRISCV64; -+ context_.riscv64 = &context_union_.riscv64; -+ InitializeCPUContextRISCV( -+ thread.thread_info.thread_context.t64, -+ thread.thread_info.float_context.f64, -+ context_.riscv64); -+ } else { -+ context_.architecture = kCPUArchitectureRISCV; -+ context_.riscv = &context_union_.riscv; -+ InitializeCPUContextRISCV( -+ thread.thread_info.thread_context.t32, -+ thread.thread_info.float_context.f32, -+ context_.riscv); -+ } - #else - #error Port. - #endif -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h -@@ -68,6 +68,9 @@ class ThreadSnapshotLinux final : public - #elif defined(ARCH_CPU_MIPS_FAMILY) - CPUContextMIPS mipsel; - CPUContextMIPS64 mips64; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ CPUContextRISCV riscv; -+ CPUContextRISCV64 riscv64; - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/util/linux/ptracer.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/util/linux/ptracer.cc -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/util/linux/ptracer.cc -@@ -398,6 +398,96 @@ bool GetThreadArea64(pid_t tid, - return true; - } - -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ -+template -+bool GetRegisterSet(pid_t tid, int set, Destination* dest, bool can_log) { -+ iovec iov; -+ iov.iov_base = dest; -+ iov.iov_len = sizeof(*dest); -+ if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast(set), &iov) != 0) { -+ PLOG_IF(ERROR, can_log) << "ptrace"; -+ return false; -+ } -+ if (iov.iov_len != sizeof(*dest)) { -+ LOG_IF(ERROR, can_log) << "Unexpected registers size"; -+ return false; -+ } -+ return true; -+} -+ -+bool GetFloatingPointRegisters32(pid_t tid, -+ FloatContext* context, -+ bool can_log) { -+ return false; -+} -+ -+bool GetFloatingPointRegisters64(pid_t tid, -+ FloatContext* context, -+ bool can_log) { -+ return GetRegisterSet(tid, NT_PRFPREG, &context->f64.f, can_log); -+} -+ -+bool GetThreadArea32(pid_t tid, -+ const ThreadContext& context, -+ LinuxVMAddress* address, -+ bool can_log) { -+ return false; -+} -+ -+bool GetThreadArea64(pid_t tid, -+ const ThreadContext& context, -+ LinuxVMAddress* address, -+ bool can_log) { -+ *address = context.t64.tp; -+ return true; -+} -+ -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ -+template -+bool GetRegisterSet(pid_t tid, int set, Destination* dest, bool can_log) { -+ iovec iov; -+ iov.iov_base = dest; -+ iov.iov_len = sizeof(*dest); -+ if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast(set), &iov) != 0) { -+ PLOG_IF(ERROR, can_log) << "ptrace"; -+ return false; -+ } -+ if (iov.iov_len != sizeof(*dest)) { -+ LOG_IF(ERROR, can_log) << "Unexpected registers size"; -+ return false; -+ } -+ return true; -+} -+ -+bool GetFloatingPointRegisters32(pid_t tid, -+ FloatContext* context, -+ bool can_log) { -+ return false; -+} -+ -+bool GetFloatingPointRegisters64(pid_t tid, -+ FloatContext* context, -+ bool can_log) { -+ return GetRegisterSet(tid, NT_PRFPREG, &context->f64.f, can_log); -+} -+ -+bool GetThreadArea32(pid_t tid, -+ const ThreadContext& context, -+ LinuxVMAddress* address, -+ bool can_log) { -+ return false; -+} -+ -+bool GetThreadArea64(pid_t tid, -+ const ThreadContext& context, -+ LinuxVMAddress* address, -+ bool can_log) { -+ *address = context.t64.tp; -+ return true; -+} -+ - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -Index: qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/util/linux/thread_info.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.11.orig/src/3rdparty/chromium/third_party/crashpad/crashpad/util/linux/thread_info.h -+++ qtwebengine-everywhere-src-5.15.11/src/3rdparty/chromium/third_party/crashpad/crashpad/util/linux/thread_info.h -@@ -79,6 +79,40 @@ union ThreadContext { - uint32_t cp0_status; - uint32_t cp0_cause; - uint32_t padding1_; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ // Reflects user_regs_struct in asm/ptrace.h. -+ uint32_t pc; -+ uint32_t ra; -+ uint32_t sp; -+ uint32_t gp; -+ uint32_t tp; -+ uint32_t t0; -+ uint32_t t1; -+ uint32_t t2; -+ uint32_t s0; -+ uint32_t s1; -+ uint32_t a0; -+ uint32_t a1; -+ uint32_t a2; -+ uint32_t a3; -+ uint32_t a4; -+ uint32_t a5; -+ uint32_t a6; -+ uint32_t a7; -+ uint32_t s2; -+ uint32_t s3; -+ uint32_t s4; -+ uint32_t s5; -+ uint32_t s6; -+ uint32_t s7; -+ uint32_t s8; -+ uint32_t s9; -+ uint32_t s10; -+ uint32_t s11; -+ uint32_t t3; -+ uint32_t t4; -+ uint32_t t5; -+ uint32_t t6; - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -@@ -132,6 +166,40 @@ union ThreadContext { - uint64_t cp0_badvaddr; - uint64_t cp0_status; - uint64_t cp0_cause; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ // Reflects user_regs_struct in asm/ptrace.h. -+ uint64_t pc; -+ uint64_t ra; -+ uint64_t sp; -+ uint64_t gp; -+ uint64_t tp; -+ uint64_t t0; -+ uint64_t t1; -+ uint64_t t2; -+ uint64_t s0; -+ uint64_t s1; -+ uint64_t a0; -+ uint64_t a1; -+ uint64_t a2; -+ uint64_t a3; -+ uint64_t a4; -+ uint64_t a5; -+ uint64_t a6; -+ uint64_t a7; -+ uint64_t s2; -+ uint64_t s3; -+ uint64_t s4; -+ uint64_t s5; -+ uint64_t s6; -+ uint64_t s7; -+ uint64_t s8; -+ uint64_t s9; -+ uint64_t s10; -+ uint64_t s11; -+ uint64_t t3; -+ uint64_t t4; -+ uint64_t t5; -+ uint64_t t6; - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -@@ -143,11 +211,12 @@ union ThreadContext { - using NativeThreadContext = user_regs; - #elif defined(ARCH_CPU_MIPS_FAMILY) - // No appropriate NativeThreadsContext type available for MIPS -+#elif defined(ARCH_CPU_RISCV_FAMILY) - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64 - --#if !defined(ARCH_CPU_MIPS_FAMILY) -+#if !defined(ARCH_CPU_MIPS_FAMILY) && !defined(ARCH_CPU_RISCV_FAMILY) - #if defined(ARCH_CPU_32_BITS) - static_assert(sizeof(t32_t) == sizeof(NativeThreadContext), "Size mismatch"); - #else // ARCH_CPU_64_BITS -@@ -218,6 +287,9 @@ union FloatContext { - } fpregs[32]; - uint32_t fpcsr; - uint32_t fpu_id; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ uint64_t f[32]; -+ uint32_t fcsr; - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -@@ -252,6 +324,9 @@ union FloatContext { - double fpregs[32]; - uint32_t fpcsr; - uint32_t fpu_id; -+#elif defined(ARCH_CPU_RISCV_FAMILY) -+ uint64_t f[32]; -+ uint32_t fcsr; - #else - #error Port. - #endif // ARCH_CPU_X86_FAMILY -@@ -280,6 +355,7 @@ union FloatContext { - static_assert(sizeof(f64) == sizeof(user_fpsimd_struct), "Size mismatch"); - #elif defined(ARCH_CPU_MIPS_FAMILY) - // No appropriate floating point context native type for available MIPS. -+#elif defined(ARCH_CPU_RISCV_FAMILY) - #else - #error Port. - #endif // ARCH_CPU_X86 diff --git a/riscv-sandbox.patch b/riscv-sandbox.patch deleted file mode 100644 index 7544f1c..0000000 --- a/riscv-sandbox.patch +++ /dev/null @@ -1,2166 +0,0 @@ -riscv64 support patch taken from Opensuse: -https://build.opensuse.org/package/show/openSUSE:Factory:RISCV/libqt5-qtwebengine?rev=110 - -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/features.gni -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/features.gni -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/features.gni -@@ -11,7 +11,8 @@ import("//build/config/nacl/config.gni") - use_seccomp_bpf = (is_linux || is_chromeos || is_android) && - (current_cpu == "x86" || current_cpu == "x64" || - current_cpu == "arm" || current_cpu == "arm64" || -- current_cpu == "mipsel" || current_cpu == "mips64el") -+ current_cpu == "mipsel" || current_cpu == "mips64el" || -+ current_cpu == "riscv64") - - use_seccomp_bpf = use_seccomp_bpf || is_nacl_nonsfi - -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h -@@ -56,6 +56,12 @@ - #define MAX_PUBLIC_SYSCALL __NR_syscalls - #define MAX_SYSCALL MAX_PUBLIC_SYSCALL - -+#elif defined(__riscv) -+ -+#define MIN_SYSCALL 0u -+#define MAX_PUBLIC_SYSCALL 1024u -+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL -+ - #else - #error "Unsupported architecture" - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h -@@ -346,6 +346,48 @@ struct regs_struct { - #define SECCOMP_PT_PARM4(_regs) (_regs).regs[3] - #define SECCOMP_PT_PARM5(_regs) (_regs).regs[4] - #define SECCOMP_PT_PARM6(_regs) (_regs).regs[5] -+ -+#elif defined(__riscv) -+struct regs_struct { -+ unsigned long regs[32]; -+}; -+ -+#define SECCOMP_ARCH AUDIT_ARCH_RISCV64 -+ -+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.__gregs[_reg]) -+ -+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, REG_A0) -+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, REG_A0+7) -+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.__gregs[REG_PC] -+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, REG_A0) -+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, REG_A0+1) -+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, REG_A0+2) -+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, REG_A0+3) -+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, REG_A0+4) -+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, REG_A0+5) -+#define SECCOMP_PARM7(_ctx) SECCOMP_REG(_ctx, REG_A0+6) -+ -+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr)) -+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch)) -+#define SECCOMP_IP_MSB_IDX \ -+ (offsetof(struct arch_seccomp_data, instruction_pointer) + 4) -+#define SECCOMP_IP_LSB_IDX \ -+ (offsetof(struct arch_seccomp_data, instruction_pointer) + 0) -+#define SECCOMP_ARG_MSB_IDX(nr) \ -+ (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4) -+#define SECCOMP_ARG_LSB_IDX(nr) \ -+ (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0) -+ -+#define SECCOMP_PT_RESULT(_regs) (_regs).regs[REG_A0] -+#define SECCOMP_PT_SYSCALL(_regs) (_regs).regs[REG_A0+7] -+#define SECCOMP_PT_IP(_regs) (_regs).regs[REG_PC] -+#define SECCOMP_PT_PARM1(_regs) (_regs).regs[REG_A0] -+#define SECCOMP_PT_PARM2(_regs) (_regs).regs[REG_A0+1] -+#define SECCOMP_PT_PARM3(_regs) (_regs).regs[REG_A0+2] -+#define SECCOMP_PT_PARM4(_regs) (_regs).regs[REG_A0+3] -+#define SECCOMP_PT_PARM5(_regs) (_regs).regs[REG_A0+4] -+#define SECCOMP_PT_PARM6(_regs) (_regs).regs[REG_A0+5] -+#define SECCOMP_PT_PARM7(_regs) (_regs).regs[REG_A0+6] - #else - #error Unsupported target platform - -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - #if defined(ANDROID) - // Work-around for buggy headers in Android's NDK -@@ -2013,7 +2014,15 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN - BPF_ASSERT_EQ(kTraceData, data); - - regs_struct regs; -+#if defined(__riscv) -+ iovec iov; -+ iov.iov_base = ®s; -+ iov.iov_len = sizeof(regs); -+ BPF_ASSERT_NE(-1, ptrace(PTRACE_GETREGSET, pid, -+ reinterpret_case(NT_PRSTATUS), &iov)); -+#else - BPF_ASSERT_NE(-1, ptrace(PTRACE_GETREGS, pid, NULL, ®s)); -+#endif - switch (SECCOMP_PT_SYSCALL(regs)) { - case __NR_write: - // Skip writes to stdout, make it return kExpectedReturnValue. Allow -@@ -2021,7 +2030,14 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN - if (SECCOMP_PT_PARM1(regs) == STDOUT_FILENO) { - BPF_ASSERT_NE(-1, SetSyscall(pid, ®s, -1)); - SECCOMP_PT_RESULT(regs) = kExpectedReturnValue; -+#if defined(__riscv) -+ iov.iov_len = sizeof(regs); -+ BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGSET, pid, -+ reinterpret_cast(NT_PRSTATUS), -+ &iov)); -+#else - BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGS, pid, NULL, ®s)); -+#endif - } - break; - -@@ -2029,7 +2045,13 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN - // Rewrite to exit(kExpectedReturnValue). - BPF_ASSERT_NE(-1, SetSyscall(pid, ®s, __NR_exit)); - SECCOMP_PT_PARM1(regs) = kExpectedReturnValue; -+#if defined(__riscv) -+ iov.iov_len = sizeof(regs); -+ BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGSET, pid, -+ reinterpret_cast(NT_PRSTATUS), &iov)); -+#else - BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGS, pid, NULL, ®s)); -+#endif - break; - - default: -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc -@@ -59,6 +59,9 @@ bool IsBaselinePolicyAllowed(int sysno) - #if defined(__mips__) - SyscallSets::IsMipsPrivate(sysno) || - #endif -+#if defined(__riscv) -+ SyscallSets::IsRiscvPrivate(sysno) || -+#endif - SyscallSets::IsAllowedOperationOnFd(sysno); - } - -@@ -181,7 +184,7 @@ ResultExpr EvaluateSyscallImpl(int fs_de - return RestrictFcntlCommands(); - #endif - --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - // fork() is never used as a system call (clone() is used instead), but we - // have seen it in fallback code on Android. - if (sysno == __NR_fork) { -@@ -226,7 +229,7 @@ ResultExpr EvaluateSyscallImpl(int fs_de - } - - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - if (sysno == __NR_mmap) - return RestrictMmapFlags(); - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc -@@ -243,7 +243,7 @@ BPF_TEST_C(BaselinePolicy, GetRandom, Ba - } - - // Not all architectures can restrict the domain for socketpair(). --#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) -+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__riscv) - BPF_DEATH_TEST_C(BaselinePolicy, - SocketpairWrongDomain, - DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), -@@ -252,7 +252,7 @@ BPF_DEATH_TEST_C(BaselinePolicy, - ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv)); - _exit(1); - } --#endif // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) -+#endif // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__riscv) - - BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) { - errno = 0; -@@ -316,7 +316,7 @@ TEST_BASELINE_SIGSYS(__NR_sysinfo) - TEST_BASELINE_SIGSYS(__NR_syslog) - TEST_BASELINE_SIGSYS(__NR_timer_create) - --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - TEST_BASELINE_SIGSYS(__NR_eventfd) - TEST_BASELINE_SIGSYS(__NR_inotify_init) - TEST_BASELINE_SIGSYS(__NR_vserver) -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc -@@ -41,6 +41,7 @@ - #include - #include - #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(__arm__) && \ -+ !defined(__riscv) && \ - !defined(__aarch64__) && !defined(PTRACE_GET_THREAD_AREA) - - // Also include asm/ptrace-abi.h since ptrace.h in older libc (for instance -@@ -411,7 +412,7 @@ ResultExpr RestrictPrlimitToGetrlimit(pi - ResultExpr RestrictPtrace() { - const Arg request(0); - return Switch(request).CASES(( --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - PTRACE_GETREGS, - PTRACE_GETFPREGS, - #if defined(TRACE_GET_THREAD_AREA) -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc -@@ -7,6 +7,7 @@ - #include - #include - #include -+#include - #include - #include - #include -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc -@@ -86,7 +86,7 @@ bool SyscallSets::IsUmask(int sysno) { - // Both EPERM and ENOENT are valid errno unless otherwise noted in comment. - bool SyscallSets::IsFileSystem(int sysno) { - switch (sysno) { --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_access: // EPERM not a valid errno. - case __NR_chmod: - case __NR_chown: -@@ -112,13 +112,13 @@ bool SyscallSets::IsFileSystem(int sysno - #endif - case __NR_ustat: // Same as above. Deprecated. - case __NR_utimes: --#endif // !defined(__aarch64__) -+#endif // !defined(__aarch64__) && !defined(__riscv) - - case __NR_execve: - case __NR_faccessat: // EPERM not a valid errno. - case __NR_fchmodat: - case __NR_fchownat: // Should be called chownat ? --#if defined(__x86_64__) || defined(__aarch64__) -+#if defined(__x86_64__) || defined(__aarch64__) || defined(__riscv) - case __NR_newfstatat: // fstatat(). EPERM not a valid errno. - #elif defined(__i386__) || defined(__arm__) || \ - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)) -@@ -202,7 +202,7 @@ bool SyscallSets::IsAllowedFileSystemAcc - case __NR_oldfstat: - #endif - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_sync_file_range: // EPERM not a valid errno. - #elif defined(__arm__) - case __NR_arm_sync_file_range: // EPERM not a valid errno. -@@ -226,7 +226,7 @@ bool SyscallSets::IsDeniedFileSystemAcce - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)) - case __NR_ftruncate64: - #endif --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_getdents: // EPERM not a valid errno. - #endif - case __NR_getdents64: // EPERM not a valid errno. -@@ -305,7 +305,7 @@ bool SyscallSets::IsProcessPrivilegeChan - bool SyscallSets::IsProcessGroupOrSession(int sysno) { - switch (sysno) { - case __NR_setpgid: --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_getpgrp: - #endif - case __NR_setsid: -@@ -334,7 +334,7 @@ bool SyscallSets::IsAllowedSignalHandlin - case __NR_rt_sigsuspend: - case __NR_rt_tgsigqueueinfo: - case __NR_sigaltstack: --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_signalfd: - #endif - case __NR_signalfd4: -@@ -358,12 +358,12 @@ bool SyscallSets::IsAllowedOperationOnFd - switch (sysno) { - case __NR_close: - case __NR_dup: --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_dup2: - #endif - case __NR_dup3: - #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_shutdown: - #endif - return true; -@@ -402,7 +402,7 @@ bool SyscallSets::IsAllowedProcessStartO - return true; - case __NR_clone: // Should be parameter-restricted. - case __NR_setns: // Privileged. --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_fork: - #endif - #if defined(__i386__) || defined(__x86_64__) -@@ -413,7 +413,7 @@ bool SyscallSets::IsAllowedProcessStartO - #endif - case __NR_set_tid_address: - case __NR_unshare: --#if !defined(__mips__) && !defined(__aarch64__) -+#if !defined(__mips__) && !defined(__aarch64__) && !defined(__riscv) - case __NR_vfork: - #endif - default: -@@ -434,7 +434,7 @@ bool SyscallSets::IsAllowedFutex(int sys - - bool SyscallSets::IsAllowedEpoll(int sysno) { - switch (sysno) { --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_epoll_create: - case __NR_epoll_wait: - #endif -@@ -455,14 +455,14 @@ bool SyscallSets::IsAllowedEpoll(int sys - - bool SyscallSets::IsAllowedGetOrModifySocket(int sysno) { - switch (sysno) { --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_pipe: - #endif - case __NR_pipe2: - return true; - default: - #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_socketpair: // We will want to inspect its argument. - #endif - return false; -@@ -472,7 +472,7 @@ bool SyscallSets::IsAllowedGetOrModifySo - bool SyscallSets::IsDeniedGetOrModifySocket(int sysno) { - switch (sysno) { - #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_accept: - case __NR_accept4: - case __NR_bind: -@@ -526,7 +526,7 @@ bool SyscallSets::IsAllowedAddressSpaceA - case __NR_mincore: - case __NR_mlockall: - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_mmap: - #endif - #if defined(__i386__) || defined(__arm__) || \ -@@ -559,7 +559,7 @@ bool SyscallSets::IsAllowedGeneralIo(int - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)) - case __NR__llseek: - #endif --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_poll: - #endif - case __NR_ppoll: -@@ -572,7 +572,7 @@ bool SyscallSets::IsAllowedGeneralIo(int - case __NR_recv: - #endif - #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_recvfrom: // Could specify source. - case __NR_recvmsg: // Could specify source. - #endif -@@ -587,7 +587,7 @@ bool SyscallSets::IsAllowedGeneralIo(int - case __NR_send: - #endif - #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_sendmsg: // Could specify destination. - case __NR_sendto: // Could specify destination. - #endif -@@ -637,7 +637,7 @@ bool SyscallSets::IsSeccomp(int sysno) { - bool SyscallSets::IsAllowedBasicScheduler(int sysno) { - switch (sysno) { - case __NR_sched_yield: --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_pause: - #endif - case __NR_nanosleep: -@@ -721,7 +721,7 @@ bool SyscallSets::IsNuma(int sysno) { - case __NR_getcpu: - case __NR_mbind: - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_migrate_pages: - #endif - case __NR_move_pages: -@@ -750,7 +750,7 @@ bool SyscallSets::IsGlobalProcessEnviron - switch (sysno) { - case __NR_acct: // Privileged. - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_getrlimit: - #endif - #if defined(__i386__) || defined(__arm__) -@@ -785,7 +785,7 @@ bool SyscallSets::IsDebug(int sysno) { - - bool SyscallSets::IsGlobalSystemStatus(int sysno) { - switch (sysno) { --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR__sysctl: - case __NR_sysfs: - #endif -@@ -803,7 +803,7 @@ bool SyscallSets::IsGlobalSystemStatus(i - - bool SyscallSets::IsEventFd(int sysno) { - switch (sysno) { --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_eventfd: - #endif - case __NR_eventfd2: -@@ -839,6 +839,7 @@ bool SyscallSets::IsKeyManagement(int sy - } - - #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ -+ defined(__riscv) || \ - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) - bool SyscallSets::IsSystemVSemaphores(int sysno) { - switch (sysno) { -@@ -854,7 +855,7 @@ bool SyscallSets::IsSystemVSemaphores(in - #endif - - #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ -- defined(__aarch64__) || \ -+ defined(__aarch64__) || defined(__riscv) || \ - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) - // These give a lot of ambient authority and bypass the setuid sandbox. - bool SyscallSets::IsSystemVSharedMemory(int sysno) { -@@ -871,6 +872,7 @@ bool SyscallSets::IsSystemVSharedMemory( - #endif - - #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ -+ defined(__riscv) || \ - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) - bool SyscallSets::IsSystemVMessageQueue(int sysno) { - switch (sysno) { -@@ -902,6 +904,7 @@ bool SyscallSets::IsSystemVIpc(int sysno - - bool SyscallSets::IsAnySystemV(int sysno) { - #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ -+ defined(__riscv) || \ - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) - return IsSystemVMessageQueue(sysno) || IsSystemVSemaphores(sysno) || - IsSystemVSharedMemory(sysno); -@@ -935,7 +938,7 @@ bool SyscallSets::IsAdvancedScheduler(in - bool SyscallSets::IsInotify(int sysno) { - switch (sysno) { - case __NR_inotify_add_watch: --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_inotify_init: - #endif - case __NR_inotify_init1: -@@ -1066,7 +1069,7 @@ bool SyscallSets::IsMisc(int sysno) { - #if defined(__x86_64__) - case __NR_tuxcall: - #endif --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_vserver: - #endif - return true; -@@ -1101,6 +1104,18 @@ bool SyscallSets::IsArmPrivate(int sysno - } - #endif // defined(__arm__) - -+#if defined(__riscv) -+bool SyscallSets::IsRiscvPrivate(int sysno) { -+ switch (sysno) { -+ case __NR_riscv_hwprobe: -+ case __NR_riscv_flush_icache: -+ return true; -+ default: -+ return false; -+ } -+} -+#endif // defined(__riscv) -+ - #if defined(__mips__) - bool SyscallSets::IsMipsPrivate(int sysno) { - switch (sysno) { -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h -@@ -49,7 +49,7 @@ class SANDBOX_EXPORT SyscallSets { - #endif - - #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - static bool IsNetworkSocketInformation(int sysno); - #endif - -@@ -72,18 +72,21 @@ class SANDBOX_EXPORT SyscallSets { - static bool IsAsyncIo(int sysno); - static bool IsKeyManagement(int sysno); - #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ -- (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) -+ (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) || \ -+ defined(__riscv) - static bool IsSystemVSemaphores(int sysno); - #endif - #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ - defined(__aarch64__) || \ -- (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) -+ (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) || \ -+ defined(__riscv) - // These give a lot of ambient authority and bypass the setuid sandbox. - static bool IsSystemVSharedMemory(int sysno); - #endif - - #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \ -- (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) -+ (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)) || \ -+ defined(__riscv) - static bool IsSystemVMessageQueue(int sysno); - #endif - -@@ -110,6 +113,9 @@ class SANDBOX_EXPORT SyscallSets { - static bool IsMipsPrivate(int sysno); - static bool IsMipsMisc(int sysno); - #endif // defined(__mips__) -+#if defined(__riscv) -+ static bool IsRiscvPrivate(int sysno); -+#endif - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(SyscallSets); - }; -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf/syscall.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf/syscall.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf/syscall.cc -@@ -18,7 +18,7 @@ namespace sandbox { - namespace { - - #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ -- defined(ARCH_CPU_MIPS_FAMILY) -+ defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_RISCV_FAMILY) - // Number that's not currently used by any Linux kernel ABIs. - const int kInvalidSyscallNumber = 0x351d3; - #else -@@ -312,6 +312,28 @@ asm(// We need to be able to tell the ke - "2:ret\n" - ".cfi_endproc\n" - ".size SyscallAsm, .-SyscallAsm\n" -+#elif defined(__riscv) -+ ".text\n" -+ ".align 2\n" -+ ".type SyscallAsm, %function\n" -+ "SyscallAsm:\n" -+ ".cfi_startproc\n" -+ "bgez a0,1f\n" -+ "lla a0,2f\n" -+ "j 2f\n" -+ "1:mv a7, a0\n" -+ "ld a0, (a1)\n" -+ "ld a2, 16(a1)\n" -+ "ld a3, 24(a1)\n" -+ "ld a4, 32(a1)\n" -+ "ld a5, 40(a1)\n" -+ "ld a6, 48(a1)\n" -+ "ld a1, 8(a1)\n" -+ // Enter the kernel -+ "scall\n" -+ "2:ret\n" -+ ".cfi_endproc\n" -+ ".size SyscallAsm, .-SyscallAsm\n" - #endif - ); // asm - -@@ -323,6 +345,10 @@ intptr_t SyscallAsm(intptr_t nr, const i - extern "C" { - intptr_t SyscallAsm(intptr_t nr, const intptr_t args[8]); - } -+#elif defined(__riscv) -+extern "C" { -+intptr_t SyscallAsm(intptr_t nr, const intptr_t args[7]); -+} - #endif - - } // namespace -@@ -355,6 +381,10 @@ intptr_t Syscall::Call(int nr, - // where that makes sense. - #if defined(__mips__) - const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7}; -+#elif defined(__riscv) -+ DCHECK_EQ(p7, 0) << " Support for syscalls with more than seven arguments " -+ "not added for this architecture"; -+ const intptr_t args[7] = {p0, p1, p2, p3, p4, p5, p6}; - #else - DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not " - "added for this architecture"; -@@ -429,6 +459,8 @@ intptr_t Syscall::Call(int nr, - ret = inout; - } - -+#elif defined(__riscv) -+ intptr_t ret = SyscallAsm(nr, args); - #else - #error "Unimplemented architecture" - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf/trap.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/seccomp-bpf/trap.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/seccomp-bpf/trap.cc -@@ -217,6 +217,18 @@ void Trap::SigSys(int nr, LinuxSigInfo* - SECCOMP_PARM6(ctx), - SECCOMP_PARM7(ctx), - SECCOMP_PARM8(ctx)); -+#elif defined(__riscv) -+ // RISC-V supports up to seven arguments for syscall. -+ // However, seccomp bpf can filter only up to six arguments, so using seven -+ // arguments has sense only when using UnsafeTrap() handler. -+ rc = Syscall::Call(SECCOMP_SYSCALL(ctx), -+ SECCOMP_PARM1(ctx), -+ SECCOMP_PARM2(ctx), -+ SECCOMP_PARM3(ctx), -+ SECCOMP_PARM4(ctx), -+ SECCOMP_PARM5(ctx), -+ SECCOMP_PARM6(ctx), -+ SECCOMP_PARM7(ctx)); - #else - rc = Syscall::Call(SECCOMP_SYSCALL(ctx), - SECCOMP_PARM1(ctx), -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/services/credentials.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/services/credentials.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/services/credentials.cc -@@ -81,7 +81,7 @@ bool ChrootToSafeEmptyDir() { - pid_t pid = -1; - alignas(16) char stack_buf[PTHREAD_STACK_MIN]; - #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ -- defined(ARCH_CPU_MIPS_FAMILY) -+ defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_RISCV_FAMILY) - // The stack grows downward. - void* stack = stack_buf + sizeof(stack_buf); - #else -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/services/syscall_wrappers.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/services/syscall_wrappers.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/services/syscall_wrappers.cc -@@ -61,7 +61,7 @@ long sys_clone(unsigned long flags, - #if defined(ARCH_CPU_X86_64) - return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls); - #elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \ -- defined(ARCH_CPU_MIPS_FAMILY) -+ defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_RISCV_FAMILY) - // CONFIG_CLONE_BACKWARDS defined. - return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid); - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/syscall_broker/broker_process.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/syscall_broker/broker_process.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/syscall_broker/broker_process.cc -@@ -128,43 +128,43 @@ bool BrokerProcess::IsSyscallBrokerable( - // and are default disabled in Android. So, we should refuse to broker them - // to be consistent with the platform's restrictions. - switch (sysno) { --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_access: - #endif - case __NR_faccessat: - return !fast_check || allowed_command_set_.test(COMMAND_ACCESS); - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_mkdir: - #endif - case __NR_mkdirat: - return !fast_check || allowed_command_set_.test(COMMAND_MKDIR); - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_open: - #endif - case __NR_openat: - return !fast_check || allowed_command_set_.test(COMMAND_OPEN); - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_readlink: - #endif - case __NR_readlinkat: - return !fast_check || allowed_command_set_.test(COMMAND_READLINK); - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_rename: - #endif - case __NR_renameat: - case __NR_renameat2: - return !fast_check || allowed_command_set_.test(COMMAND_RENAME); - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_rmdir: - return !fast_check || allowed_command_set_.test(COMMAND_RMDIR); - #endif - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_stat: - case __NR_lstat: - #endif -@@ -174,7 +174,7 @@ bool BrokerProcess::IsSyscallBrokerable( - #if defined(__NR_fstatat64) - case __NR_fstatat64: - #endif --#if defined(__x86_64__) || defined(__aarch64__) -+#if defined(__x86_64__) || defined(__aarch64__) || defined(__riscv) - case __NR_newfstatat: - #endif - return !fast_check || allowed_command_set_.test(COMMAND_STAT); -@@ -189,7 +189,7 @@ bool BrokerProcess::IsSyscallBrokerable( - return !fast_check || allowed_command_set_.test(COMMAND_STAT); - #endif - --#if !defined(__aarch64__) && !defined(OS_ANDROID) -+#if !defined(__aarch64__) && !defined(OS_ANDROID) && !defined(__riscv) - case __NR_unlink: - return !fast_check || allowed_command_set_.test(COMMAND_UNLINK); - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_seccomp.h -@@ -41,6 +41,9 @@ - #ifndef EM_AARCH64 - #define EM_AARCH64 183 - #endif -+#ifndef EM_RISCV -+#define EM_RISCV 243 -+#endif - - #ifndef __AUDIT_ARCH_64BIT - #define __AUDIT_ARCH_64BIT 0x80000000 -@@ -73,6 +76,9 @@ - #ifndef AUDIT_ARCH_AARCH64 - #define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) - #endif -+#ifndef AUDIT_ARCH_RISCV64 -+#define AUDIT_ARCH_RISCV64 (EM_RISCV|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -+#endif - - // For prctl.h - #ifndef PR_SET_SECCOMP -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_signal.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/system_headers/linux_signal.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_signal.h -@@ -13,7 +13,7 @@ - // (not undefined, but defined different values and in different memory - // layouts). So, fill the gap here. - #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - - #define LINUX_SIGHUP 1 - #define LINUX_SIGINT 2 -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_stat.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/system_headers/linux_stat.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_stat.h -@@ -132,7 +132,7 @@ struct kernel_stat { - int st_blocks; - int st_pad4[14]; - }; --#elif defined(__aarch64__) -+#elif defined(__aarch64__) || defined(__riscv) - struct kernel_stat { - unsigned long st_dev; - unsigned long st_ino; -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_syscalls.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/linux/system_headers/linux_syscalls.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/linux_syscalls.h -@@ -35,5 +35,9 @@ - #include "sandbox/linux/system_headers/arm64_linux_syscalls.h" - #endif - -+#if defined(__riscv) && __riscv_xlen == 64 -+#include "sandbox/linux/system_headers/riscv64_linux_syscalls.h" -+#endif -+ - #endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_ - -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/riscv64_linux_syscalls.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/linux/system_headers/riscv64_linux_syscalls.h -@@ -0,0 +1,1226 @@ -+// Copyright 2014 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_RISCV64_LINUX_SYSCALLS_H_ -+#define SANDBOX_LINUX_SYSTEM_HEADERS_RISCV64_LINUX_SYSCALLS_H_ -+ -+#include -+ -+#if !defined(__NR_io_setup) -+#define __NR_io_setup 0 -+#endif -+ -+#if !defined(__NR_io_destroy) -+#define __NR_io_destroy 1 -+#endif -+ -+#if !defined(__NR_io_submit) -+#define __NR_io_submit 2 -+#endif -+ -+#if !defined(__NR_io_cancel) -+#define __NR_io_cancel 3 -+#endif -+ -+#if !defined(__NR_io_getevents) -+#define __NR_io_getevents 4 -+#endif -+ -+#if !defined(__NR_setxattr) -+#define __NR_setxattr 5 -+#endif -+ -+#if !defined(__NR_lsetxattr) -+#define __NR_lsetxattr 6 -+#endif -+ -+#if !defined(__NR_fsetxattr) -+#define __NR_fsetxattr 7 -+#endif -+ -+#if !defined(__NR_getxattr) -+#define __NR_getxattr 8 -+#endif -+ -+#if !defined(__NR_lgetxattr) -+#define __NR_lgetxattr 9 -+#endif -+ -+#if !defined(__NR_fgetxattr) -+#define __NR_fgetxattr 10 -+#endif -+ -+#if !defined(__NR_listxattr) -+#define __NR_listxattr 11 -+#endif -+ -+#if !defined(__NR_llistxattr) -+#define __NR_llistxattr 12 -+#endif -+ -+#if !defined(__NR_flistxattr) -+#define __NR_flistxattr 13 -+#endif -+ -+#if !defined(__NR_removexattr) -+#define __NR_removexattr 14 -+#endif -+ -+#if !defined(__NR_lremovexattr) -+#define __NR_lremovexattr 15 -+#endif -+ -+#if !defined(__NR_fremovexattr) -+#define __NR_fremovexattr 16 -+#endif -+ -+#if !defined(__NR_getcwd) -+#define __NR_getcwd 17 -+#endif -+ -+#if !defined(__NR_lookup_dcookie) -+#define __NR_lookup_dcookie 18 -+#endif -+ -+#if !defined(__NR_eventfd2) -+#define __NR_eventfd2 19 -+#endif -+ -+#if !defined(__NR_epoll_create1) -+#define __NR_epoll_create1 20 -+#endif -+ -+#if !defined(__NR_epoll_ctl) -+#define __NR_epoll_ctl 21 -+#endif -+ -+#if !defined(__NR_epoll_pwait) -+#define __NR_epoll_pwait 22 -+#endif -+ -+#if !defined(__NR_dup) -+#define __NR_dup 23 -+#endif -+ -+#if !defined(__NR_dup3) -+#define __NR_dup3 24 -+#endif -+ -+#if !defined(__NR_fcntl) -+#define __NR_fcntl 25 -+#endif -+ -+#if !defined(__NR_inotify_init1) -+#define __NR_inotify_init1 26 -+#endif -+ -+#if !defined(__NR_inotify_add_watch) -+#define __NR_inotify_add_watch 27 -+#endif -+ -+#if !defined(__NR_inotify_rm_watch) -+#define __NR_inotify_rm_watch 28 -+#endif -+ -+#if !defined(__NR_ioctl) -+#define __NR_ioctl 29 -+#endif -+ -+#if !defined(__NR_ioprio_set) -+#define __NR_ioprio_set 30 -+#endif -+ -+#if !defined(__NR_ioprio_get) -+#define __NR_ioprio_get 31 -+#endif -+ -+#if !defined(__NR_flock) -+#define __NR_flock 32 -+#endif -+ -+#if !defined(__NR_mknodat) -+#define __NR_mknodat 33 -+#endif -+ -+#if !defined(__NR_mkdirat) -+#define __NR_mkdirat 34 -+#endif -+ -+#if !defined(__NR_unlinkat) -+#define __NR_unlinkat 35 -+#endif -+ -+#if !defined(__NR_symlinkat) -+#define __NR_symlinkat 36 -+#endif -+ -+#if !defined(__NR_linkat) -+#define __NR_linkat 37 -+#endif -+ -+#if !defined(__NR_renameat) -+#define __NR_renameat 38 -+#endif -+ -+#if !defined(__NR_umount2) -+#define __NR_umount2 39 -+#endif -+ -+#if !defined(__NR_mount) -+#define __NR_mount 40 -+#endif -+ -+#if !defined(__NR_pivot_root) -+#define __NR_pivot_root 41 -+#endif -+ -+#if !defined(__NR_nfsservctl) -+#define __NR_nfsservctl 42 -+#endif -+ -+#if !defined(__NR_statfs) -+#define __NR_statfs 43 -+#endif -+ -+#if !defined(__NR_fstatfs) -+#define __NR_fstatfs 44 -+#endif -+ -+#if !defined(__NR_truncate) -+#define __NR_truncate 45 -+#endif -+ -+#if !defined(__NR_ftruncate) -+#define __NR_ftruncate 46 -+#endif -+ -+#if !defined(__NR_fallocate) -+#define __NR_fallocate 47 -+#endif -+ -+#if !defined(__NR_faccessat) -+#define __NR_faccessat 48 -+#endif -+ -+#if !defined(__NR_chdir) -+#define __NR_chdir 49 -+#endif -+ -+#if !defined(__NR_fchdir) -+#define __NR_fchdir 50 -+#endif -+ -+#if !defined(__NR_chroot) -+#define __NR_chroot 51 -+#endif -+ -+#if !defined(__NR_fchmod) -+#define __NR_fchmod 52 -+#endif -+ -+#if !defined(__NR_fchmodat) -+#define __NR_fchmodat 53 -+#endif -+ -+#if !defined(__NR_fchownat) -+#define __NR_fchownat 54 -+#endif -+ -+#if !defined(__NR_fchown) -+#define __NR_fchown 55 -+#endif -+ -+#if !defined(__NR_openat) -+#define __NR_openat 56 -+#endif -+ -+#if !defined(__NR_close) -+#define __NR_close 57 -+#endif -+ -+#if !defined(__NR_vhangup) -+#define __NR_vhangup 58 -+#endif -+ -+#if !defined(__NR_pipe2) -+#define __NR_pipe2 59 -+#endif -+ -+#if !defined(__NR_quotactl) -+#define __NR_quotactl 60 -+#endif -+ -+#if !defined(__NR_getdents64) -+#define __NR_getdents64 61 -+#endif -+ -+#if !defined(__NR_lseek) -+#define __NR_lseek 62 -+#endif -+ -+#if !defined(__NR_read) -+#define __NR_read 63 -+#endif -+ -+#if !defined(__NR_write) -+#define __NR_write 64 -+#endif -+ -+#if !defined(__NR_readv) -+#define __NR_readv 65 -+#endif -+ -+#if !defined(__NR_writev) -+#define __NR_writev 66 -+#endif -+ -+#if !defined(__NR_pread64) -+#define __NR_pread64 67 -+#endif -+ -+#if !defined(__NR_pwrite64) -+#define __NR_pwrite64 68 -+#endif -+ -+#if !defined(__NR_preadv) -+#define __NR_preadv 69 -+#endif -+ -+#if !defined(__NR_pwritev) -+#define __NR_pwritev 70 -+#endif -+ -+#if !defined(__NR_sendfile) -+#define __NR_sendfile 71 -+#endif -+ -+#if !defined(__NR_pselect6) -+#define __NR_pselect6 72 -+#endif -+ -+#if !defined(__NR_ppoll) -+#define __NR_ppoll 73 -+#endif -+ -+#if !defined(__NR_signalfd4) -+#define __NR_signalfd4 74 -+#endif -+ -+#if !defined(__NR_vmsplice) -+#define __NR_vmsplice 75 -+#endif -+ -+#if !defined(__NR_splice) -+#define __NR_splice 76 -+#endif -+ -+#if !defined(__NR_tee) -+#define __NR_tee 77 -+#endif -+ -+#if !defined(__NR_readlinkat) -+#define __NR_readlinkat 78 -+#endif -+ -+#if !defined(__NR_newfstatat) -+#define __NR_newfstatat 79 -+#endif -+ -+#if !defined(__NR_fstat) -+#define __NR_fstat 80 -+#endif -+ -+#if !defined(__NR_sync) -+#define __NR_sync 81 -+#endif -+ -+#if !defined(__NR_fsync) -+#define __NR_fsync 82 -+#endif -+ -+#if !defined(__NR_fdatasync) -+#define __NR_fdatasync 83 -+#endif -+ -+#if !defined(__NR_sync_file_range) -+#define __NR_sync_file_range 84 -+#endif -+ -+#if !defined(__NR_timerfd_create) -+#define __NR_timerfd_create 85 -+#endif -+ -+#if !defined(__NR_timerfd_settime) -+#define __NR_timerfd_settime 86 -+#endif -+ -+#if !defined(__NR_timerfd_gettime) -+#define __NR_timerfd_gettime 87 -+#endif -+ -+#if !defined(__NR_utimensat) -+#define __NR_utimensat 88 -+#endif -+ -+#if !defined(__NR_acct) -+#define __NR_acct 89 -+#endif -+ -+#if !defined(__NR_capget) -+#define __NR_capget 90 -+#endif -+ -+#if !defined(__NR_capset) -+#define __NR_capset 91 -+#endif -+ -+#if !defined(__NR_personality) -+#define __NR_personality 92 -+#endif -+ -+#if !defined(__NR_exit) -+#define __NR_exit 93 -+#endif -+ -+#if !defined(__NR_exit_group) -+#define __NR_exit_group 94 -+#endif -+ -+#if !defined(__NR_waitid) -+#define __NR_waitid 95 -+#endif -+ -+#if !defined(__NR_set_tid_address) -+#define __NR_set_tid_address 96 -+#endif -+ -+#if !defined(__NR_unshare) -+#define __NR_unshare 97 -+#endif -+ -+#if !defined(__NR_futex) -+#define __NR_futex 98 -+#endif -+ -+#if !defined(__NR_set_robust_list) -+#define __NR_set_robust_list 99 -+#endif -+ -+#if !defined(__NR_get_robust_list) -+#define __NR_get_robust_list 100 -+#endif -+ -+#if !defined(__NR_nanosleep) -+#define __NR_nanosleep 101 -+#endif -+ -+#if !defined(__NR_getitimer) -+#define __NR_getitimer 102 -+#endif -+ -+#if !defined(__NR_setitimer) -+#define __NR_setitimer 103 -+#endif -+ -+#if !defined(__NR_kexec_load) -+#define __NR_kexec_load 104 -+#endif -+ -+#if !defined(__NR_init_module) -+#define __NR_init_module 105 -+#endif -+ -+#if !defined(__NR_delete_module) -+#define __NR_delete_module 106 -+#endif -+ -+#if !defined(__NR_timer_create) -+#define __NR_timer_create 107 -+#endif -+ -+#if !defined(__NR_timer_gettime) -+#define __NR_timer_gettime 108 -+#endif -+ -+#if !defined(__NR_timer_getoverrun) -+#define __NR_timer_getoverrun 109 -+#endif -+ -+#if !defined(__NR_timer_settime) -+#define __NR_timer_settime 110 -+#endif -+ -+#if !defined(__NR_timer_delete) -+#define __NR_timer_delete 111 -+#endif -+ -+#if !defined(__NR_clock_settime) -+#define __NR_clock_settime 112 -+#endif -+ -+#if !defined(__NR_clock_gettime) -+#define __NR_clock_gettime 113 -+#endif -+ -+#if !defined(__NR_clock_getres) -+#define __NR_clock_getres 114 -+#endif -+ -+#if !defined(__NR_clock_nanosleep) -+#define __NR_clock_nanosleep 115 -+#endif -+ -+#if !defined(__NR_syslog) -+#define __NR_syslog 116 -+#endif -+ -+#if !defined(__NR_ptrace) -+#define __NR_ptrace 117 -+#endif -+ -+#if !defined(__NR_sched_setparam) -+#define __NR_sched_setparam 118 -+#endif -+ -+#if !defined(__NR_sched_setscheduler) -+#define __NR_sched_setscheduler 119 -+#endif -+ -+#if !defined(__NR_sched_getscheduler) -+#define __NR_sched_getscheduler 120 -+#endif -+ -+#if !defined(__NR_sched_getparam) -+#define __NR_sched_getparam 121 -+#endif -+ -+#if !defined(__NR_sched_setaffinity) -+#define __NR_sched_setaffinity 122 -+#endif -+ -+#if !defined(__NR_sched_getaffinity) -+#define __NR_sched_getaffinity 123 -+#endif -+ -+#if !defined(__NR_sched_yield) -+#define __NR_sched_yield 124 -+#endif -+ -+#if !defined(__NR_sched_get_priority_max) -+#define __NR_sched_get_priority_max 125 -+#endif -+ -+#if !defined(__NR_sched_get_priority_min) -+#define __NR_sched_get_priority_min 126 -+#endif -+ -+#if !defined(__NR_sched_rr_get_interval) -+#define __NR_sched_rr_get_interval 127 -+#endif -+ -+#if !defined(__NR_restart_syscall) -+#define __NR_restart_syscall 128 -+#endif -+ -+#if !defined(__NR_kill) -+#define __NR_kill 129 -+#endif -+ -+#if !defined(__NR_tkill) -+#define __NR_tkill 130 -+#endif -+ -+#if !defined(__NR_tgkill) -+#define __NR_tgkill 131 -+#endif -+ -+#if !defined(__NR_sigaltstack) -+#define __NR_sigaltstack 132 -+#endif -+ -+#if !defined(__NR_rt_sigsuspend) -+#define __NR_rt_sigsuspend 133 -+#endif -+ -+#if !defined(__NR_rt_sigaction) -+#define __NR_rt_sigaction 134 -+#endif -+ -+#if !defined(__NR_rt_sigprocmask) -+#define __NR_rt_sigprocmask 135 -+#endif -+ -+#if !defined(__NR_rt_sigpending) -+#define __NR_rt_sigpending 136 -+#endif -+ -+#if !defined(__NR_rt_sigtimedwait) -+#define __NR_rt_sigtimedwait 137 -+#endif -+ -+#if !defined(__NR_rt_sigqueueinfo) -+#define __NR_rt_sigqueueinfo 138 -+#endif -+ -+#if !defined(__NR_rt_sigreturn) -+#define __NR_rt_sigreturn 139 -+#endif -+ -+#if !defined(__NR_setpriority) -+#define __NR_setpriority 140 -+#endif -+ -+#if !defined(__NR_getpriority) -+#define __NR_getpriority 141 -+#endif -+ -+#if !defined(__NR_reboot) -+#define __NR_reboot 142 -+#endif -+ -+#if !defined(__NR_setregid) -+#define __NR_setregid 143 -+#endif -+ -+#if !defined(__NR_setgid) -+#define __NR_setgid 144 -+#endif -+ -+#if !defined(__NR_setreuid) -+#define __NR_setreuid 145 -+#endif -+ -+#if !defined(__NR_setuid) -+#define __NR_setuid 146 -+#endif -+ -+#if !defined(__NR_setresuid) -+#define __NR_setresuid 147 -+#endif -+ -+#if !defined(__NR_getresuid) -+#define __NR_getresuid 148 -+#endif -+ -+#if !defined(__NR_setresgid) -+#define __NR_setresgid 149 -+#endif -+ -+#if !defined(__NR_getresgid) -+#define __NR_getresgid 150 -+#endif -+ -+#if !defined(__NR_setfsuid) -+#define __NR_setfsuid 151 -+#endif -+ -+#if !defined(__NR_setfsgid) -+#define __NR_setfsgid 152 -+#endif -+ -+#if !defined(__NR_times) -+#define __NR_times 153 -+#endif -+ -+#if !defined(__NR_setpgid) -+#define __NR_setpgid 154 -+#endif -+ -+#if !defined(__NR_getpgid) -+#define __NR_getpgid 155 -+#endif -+ -+#if !defined(__NR_getsid) -+#define __NR_getsid 156 -+#endif -+ -+#if !defined(__NR_setsid) -+#define __NR_setsid 157 -+#endif -+ -+#if !defined(__NR_getgroups) -+#define __NR_getgroups 158 -+#endif -+ -+#if !defined(__NR_setgroups) -+#define __NR_setgroups 159 -+#endif -+ -+#if !defined(__NR_uname) -+#define __NR_uname 160 -+#endif -+ -+#if !defined(__NR_sethostname) -+#define __NR_sethostname 161 -+#endif -+ -+#if !defined(__NR_setdomainname) -+#define __NR_setdomainname 162 -+#endif -+ -+#if !defined(__NR_getrlimit) -+#define __NR_getrlimit 163 -+#endif -+ -+#if !defined(__NR_setrlimit) -+#define __NR_setrlimit 164 -+#endif -+ -+#if !defined(__NR_getrusage) -+#define __NR_getrusage 165 -+#endif -+ -+#if !defined(__NR_umask) -+#define __NR_umask 166 -+#endif -+ -+#if !defined(__NR_prctl) -+#define __NR_prctl 167 -+#endif -+ -+#if !defined(__NR_getcpu) -+#define __NR_getcpu 168 -+#endif -+ -+#if !defined(__NR_gettimeofday) -+#define __NR_gettimeofday 169 -+#endif -+ -+#if !defined(__NR_settimeofday) -+#define __NR_settimeofday 170 -+#endif -+ -+#if !defined(__NR_adjtimex) -+#define __NR_adjtimex 171 -+#endif -+ -+#if !defined(__NR_getpid) -+#define __NR_getpid 172 -+#endif -+ -+#if !defined(__NR_getppid) -+#define __NR_getppid 173 -+#endif -+ -+#if !defined(__NR_getuid) -+#define __NR_getuid 174 -+#endif -+ -+#if !defined(__NR_geteuid) -+#define __NR_geteuid 175 -+#endif -+ -+#if !defined(__NR_getgid) -+#define __NR_getgid 176 -+#endif -+ -+#if !defined(__NR_getegid) -+#define __NR_getegid 177 -+#endif -+ -+#if !defined(__NR_gettid) -+#define __NR_gettid 178 -+#endif -+ -+#if !defined(__NR_sysinfo) -+#define __NR_sysinfo 179 -+#endif -+ -+#if !defined(__NR_mq_open) -+#define __NR_mq_open 180 -+#endif -+ -+#if !defined(__NR_mq_unlink) -+#define __NR_mq_unlink 181 -+#endif -+ -+#if !defined(__NR_mq_timedsend) -+#define __NR_mq_timedsend 182 -+#endif -+ -+#if !defined(__NR_mq_timedreceive) -+#define __NR_mq_timedreceive 183 -+#endif -+ -+#if !defined(__NR_mq_notify) -+#define __NR_mq_notify 184 -+#endif -+ -+#if !defined(__NR_mq_getsetattr) -+#define __NR_mq_getsetattr 185 -+#endif -+ -+#if !defined(__NR_msgget) -+#define __NR_msgget 186 -+#endif -+ -+#if !defined(__NR_msgctl) -+#define __NR_msgctl 187 -+#endif -+ -+#if !defined(__NR_msgrcv) -+#define __NR_msgrcv 188 -+#endif -+ -+#if !defined(__NR_msgsnd) -+#define __NR_msgsnd 189 -+#endif -+ -+#if !defined(__NR_semget) -+#define __NR_semget 190 -+#endif -+ -+#if !defined(__NR_semctl) -+#define __NR_semctl 191 -+#endif -+ -+#if !defined(__NR_semtimedop) -+#define __NR_semtimedop 192 -+#endif -+ -+#if !defined(__NR_semop) -+#define __NR_semop 193 -+#endif -+ -+#if !defined(__NR_shmget) -+#define __NR_shmget 194 -+#endif -+ -+#if !defined(__NR_shmctl) -+#define __NR_shmctl 195 -+#endif -+ -+#if !defined(__NR_shmat) -+#define __NR_shmat 196 -+#endif -+ -+#if !defined(__NR_shmdt) -+#define __NR_shmdt 197 -+#endif -+ -+#if !defined(__NR_socket) -+#define __NR_socket 198 -+#endif -+ -+#if !defined(__NR_socketpair) -+#define __NR_socketpair 199 -+#endif -+ -+#if !defined(__NR_bind) -+#define __NR_bind 200 -+#endif -+ -+#if !defined(__NR_listen) -+#define __NR_listen 201 -+#endif -+ -+#if !defined(__NR_accept) -+#define __NR_accept 202 -+#endif -+ -+#if !defined(__NR_connect) -+#define __NR_connect 203 -+#endif -+ -+#if !defined(__NR_getsockname) -+#define __NR_getsockname 204 -+#endif -+ -+#if !defined(__NR_getpeername) -+#define __NR_getpeername 205 -+#endif -+ -+#if !defined(__NR_sendto) -+#define __NR_sendto 206 -+#endif -+ -+#if !defined(__NR_recvfrom) -+#define __NR_recvfrom 207 -+#endif -+ -+#if !defined(__NR_setsockopt) -+#define __NR_setsockopt 208 -+#endif -+ -+#if !defined(__NR_getsockopt) -+#define __NR_getsockopt 209 -+#endif -+ -+#if !defined(__NR_shutdown) -+#define __NR_shutdown 210 -+#endif -+ -+#if !defined(__NR_sendmsg) -+#define __NR_sendmsg 211 -+#endif -+ -+#if !defined(__NR_recvmsg) -+#define __NR_recvmsg 212 -+#endif -+ -+#if !defined(__NR_readahead) -+#define __NR_readahead 213 -+#endif -+ -+#if !defined(__NR_brk) -+#define __NR_brk 214 -+#endif -+ -+#if !defined(__NR_munmap) -+#define __NR_munmap 215 -+#endif -+ -+#if !defined(__NR_mremap) -+#define __NR_mremap 216 -+#endif -+ -+#if !defined(__NR_add_key) -+#define __NR_add_key 217 -+#endif -+ -+#if !defined(__NR_request_key) -+#define __NR_request_key 218 -+#endif -+ -+#if !defined(__NR_keyctl) -+#define __NR_keyctl 219 -+#endif -+ -+#if !defined(__NR_clone) -+#define __NR_clone 220 -+#endif -+ -+#if !defined(__NR_execve) -+#define __NR_execve 221 -+#endif -+ -+#if !defined(__NR_mmap) -+#define __NR_mmap 222 -+#endif -+ -+#if !defined(__NR_fadvise64) -+#define __NR_fadvise64 223 -+#endif -+ -+#if !defined(__NR_swapon) -+#define __NR_swapon 224 -+#endif -+ -+#if !defined(__NR_swapoff) -+#define __NR_swapoff 225 -+#endif -+ -+#if !defined(__NR_mprotect) -+#define __NR_mprotect 226 -+#endif -+ -+#if !defined(__NR_msync) -+#define __NR_msync 227 -+#endif -+ -+#if !defined(__NR_mlock) -+#define __NR_mlock 228 -+#endif -+ -+#if !defined(__NR_munlock) -+#define __NR_munlock 229 -+#endif -+ -+#if !defined(__NR_mlockall) -+#define __NR_mlockall 230 -+#endif -+ -+#if !defined(__NR_munlockall) -+#define __NR_munlockall 231 -+#endif -+ -+#if !defined(__NR_mincore) -+#define __NR_mincore 232 -+#endif -+ -+#if !defined(__NR_madvise) -+#define __NR_madvise 233 -+#endif -+ -+#if !defined(__NR_remap_file_pages) -+#define __NR_remap_file_pages 234 -+#endif -+ -+#if !defined(__NR_mbind) -+#define __NR_mbind 235 -+#endif -+ -+#if !defined(__NR_get_mempolicy) -+#define __NR_get_mempolicy 236 -+#endif -+ -+#if !defined(__NR_set_mempolicy) -+#define __NR_set_mempolicy 237 -+#endif -+ -+#if !defined(__NR_migrate_pages) -+#define __NR_migrate_pages 238 -+#endif -+ -+#if !defined(__NR_move_pages) -+#define __NR_move_pages 239 -+#endif -+ -+#if !defined(__NR_rt_tgsigqueueinfo) -+#define __NR_rt_tgsigqueueinfo 240 -+#endif -+ -+#if !defined(__NR_perf_event_open) -+#define __NR_perf_event_open 241 -+#endif -+ -+#if !defined(__NR_accept4) -+#define __NR_accept4 242 -+#endif -+ -+#if !defined(__NR_recvmmsg) -+#define __NR_recvmmsg 243 -+#endif -+ -+#if !defined(__NR_riscv_hwprobe) -+#define __NR_riscv_hwprobe 258 -+#endif -+ -+#if !defined(__NR_riscv_flush_icache) -+#define __NR_riscv_flush_icache 259 -+#endif -+ -+#if !defined(__NR_wait4) -+#define __NR_wait4 260 -+#endif -+ -+#if !defined(__NR_prlimit64) -+#define __NR_prlimit64 261 -+#endif -+ -+#if !defined(__NR_fanotify_init) -+#define __NR_fanotify_init 262 -+#endif -+ -+#if !defined(__NR_fanotify_mark) -+#define __NR_fanotify_mark 263 -+#endif -+ -+#if !defined(__NR_name_to_handle_at) -+#define __NR_name_to_handle_at 264 -+#endif -+ -+#if !defined(__NR_open_by_handle_at) -+#define __NR_open_by_handle_at 265 -+#endif -+ -+#if !defined(__NR_clock_adjtime) -+#define __NR_clock_adjtime 266 -+#endif -+ -+#if !defined(__NR_syncfs) -+#define __NR_syncfs 267 -+#endif -+ -+#if !defined(__NR_setns) -+#define __NR_setns 268 -+#endif -+ -+#if !defined(__NR_sendmmsg) -+#define __NR_sendmmsg 269 -+#endif -+ -+#if !defined(__NR_process_vm_readv) -+#define __NR_process_vm_readv 270 -+#endif -+ -+#if !defined(__NR_process_vm_writev) -+#define __NR_process_vm_writev 271 -+#endif -+ -+#if !defined(__NR_kcmp) -+#define __NR_kcmp 272 -+#endif -+ -+#if !defined(__NR_finit_module) -+#define __NR_finit_module 273 -+#endif -+ -+#if !defined(__NR_sched_setattr) -+#define __NR_sched_setattr 274 -+#endif -+ -+#if !defined(__NR_sched_getattr) -+#define __NR_sched_getattr 275 -+#endif -+ -+#if !defined(__NR_renameat2) -+#define __NR_renameat2 276 -+#endif -+ -+#if !defined(__NR_seccomp) -+#define __NR_seccomp 277 -+#endif -+ -+#if !defined(__NR_getrandom) -+#define __NR_getrandom 278 -+#endif -+ -+#if !defined(__NR_memfd_create) -+#define __NR_memfd_create 279 -+#endif -+ -+#if !defined(__NR_bpf) -+#define __NR_bpf 280 -+#endif -+ -+#if !defined(__NR_execveat) -+#define __NR_execveat 281 -+#endif -+ -+#if !defined(__NR_userfaultfd) -+#define __NR_userfaultfd 282 -+#endif -+ -+#if !defined(__NR_membarrier) -+#define __NR_membarrier 283 -+#endif -+ -+#if !defined(__NR_mlock2) -+#define __NR_mlock2 284 -+#endif -+ -+#if !defined(__NR_copy_file_range) -+#define __NR_copy_file_range 285 -+#endif -+ -+#if !defined(__NR_preadv2) -+#define __NR_preadv2 286 -+#endif -+ -+#if !defined(__NR_pwritev2) -+#define __NR_pwritev2 287 -+#endif -+ -+#if !defined(__NR_pkey_mprotect) -+#define __NR_pkey_mprotect 288 -+#endif -+ -+#if !defined(__NR_pkey_alloc) -+#define __NR_pkey_alloc 289 -+#endif -+ -+#if !defined(__NR_pkey_free) -+#define __NR_pkey_free 290 -+#endif -+ -+#if !defined(__NR_statx) -+#define __NR_statx 291 -+#endif -+ -+#if !defined(__NR_io_pgetevents) -+#define __NR_io_pgetevents 292 -+#endif -+ -+#if !defined(__NR_rseq) -+#define __NR_rseq 293 -+#endif -+ -+#if !defined(__NR_kexec_file_load) -+#define __NR_kexec_file_load 294 -+#endif -+ -+#if !defined(__NR_pidfd_send_signal) -+#define __NR_pidfd_send_signal 424 -+#endif -+ -+#if !defined(__NR_io_uring_setup) -+#define __NR_io_uring_setup 425 -+#endif -+ -+#if !defined(__NR_io_uring_enter) -+#define __NR_io_uring_enter 426 -+#endif -+ -+#if !defined(__NR_io_uring_register) -+#define __NR_io_uring_register 427 -+#endif -+ -+#if !defined(__NR_open_tree) -+#define __NR_open_tree 428 -+#endif -+ -+#if !defined(__NR_move_mount) -+#define __NR_move_mount 429 -+#endif -+ -+#if !defined(__NR_fsopen) -+#define __NR_fsopen 430 -+#endif -+ -+#if !defined(__NR_fsconfig) -+#define __NR_fsconfig 431 -+#endif -+ -+#if !defined(__NR_fsmount) -+#define __NR_fsmount 432 -+#endif -+ -+#if !defined(__NR_fspick) -+#define __NR_fspick 433 -+#endif -+ -+#if !defined(__NR_pidfd_open) -+#define __NR_pidfd_open 434 -+#endif -+ -+#if !defined(__NR_clone3) -+#define __NR_clone3 435 -+#endif -+ -+#if !defined(__NR_close_range) -+#define __NR_close_range 436 -+#endif -+ -+#if !defined(__NR_openat2) -+#define __NR_openat2 437 -+#endif -+ -+#if !defined(__NR_pidfd_getfd) -+#define __NR_pidfd_getfd 438 -+#endif -+ -+#if !defined(__NR_faccessat2) -+#define __NR_faccessat2 439 -+#endif -+ -+#if !defined(__NR_process_madvise) -+#define __NR_process_madvise 440 -+#endif -+ -+#if !defined(__NR_epoll_pwait2) -+#define __NR_epoll_pwait2 441 -+#endif -+ -+#if !defined(__NR_mount_setattr) -+#define __NR_mount_setattr 442 -+#endif -+ -+#if !defined(__NR_quotactl_path) -+#define __NR_quotactl_path 443 -+#endif -+ -+#if !defined(__NR_landlock_create_ruleset) -+#define __NR_landlock_create_ruleset 444 -+#endif -+ -+#if !defined(__NR_landlock_add_rule) -+#define __NR_landlock_add_rule 445 -+#endif -+ -+#if !defined(__NR_landlock_restrict_self) -+#define __NR_landlock_restrict_self 446 -+#endif -+ -+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_RISCV64_LINUX_SYSCALLS_H_ -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_cdm_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_cdm_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_cdm_policy_linux.cc -@@ -33,7 +33,7 @@ ResultExpr CdmProcessPolicy::EvaluateSys - case __NR_ftruncate: - case __NR_fallocate: - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_getrlimit: - #endif - #if defined(__i386__) || defined(__arm__) -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_cros_amd_gpu_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_cros_amd_gpu_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_cros_amd_gpu_policy_linux.cc -@@ -38,7 +38,7 @@ ResultExpr CrosAmdGpuProcessPolicy::Eval - case __NR_sched_setscheduler: - case __NR_sysinfo: - case __NR_uname: --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_readlink: - case __NR_stat: - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_gpu_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_gpu_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_gpu_policy_linux.cc -@@ -70,7 +70,7 @@ ResultExpr GpuProcessPolicy::EvaluateSys - (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)) - case __NR_ftruncate64: - #endif --#if !defined(__aarch64__) -+#if !defined(__aarch64__) && !defined(__riscv) - case __NR_getdents: - #endif - case __NR_getdents64: -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_print_compositor_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_print_compositor_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_print_compositor_policy_linux.cc -@@ -33,7 +33,7 @@ ResultExpr PrintCompositorProcessPolicy: - case __NR_fdatasync: - case __NR_fsync: - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined (__riscv) - case __NR_getrlimit: - #endif - #if defined(__i386__) || defined(__arm__) -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_renderer_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_renderer_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_renderer_policy_linux.cc -@@ -68,7 +68,7 @@ ResultExpr RendererProcessPolicy::Evalua - case __NR_ftruncate64: - #endif - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_getrlimit: - case __NR_setrlimit: - // We allow setrlimit to dynamically adjust the address space limit as -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_sharing_service_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_sharing_service_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_sharing_service_policy_linux.cc -@@ -26,7 +26,7 @@ ResultExpr SharingServiceProcessPolicy:: - return RestrictIoctl(); - // Allow the system calls below. - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_getrlimit: - #endif - #if defined(__i386__) || defined(__arm__) -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_utility_policy_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/bpf_utility_policy_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/bpf_utility_policy_linux.cc -@@ -34,7 +34,7 @@ ResultExpr UtilityProcessPolicy::Evaluat - case __NR_fdatasync: - case __NR_fsync: - #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \ -- defined(__aarch64__) -+ defined(__aarch64__) || defined(__riscv) - case __NR_getrlimit: - #endif - #if defined(__i386__) || defined(__arm__) -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc -@@ -64,7 +64,7 @@ using sandbox::bpf_dsl::ResultExpr; - - // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure - // that we think twice about this when adding a new architecture. --#if !defined(ARCH_CPU_ARM64) && !defined(ARCH_CPU_MIPS64EL) -+#if !defined(ARCH_CPU_ARM64) && !defined(ARCH_CPU_MIPS64EL) && !defined(ARCH_CPU_RISCV64) - #error "Seccomp-bpf disabled on supported architecture!" - #endif // !defined(ARCH_CPU_ARM64) && !defined(ARCH_CPU_MIPS64EL) - diff --git a/riscv-v8.patch b/riscv-v8.patch deleted file mode 100644 index 80f75c2..0000000 --- a/riscv-v8.patch +++ /dev/null @@ -1,33258 +0,0 @@ -riscv64 support patch taken from Opensuse: -https://build.opensuse.org/package/show/openSUSE:Factory:RISCV/libqt5-qtwebengine?rev=110 - -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/BUILD.gn -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/BUILD.gn -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/BUILD.gn -@@ -714,7 +714,7 @@ config("toolchain") { - - # Mips64el/mipsel simulators. - if (target_is_simulator && -- (v8_current_cpu == "mipsel" || v8_current_cpu == "mips64el")) { -+ (v8_current_cpu == "mipsel" || v8_current_cpu == "mips64el" || v8_current_cpu == "riscv64")) { - defines += [ "_MIPS_TARGET_SIMULATOR" ] - } - -@@ -817,6 +817,21 @@ config("toolchain") { - } - } - -+ # Under simulator build, compiler will not provide __riscv_xlen. Define here -+ if (v8_current_cpu == "riscv") { -+ defines += [ "V8_TARGET_ARCH_RISCV" ] -+ defines += [ "__riscv_xlen=32" ] -+ } -+ -+ if (v8_current_cpu == "riscv64") { -+ defines += [ "V8_TARGET_ARCH_RISCV64" ] -+ defines += [ "__riscv_xlen=64" ] -+ #FIXME: Temporarily use MIPS macro for the building. -+ defines += [ -+ "CAN_USE_FPU_INSTRUCTIONS", -+ ] -+ } -+ - if (v8_current_cpu == "x86") { - defines += [ "V8_TARGET_ARCH_IA32" ] - if (is_win) { -@@ -905,7 +920,7 @@ config("toolchain") { - } - - if (v8_current_cpu == "x64" || v8_current_cpu == "arm64" || -- v8_current_cpu == "mips64el") { -+ v8_current_cpu == "mips64el" || v8_current_cpu == "riscv64") { - cflags += [ "-Wshorten-64-to-32" ] - } - } -@@ -1888,6 +1903,16 @@ v8_source_set("v8_initializers") { - ### gcmole(arch:s390) ### - "src/builtins/s390/builtins-s390.cc", - ] -+ } else if (v8_current_cpu == "riscv64") { -+ sources += [ -+ ### gcmole(arch:riscv64) ### -+ "src/builtins/riscv64/builtins-riscv64.cc", -+ ] -+ } else if (v8_current_cpu == "riscv") { -+ sources += [ -+ ### gcmole(arch:riscv) ### -+ "src/builtins/riscv/builtins-riscv.cc", -+ ] - } - - if (!v8_enable_i18n_support) { -@@ -3762,6 +3787,60 @@ v8_source_set("v8_base_without_compiler" - "src/regexp/s390/regexp-macro-assembler-s390.h", - "src/wasm/baseline/s390/liftoff-assembler-s390.h", - ] -+ } else if (v8_current_cpu == "riscv64") { -+ sources += [ ### gcmole(arch:riscv64) ### -+ "src/codegen/riscv64/assembler-riscv64-inl.h", -+ "src/codegen/riscv64/assembler-riscv64.cc", -+ "src/codegen/riscv64/assembler-riscv64.h", -+ "src/codegen/riscv64/constants-riscv64.cc", -+ "src/codegen/riscv64/constants-riscv64.h", -+ "src/codegen/riscv64/cpu-riscv64.cc", -+ "src/codegen/riscv64/interface-descriptors-riscv64.cc", -+ "src/codegen/riscv64/macro-assembler-riscv64.cc", -+ "src/codegen/riscv64/macro-assembler-riscv64.h", -+ "src/codegen/riscv64/register-riscv64.h", -+ "src/compiler/backend/riscv64/code-generator-riscv64.cc", -+ "src/compiler/backend/riscv64/instruction-codes-riscv64.h", -+ "src/compiler/backend/riscv64/instruction-scheduler-riscv64.cc", -+ "src/compiler/backend/riscv64/instruction-selector-riscv64.cc", -+ "src/debug/riscv64/debug-riscv64.cc", -+ "src/deoptimizer/riscv64/deoptimizer-riscv64.cc", -+ "src/diagnostics/riscv64/disasm-riscv64.cc", -+ "src/execution/riscv64/frame-constants-riscv64.cc", -+ "src/execution/riscv64/frame-constants-riscv64.h", -+ "src/execution/riscv64/simulator-riscv64.cc", -+ "src/execution/riscv64/simulator-riscv64.h", -+ "src/regexp/riscv64/regexp-macro-assembler-riscv64.cc", -+ "src/regexp/riscv64/regexp-macro-assembler-riscv64.h", -+ "src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h", -+ ] -+ } else if (v8_current_cpu == "riscv") { -+ sources += [ ### gcmole(arch:riscv) ### -+ "src/codegen/riscv/assembler-riscv-inl.h", -+ "src/codegen/riscv/assembler-riscv.cc", -+ "src/codegen/riscv/assembler-riscv.h", -+ "src/codegen/riscv/constants-riscv.cc", -+ "src/codegen/riscv/constants-riscv.h", -+ "src/codegen/riscv/cpu-riscv.cc", -+ "src/codegen/riscv/interface-descriptors-riscv.cc", -+ "src/codegen/riscv/macro-assembler-riscv.cc", -+ "src/codegen/riscv/macro-assembler-riscv.h", -+ "src/codegen/riscv/register-riscv.h", -+ "src/compiler/backend/riscv/code-generator-riscv.cc", -+ "src/compiler/backend/riscv/instruction-codes-riscv.h", -+ "src/compiler/backend/riscv/instruction-scheduler-riscv.cc", -+ "src/compiler/backend/riscv/instruction-selector-riscv.cc", -+ "src/debug/riscv/debug-riscv.cc", -+ "src/deoptimizer/riscv/deoptimizer-riscv.cc", -+ "src/diagnostics/riscv/disasm-riscv.cc", -+ "src/execution/riscv/frame-constants-riscv.cc", -+ "src/execution/riscv/frame-constants-riscv.h", -+ "src/execution/riscv/simulator-riscv.cc", -+ "src/execution/riscv/simulator-riscv.h", -+ "src/regexp/riscv/regexp-macro-assembler-riscv.cc", -+ "src/regexp/riscv/regexp-macro-assembler-riscv.h", -+ "src/wasm/baseline/riscv/liftoff-assembler-riscv.h", -+ ] - } - - configs = [ -@@ -3862,7 +3941,8 @@ v8_source_set("v8_base_without_compiler" - if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel" || - v8_current_cpu == "mips64" || v8_current_cpu == "mips64el" || - v8_current_cpu == "ppc" || v8_current_cpu == "ppc64" || -- v8_current_cpu == "s390" || v8_current_cpu == "s390x") { -+ v8_current_cpu == "s390" || v8_current_cpu == "s390x" || -+ v8_current_cpu == "riscv64" || v8_current_cpu == "riscv") { - libs += [ "atomic" ] - } - -@@ -4197,7 +4277,7 @@ v8_component("v8_libbase") { - } - - if (is_ubsan && (v8_current_cpu == "x86" || v8_current_cpu == "arm" || -- v8_current_cpu == "mips")) { -+ v8_current_cpu == "mips" || v8_current_cpu == "riscv")) { - # Special UBSan 32-bit requirement. - sources += [ "src/base/ubsan.cc" ] - } -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/gni/snapshot_toolchain.gni -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/gni/snapshot_toolchain.gni -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/gni/snapshot_toolchain.gni -@@ -79,7 +79,8 @@ if (v8_snapshot_toolchain == "") { - - if (v8_current_cpu == "x64" || v8_current_cpu == "x86") { - _cpus = v8_current_cpu -- } else if (v8_current_cpu == "arm64" || v8_current_cpu == "mips64el") { -+ } else if (v8_current_cpu == "arm64" || v8_current_cpu == "mips64el" -+ || v8_current_cpu == "riscv64") { - if (is_win && v8_current_cpu == "arm64") { - # set _cpus to blank for Windows ARM64 so host_toolchain could be - # selected as snapshot toolchain later. -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/infra/mb/mb_config.pyl -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/infra/mb/mb_config.pyl -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/infra/mb/mb_config.pyl -@@ -33,6 +33,12 @@ - 'ppc64.debug.sim': 'default_debug_ppc64_sim', - 'ppc64.optdebug.sim': 'default_optdebug_ppc64_sim', - 'ppc64.release.sim': 'default_release_ppc64_sim', -+ 'riscv64.debug': 'default_debug_riscv64', -+ 'riscv64.optdebug': 'default_optdebug_riscv64', -+ 'riscv64.release': 'default_release_riscv64', -+ 'riscv64.debug.sim': 'default_debug_riscv64_sim', -+ 'riscv64.optdebug.sim': 'default_optdebug_riscv64_sim', -+ 'riscv64.release.sim': 'default_release_riscv64_sim', - 's390x.debug': 'default_debug_s390x', - 's390x.optdebug': 'default_optdebug_s390x', - 's390x.release': 'default_release_s390x', -@@ -175,6 +181,8 @@ - # IBM. - 'V8 Linux - ppc64 - sim': 'release_simulate_ppc64', - 'V8 Linux - s390x - sim': 'release_simulate_s390x', -+ # RISC-V -+ 'V8 Linux - riscv64 - sim': 'release_simulate_riscv64', - }, - 'client.v8.branches': { - 'V8 Linux - previous branch': 'release_x86', -@@ -207,6 +215,9 @@ - 'V8 s390x - sim - previous branch': 'release_simulate_s390x', - 'V8 s390x - sim - beta branch': 'release_simulate_s390x', - 'V8 s390x - sim - stable branch': 'release_simulate_s390x', -+ 'V8 riscv64 - sim - previous branch': 'release_simulate_riscv64', -+ 'V8 riscv64 - sim - beta branch': 'release_simulate_riscv64', -+ 'V8 riscv64 - sim - stable branch': 'release_simulate_riscv64', - }, - 'tryserver.v8': { - 'v8_android_arm_compile_rel': 'release_android_arm', -@@ -323,6 +334,18 @@ - 'debug', 'simulate_mips64el', 'v8_enable_slow_dchecks'], - 'default_release_mips64el': [ - 'release', 'simulate_mips64el'], -+ 'default_debug_riscv64': [ -+ 'debug', 'riscv64', 'gcc', 'v8_enable_slow_dchecks', 'v8_full_debug'], -+ 'default_optdebug_riscv64': [ -+ 'debug', 'riscv64', 'gcc', 'v8_enable_slow_dchecks'], -+ 'default_release_riscv64': [ -+ 'release', 'riscv64', 'gcc'], -+ 'default_debug_riscv64_sim': [ -+ 'debug', 'simulate_riscv64', 'v8_enable_slow_dchecks', 'v8_full_debug'], -+ 'default_optdebug_riscv64_sim': [ -+ 'debug', 'simulate_riscv64', 'v8_enable_slow_dchecks'], -+ 'default_release_riscv64_sim': [ -+ 'release', 'simulate_riscv64'], - 'default_debug_ppc64': [ - 'debug', 'ppc64', 'gcc', 'v8_enable_slow_dchecks', 'v8_full_debug'], - 'default_optdebug_ppc64': [ -@@ -410,6 +433,8 @@ - 'release_bot', 'simulate_mips64el'], - 'release_simulate_ppc64': [ - 'release_bot', 'simulate_ppc64'], -+ 'release_simulate_riscv64': [ -+ 'release_bot', 'simulate_riscv64'], - 'release_simulate_s390x': [ - 'release_bot', 'simulate_s390x'], - -@@ -812,6 +837,10 @@ - 'gn_args': 'target_cpu="x64" v8_target_cpu="ppc64"', - }, - -+ 'simulate_riscv64': { -+ 'gn_args': 'target_cpu="x64" v8_target_cpu="riscv64"', -+ }, -+ - 'simulate_s390x': { - 'gn_args': 'target_cpu="x64" v8_target_cpu="s390x"', - }, -@@ -918,6 +947,10 @@ - 'gn_args': 'target_cpu="ppc64" use_custom_libcxx=false', - }, - -+ 'riscv64': { -+ 'gn_args': 'target_cpu="riscv64" use_custom_libcxx=false', -+ }, -+ - 'x64': { - 'gn_args': 'target_cpu="x64"', - }, -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/build_config.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/base/build_config.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/build_config.h -@@ -46,6 +46,16 @@ - #else - #define V8_HOST_ARCH_32_BIT 1 - #endif -+#elif defined(__riscv) || defined(__riscv__) -+#if __riscv_xlen == 64 -+#define V8_HOST_ARCH_RISCV64 1 -+#define V8_HOST_ARCH_64_BIT 1 -+#elif __riscv_xlen == 32 -+#define V8_HOST_ARCH_RISCV 1 -+#define V8_HOST_ARCH_32_BIT 1 -+#else -+#error "Cannot detect Riscv's bitwidth" -+#endif - #else - #error "Host architecture was not detected as supported by v8" - #endif -@@ -77,7 +87,8 @@ - // environment as presented by the compiler. - #if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && \ - !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64 && \ -- !V8_TARGET_ARCH_PPC && !V8_TARGET_ARCH_PPC64 && !V8_TARGET_ARCH_S390 -+ !V8_TARGET_ARCH_PPC && !V8_TARGET_ARCH_PPC64 && !V8_TARGET_ARCH_S390 && \ -+ !V8_TARGET_ARCH_RISCV64 && !V8_TARGET_ARCH_RISCV - #if defined(_M_X64) || defined(__x86_64__) - #define V8_TARGET_ARCH_X64 1 - #elif defined(_M_IX86) || defined(__i386__) -@@ -94,6 +105,12 @@ - #define V8_TARGET_ARCH_PPC64 1 - #elif defined(_ARCH_PPC) - #define V8_TARGET_ARCH_PPC 1 -+#elif defined(__riscv) || defined(__riscv__) -+#if __riscv_xlen == 64 -+#define V8_TARGET_ARCH_RISCV64 1 -+#elif __riscv_xlen == 32 -+#define V8_TARGET_ARCH_RISCV 1 -+#endif - #else - #error Target architecture was not detected as supported by v8 - #endif -@@ -128,6 +145,10 @@ - #else - #define V8_TARGET_ARCH_32_BIT 1 - #endif -+#elif V8_TARGET_ARCH_RISCV64 -+#define V8_TARGET_ARCH_64_BIT 1 -+#elif V8_TARGET_ARCH_RISCV -+#define V8_TARGET_ARCH_32_BIT 1 - #else - #error Unknown target architecture pointer size - #endif -@@ -156,6 +177,13 @@ - #if (V8_TARGET_ARCH_MIPS64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_MIPS64)) - #error Target architecture mips64 is only supported on mips64 and x64 host - #endif -+#if (V8_TARGET_ARCH_RISCV64 && !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_RISCV64)) -+#error Target architecture riscv64 is only supported on riscv64 and x64 host -+#endif -+#if (V8_TARGET_ARCH_RISCV && \ -+ !(V8_HOST_ARCH_X64 || V8_HOST_ARCH_RISCV || V8_HOST_ARCH_RISCV64)) -+#error Target architecture riscv (32) is only supported on riscv(32), riscv64, and x64 host -+#endif - - // Determine architecture endianness. - #if V8_TARGET_ARCH_IA32 -@@ -190,6 +218,8 @@ - #else - #define V8_TARGET_BIG_ENDIAN 1 - #endif -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+#define V8_TARGET_LITTLE_ENDIAN 1 - #else - #error Unknown target architecture endianness - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/compiler-specific.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/base/compiler-specific.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/compiler-specific.h -@@ -96,9 +96,10 @@ - // do not support adding noexcept to default members. - // Disabled on MSVC because constructors of standard containers are not noexcept - // there. --#if ((!defined(V8_CC_GNU) && !defined(V8_CC_MSVC) && \ -- !defined(V8_TARGET_ARCH_MIPS) && !defined(V8_TARGET_ARCH_MIPS64) && \ -- !defined(V8_TARGET_ARCH_PPC) && !defined(V8_TARGET_ARCH_PPC64)) || \ -+#if ((!defined(V8_CC_GNU) && !defined(V8_CC_MSVC) && \ -+ !defined(V8_TARGET_ARCH_MIPS) && !defined(V8_TARGET_ARCH_MIPS64) && \ -+ !defined(V8_TARGET_ARCH_PPC) && !defined(V8_TARGET_ARCH_PPC64) && \ -+ !defined(V8_TARGET_ARCH_RISCV64) && !defined(V8_TARGET_ARCH_RISCV)) || \ - (defined(__clang__) && __cplusplus > 201300L)) - #define V8_NOEXCEPT noexcept - #else -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/macros.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/base/macros.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/macros.h -@@ -12,6 +12,8 @@ - #include "src/base/compiler-specific.h" - #include "src/base/logging.h" - -+#define DEBUG_PRINTF(...) if (FLAG_debug_riscv) { printf(__VA_ARGS__); } -+ - // No-op macro which is used to work around MSVC's funky VA_ARGS support. - #define EXPAND(x) x - -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/platform/platform-posix.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/base/platform/platform-posix.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/base/platform/platform-posix.cc -@@ -324,6 +324,12 @@ void* OS::GetRandomMmapAddr() { - // 42 bits of virtual addressing. Truncate to 40 bits to allow kernel chance - // to fulfill request. - raw_addr &= uint64_t{0xFFFFFF0000}; -+#elif V8_TARGET_ARCH_RISCV64 -+ // FIXME(RISCV): We need more information from the kernel to correctly mask -+ // this address for RISC-V. -+ raw_addr &= uint64_t{0xFFFFFF0000}; -+#elif V8_TARGET_ARCH_RISCV -+ #error RISCV archiecture not supported - #else - raw_addr &= 0x3FFFF000; - -@@ -512,6 +518,8 @@ void OS::DebugBreak() { - #elif V8_HOST_ARCH_S390 - // Software breakpoint instruction is 0x0001 - asm volatile(".word 0x0001"); -+#elif V8_HOST_ARCH_RISCV64 || V8_HOST_ARCH_RISCV -+ asm("ebreak"); - #else - #error Unsupported host architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/builtins/builtins-sharedarraybuffer-gen.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/builtins/builtins-sharedarraybuffer-gen.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/builtins/builtins-sharedarraybuffer-gen.cc -@@ -379,7 +379,9 @@ TF_BUILTIN(AtomicsExchange, SharedArrayB - // 2. Let i be ? ValidateAtomicAccess(typedArray, index). - TNode index_word = ValidateAtomicAccess(array, index, context); - --#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -+#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_RISCV64 || \ -+ V8_TARGET_ARCH_RISCV -+ // FIXME(RISCV): Review this special case once atomics are added - USE(array_buffer); - TNode index_number = ChangeUintPtrToTagged(index_word); - Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_number, -@@ -481,7 +483,8 @@ TF_BUILTIN(AtomicsExchange, SharedArrayB - // This shouldn't happen, we've already validated the type. - BIND(&other); - Unreachable(); --#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -+#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || -+ // V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV - - BIND(&detached); - { -@@ -510,7 +513,9 @@ TF_BUILTIN(AtomicsCompareExchange, Share - TNode index_word = ValidateAtomicAccess(array, index, context); - - #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ -- V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X -+ V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X || \ -+ V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+ // FIXME(RISCV): Review this special case once atomics are added - USE(array_buffer); - TNode index_number = ChangeUintPtrToTagged(index_word); - Return(CallRuntime(Runtime::kAtomicsCompareExchange, context, array, -@@ -632,6 +637,7 @@ TF_BUILTIN(AtomicsCompareExchange, Share - Unreachable(); - #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 - // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X -+ // || V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV - - BIND(&detached); - { -@@ -679,7 +685,9 @@ void SharedArrayBufferBuiltinsAssembler: - TNode index_word = ValidateAtomicAccess(array, index, context); - - #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ -- V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X -+ V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X || \ -+ V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+ // FIXME(RISCV): Review this special case once atomics are added - USE(array_buffer); - TNode index_number = ChangeUintPtrToTagged(index_word); - Return(CallRuntime(runtime_function, context, array, index_number, value)); -@@ -783,6 +791,7 @@ void SharedArrayBufferBuiltinsAssembler: - Unreachable(); - #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 - // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X -+ // || V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV - - BIND(&detached); - ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name); -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/builtins/builtins.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/builtins/builtins.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/builtins/builtins.cc -@@ -490,14 +490,17 @@ bool Builtins::CodeObjectIsExecutable(in - case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit: - return true; - default: --#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -+#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_RISCV64 || \ -+ V8_TARGET_ARCH_RISCV -+ // FIXME(RISCV): Is this correct for RISC-V? - // TODO(Loongson): Move non-JS linkage builtins code objects into RO_SPACE - // caused MIPS platform to crash, and we need some time to handle it. Now - // disable this change temporarily on MIPS platform. - return true; - #else - return false; --#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -+#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || -+ // V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV - } - } - -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/builtins/riscv64/builtins-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/builtins/riscv64/builtins-riscv64.cc -@@ -0,0 +1,3197 @@ -+// Copyright 2012 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. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/api/api-arguments.h" -+#include "src/codegen/code-factory.h" -+#include "src/debug/debug.h" -+#include "src/deoptimizer/deoptimizer.h" -+#include "src/execution/frame-constants.h" -+#include "src/execution/frames.h" -+#include "src/logging/counters.h" -+// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop. -+#include "src/codegen/macro-assembler-inl.h" -+#include "src/codegen/register-configuration.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/heap/heap-inl.h" -+#include "src/objects/cell.h" -+#include "src/objects/foreign.h" -+#include "src/objects/heap-number.h" -+#include "src/objects/js-generator.h" -+#include "src/objects/objects-inl.h" -+#include "src/objects/smi.h" -+#include "src/runtime/runtime.h" -+#include "src/wasm/wasm-linkage.h" -+#include "src/wasm/wasm-objects.h" -+ -+namespace v8 { -+namespace internal { -+ -+#define __ ACCESS_MASM(masm) -+ -+void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address) { -+ __ li(kJavaScriptCallExtraArg1Register, ExternalReference::Create(address)); -+ __ Jump(BUILTIN_CODE(masm->isolate(), AdaptorWithBuiltinExitFrame), -+ RelocInfo::CODE_TARGET); -+} -+ -+static void GenerateTailCallToReturnedCode(MacroAssembler* masm, -+ Runtime::FunctionId function_id) { -+ // ----------- S t a t e ------------- -+ // -- a1 : target function (preserved for callee) -+ // -- a3 : new target (preserved for callee) -+ // ----------------------------------- -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ // Push a copy of the function onto the stack. -+ // Push a copy of the target function and the new target. -+ __ Push(a1, a3, a1); -+ -+ __ CallRuntime(function_id, 1); -+ // Restore target function and new target. -+ __ Pop(a1, a3); -+ } -+ -+ static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch"); -+ __ Add64(a2, a0, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Jump(a2); -+} -+ -+namespace { -+ -+enum StackLimitKind { kInterruptStackLimit, kRealStackLimit }; -+ -+void LoadStackLimit(MacroAssembler* masm, Register destination, -+ StackLimitKind kind) { -+ DCHECK(masm->root_array_available()); -+ Isolate* isolate = masm->isolate(); -+ ExternalReference limit = -+ kind == StackLimitKind::kRealStackLimit -+ ? ExternalReference::address_of_real_jslimit(isolate) -+ : ExternalReference::address_of_jslimit(isolate); -+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit)); -+ -+ intptr_t offset = -+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit); -+ CHECK(is_int32(offset)); -+ __ Ld(destination, MemOperand(kRootRegister, static_cast(offset))); -+} -+ -+void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : number of arguments -+ // -- a1 : constructor function -+ // -- a3 : new target -+ // -- cp : context -+ // -- ra : return address -+ // -- sp[...]: constructor arguments -+ // ----------------------------------- -+ -+ // Enter a construct frame. -+ { -+ FrameScope scope(masm, StackFrame::CONSTRUCT); -+ -+ // Preserve the incoming parameters on the stack. -+ __ SmiTag(a0); -+ __ Push(cp, a0); -+ __ SmiUntag(a0); -+ -+ // The receiver for the builtin/api call. -+ __ PushRoot(RootIndex::kTheHoleValue); -+ -+ // Set up pointer to last argument. -+ __ Add64(t2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); -+ -+ // Copy arguments and receiver to the expression stack. -+ Label loop, entry; -+ __ Move(t4, a0); -+ // ----------- S t a t e ------------- -+ // -- a0: number of arguments (untagged) -+ // -- a3: new target -+ // -- t2: pointer to last argument -+ // -- t4: counter -+ // -- sp[0*kPointerSize]: the hole (receiver) -+ // -- sp[1*kPointerSize]: number of arguments (tagged) -+ // -- sp[2*kPointerSize]: context -+ // ----------------------------------- -+ __ Branch(&entry); -+ __ bind(&loop); -+ __ CalcScaledAddress(t0, t2, t4, kPointerSizeLog2); -+ __ Ld(t1, MemOperand(t0)); -+ __ push(t1); -+ __ bind(&entry); -+ __ Add64(t4, t4, Operand(-1)); -+ __ Branch(&loop, greater_equal, t4, Operand(zero_reg)); -+ -+ // Call the function. -+ // a0: number of arguments (untagged) -+ // a1: constructor function -+ // a3: new target -+ __ InvokeFunctionWithNewTarget(a1, a3, a0, CALL_FUNCTION); -+ -+ // Restore context from the frame. -+ __ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); -+ // Restore smi-tagged arguments count from the frame. -+ __ Ld(a1, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); -+ // Leave construct frame. -+ } -+ -+ // Remove caller arguments from the stack and return. -+ __ SmiScale(a4, a1, kPointerSizeLog2); -+ __ Add64(sp, sp, a4); -+ __ Add64(sp, sp, kPointerSize); -+ __ Ret(); -+} -+ -+static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, -+ Register scratch1, Register scratch2, -+ Label* stack_overflow) { -+ // Check the stack for overflow. We are not trying to catch -+ // interruptions (e.g. debug break and preemption) here, so the "real stack -+ // limit" is checked. -+ LoadStackLimit(masm, scratch1, StackLimitKind::kRealStackLimit); -+ // Make scratch1 the space we have left. The stack might already be overflowed -+ // here which will cause scratch1 to become negative. -+ __ Sub64(scratch1, sp, scratch1); -+ // Check if the arguments will overflow the stack. -+ __ Sll64(scratch2, num_args, kPointerSizeLog2); -+ // Signed comparison. -+ __ Branch(stack_overflow, le, scratch1, Operand(scratch2)); -+} -+ -+} // namespace -+ -+// The construct stub for ES5 constructor functions and ES6 class constructors. -+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0: number of arguments (untagged) -+ // -- a1: constructor function -+ // -- a3: new target -+ // -- cp: context -+ // -- ra: return address -+ // -- sp[...]: constructor arguments -+ // ----------------------------------- -+ -+ // Enter a construct frame. -+ { -+ FrameScope scope(masm, StackFrame::CONSTRUCT); -+ Label post_instantiation_deopt_entry, not_create_implicit_receiver; -+ -+ // Preserve the incoming parameters on the stack. -+ __ SmiTag(a0); -+ __ Push(cp, a0, a1); -+ __ PushRoot(RootIndex::kTheHoleValue); -+ __ Push(a3); -+ -+ // ----------- S t a t e ------------- -+ // -- sp[0*kPointerSize]: new target -+ // -- sp[1*kPointerSize]: padding -+ // -- a1 and sp[2*kPointerSize]: constructor function -+ // -- sp[3*kPointerSize]: number of arguments (tagged) -+ // -- sp[4*kPointerSize]: context -+ // ----------------------------------- -+ -+ __ Ld(t2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lwu(t2, FieldMemOperand(t2, SharedFunctionInfo::kFlagsOffset)); -+ __ DecodeField(t2); -+ __ JumpIfIsInRange(t2, kDefaultDerivedConstructor, kDerivedConstructor, -+ ¬_create_implicit_receiver); -+ -+ // If not derived class constructor: Allocate the new receiver object. -+ __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1, -+ t2, t4); -+ __ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), -+ RelocInfo::CODE_TARGET); -+ __ Branch(&post_instantiation_deopt_entry); -+ -+ // Else: use TheHoleValue as receiver for constructor call -+ __ bind(¬_create_implicit_receiver); -+ __ LoadRoot(a0, RootIndex::kTheHoleValue); -+ -+ // ----------- S t a t e ------------- -+ // -- a0: receiver -+ // -- Slot 4 / sp[0*kPointerSize]: new target -+ // -- Slot 3 / sp[1*kPointerSize]: padding -+ // -- Slot 2 / sp[2*kPointerSize]: constructor function -+ // -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged) -+ // -- Slot 0 / sp[4*kPointerSize]: context -+ // ----------------------------------- -+ // Deoptimizer enters here. -+ masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset( -+ masm->pc_offset()); -+ __ bind(&post_instantiation_deopt_entry); -+ -+ // Restore new target. -+ __ Pop(a3); -+ // Push the allocated receiver to the stack. We need two copies -+ // because we may have to return the original one and the calling -+ // conventions dictate that the called function pops the receiver. -+ __ Push(a0, a0); -+ -+ // ----------- S t a t e ------------- -+ // -- r3: new target -+ // -- sp[0*kPointerSize]: implicit receiver -+ // -- sp[1*kPointerSize]: implicit receiver -+ // -- sp[2*kPointerSize]: padding -+ // -- sp[3*kPointerSize]: constructor function -+ // -- sp[4*kPointerSize]: number of arguments (tagged) -+ // -- sp[5*kPointerSize]: context -+ // ----------------------------------- -+ -+ // Restore constructor function and argument count. -+ __ Ld(a1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset)); -+ __ Ld(a0, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); -+ __ SmiUntag(a0); -+ -+ // Set up pointer to last argument. -+ __ Add64(t2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); -+ -+ Label enough_stack_space, stack_overflow; -+ Generate_StackOverflowCheck(masm, a0, t0, t1, &stack_overflow); -+ __ Branch(&enough_stack_space); -+ -+ __ bind(&stack_overflow); -+ // Restore the context from the frame. -+ __ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ // Unreachable code. -+ __ break_(0xCC); -+ -+ __ bind(&enough_stack_space); -+ -+ // Copy arguments and receiver to the expression stack. -+ Label loop, entry; -+ __ Move(t4, a0); -+ // ----------- S t a t e ------------- -+ // -- a0: number of arguments (untagged) -+ // -- a3: new target -+ // -- t2: pointer to last argument -+ // -- t4: counter -+ // -- sp[0*kPointerSize]: implicit receiver -+ // -- sp[1*kPointerSize]: implicit receiver -+ // -- sp[2*kPointerSize]: padding -+ // -- a1 and sp[3*kPointerSize]: constructor function -+ // -- sp[4*kPointerSize]: number of arguments (tagged) -+ // -- sp[5*kPointerSize]: context -+ // ----------------------------------- -+ __ Branch(&entry); -+ __ bind(&loop); -+ __ CalcScaledAddress(t0, t2, t4, kPointerSizeLog2); -+ __ Ld(t1, MemOperand(t0)); -+ __ push(t1); -+ __ bind(&entry); -+ __ Add64(t4, t4, Operand(-1)); -+ __ Branch(&loop, greater_equal, t4, Operand(zero_reg)); -+ -+ // Call the function. -+ __ InvokeFunctionWithNewTarget(a1, a3, a0, CALL_FUNCTION); -+ -+ // ----------- S t a t e ------------- -+ // -- a0: constructor result -+ // -- sp[0*kPointerSize]: implicit receiver -+ // -- sp[1*kPointerSize]: padding -+ // -- sp[2*kPointerSize]: constructor function -+ // -- sp[3*kPointerSize]: number of arguments -+ // -- sp[4*kPointerSize]: context -+ // ----------------------------------- -+ -+ // Store offset of return address for deoptimizer. -+ masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset( -+ masm->pc_offset()); -+ -+ // Restore the context from the frame. -+ __ Ld(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); -+ -+ // If the result is an object (in the ECMA sense), we should get rid -+ // of the receiver and use the result; see ECMA-262 section 13.2.2-7 -+ // on page 74. -+ Label use_receiver, do_throw, leave_frame; -+ -+ // If the result is undefined, we jump out to using the implicit receiver. -+ __ JumpIfRoot(a0, RootIndex::kUndefinedValue, &use_receiver); -+ -+ // Otherwise we do a smi check and fall through to check if the return value -+ // is a valid receiver. -+ -+ // If the result is a smi, it is *not* an object in the ECMA sense. -+ __ JumpIfSmi(a0, &use_receiver); -+ -+ // If the type of the result (stored in its map) is less than -+ // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense. -+ __ GetObjectType(a0, t2, t2); -+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); -+ __ Branch(&leave_frame, greater_equal, t2, Operand(FIRST_JS_RECEIVER_TYPE)); -+ __ Branch(&use_receiver); -+ -+ __ bind(&do_throw); -+ __ CallRuntime(Runtime::kThrowConstructorReturnedNonObject); -+ -+ // Throw away the result of the constructor invocation and use the -+ // on-stack receiver as the result. -+ __ bind(&use_receiver); -+ __ Ld(a0, MemOperand(sp, 0 * kPointerSize)); -+ __ JumpIfRoot(a0, RootIndex::kTheHoleValue, &do_throw); -+ -+ __ bind(&leave_frame); -+ // Restore smi-tagged arguments count from the frame. -+ __ Ld(a1, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); -+ // Leave construct frame. -+ } -+ // Remove caller arguments from the stack and return. -+ __ SmiScale(a4, a1, kPointerSizeLog2); -+ __ Add64(sp, sp, a4); -+ __ Add64(sp, sp, kPointerSize); -+ __ Ret(); -+} -+ -+void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { -+ Generate_JSBuiltinsConstructStubHelper(masm); -+} -+ -+static void GetSharedFunctionInfoBytecode(MacroAssembler* masm, -+ Register sfi_data, -+ Register scratch1) { -+ Label done; -+ -+ __ GetObjectType(sfi_data, scratch1, scratch1); -+ __ Branch(&done, ne, scratch1, Operand(INTERPRETER_DATA_TYPE)); -+ __ Ld(sfi_data, -+ FieldMemOperand(sfi_data, InterpreterData::kBytecodeArrayOffset)); -+ -+ __ bind(&done); -+} -+ -+// static -+void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the value to pass to the generator -+ // -- a1 : the JSGeneratorObject to resume -+ // -- ra : return address -+ // ----------------------------------- -+ __ AssertGeneratorObject(a1); -+ -+ // Store input value into generator object. -+ __ Sd(a0, FieldMemOperand(a1, JSGeneratorObject::kInputOrDebugPosOffset)); -+ __ RecordWriteField(a1, JSGeneratorObject::kInputOrDebugPosOffset, a0, a3, -+ kRAHasNotBeenSaved, kDontSaveFPRegs); -+ -+ // Load suspended function and context. -+ __ Ld(a4, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset)); -+ __ Ld(cp, FieldMemOperand(a4, JSFunction::kContextOffset)); -+ -+ // Flood function if we are stepping. -+ Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator; -+ Label stepping_prepared; -+ ExternalReference debug_hook = -+ ExternalReference::debug_hook_on_function_call_address(masm->isolate()); -+ __ li(a5, debug_hook); -+ __ Lb(a5, MemOperand(a5)); -+ __ Branch(&prepare_step_in_if_stepping, ne, a5, Operand(zero_reg)); -+ -+ // Flood function if we need to continue stepping in the suspended generator. -+ ExternalReference debug_suspended_generator = -+ ExternalReference::debug_suspended_generator_address(masm->isolate()); -+ __ li(a5, debug_suspended_generator); -+ __ Ld(a5, MemOperand(a5)); -+ __ Branch(&prepare_step_in_suspended_generator, eq, a1, Operand(a5)); -+ __ bind(&stepping_prepared); -+ -+ // Check the stack for overflow. We are not trying to catch interruptions -+ // (i.e. debug break and preemption) here, so check the "real stack limit". -+ Label stack_overflow; -+ LoadStackLimit(masm, kScratchReg, StackLimitKind::kRealStackLimit); -+ __ Branch(&stack_overflow, Uless, sp, Operand(kScratchReg)); -+ -+ // Push receiver. -+ __ Ld(a5, FieldMemOperand(a1, JSGeneratorObject::kReceiverOffset)); -+ __ Push(a5); -+ -+ // ----------- S t a t e ------------- -+ // -- a1 : the JSGeneratorObject to resume -+ // -- a4 : generator function -+ // -- cp : generator context -+ // -- ra : return address -+ // -- sp[0] : generator receiver -+ // ----------------------------------- -+ -+ // Push holes for arguments to generator function. Since the parser forced -+ // context allocation for any variables in generators, the actual argument -+ // values have already been copied into the context and these dummy values -+ // will never be used. -+ __ Ld(a3, FieldMemOperand(a4, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lhu(a3, -+ FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset)); -+ __ Ld(t1, -+ FieldMemOperand(a1, JSGeneratorObject::kParametersAndRegistersOffset)); -+ { -+ Label done_loop, loop; -+ __ Move(t2, zero_reg); -+ __ bind(&loop); -+ __ Sub64(a3, a3, Operand(1)); -+ __ Branch(&done_loop, lt, a3, Operand(zero_reg)); -+ __ CalcScaledAddress(kScratchReg, t1, t2, kPointerSizeLog2); -+ __ Ld(kScratchReg, FieldMemOperand(kScratchReg, FixedArray::kHeaderSize)); -+ __ Push(kScratchReg); -+ __ Add64(t2, t2, Operand(1)); -+ __ Branch(&loop); -+ __ bind(&done_loop); -+ } -+ -+ // Underlying function needs to have bytecode available. -+ if (FLAG_debug_code) { -+ __ Ld(a3, FieldMemOperand(a4, JSFunction::kSharedFunctionInfoOffset)); -+ __ Ld(a3, FieldMemOperand(a3, SharedFunctionInfo::kFunctionDataOffset)); -+ GetSharedFunctionInfoBytecode(masm, a3, a0); -+ __ GetObjectType(a3, a3, a3); -+ __ Assert(eq, AbortReason::kMissingBytecodeArray, a3, -+ Operand(BYTECODE_ARRAY_TYPE)); -+ } -+ -+ // Resume (Ignition/TurboFan) generator object. -+ { -+ __ Ld(a0, FieldMemOperand(a4, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lhu(a0, FieldMemOperand( -+ a0, SharedFunctionInfo::kFormalParameterCountOffset)); -+ // We abuse new.target both to indicate that this is a resume call and to -+ // pass in the generator object. In ordinary calls, new.target is always -+ // undefined because generator functions are non-constructable. -+ __ Move(a3, a1); -+ __ Move(a1, a4); -+ static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch"); -+ __ Ld(a2, FieldMemOperand(a1, JSFunction::kCodeOffset)); -+ __ Add64(a2, a2, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Jump(a2); -+ } -+ -+ __ bind(&prepare_step_in_if_stepping); -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ Push(a1, a4); -+ // Push hole as receiver since we do not use it for stepping. -+ __ PushRoot(RootIndex::kTheHoleValue); -+ __ CallRuntime(Runtime::kDebugOnFunctionCall); -+ __ Pop(a1); -+ } -+ __ Ld(a4, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset)); -+ __ Branch(&stepping_prepared); -+ -+ __ bind(&prepare_step_in_suspended_generator); -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ Push(a1); -+ __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator); -+ __ Pop(a1); -+ } -+ __ Ld(a4, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset)); -+ __ Branch(&stepping_prepared); -+ -+ __ bind(&stack_overflow); -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ __ break_(0xCC); // This should be unreachable. -+ } -+} -+ -+void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ Push(a1); -+ __ CallRuntime(Runtime::kThrowConstructedNonConstructable); -+} -+ -+// Clobbers scratch1 and scratch2; preserves all other registers. -+static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc, -+ Register scratch1, Register scratch2) { -+ // Check the stack for overflow. We are not trying to catch -+ // interruptions (e.g. debug break and preemption) here, so the "real stack -+ // limit" is checked. -+ Label okay; -+ LoadStackLimit(masm, scratch1, StackLimitKind::kRealStackLimit); -+ // Make a2 the space we have left. The stack might already be overflowed -+ // here which will cause r2 to become negative. -+ __ Sub64(scratch1, sp, scratch1); -+ // Check if the arguments will overflow the stack. -+ __ Sll64(scratch2, argc, kPointerSizeLog2); -+ __ Branch(&okay, gt, scratch1, Operand(scratch2)); // Signed comparison. -+ -+ // Out of stack space. -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ -+ __ bind(&okay); -+} -+ -+namespace { -+ -+// Called with the native C calling convention. The corresponding function -+// signature is either: -+// -+// using JSEntryFunction = GeneratedCode; -+// or -+// using JSEntryFunction = GeneratedCode; -+void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type, -+ Builtins::Name entry_trampoline) { -+ Label invoke, handler_entry, exit; -+ -+ { -+ NoRootArrayScope no_root_array(masm); -+ -+ // TODO(plind): unify the ABI description here. -+ // Registers: -+ // either -+ // a0: root register value -+ // a1: entry address -+ // a2: function -+ // a3: receiver -+ // a4: argc -+ // a5: argv -+ // or -+ // a0: root register value -+ // a1: microtask_queue -+ -+ // Save callee saved registers on the stack. -+ __ MultiPush(kCalleeSaved | ra.bit()); -+ -+ // Save callee-saved FPU registers. -+ __ MultiPushFPU(kCalleeSavedFPU); -+ // Set up the reserved register for 0.0. -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0); -+ -+ // Initialize the root register. -+ // C calling convention. The first argument is passed in a0. -+ __ Move(kRootRegister, a0); -+ } -+ -+ // a1: entry address -+ // a2: function -+ // a3: receiver -+ // a4: argc -+ // a5: argv -+ -+ // We build an EntryFrame. -+ __ li(s1, Operand(-1)); // Push a bad frame pointer to fail if it is used. -+ __ li(s2, Operand(StackFrame::TypeToMarker(type))); -+ __ li(s3, Operand(StackFrame::TypeToMarker(type))); -+ ExternalReference c_entry_fp = ExternalReference::Create( -+ IsolateAddressId::kCEntryFPAddress, masm->isolate()); -+ __ li(s4, c_entry_fp); -+ __ Ld(s4, MemOperand(s4)); -+ __ Push(s1, s2, s3, s4); -+ // Set up frame pointer for the frame to be pushed. -+ __ Add64(fp, sp, -EntryFrameConstants::kCallerFPOffset); -+ // Registers: -+ // either -+ // a1: entry address -+ // a2: function -+ // a3: receiver -+ // a4: argc -+ // a5: argv -+ // or -+ // a1: microtask_queue -+ // -+ // Stack: -+ // caller fp | -+ // function slot | entry frame -+ // context slot | -+ // bad fp (0xFF...F) | -+ // callee saved registers + ra -+ // [ O32: 4 args slots] -+ // args -+ -+ // If this is the outermost JS call, set js_entry_sp value. -+ Label non_outermost_js; -+ ExternalReference js_entry_sp = ExternalReference::Create( -+ IsolateAddressId::kJSEntrySPAddress, masm->isolate()); -+ __ li(s1, js_entry_sp); -+ __ Ld(s2, MemOperand(s1)); -+ __ Branch(&non_outermost_js, ne, s2, Operand(zero_reg)); -+ __ Sd(fp, MemOperand(s1)); -+ __ li(s3, Operand(StackFrame::OUTERMOST_JSENTRY_FRAME)); -+ Label cont; -+ __ Branch(&cont); -+ __ bind(&non_outermost_js); -+ __ li(s3, Operand(StackFrame::INNER_JSENTRY_FRAME)); -+ __ bind(&cont); -+ __ push(s3); -+ -+ // Jump to a faked try block that does the invoke, with a faked catch -+ // block that sets the pending exception. -+ __ Branch(&invoke); -+ __ bind(&handler_entry); -+ -+ // Store the current pc as the handler offset. It's used later to create the -+ // handler table. -+ masm->isolate()->builtins()->SetJSEntryHandlerOffset(handler_entry.pos()); -+ -+ // Caught exception: Store result (exception) in the pending exception -+ // field in the JSEnv and return a failure sentinel. Coming in here the -+ // fp will be invalid because the PushStackHandler below sets it to 0 to -+ // signal the existence of the JSEntry frame. -+ __ li(s1, ExternalReference::Create( -+ IsolateAddressId::kPendingExceptionAddress, masm->isolate())); -+ __ Sd(a0, MemOperand(s1)); // We come back from 'invoke'. result is in a0. -+ __ LoadRoot(a0, RootIndex::kException); -+ __ Branch(&exit); -+ -+ // Invoke: Link this frame into the handler chain. -+ __ bind(&invoke); -+ __ PushStackHandler(); -+ // If an exception not caught by another handler occurs, this handler -+ // returns control to the code after the bal(&invoke) above, which -+ // restores all kCalleeSaved registers (including cp and fp) to their -+ // saved values before returning a failure to C. -+ // -+ // Registers: -+ // either -+ // a0: root register value -+ // a1: entry address -+ // a2: function -+ // a3: receiver -+ // a4: argc -+ // a5: argv -+ // or -+ // a0: root register value -+ // a1: microtask_queue -+ // -+ // Stack: -+ // handler frame -+ // entry frame -+ // callee saved registers + ra -+ // [ O32: 4 args slots] -+ // args -+ // -+ // Invoke the function by calling through JS entry trampoline builtin and -+ // pop the faked function when we return. -+ -+ Handle trampoline_code = -+ masm->isolate()->builtins()->builtin_handle(entry_trampoline); -+ __ Call(trampoline_code, RelocInfo::CODE_TARGET); -+ -+ // Unlink this frame from the handler chain. -+ __ PopStackHandler(); -+ -+ __ bind(&exit); // a0 holds result -+ // Check if the current stack frame is marked as the outermost JS frame. -+ Label non_outermost_js_2; -+ __ pop(a5); -+ __ Branch(&non_outermost_js_2, ne, a5, -+ Operand(StackFrame::OUTERMOST_JSENTRY_FRAME)); -+ __ li(a5, js_entry_sp); -+ __ Sd(zero_reg, MemOperand(a5)); -+ __ bind(&non_outermost_js_2); -+ -+ // Restore the top frame descriptors from the stack. -+ __ pop(a5); -+ __ li(a4, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, -+ masm->isolate())); -+ __ Sd(a5, MemOperand(a4)); -+ -+ // Reset the stack to the callee saved registers. -+ __ Add64(sp, sp, -EntryFrameConstants::kCallerFPOffset); -+ -+ // Restore callee-saved fpu registers. -+ __ MultiPopFPU(kCalleeSavedFPU); -+ -+ // Restore callee saved registers from the stack. -+ __ MultiPop(kCalleeSaved | ra.bit()); -+ // Return. -+ __ Jump(ra); -+} -+ -+} // namespace -+ -+void Builtins::Generate_JSEntry(MacroAssembler* masm) { -+ Generate_JSEntryVariant(masm, StackFrame::ENTRY, -+ Builtins::kJSEntryTrampoline); -+} -+ -+void Builtins::Generate_JSConstructEntry(MacroAssembler* masm) { -+ Generate_JSEntryVariant(masm, StackFrame::CONSTRUCT_ENTRY, -+ Builtins::kJSConstructEntryTrampoline); -+} -+ -+void Builtins::Generate_JSRunMicrotasksEntry(MacroAssembler* masm) { -+ Generate_JSEntryVariant(masm, StackFrame::ENTRY, -+ Builtins::kRunMicrotasksTrampoline); -+} -+ -+static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, -+ bool is_construct) { -+ // ----------- S t a t e ------------- -+ // -- a1: new.target -+ // -- a2: function -+ // -- a3: receiver_pointer -+ // -- a4: argc -+ // -- a5: argv -+ // ----------------------------------- -+ -+ // Enter an internal frame. -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ -+ // Setup the context (we need to use the caller context from the isolate). -+ ExternalReference context_address = ExternalReference::Create( -+ IsolateAddressId::kContextAddress, masm->isolate()); -+ __ li(cp, context_address); -+ __ Ld(cp, MemOperand(cp)); -+ -+ // Push the function and the receiver onto the stack. -+ __ Push(a2, a3); -+ -+ // Check if we have enough stack space to push all arguments. -+ // Clobbers a0 and a3. -+ Generate_CheckStackOverflow(masm, a4, a0, a3); -+ -+ // Setup new.target, function and argc. -+ __ Move(a3, a1); -+ __ Move(a1, a2); -+ __ Move(a0, a4); -+ -+ // a0: argc -+ // a1: function -+ // a3: new.target -+ // a5: argv -+ -+ // Copy arguments to the stack in a loop. -+ // a3: argc -+ // a5: argv, i.e. points to first arg -+ Label loop, entry; -+ __ CalcScaledAddress(s1, a5, a4, kPointerSizeLog2); -+ __ Branch(&entry); -+ // s1 points past last arg. -+ __ bind(&loop); -+ __ Ld(s2, MemOperand(a5)); // Read next parameter. -+ __ Add64(a5, a5, kPointerSize); -+ __ Ld(s2, MemOperand(s2)); // Dereference handle. -+ __ push(s2); // Push parameter. -+ __ bind(&entry); -+ __ Branch(&loop, ne, a5, Operand(s1)); -+ -+ // a0: argc -+ // a1: function -+ // a3: new.target -+ -+ // Initialize all JavaScript callee-saved registers, since they will be seen -+ // by the garbage collector as part of handlers. -+ __ LoadRoot(a4, RootIndex::kUndefinedValue); -+ __ Move(a5, a4); -+ __ Move(s1, a4); -+ __ Move(s2, a4); -+ __ Move(s3, a4); -+ __ Move(s4, a4); -+ __ Move(s5, a4); -+ // s6 holds the root address. Do not clobber. -+ // s7 is cp. Do not init. -+ -+ // Invoke the code. -+ Handle builtin = is_construct -+ ? BUILTIN_CODE(masm->isolate(), Construct) -+ : masm->isolate()->builtins()->Call(); -+ __ Call(builtin, RelocInfo::CODE_TARGET); -+ -+ // Leave internal frame. -+ } -+ __ Jump(ra); -+} -+ -+void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { -+ Generate_JSEntryTrampolineHelper(masm, false); -+} -+ -+void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { -+ Generate_JSEntryTrampolineHelper(masm, true); -+} -+ -+void Builtins::Generate_RunMicrotasksTrampoline(MacroAssembler* masm) { -+ // a1: microtask_queue -+ __ Move(RunMicrotasksDescriptor::MicrotaskQueueRegister(), a1); -+ __ Jump(BUILTIN_CODE(masm->isolate(), RunMicrotasks), RelocInfo::CODE_TARGET); -+} -+ -+static void ReplaceClosureCodeWithOptimizedCode(MacroAssembler* masm, -+ Register optimized_code, -+ Register closure, -+ Register scratch1, -+ Register scratch2) { -+ // Store code entry in the closure. -+ __ Sd(optimized_code, FieldMemOperand(closure, JSFunction::kCodeOffset)); -+ __ Move(scratch1, optimized_code); // Write barrier clobbers scratch1 below. -+ __ RecordWriteField(closure, JSFunction::kCodeOffset, scratch1, scratch2, -+ kRAHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, -+ OMIT_SMI_CHECK); -+} -+ -+static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch) { -+ Register args_count = scratch; -+ -+ // Get the arguments + receiver count. -+ __ Ld(args_count, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); -+ __ Lw(t0, FieldMemOperand(args_count, BytecodeArray::kParameterSizeOffset)); -+ -+ // Leave the frame (also dropping the register file). -+ __ LeaveFrame(StackFrame::INTERPRETED); -+ -+ // Drop receiver + arguments. -+ __ Add64(sp, sp, args_count); -+} -+ -+// Tail-call |function_id| if |smi_entry| == |marker| -+static void TailCallRuntimeIfMarkerEquals(MacroAssembler* masm, -+ Register smi_entry, -+ OptimizationMarker marker, -+ Runtime::FunctionId function_id) { -+ Label no_match; -+ __ Branch(&no_match, ne, smi_entry, Operand(Smi::FromEnum(marker))); -+ GenerateTailCallToReturnedCode(masm, function_id); -+ __ bind(&no_match); -+} -+ -+static void TailCallOptimizedCodeSlot(MacroAssembler* masm, -+ Register optimized_code_entry, -+ Register scratch1, Register scratch2) { -+ // ----------- S t a t e ------------- -+ // -- a3 : new target (preserved for callee if needed, and caller) -+ // -- a1 : target function (preserved for callee if needed, and caller) -+ // ----------------------------------- -+ DCHECK(!AreAliased(optimized_code_entry, a1, a3, scratch1, scratch2)); -+ -+ Register closure = a1; -+ -+ // Check if the optimized code is marked for deopt. If it is, call the -+ // runtime to clear it. -+ Label found_deoptimized_code; -+ __ Ld(a5, -+ FieldMemOperand(optimized_code_entry, Code::kCodeDataContainerOffset)); -+ __ Lw(a5, FieldMemOperand(a5, CodeDataContainer::kKindSpecificFlagsOffset)); -+ __ And(a5, a5, Operand(1 << Code::kMarkedForDeoptimizationBit)); -+ __ Branch(&found_deoptimized_code, ne, a5, Operand(zero_reg)); -+ -+ // Optimized code is good, get it into the closure and link the closure into -+ // the optimized functions list, then tail call the optimized code. -+ // The feedback vector is no longer used, so re-use it as a scratch -+ // register. -+ ReplaceClosureCodeWithOptimizedCode(masm, optimized_code_entry, closure, -+ scratch1, scratch2); -+ -+ static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch"); -+ __ Add64(a2, optimized_code_entry, -+ Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Jump(a2); -+ -+ // Optimized code slot contains deoptimized code, evict it and re-enter the -+ // closure's code. -+ __ bind(&found_deoptimized_code); -+ GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot); -+} -+ -+static void MaybeOptimizeCode(MacroAssembler* masm, Register feedback_vector, -+ Register optimization_marker) { -+ // ----------- S t a t e ------------- -+ // -- a3 : new target (preserved for callee if needed, and caller) -+ // -- a1 : target function (preserved for callee if needed, and caller) -+ // -- feedback vector (preserved for caller if needed) -+ // -- optimization_marker : a Smi containing a non-zero optimization marker. -+ // ----------------------------------- -+ DCHECK(!AreAliased(feedback_vector, a1, a3, optimization_marker)); -+ -+ // TODO(v8:8394): The logging of first execution will break if -+ // feedback vectors are not allocated. We need to find a different way of -+ // logging these events if required. -+ TailCallRuntimeIfMarkerEquals(masm, optimization_marker, -+ OptimizationMarker::kLogFirstExecution, -+ Runtime::kFunctionFirstExecution); -+ TailCallRuntimeIfMarkerEquals(masm, optimization_marker, -+ OptimizationMarker::kCompileOptimized, -+ Runtime::kCompileOptimized_NotConcurrent); -+ TailCallRuntimeIfMarkerEquals(masm, optimization_marker, -+ OptimizationMarker::kCompileOptimizedConcurrent, -+ Runtime::kCompileOptimized_Concurrent); -+ -+ // Otherwise, the marker is InOptimizationQueue, so fall through hoping -+ // that an interrupt will eventually update the slot with optimized code. -+ if (FLAG_debug_code) { -+ __ Assert(eq, AbortReason::kExpectedOptimizationSentinel, -+ optimization_marker, -+ Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); -+ } -+} -+ -+// Advance the current bytecode offset. This simulates what all bytecode -+// handlers do upon completion of the underlying operation. Will bail out to a -+// label if the bytecode (without prefix) is a return bytecode. Will not advance -+// the bytecode offset if the current bytecode is a JumpLoop, instead just -+// re-executing the JumpLoop to jump to the correct bytecode. -+static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, -+ Register bytecode_array, -+ Register bytecode_offset, -+ Register bytecode, Register scratch1, -+ Register scratch2, Register scratch3, -+ Label* if_return) { -+ Register bytecode_size_table = scratch1; -+ -+ // The bytecode offset value will be increased by one in wide and extra wide -+ // cases. In the case of having a wide or extra wide JumpLoop bytecode, we -+ // will restore the original bytecode. In order to simplify the code, we have -+ // a backup of it. -+ Register original_bytecode_offset = scratch3; -+ DCHECK(!AreAliased(bytecode_array, bytecode_offset, bytecode, -+ bytecode_size_table, original_bytecode_offset)); -+ __ Move(original_bytecode_offset, bytecode_offset); -+ __ li(bytecode_size_table, ExternalReference::bytecode_size_table_address()); -+ -+ // Check if the bytecode is a Wide or ExtraWide prefix bytecode. -+ Label process_bytecode, extra_wide; -+ STATIC_ASSERT(0 == static_cast(interpreter::Bytecode::kWide)); -+ STATIC_ASSERT(1 == static_cast(interpreter::Bytecode::kExtraWide)); -+ STATIC_ASSERT(2 == static_cast(interpreter::Bytecode::kDebugBreakWide)); -+ STATIC_ASSERT(3 == -+ static_cast(interpreter::Bytecode::kDebugBreakExtraWide)); -+ __ Branch(&process_bytecode, Ugreater, bytecode, Operand(3)); -+ __ And(scratch2, bytecode, Operand(1)); -+ __ Branch(&extra_wide, ne, scratch2, Operand(zero_reg)); -+ -+ // Load the next bytecode and update table to the wide scaled table. -+ __ Add64(bytecode_offset, bytecode_offset, Operand(1)); -+ __ Add64(scratch2, bytecode_array, bytecode_offset); -+ __ Lbu(bytecode, MemOperand(scratch2)); -+ __ Add64(bytecode_size_table, bytecode_size_table, -+ Operand(kIntSize * interpreter::Bytecodes::kBytecodeCount)); -+ __ Branch(&process_bytecode); -+ -+ __ bind(&extra_wide); -+ // Load the next bytecode and update table to the extra wide scaled table. -+ __ Add64(bytecode_offset, bytecode_offset, Operand(1)); -+ __ Add64(scratch2, bytecode_array, bytecode_offset); -+ __ Lbu(bytecode, MemOperand(scratch2)); -+ __ Add64(bytecode_size_table, bytecode_size_table, -+ Operand(2 * kIntSize * interpreter::Bytecodes::kBytecodeCount)); -+ -+ __ bind(&process_bytecode); -+ -+// Bailout to the return label if this is a return bytecode. -+#define JUMP_IF_EQUAL(NAME) \ -+ __ Branch(if_return, eq, bytecode, \ -+ Operand(static_cast(interpreter::Bytecode::k##NAME))); -+ RETURN_BYTECODE_LIST(JUMP_IF_EQUAL) -+#undef JUMP_IF_EQUAL -+ -+ // If this is a JumpLoop, re-execute it to perform the jump to the beginning -+ // of the loop. -+ Label end, not_jump_loop; -+ __ Branch(¬_jump_loop, ne, bytecode, -+ Operand(static_cast(interpreter::Bytecode::kJumpLoop))); -+ // We need to restore the original bytecode_offset since we might have -+ // increased it to skip the wide / extra-wide prefix bytecode. -+ __ Move(bytecode_offset, original_bytecode_offset); -+ __ Branch(&end); -+ -+ __ bind(¬_jump_loop); -+ // Otherwise, load the size of the current bytecode and advance the offset. -+ __ CalcScaledAddress(scratch2, bytecode_size_table, bytecode, 2); -+ __ Lw(scratch2, MemOperand(scratch2)); -+ __ Add64(bytecode_offset, bytecode_offset, scratch2); -+ -+ __ bind(&end); -+} -+ -+// Generate code for entering a JS function with the interpreter. -+// On entry to the function the receiver and arguments have been pushed on the -+// stack left to right. The actual argument count matches the formal parameter -+// count expected by the function. -+// -+// The live registers are: -+// o a1: the JS function object being called. -+// o a3: the incoming new target or generator object -+// o cp: our context -+// o fp: the caller's frame pointer -+// o sp: stack pointer -+// o ra: return address -+// -+// The function builds an interpreter frame. See InterpreterFrameConstants in -+// frames.h for its layout. -+void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { -+ Register closure = a1; -+ Register feedback_vector = a2; -+ -+ // Get the bytecode array from the function object and load it into -+ // kInterpreterBytecodeArrayRegister. -+ __ Ld(a0, FieldMemOperand(closure, JSFunction::kSharedFunctionInfoOffset)); -+ __ Ld(kInterpreterBytecodeArrayRegister, -+ FieldMemOperand(a0, SharedFunctionInfo::kFunctionDataOffset)); -+ GetSharedFunctionInfoBytecode(masm, kInterpreterBytecodeArrayRegister, a4); -+ -+ // The bytecode array could have been flushed from the shared function info, -+ // if so, call into CompileLazy. -+ Label compile_lazy; -+ __ GetObjectType(kInterpreterBytecodeArrayRegister, a0, a0); -+ __ Branch(&compile_lazy, ne, a0, Operand(BYTECODE_ARRAY_TYPE)); -+ -+ // Load the feedback vector from the closure. -+ __ Ld(feedback_vector, -+ FieldMemOperand(closure, JSFunction::kFeedbackCellOffset)); -+ __ Ld(feedback_vector, FieldMemOperand(feedback_vector, Cell::kValueOffset)); -+ -+ Label push_stack_frame; -+ // Check if feedback vector is valid. If valid, check for optimized code -+ // and update invocation count. Otherwise, setup the stack frame. -+ __ Ld(a4, FieldMemOperand(feedback_vector, HeapObject::kMapOffset)); -+ __ Lhu(a4, FieldMemOperand(a4, Map::kInstanceTypeOffset)); -+ __ Branch(&push_stack_frame, ne, a4, Operand(FEEDBACK_VECTOR_TYPE)); -+ -+ // Read off the optimized code slot in the feedback vector, and if there -+ // is optimized code or an optimization marker, call that instead. -+ Register optimized_code_entry = a4; -+ __ Ld(optimized_code_entry, -+ FieldMemOperand(feedback_vector, -+ FeedbackVector::kOptimizedCodeWeakOrSmiOffset)); -+ -+ // Check if the optimized code slot is not empty. -+ Label optimized_code_slot_not_empty; -+ -+ __ Branch(&optimized_code_slot_not_empty, ne, optimized_code_entry, -+ Operand(Smi::FromEnum(OptimizationMarker::kNone))); -+ -+ Label not_optimized; -+ __ bind(¬_optimized); -+ -+ // Increment invocation count for the function. -+ __ Lw(a4, FieldMemOperand(feedback_vector, -+ FeedbackVector::kInvocationCountOffset)); -+ __ Add32(a4, a4, Operand(1)); -+ __ Sw(a4, FieldMemOperand(feedback_vector, -+ FeedbackVector::kInvocationCountOffset)); -+ -+ // Open a frame scope to indicate that there is a frame on the stack. The -+ // MANUAL indicates that the scope shouldn't actually generate code to set up -+ // the frame (that is done below). -+ __ bind(&push_stack_frame); -+ FrameScope frame_scope(masm, StackFrame::MANUAL); -+ __ PushStandardFrame(closure); -+ -+ // Reset code age and the OSR arming. The OSR field and BytecodeAgeOffset are -+ // 8-bit fields next to each other, so we could just optimize by writing a -+ // 16-bit. These static asserts guard our assumption is valid. -+ STATIC_ASSERT(BytecodeArray::kBytecodeAgeOffset == -+ BytecodeArray::kOsrNestingLevelOffset + kCharSize); -+ STATIC_ASSERT(BytecodeArray::kNoAgeBytecodeAge == 0); -+ __ Sh(zero_reg, FieldMemOperand(kInterpreterBytecodeArrayRegister, -+ BytecodeArray::kOsrNestingLevelOffset)); -+ -+ // Load initial bytecode offset. -+ __ li(kInterpreterBytecodeOffsetRegister, -+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); -+ -+ // Push bytecode array and Smi tagged bytecode array offset. -+ __ SmiTag(a4, kInterpreterBytecodeOffsetRegister); -+ __ Push(kInterpreterBytecodeArrayRegister, a4); -+ -+ // Allocate the local and temporary register file on the stack. -+ Label stack_overflow; -+ { -+ // Load frame size (word) from the BytecodeArray object. -+ __ Lw(a4, FieldMemOperand(kInterpreterBytecodeArrayRegister, -+ BytecodeArray::kFrameSizeOffset)); -+ -+ // Do a stack check to ensure we don't go over the limit. -+ __ Sub64(a5, sp, Operand(a4)); -+ LoadStackLimit(masm, a2, StackLimitKind::kRealStackLimit); -+ __ Branch(&stack_overflow, Uless, a5, Operand(a2)); -+ -+ // If ok, push undefined as the initial value for all register file entries. -+ Label loop_header; -+ Label loop_check; -+ __ LoadRoot(a5, RootIndex::kUndefinedValue); -+ __ Branch(&loop_check); -+ __ bind(&loop_header); -+ // TODO(rmcilroy): Consider doing more than one push per loop iteration. -+ __ push(a5); -+ // Continue loop if not done. -+ __ bind(&loop_check); -+ __ Sub64(a4, a4, Operand(kPointerSize)); -+ __ Branch(&loop_header, ge, a4, Operand(zero_reg)); -+ } -+ -+ // If the bytecode array has a valid incoming new target or generator object -+ // register, initialize it with incoming value which was passed in r3. -+ Label no_incoming_new_target_or_generator_register; -+ __ Lw(a5, FieldMemOperand( -+ kInterpreterBytecodeArrayRegister, -+ BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset)); -+ __ Branch(&no_incoming_new_target_or_generator_register, eq, a5, -+ Operand(zero_reg)); -+ __ CalcScaledAddress(a5, fp, a5, kPointerSizeLog2); -+ __ Sd(a3, MemOperand(a5)); -+ __ bind(&no_incoming_new_target_or_generator_register); -+ -+ // Perform interrupt stack check. -+ // TODO(solanes): Merge with the real stack limit check above. -+ Label stack_check_interrupt, after_stack_check_interrupt; -+ LoadStackLimit(masm, a5, StackLimitKind::kInterruptStackLimit); -+ __ Branch(&stack_check_interrupt, Uless, sp, Operand(a5)); -+ __ bind(&after_stack_check_interrupt); -+ -+ // Load accumulator as undefined. -+ __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kUndefinedValue); -+ -+ // Load the dispatch table into a register and dispatch to the bytecode -+ // handler at the current bytecode offset. -+ Label do_dispatch; -+ __ bind(&do_dispatch); -+ __ li(kInterpreterDispatchTableRegister, -+ ExternalReference::interpreter_dispatch_table_address(masm->isolate())); -+ __ Add64(a1, kInterpreterBytecodeArrayRegister, -+ kInterpreterBytecodeOffsetRegister); -+ __ Lbu(a7, MemOperand(a1)); -+ __ CalcScaledAddress(kScratchReg, kInterpreterDispatchTableRegister, a7, -+ kPointerSizeLog2); -+ __ Ld(kJavaScriptCallCodeStartRegister, MemOperand(kScratchReg)); -+ __ Call(kJavaScriptCallCodeStartRegister); -+ masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset()); -+ -+ // Any returns to the entry trampoline are either due to the return bytecode -+ // or the interpreter tail calling a builtin and then a dispatch. -+ -+ // Get bytecode array and bytecode offset from the stack frame. -+ __ Ld(kInterpreterBytecodeArrayRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); -+ __ Ld(kInterpreterBytecodeOffsetRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); -+ __ SmiUntag(kInterpreterBytecodeOffsetRegister); -+ -+ // Either return, or advance to the next bytecode and dispatch. -+ Label do_return; -+ __ Add64(a1, kInterpreterBytecodeArrayRegister, -+ kInterpreterBytecodeOffsetRegister); -+ __ Lbu(a1, MemOperand(a1)); -+ AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, -+ kInterpreterBytecodeOffsetRegister, a1, a2, a3, -+ a4, &do_return); -+ __ Branch(&do_dispatch); -+ -+ __ bind(&do_return); -+ // The return value is in a0. -+ LeaveInterpreterFrame(masm, t0); -+ __ Jump(ra); -+ -+ __ bind(&stack_check_interrupt); -+ // Modify the bytecode offset in the stack to be kFunctionEntryBytecodeOffset -+ // for the call to the StackGuard. -+ __ li(kInterpreterBytecodeOffsetRegister, -+ Operand(Smi::FromInt(BytecodeArray::kHeaderSize - kHeapObjectTag + -+ kFunctionEntryBytecodeOffset))); -+ __ Sd(kInterpreterBytecodeOffsetRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); -+ __ CallRuntime(Runtime::kStackGuard); -+ -+ // After the call, restore the bytecode array, bytecode offset and accumulator -+ // registers again. Also, restore the bytecode offset in the stack to its -+ // previous value. -+ __ Ld(kInterpreterBytecodeArrayRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); -+ __ li(kInterpreterBytecodeOffsetRegister, -+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); -+ __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kUndefinedValue); -+ -+ __ SmiTag(a5, kInterpreterBytecodeOffsetRegister); -+ __ Sd(a5, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); -+ -+ __ Branch(&after_stack_check_interrupt); -+ -+ __ bind(&optimized_code_slot_not_empty); -+ Label maybe_has_optimized_code; -+ // Check if optimized code marker is actually a weak reference to the -+ // optimized code as opposed to an optimization marker. -+ __ JumpIfNotSmi(optimized_code_entry, &maybe_has_optimized_code); -+ MaybeOptimizeCode(masm, feedback_vector, optimized_code_entry); -+ // Fall through if there's no runnable optimized code. -+ __ Branch(¬_optimized); -+ -+ __ bind(&maybe_has_optimized_code); -+ // Load code entry from the weak reference, if it was cleared, resume -+ // execution of unoptimized code. -+ __ LoadWeakValue(optimized_code_entry, optimized_code_entry, ¬_optimized); -+ TailCallOptimizedCodeSlot(masm, optimized_code_entry, t4, a5); -+ -+ __ bind(&compile_lazy); -+ GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy); -+ // Unreachable code. -+ __ break_(0xCC); -+ -+ __ bind(&stack_overflow); -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ // Unreachable code. -+ __ break_(0xCC); -+} -+ -+static void Generate_InterpreterPushArgs(MacroAssembler* masm, -+ Register num_args, Register index, -+ Register scratch, Register scratch2) { -+ // Find the address of the last argument. -+ __ Move(scratch2, num_args); -+ __ Sll64(scratch2, scratch2, kPointerSizeLog2); -+ __ Sub64(scratch2, index, Operand(scratch2)); -+ -+ // Push the arguments. -+ Label loop_header, loop_check; -+ __ Branch(&loop_check); -+ __ bind(&loop_header); -+ __ Ld(scratch, MemOperand(index)); -+ __ Add64(index, index, Operand(-kPointerSize)); -+ __ push(scratch); -+ __ bind(&loop_check); -+ __ Branch(&loop_header, Ugreater, index, Operand(scratch2)); -+} -+ -+// static -+void Builtins::Generate_InterpreterPushArgsThenCallImpl( -+ MacroAssembler* masm, ConvertReceiverMode receiver_mode, -+ InterpreterPushArgsMode mode) { -+ DCHECK(mode != InterpreterPushArgsMode::kArrayFunction); -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a2 : the address of the first argument to be pushed. Subsequent -+ // arguments should be consecutive above this, in the same order as -+ // they are to be pushed onto the stack. -+ // -- a1 : the target to call (can be any Object). -+ // ----------------------------------- -+ Label stack_overflow; -+ -+ __ Add64(a3, a0, Operand(1)); // Add one for receiver. -+ -+ // Push "undefined" as the receiver arg if we need to. -+ if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { -+ __ PushRoot(RootIndex::kUndefinedValue); -+ __ Sub64(a3, a3, Operand(1)); // Subtract one for receiver. -+ } -+ -+ Generate_StackOverflowCheck(masm, a3, a4, t0, &stack_overflow); -+ -+ // This function modifies a2, t0 and a4. -+ Generate_InterpreterPushArgs(masm, a3, a2, a4, t0); -+ -+ if (mode == InterpreterPushArgsMode::kWithFinalSpread) { -+ __ Pop(a2); // Pass the spread in a register -+ __ Sub64(a0, a0, Operand(1)); // Subtract one for spread -+ } -+ -+ // Call the target. -+ if (mode == InterpreterPushArgsMode::kWithFinalSpread) { -+ __ Jump(BUILTIN_CODE(masm->isolate(), CallWithSpread), -+ RelocInfo::CODE_TARGET); -+ } else { -+ __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny), -+ RelocInfo::CODE_TARGET); -+ } -+ -+ __ bind(&stack_overflow); -+ { -+ __ TailCallRuntime(Runtime::kThrowStackOverflow); -+ // Unreachable code. -+ __ break_(0xCC); -+ } -+} -+ -+// static -+void Builtins::Generate_InterpreterPushArgsThenConstructImpl( -+ MacroAssembler* masm, InterpreterPushArgsMode mode) { -+ // ----------- S t a t e ------------- -+ // -- a0 : argument count (not including receiver) -+ // -- a3 : new target -+ // -- a1 : constructor to call -+ // -- a2 : allocation site feedback if available, undefined otherwise. -+ // -- a4 : address of the first argument -+ // ----------------------------------- -+ Label stack_overflow; -+ -+ // Push a slot for the receiver. -+ __ push(zero_reg); -+ -+ Generate_StackOverflowCheck(masm, a0, a5, t0, &stack_overflow); -+ -+ // This function modifies t0, a4 and a5. -+ Generate_InterpreterPushArgs(masm, a0, a4, a5, t0); -+ -+ if (mode == InterpreterPushArgsMode::kWithFinalSpread) { -+ __ Pop(a2); // Pass the spread in a register -+ __ Sub64(a0, a0, Operand(1)); // Subtract one for spread -+ } else { -+ __ AssertUndefinedOrAllocationSite(a2, t0); -+ } -+ -+ if (mode == InterpreterPushArgsMode::kArrayFunction) { -+ __ AssertFunction(a1); -+ -+ // Tail call to the function-specific construct stub (still in the caller -+ // context at this point). -+ __ Jump(BUILTIN_CODE(masm->isolate(), ArrayConstructorImpl), -+ RelocInfo::CODE_TARGET); -+ } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) { -+ // Call the constructor with a0, a1, and a3 unmodified. -+ __ Jump(BUILTIN_CODE(masm->isolate(), ConstructWithSpread), -+ RelocInfo::CODE_TARGET); -+ } else { -+ DCHECK_EQ(InterpreterPushArgsMode::kOther, mode); -+ // Call the constructor with a0, a1, and a3 unmodified. -+ __ Jump(BUILTIN_CODE(masm->isolate(), Construct), RelocInfo::CODE_TARGET); -+ } -+ -+ __ bind(&stack_overflow); -+ { -+ __ TailCallRuntime(Runtime::kThrowStackOverflow); -+ // Unreachable code. -+ __ break_(0xCC); -+ } -+} -+ -+static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { -+ // Set the return address to the correct point in the interpreter entry -+ // trampoline. -+ Label builtin_trampoline, trampoline_loaded; -+ Smi interpreter_entry_return_pc_offset( -+ masm->isolate()->heap()->interpreter_entry_return_pc_offset()); -+ DCHECK_NE(interpreter_entry_return_pc_offset, Smi::zero()); -+ -+ // If the SFI function_data is an InterpreterData, the function will have a -+ // custom copy of the interpreter entry trampoline for profiling. If so, -+ // get the custom trampoline, otherwise grab the entry address of the global -+ // trampoline. -+ __ Ld(t0, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); -+ __ Ld(t0, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset)); -+ __ Ld(t0, FieldMemOperand(t0, SharedFunctionInfo::kFunctionDataOffset)); -+ __ GetObjectType(t0, kInterpreterDispatchTableRegister, -+ kInterpreterDispatchTableRegister); -+ __ Branch(&builtin_trampoline, ne, kInterpreterDispatchTableRegister, -+ Operand(INTERPRETER_DATA_TYPE)); -+ -+ __ Ld(t0, FieldMemOperand(t0, InterpreterData::kInterpreterTrampolineOffset)); -+ __ Add64(t0, t0, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Branch(&trampoline_loaded); -+ -+ __ bind(&builtin_trampoline); -+ __ li(t0, ExternalReference:: -+ address_of_interpreter_entry_trampoline_instruction_start( -+ masm->isolate())); -+ __ Ld(t0, MemOperand(t0)); -+ -+ __ bind(&trampoline_loaded); -+ __ Add64(ra, t0, Operand(interpreter_entry_return_pc_offset.value())); -+ -+ // Initialize the dispatch table register. -+ __ li(kInterpreterDispatchTableRegister, -+ ExternalReference::interpreter_dispatch_table_address(masm->isolate())); -+ -+ // Get the bytecode array pointer from the frame. -+ __ Ld(kInterpreterBytecodeArrayRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); -+ -+ if (FLAG_debug_code) { -+ // Check function data field is actually a BytecodeArray object. -+ __ SmiTst(kInterpreterBytecodeArrayRegister, kScratchReg); -+ __ Assert(ne, -+ AbortReason::kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, -+ kScratchReg, Operand(zero_reg)); -+ __ GetObjectType(kInterpreterBytecodeArrayRegister, a1, a1); -+ __ Assert(eq, -+ AbortReason::kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, -+ a1, Operand(BYTECODE_ARRAY_TYPE)); -+ } -+ -+ // Get the target bytecode offset from the frame. -+ __ SmiUntag(kInterpreterBytecodeOffsetRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); -+ -+ if (FLAG_debug_code) { -+ Label okay; -+ __ Branch(&okay, ge, kInterpreterBytecodeOffsetRegister, -+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); -+ // Unreachable code. -+ __ break_(0xCC); -+ __ bind(&okay); -+ } -+ -+ // Dispatch to the target bytecode. -+ __ Add64(a1, kInterpreterBytecodeArrayRegister, -+ kInterpreterBytecodeOffsetRegister); -+ __ Lbu(a7, MemOperand(a1)); -+ __ CalcScaledAddress(a1, kInterpreterDispatchTableRegister, a7, -+ kPointerSizeLog2); -+ __ Ld(kJavaScriptCallCodeStartRegister, MemOperand(a1)); -+ __ Jump(kJavaScriptCallCodeStartRegister); -+} -+ -+void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { -+ // Advance the current bytecode offset stored within the given interpreter -+ // stack frame. This simulates what all bytecode handlers do upon completion -+ // of the underlying operation. -+ __ Ld(kInterpreterBytecodeArrayRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeArrayFromFp)); -+ __ Ld(kInterpreterBytecodeOffsetRegister, -+ MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); -+ __ SmiUntag(kInterpreterBytecodeOffsetRegister); -+ -+ Label enter_bytecode, function_entry_bytecode; -+ __ Branch(&function_entry_bytecode, eq, kInterpreterBytecodeOffsetRegister, -+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag + -+ kFunctionEntryBytecodeOffset)); -+ -+ // Load the current bytecode. -+ __ Add64(a1, kInterpreterBytecodeArrayRegister, -+ kInterpreterBytecodeOffsetRegister); -+ __ Lbu(a1, MemOperand(a1)); -+ -+ // Advance to the next bytecode. -+ Label if_return; -+ AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, -+ kInterpreterBytecodeOffsetRegister, a1, a2, a3, -+ a4, &if_return); -+ -+ __ bind(&enter_bytecode); -+ // Convert new bytecode offset to a Smi and save in the stackframe. -+ __ SmiTag(a2, kInterpreterBytecodeOffsetRegister); -+ __ Sd(a2, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); -+ -+ Generate_InterpreterEnterBytecode(masm); -+ -+ __ bind(&function_entry_bytecode); -+ // If the code deoptimizes during the implicit function entry stack interrupt -+ // check, it will have a bailout ID of kFunctionEntryBytecodeOffset, which is -+ // not a valid bytecode offset. Detect this case and advance to the first -+ // actual bytecode. -+ __ li(kInterpreterBytecodeOffsetRegister, -+ Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); -+ __ Branch(&enter_bytecode); -+ -+ // We should never take the if_return path. -+ __ bind(&if_return); -+ __ Abort(AbortReason::kInvalidBytecodeAdvance); -+} -+ -+void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { -+ Generate_InterpreterEnterBytecode(masm); -+} -+ -+namespace { -+void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, -+ bool java_script_builtin, -+ bool with_result) { -+ const RegisterConfiguration* config(RegisterConfiguration::Default()); -+ int allocatable_register_count = config->num_allocatable_general_registers(); -+ if (with_result) { -+ // Overwrite the hole inserted by the deoptimizer with the return value from -+ // the LAZY deopt point. -+ __ Sd(a0, -+ MemOperand( -+ sp, config->num_allocatable_general_registers() * kPointerSize + -+ BuiltinContinuationFrameConstants::kFixedFrameSize)); -+ } -+ for (int i = allocatable_register_count - 1; i >= 0; --i) { -+ int code = config->GetAllocatableGeneralCode(i); -+ __ Pop(Register::from_code(code)); -+ if (java_script_builtin && code == kJavaScriptCallArgCountRegister.code()) { -+ __ SmiUntag(Register::from_code(code)); -+ } -+ } -+ __ Ld(fp, MemOperand( -+ sp, BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); -+ // Load builtin index (stored as a Smi) and use it to get the builtin start -+ // address from the builtins table. -+ __ Pop(t0); -+ __ Add64(sp, sp, -+ Operand(BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); -+ __ Pop(ra); -+ __ LoadEntryFromBuiltinIndex(t0); -+ __ Jump(t0); -+} -+} // namespace -+ -+void Builtins::Generate_ContinueToCodeStubBuiltin(MacroAssembler* masm) { -+ Generate_ContinueToBuiltinHelper(masm, false, false); -+} -+ -+void Builtins::Generate_ContinueToCodeStubBuiltinWithResult( -+ MacroAssembler* masm) { -+ Generate_ContinueToBuiltinHelper(masm, false, true); -+} -+ -+void Builtins::Generate_ContinueToJavaScriptBuiltin(MacroAssembler* masm) { -+ Generate_ContinueToBuiltinHelper(masm, true, false); -+} -+ -+void Builtins::Generate_ContinueToJavaScriptBuiltinWithResult( -+ MacroAssembler* masm) { -+ Generate_ContinueToBuiltinHelper(masm, true, true); -+} -+ -+void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kNotifyDeoptimized); -+ } -+ -+ DCHECK_EQ(kInterpreterAccumulatorRegister.code(), a0.code()); -+ __ Ld(a0, MemOperand(sp, 0 * kPointerSize)); -+ __ Add64(sp, sp, Operand(1 * kPointerSize)); // Remove state. -+ __ Ret(); -+} -+ -+void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kCompileForOnStackReplacement); -+ } -+ -+ // If the code object is null, just return to the caller. -+ __ Ret(eq, a0, Operand(Smi::zero())); -+ -+ // Drop the handler frame that is be sitting on top of the actual -+ // JavaScript frame. This is the case then OSR is triggered from bytecode. -+ __ LeaveFrame(StackFrame::STUB); -+ -+ // Load deoptimization data from the code object. -+ // = [#deoptimization_data_offset] -+ __ Ld(a1, MemOperand(a0, Code::kDeoptimizationDataOffset - kHeapObjectTag)); -+ -+ // Load the OSR entrypoint offset from the deoptimization data. -+ // = [#header_size + #osr_pc_offset] -+ __ SmiUntag(a1, MemOperand(a1, FixedArray::OffsetOfElementAt( -+ DeoptimizationData::kOsrPcOffsetIndex) - -+ kHeapObjectTag)); -+ -+ // Compute the target address = code_obj + header_size + osr_offset -+ // = + #header_size + -+ __ Add64(a0, a0, a1); -+ __ Add64(ra, a0, Code::kHeaderSize - kHeapObjectTag); -+ // And "return" to the OSR entry point of the function. -+ __ Ret(); -+} -+ -+// static -+void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : argc -+ // -- sp[0] : argArray -+ // -- sp[4] : thisArg -+ // -- sp[8] : receiver -+ // ----------------------------------- -+ -+ Register argc = a0; -+ Register arg_array = a2; -+ Register receiver = a1; -+ Register this_arg = a5; -+ Register undefined_value = a3; -+ -+ __ LoadRoot(undefined_value, RootIndex::kUndefinedValue); -+ -+ // 1. Load receiver into a1, argArray into a2 (if present), remove all -+ // arguments from the stack (including the receiver), and push thisArg (if -+ // present) instead. -+ { -+ // Claim (2 - argc) dummy arguments form the stack, to put the stack in a -+ // consistent state for a simple pop operation. -+ -+ __ Sub64(sp, sp, Operand(2 * kPointerSize)); -+ __ CalcScaledAddress(sp, sp, argc, kPointerSizeLog2); -+ __ Pop(this_arg, arg_array); // Overwrite argc -+ -+ Label done0, done1; -+ __ Branch(&done0, ne, argc, Operand(zero_reg)); -+ __ Move(arg_array, undefined_value); // if argc == 0 -+ __ Move(this_arg, undefined_value); // if argc == 0 -+ __ bind(&done0); // else (i.e., argc > 0) -+ -+ __ Branch(&done1, ne, argc, Operand(1)); -+ __ Move(arg_array, undefined_value); // if argc == 1 -+ __ bind(&done1); // else (i.e., argc > 1) -+ -+ __ Ld(receiver, MemOperand(sp)); -+ __ Sd(this_arg, MemOperand(sp)); -+ } -+ -+ // ----------- S t a t e ------------- -+ // -- a2 : argArray -+ // -- a1 : receiver -+ // -- a3 : undefined root value -+ // -- sp[0] : thisArg -+ // ----------------------------------- -+ -+ // 2. We don't need to check explicitly for callable receiver here, -+ // since that's the first thing the Call/CallWithArrayLike builtins -+ // will do. -+ -+ // 3. Tail call with no arguments if argArray is null or undefined. -+ Label no_arguments; -+ __ JumpIfRoot(arg_array, RootIndex::kNullValue, &no_arguments); -+ __ Branch(&no_arguments, eq, arg_array, Operand(undefined_value)); -+ -+ // 4a. Apply the receiver to the given argArray. -+ __ Jump(BUILTIN_CODE(masm->isolate(), CallWithArrayLike), -+ RelocInfo::CODE_TARGET); -+ -+ // 4b. The argArray is either null or undefined, so we tail call without any -+ // arguments to the receiver. -+ __ bind(&no_arguments); -+ { -+ __ Move(a0, zero_reg); -+ DCHECK(receiver == a1); -+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); -+ } -+} -+ -+// static -+void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { -+ // 1. Make sure we have at least one argument. -+ // a0: actual number of arguments -+ { -+ Label done; -+ __ Branch(&done, ne, a0, Operand(zero_reg)); -+ __ PushRoot(RootIndex::kUndefinedValue); -+ __ Add64(a0, a0, Operand(1)); -+ __ bind(&done); -+ } -+ -+ // 2. Get the function to call (passed as receiver) from the stack. -+ // a0: actual number of arguments -+ __ CalcScaledAddress(kScratchReg, sp, a0, kPointerSizeLog2); -+ __ Ld(a1, MemOperand(kScratchReg)); -+ -+ // 3. Shift arguments and return address one slot down on the stack -+ // (overwriting the original receiver). Adjust argument count to make -+ // the original first argument the new receiver. -+ // a0: actual number of arguments -+ // a1: function -+ { -+ Label loop; -+ // Calculate the copy start address (destination). Copy end address is sp. -+ __ CalcScaledAddress(a2, sp, a0, kPointerSizeLog2); -+ -+ __ bind(&loop); -+ __ Ld(kScratchReg, MemOperand(a2, -kPointerSize)); -+ __ Sd(kScratchReg, MemOperand(a2)); -+ __ Sub64(a2, a2, Operand(kPointerSize)); -+ __ Branch(&loop, ne, a2, Operand(sp)); -+ // Adjust the actual number of arguments and remove the top element -+ // (which is a copy of the last argument). -+ __ Sub64(a0, a0, Operand(1)); -+ __ Pop(); -+ } -+ -+ // 4. Call the callable. -+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); -+} -+ -+void Builtins::Generate_ReflectApply(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : argc -+ // -- sp[0] : argumentsList (if argc ==3) -+ // -- sp[4] : thisArgument (if argc >=2) -+ // -- sp[8] : target (if argc >=1) -+ // -- sp[12] : receiver -+ // ----------------------------------- -+ -+ Register argc = a0; -+ Register arguments_list = a2; -+ Register target = a1; -+ Register this_argument = a5; -+ Register undefined_value = a3; -+ -+ __ LoadRoot(undefined_value, RootIndex::kUndefinedValue); -+ -+ // 1. Load target into a1 (if present), argumentsList into a2 (if present), -+ // remove all arguments from the stack (including the receiver), and push -+ // thisArgument (if present) instead. -+ { -+ // Claim (3 - argc) dummy arguments form the stack, to put the stack in a -+ // consistent state for a simple pop operation. -+ -+ __ Sub64(sp, sp, Operand(3 * kPointerSize)); -+ __ CalcScaledAddress(sp, sp, argc, kPointerSizeLog2); -+ __ Pop(target, this_argument, arguments_list); -+ -+ Label done0, done1, done2; -+ __ Branch(&done0, ne, argc, Operand(zero_reg)); -+ __ Move(arguments_list, undefined_value); // if argc == 0 -+ __ Move(this_argument, undefined_value); // if argc == 0 -+ __ Move(target, undefined_value); // if argc == 0 -+ __ bind(&done0); // argc != 0 -+ -+ __ Branch(&done1, ne, argc, Operand(1)); -+ __ Move(arguments_list, undefined_value); // if argc == 1 -+ __ Move(this_argument, undefined_value); // if argc == 1 -+ __ bind(&done1); // argc > 1 -+ -+ __ Branch(&done2, ne, argc, Operand(2)); -+ __ Move(arguments_list, undefined_value); // if argc == 2 -+ __ bind(&done2); // argc > 2 -+ -+ __ Sd(this_argument, MemOperand(sp, 0)); // Overwrite receiver -+ } -+ -+ // ----------- S t a t e ------------- -+ // -- a2 : argumentsList -+ // -- a1 : target -+ // -- a3 : undefined root value -+ // -- sp[0] : thisArgument -+ // ----------------------------------- -+ -+ // 2. We don't need to check explicitly for callable target here, -+ // since that's the first thing the Call/CallWithArrayLike builtins -+ // will do. -+ -+ // 3. Apply the target to the given argumentsList. -+ __ Jump(BUILTIN_CODE(masm->isolate(), CallWithArrayLike), -+ RelocInfo::CODE_TARGET); -+} -+ -+void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : argc -+ // -- sp[0] : new.target (optional) (dummy value if argc <= 2) -+ // -- sp[4] : argumentsList (dummy value if argc <= 1) -+ // -- sp[8] : target (dummy value if argc == 0) -+ // -- sp[12] : receiver -+ // ----------------------------------- -+ Register argc = a0; -+ Register arguments_list = a2; -+ Register target = a1; -+ Register new_target = a3; -+ Register undefined_value = a4; -+ -+ __ LoadRoot(undefined_value, RootIndex::kUndefinedValue); -+ -+ // 1. Load target into a1 (if present), argumentsList into a2 (if present), -+ // new.target into a3 (if present, otherwise use target), remove all -+ // arguments from the stack (including the receiver), and push thisArgument -+ // (if present) instead. -+ { -+ // Claim (3 - argc) dummy arguments form the stack, to put the stack in a -+ // consistent state for a simple pop operation. -+ __ Sub64(sp, sp, Operand(3 * kPointerSize)); -+ __ CalcScaledAddress(sp, sp, argc, kPointerSizeLog2); -+ __ Pop(target, arguments_list, new_target); -+ -+ Label done0, done1, done2; -+ __ Branch(&done0, ne, argc, Operand(zero_reg)); -+ __ Move(arguments_list, undefined_value); // if argc == 0 -+ __ Move(new_target, undefined_value); // if argc == 0 -+ __ Move(target, undefined_value); // if argc == 0 -+ __ bind(&done0); -+ -+ __ Branch(&done1, ne, argc, Operand(1)); -+ __ Move(arguments_list, undefined_value); // if argc == 1 -+ __ Move(new_target, target); // if argc == 1 -+ __ bind(&done1); -+ -+ __ Branch(&done2, ne, argc, Operand(2)); -+ __ Move(new_target, target); // if argc == 2 -+ __ bind(&done2); -+ -+ __ Sd(undefined_value, MemOperand(sp, 0)); // Overwrite receiver -+ } -+ -+ // ----------- S t a t e ------------- -+ // -- a2 : argumentsList -+ // -- a1 : target -+ // -- a3 : new.target -+ // -- sp[0] : receiver (undefined) -+ // ----------------------------------- -+ -+ // 2. We don't need to check explicitly for constructor target here, -+ // since that's the first thing the Construct/ConstructWithArrayLike -+ // builtins will do. -+ -+ // 3. We don't need to check explicitly for constructor new.target here, -+ // since that's the second thing the Construct/ConstructWithArrayLike -+ // builtins will do. -+ -+ // 4. Construct the target with the given new.target and argumentsList. -+ __ Jump(BUILTIN_CODE(masm->isolate(), ConstructWithArrayLike), -+ RelocInfo::CODE_TARGET); -+} -+ -+static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { -+ __ SmiTag(a0); -+ __ li(a4, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); -+ __ MultiPush(a0.bit() | a1.bit() | a4.bit() | fp.bit() | ra.bit()); -+ __ Push(Smi::zero()); // Padding. -+ __ Add64(fp, sp, -+ Operand(ArgumentsAdaptorFrameConstants::kFixedFrameSizeFromFp)); -+} -+ -+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : result being passed through -+ // ----------------------------------- -+ // Get the number of arguments passed (as a smi), tear down the frame and -+ // then tear down the parameters. -+ __ Ld(a1, MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); -+ __ Move(sp, fp); -+ __ MultiPop(fp.bit() | ra.bit()); -+ __ SmiScale(a4, a1, kPointerSizeLog2); -+ __ Add64(sp, sp, a4); -+ // Adjust for the receiver. -+ __ Add64(sp, sp, Operand(kPointerSize)); -+} -+ -+// static -+void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, -+ Handle code) { -+ // ----------- S t a t e ------------- -+ // -- a1 : target -+ // -- a0 : number of parameters on the stack (not including the receiver) -+ // -- a2 : arguments list (a FixedArray) -+ // -- a4 : len (number of elements to push from args) -+ // -- a3 : new.target (for [[Construct]]) -+ // ----------------------------------- -+ if (masm->emit_debug_code()) { -+ // Allow a2 to be a FixedArray, or a FixedDoubleArray if a4 == 0. -+ Label ok, fail; -+ __ AssertNotSmi(a2); -+ __ GetObjectType(a2, t5, t5); -+ __ Branch(&ok, eq, t5, Operand(FIXED_ARRAY_TYPE)); -+ __ Branch(&fail, ne, t5, Operand(FIXED_DOUBLE_ARRAY_TYPE)); -+ __ Branch(&ok, eq, a4, Operand(zero_reg)); -+ // Fall through. -+ __ bind(&fail); -+ __ Abort(AbortReason::kOperandIsNotAFixedArray); -+ -+ __ bind(&ok); -+ } -+ -+ Register args = a2; -+ Register len = a4; -+ -+ // Check for stack overflow. -+ Label stack_overflow; -+ Generate_StackOverflowCheck(masm, len, kScratchReg, a5, &stack_overflow); -+ -+ // Push arguments onto the stack (thisArgument is already on the stack). -+ { -+ Label done, push, loop; -+ Register src = a6; -+ Register scratch = len; -+ __ Add64(src, args, FixedArray::kHeaderSize - kHeapObjectTag); -+ __ Add64(a0, a0, len); // The 'len' argument for Call() or Construct(). -+ __ Branch(&done, eq, len, Operand(zero_reg)); -+ __ Sll64(scratch, len, kPointerSizeLog2); -+ __ Sub64(scratch, sp, Operand(scratch)); -+ __ LoadRoot(t1, RootIndex::kTheHoleValue); -+ __ bind(&loop); -+ __ Ld(a5, MemOperand(src)); -+ __ Branch(&push, ne, a5, Operand(t1)); -+ __ LoadRoot(a5, RootIndex::kUndefinedValue); -+ __ bind(&push); -+ __ Add64(src, src, kPointerSize); -+ __ Push(a5); -+ __ Branch(&loop, ne, scratch, Operand(sp)); -+ __ bind(&done); -+ } -+ -+ // Tail-call to the actual Call or Construct builtin. -+ __ Jump(code, RelocInfo::CODE_TARGET); -+ -+ __ bind(&stack_overflow); -+ __ TailCallRuntime(Runtime::kThrowStackOverflow); -+} -+ -+// static -+void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, -+ CallOrConstructMode mode, -+ Handle code) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a3 : the new.target (for [[Construct]] calls) -+ // -- a1 : the target to call (can be any Object) -+ // -- a2 : start index (to support rest parameters) -+ // ----------------------------------- -+ -+ // Check if new.target has a [[Construct]] internal method. -+ if (mode == CallOrConstructMode::kConstruct) { -+ Label new_target_constructor, new_target_not_constructor; -+ __ JumpIfSmi(a3, &new_target_not_constructor); -+ __ Ld(t1, FieldMemOperand(a3, HeapObject::kMapOffset)); -+ __ Lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset)); -+ __ And(t1, t1, Operand(Map::Bits1::IsConstructorBit::kMask)); -+ __ Branch(&new_target_constructor, ne, t1, Operand(zero_reg)); -+ __ bind(&new_target_not_constructor); -+ { -+ FrameScope scope(masm, StackFrame::MANUAL); -+ __ EnterFrame(StackFrame::INTERNAL); -+ __ Push(a3); -+ __ CallRuntime(Runtime::kThrowNotConstructor); -+ } -+ __ bind(&new_target_constructor); -+ } -+ -+ // Check if we have an arguments adaptor frame below the function frame. -+ Label arguments_adaptor, arguments_done; -+ __ Ld(a6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); -+ __ Ld(a7, MemOperand(a6, CommonFrameConstants::kContextOrFrameTypeOffset)); -+ __ Branch(&arguments_adaptor, eq, a7, -+ Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); -+ { -+ __ Ld(a7, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); -+ __ Ld(a7, FieldMemOperand(a7, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lhu(a7, FieldMemOperand( -+ a7, SharedFunctionInfo::kFormalParameterCountOffset)); -+ __ Move(a6, fp); -+ } -+ __ Branch(&arguments_done); -+ __ bind(&arguments_adaptor); -+ { -+ // Just get the length from the ArgumentsAdaptorFrame. -+ __ SmiUntag(a7, -+ MemOperand(a6, ArgumentsAdaptorFrameConstants::kLengthOffset)); -+ } -+ __ bind(&arguments_done); -+ -+ Label stack_done, stack_overflow; -+ __ Sub32(a7, a7, a2); -+ __ Branch(&stack_done, le, a7, Operand(zero_reg)); -+ { -+ // Check for stack overflow. -+ Generate_StackOverflowCheck(masm, a7, a4, a5, &stack_overflow); -+ -+ // Forward the arguments from the caller frame. -+ { -+ Label loop; -+ __ Add64(a0, a0, a7); -+ __ bind(&loop); -+ { -+ __ CalcScaledAddress(kScratchReg, a6, a7, kPointerSizeLog2); -+ __ Ld(kScratchReg, MemOperand(kScratchReg, 1 * kPointerSize)); -+ __ push(kScratchReg); -+ __ Sub32(a7, a7, Operand(1)); -+ __ Branch(&loop, ne, a7, Operand(zero_reg)); -+ } -+ } -+ } -+ __ Branch(&stack_done); -+ __ bind(&stack_overflow); -+ __ TailCallRuntime(Runtime::kThrowStackOverflow); -+ __ bind(&stack_done); -+ -+ // Tail-call to the {code} handler. -+ __ Jump(code, RelocInfo::CODE_TARGET); -+} -+ -+// static -+void Builtins::Generate_CallFunction(MacroAssembler* masm, -+ ConvertReceiverMode mode) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSFunction) -+ // ----------------------------------- -+ __ AssertFunction(a1); -+ -+ // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) -+ // Check that function is not a "classConstructor". -+ Label class_constructor; -+ __ Ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lwu(a3, FieldMemOperand(a2, SharedFunctionInfo::kFlagsOffset)); -+ __ And(kScratchReg, a3, -+ Operand(SharedFunctionInfo::IsClassConstructorBit::kMask)); -+ __ Branch(&class_constructor, ne, kScratchReg, Operand(zero_reg)); -+ -+ // Enter the context of the function; ToObject has to run in the function -+ // context, and we also need to take the global proxy from the function -+ // context in case of conversion. -+ __ Ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); -+ // We need to convert the receiver for non-native sloppy mode functions. -+ Label done_convert; -+ __ Lwu(a3, FieldMemOperand(a2, SharedFunctionInfo::kFlagsOffset)); -+ __ And(kScratchReg, a3, -+ Operand(SharedFunctionInfo::IsNativeBit::kMask | -+ SharedFunctionInfo::IsStrictBit::kMask)); -+ __ Branch(&done_convert, ne, kScratchReg, Operand(zero_reg)); -+ { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSFunction) -+ // -- a2 : the shared function info. -+ // -- cp : the function context. -+ // ----------------------------------- -+ -+ if (mode == ConvertReceiverMode::kNullOrUndefined) { -+ // Patch receiver to global proxy. -+ __ LoadGlobalProxy(a3); -+ } else { -+ Label convert_to_object, convert_receiver; -+ __ CalcScaledAddress(kScratchReg, sp, a0, kPointerSizeLog2); -+ __ Ld(a3, MemOperand(kScratchReg)); -+ __ JumpIfSmi(a3, &convert_to_object); -+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); -+ __ GetObjectType(a3, a4, a4); -+ __ Branch(&done_convert, Ugreater_equal, a4, -+ Operand(FIRST_JS_RECEIVER_TYPE)); -+ if (mode != ConvertReceiverMode::kNotNullOrUndefined) { -+ Label convert_global_proxy; -+ __ JumpIfRoot(a3, RootIndex::kUndefinedValue, &convert_global_proxy); -+ __ JumpIfNotRoot(a3, RootIndex::kNullValue, &convert_to_object); -+ __ bind(&convert_global_proxy); -+ { -+ // Patch receiver to global proxy. -+ __ LoadGlobalProxy(a3); -+ } -+ __ Branch(&convert_receiver); -+ } -+ __ bind(&convert_to_object); -+ { -+ // Convert receiver using ToObject. -+ // TODO(bmeurer): Inline the allocation here to avoid building the frame -+ // in the fast case? (fall back to AllocateInNewSpace?) -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ SmiTag(a0); -+ __ Push(a0, a1); -+ __ Move(a0, a3); -+ __ Push(cp); -+ __ Call(BUILTIN_CODE(masm->isolate(), ToObject), -+ RelocInfo::CODE_TARGET); -+ __ Pop(cp); -+ __ Move(a3, a0); -+ __ Pop(a0, a1); -+ __ SmiUntag(a0); -+ } -+ __ Ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); -+ __ bind(&convert_receiver); -+ } -+ __ CalcScaledAddress(kScratchReg, sp, a0, kPointerSizeLog2); -+ __ Sd(a3, MemOperand(kScratchReg)); -+ } -+ __ bind(&done_convert); -+ -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSFunction) -+ // -- a2 : the shared function info. -+ // -- cp : the function context. -+ // ----------------------------------- -+ -+ __ Lhu(a2, -+ FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset)); -+ __ InvokeFunctionCode(a1, no_reg, a2, a0, JUMP_FUNCTION); -+ -+ // The function is a "classConstructor", need to raise an exception. -+ __ bind(&class_constructor); -+ { -+ FrameScope frame(masm, StackFrame::INTERNAL); -+ __ Push(a1); -+ __ CallRuntime(Runtime::kThrowConstructorNonCallableError); -+ } -+} -+ -+// static -+void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSBoundFunction) -+ // ----------------------------------- -+ __ AssertBoundFunction(a1); -+ -+ // Patch the receiver to [[BoundThis]]. -+ { -+ __ Ld(kScratchReg, FieldMemOperand(a1, JSBoundFunction::kBoundThisOffset)); -+ __ CalcScaledAddress(a4, sp, a0, kPointerSizeLog2); -+ __ Sd(kScratchReg, MemOperand(a4)); -+ } -+ -+ // Load [[BoundArguments]] into a2 and length of that into a4. -+ __ Ld(a2, FieldMemOperand(a1, JSBoundFunction::kBoundArgumentsOffset)); -+ __ SmiUntag(a4, FieldMemOperand(a2, FixedArray::kLengthOffset)); -+ -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSBoundFunction) -+ // -- a2 : the [[BoundArguments]] (implemented as FixedArray) -+ // -- a4 : the number of [[BoundArguments]] -+ // ----------------------------------- -+ -+ // Reserve stack space for the [[BoundArguments]]. -+ { -+ Label done; -+ __ Sll64(a5, a4, kPointerSizeLog2); -+ __ Sub64(sp, sp, Operand(a5)); -+ // Check the stack for overflow. We are not trying to catch interruptions -+ // (i.e. debug break and preemption) here, so check the "real stack limit". -+ LoadStackLimit(masm, kScratchReg, StackLimitKind::kRealStackLimit); -+ __ Branch(&done, Ugreater_equal, sp, Operand(kScratchReg)); -+ // Restore the stack pointer. -+ __ Add64(sp, sp, Operand(a5)); -+ { -+ FrameScope scope(masm, StackFrame::MANUAL); -+ __ EnterFrame(StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ } -+ __ bind(&done); -+ } -+ -+ // Relocate arguments down the stack. -+ { -+ Label loop, done_loop; -+ __ Move(a5, zero_reg); -+ __ bind(&loop); -+ __ Branch(&done_loop, gt, a5, Operand(a0)); -+ __ CalcScaledAddress(a6, sp, a4, kPointerSizeLog2); -+ __ Ld(kScratchReg, MemOperand(a6)); -+ __ CalcScaledAddress(a6, sp, a5, kPointerSizeLog2); -+ __ Sd(kScratchReg, MemOperand(a6)); -+ __ Add64(a4, a4, Operand(1)); -+ __ Add64(a5, a5, Operand(1)); -+ __ Branch(&loop); -+ __ bind(&done_loop); -+ } -+ -+ // Copy [[BoundArguments]] to the stack (below the arguments). -+ { -+ Label loop, done_loop; -+ __ SmiUntag(a4, FieldMemOperand(a2, FixedArray::kLengthOffset)); -+ __ Add64(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); -+ __ bind(&loop); -+ __ Sub64(a4, a4, Operand(1)); -+ __ Branch(&done_loop, lt, a4, Operand(zero_reg)); -+ __ CalcScaledAddress(a5, a2, a4, kPointerSizeLog2); -+ __ Ld(kScratchReg, MemOperand(a5)); -+ __ CalcScaledAddress(a5, sp, a0, kPointerSizeLog2); -+ __ Sd(kScratchReg, MemOperand(a5)); -+ __ Add64(a0, a0, Operand(1)); -+ __ Branch(&loop); -+ __ bind(&done_loop); -+ } -+ -+ // Call the [[BoundTargetFunction]] via the Call builtin. -+ __ Ld(a1, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset)); -+ __ Jump(BUILTIN_CODE(masm->isolate(), Call_ReceiverIsAny), -+ RelocInfo::CODE_TARGET); -+} -+ -+// static -+void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the target to call (can be any Object). -+ // ----------------------------------- -+ -+ Label non_callable, non_smi; -+ __ JumpIfSmi(a1, &non_callable); -+ __ bind(&non_smi); -+ __ GetObjectType(a1, t1, t2); -+ __ Jump(masm->isolate()->builtins()->CallFunction(mode), -+ RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE)); -+ __ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction), -+ RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE)); -+ -+ // Check if target has a [[Call]] internal method. -+ __ Lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset)); -+ __ And(t1, t1, Operand(Map::Bits1::IsCallableBit::kMask)); -+ __ Branch(&non_callable, eq, t1, Operand(zero_reg)); -+ -+ __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq, -+ t2, Operand(JS_PROXY_TYPE)); -+ -+ // 2. Call to something else, which might have a [[Call]] internal method (if -+ // not we raise an exception). -+ // Overwrite the original receiver with the (original) target. -+ __ CalcScaledAddress(kScratchReg, sp, a0, kPointerSizeLog2); -+ __ Sd(a1, MemOperand(kScratchReg)); -+ // Let the "call_as_function_delegate" take care of the rest. -+ __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1); -+ __ Jump(masm->isolate()->builtins()->CallFunction( -+ ConvertReceiverMode::kNotNullOrUndefined), -+ RelocInfo::CODE_TARGET); -+ -+ // 3. Call to something that is not callable. -+ __ bind(&non_callable); -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ Push(a1); -+ __ CallRuntime(Runtime::kThrowCalledNonCallable); -+ } -+} -+ -+void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the constructor to call (checked to be a JSFunction) -+ // -- a3 : the new target (checked to be a constructor) -+ // ----------------------------------- -+ __ AssertConstructor(a1); -+ __ AssertFunction(a1); -+ -+ // Calling convention for function specific ConstructStubs require -+ // a2 to contain either an AllocationSite or undefined. -+ __ LoadRoot(a2, RootIndex::kUndefinedValue); -+ -+ Label call_generic_stub; -+ -+ // Jump to JSBuiltinsConstructStub or JSConstructStubGeneric. -+ __ Ld(a4, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lwu(a4, FieldMemOperand(a4, SharedFunctionInfo::kFlagsOffset)); -+ __ And(a4, a4, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); -+ __ Branch(&call_generic_stub, eq, a4, Operand(zero_reg)); -+ -+ __ Jump(BUILTIN_CODE(masm->isolate(), JSBuiltinsConstructStub), -+ RelocInfo::CODE_TARGET); -+ -+ __ bind(&call_generic_stub); -+ __ Jump(BUILTIN_CODE(masm->isolate(), JSConstructStubGeneric), -+ RelocInfo::CODE_TARGET); -+} -+ -+// static -+void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSBoundFunction) -+ // -- a3 : the new target (checked to be a constructor) -+ // ----------------------------------- -+ __ AssertConstructor(a1); -+ __ AssertBoundFunction(a1); -+ -+ // Load [[BoundArguments]] into a2 and length of that into a4. -+ __ Ld(a2, FieldMemOperand(a1, JSBoundFunction::kBoundArgumentsOffset)); -+ __ SmiUntag(a4, FieldMemOperand(a2, FixedArray::kLengthOffset)); -+ -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the function to call (checked to be a JSBoundFunction) -+ // -- a2 : the [[BoundArguments]] (implemented as FixedArray) -+ // -- a3 : the new target (checked to be a constructor) -+ // -- a4 : the number of [[BoundArguments]] -+ // ----------------------------------- -+ -+ // Reserve stack space for the [[BoundArguments]]. -+ { -+ Label done; -+ __ Sll64(a5, a4, kPointerSizeLog2); -+ __ Sub64(sp, sp, Operand(a5)); -+ // Check the stack for overflow. We are not trying to catch interruptions -+ // (i.e. debug break and preemption) here, so check the "real stack limit". -+ LoadStackLimit(masm, kScratchReg, StackLimitKind::kRealStackLimit); -+ __ Branch(&done, Ugreater_equal, sp, Operand(kScratchReg)); -+ // Restore the stack pointer. -+ __ Add64(sp, sp, Operand(a5)); -+ { -+ FrameScope scope(masm, StackFrame::MANUAL); -+ __ EnterFrame(StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ } -+ __ bind(&done); -+ } -+ -+ // Relocate arguments down the stack. -+ { -+ Label loop, done_loop; -+ __ Move(a5, zero_reg); -+ __ bind(&loop); -+ __ Branch(&done_loop, ge, a5, Operand(a0)); -+ __ CalcScaledAddress(a6, sp, a4, kPointerSizeLog2); -+ __ Ld(kScratchReg, MemOperand(a6)); -+ __ CalcScaledAddress(a6, sp, a5, kPointerSizeLog2); -+ __ Sd(kScratchReg, MemOperand(a6)); -+ __ Add64(a4, a4, Operand(1)); -+ __ Add64(a5, a5, Operand(1)); -+ __ Branch(&loop); -+ __ bind(&done_loop); -+ } -+ -+ // Copy [[BoundArguments]] to the stack (below the arguments). -+ { -+ Label loop, done_loop; -+ __ SmiUntag(a4, FieldMemOperand(a2, FixedArray::kLengthOffset)); -+ __ Add64(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); -+ __ bind(&loop); -+ __ Sub64(a4, a4, Operand(1)); -+ __ Branch(&done_loop, lt, a4, Operand(zero_reg)); -+ __ CalcScaledAddress(a5, a2, a4, kPointerSizeLog2); -+ __ Ld(kScratchReg, MemOperand(a5)); -+ __ CalcScaledAddress(a5, sp, a0, kPointerSizeLog2); -+ __ Sd(kScratchReg, MemOperand(a5)); -+ __ Add64(a0, a0, Operand(1)); -+ __ Branch(&loop); -+ __ bind(&done_loop); -+ } -+ -+ // Patch new.target to [[BoundTargetFunction]] if new.target equals target. -+ { -+ Label skip_load; -+ __ Branch(&skip_load, ne, a1, Operand(a3)); -+ __ Ld(a3, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset)); -+ __ bind(&skip_load); -+ } -+ -+ // Construct the [[BoundTargetFunction]] via the Construct builtin. -+ __ Ld(a1, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset)); -+ __ Jump(BUILTIN_CODE(masm->isolate(), Construct), RelocInfo::CODE_TARGET); -+} -+ -+// static -+void Builtins::Generate_Construct(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- a0 : the number of arguments (not including the receiver) -+ // -- a1 : the constructor to call (can be any Object) -+ // -- a3 : the new target (either the same as the constructor or -+ // the JSFunction on which new was invoked initially) -+ // ----------------------------------- -+ -+ // Check if target is a Smi. -+ Label non_constructor, non_proxy; -+ __ JumpIfSmi(a1, &non_constructor); -+ -+ // Check if target has a [[Construct]] internal method. -+ __ Ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); -+ __ Lbu(t4, FieldMemOperand(t1, Map::kBitFieldOffset)); -+ __ And(t4, t4, Operand(Map::Bits1::IsConstructorBit::kMask)); -+ __ Branch(&non_constructor, eq, t4, Operand(zero_reg)); -+ -+ // Dispatch based on instance type. -+ __ Lhu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset)); -+ __ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction), -+ RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE)); -+ -+ // Only dispatch to bound functions after checking whether they are -+ // constructors. -+ __ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction), -+ RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE)); -+ -+ // Only dispatch to proxies after checking whether they are constructors. -+ __ Branch(&non_proxy, ne, t2, Operand(JS_PROXY_TYPE)); -+ __ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), -+ RelocInfo::CODE_TARGET); -+ -+ // Called Construct on an exotic Object with a [[Construct]] internal method. -+ __ bind(&non_proxy); -+ { -+ // Overwrite the original receiver with the (original) target. -+ __ CalcScaledAddress(kScratchReg, sp, a0, kPointerSizeLog2); -+ __ Sd(a1, MemOperand(kScratchReg)); -+ // Let the "call_as_constructor_delegate" take care of the rest. -+ __ LoadNativeContextSlot(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1); -+ __ Jump(masm->isolate()->builtins()->CallFunction(), -+ RelocInfo::CODE_TARGET); -+ } -+ -+ // Called Construct on an Object that doesn't have a [[Construct]] internal -+ // method. -+ __ bind(&non_constructor); -+ __ Jump(BUILTIN_CODE(masm->isolate(), ConstructedNonConstructable), -+ RelocInfo::CODE_TARGET); -+} -+ -+void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { -+ // State setup as expected by MacroAssembler::InvokePrologue. -+ // ----------- S t a t e ------------- -+ // -- a0: actual arguments count -+ // -- a1: function (passed through to callee) -+ // -- a2: expected arguments count -+ // -- a3: new target (passed through to callee) -+ // ----------------------------------- -+ -+ Label invoke, dont_adapt_arguments, stack_overflow; -+ -+ Label enough, too_few; -+ __ Branch(&dont_adapt_arguments, eq, a2, -+ Operand(kDontAdaptArgumentsSentinel)); -+ // We use Uless as the number of argument should always be greater than 0. -+ __ Branch(&too_few, Uless, a0, Operand(a2)); -+ -+ { // Enough parameters: actual >= expected. -+ // a0: actual number of arguments as a smi -+ // a1: function -+ // a2: expected number of arguments -+ // a3: new target (passed through to callee) -+ __ bind(&enough); -+ EnterArgumentsAdaptorFrame(masm); -+ Generate_StackOverflowCheck(masm, a2, a5, kScratchReg, &stack_overflow); -+ -+ // Calculate copy start address into a0 and copy end address into a4. -+ __ SmiScale(a0, a0, kPointerSizeLog2); -+ __ Add64(a0, fp, a0); -+ // Adjust for return address and receiver. -+ __ Add64(a0, a0, Operand(2 * kPointerSize)); -+ // Compute copy end address. -+ __ Sll64(a4, a2, kPointerSizeLog2); -+ __ Sub64(a4, a0, a4); -+ -+ // Copy the arguments (including the receiver) to the new stack frame. -+ // a0: copy start address -+ // a1: function -+ // a2: expected number of arguments -+ // a3: new target (passed through to callee) -+ // a4: copy end address -+ -+ Label copy; -+ __ bind(©); -+ __ Ld(a5, MemOperand(a0)); -+ __ push(a5); -+ __ Add64(a0, a0, -kPointerSize); -+ __ Branch(©, ge, a0, Operand(a4)); -+ -+ __ Branch(&invoke); -+ } -+ -+ { // Too few parameters: Actual < expected. -+ __ bind(&too_few); -+ EnterArgumentsAdaptorFrame(masm); -+ Generate_StackOverflowCheck(masm, a2, a5, kScratchReg, &stack_overflow); -+ -+ // Calculate copy start address into a0 and copy end address into a7. -+ // a0: actual number of arguments as a smi -+ // a1: function -+ // a2: expected number of arguments -+ // a3: new target (passed through to callee) -+ __ SmiScale(a0, a0, kPointerSizeLog2); -+ __ Add64(a0, fp, a0); -+ // Adjust for return address and receiver. -+ __ Add64(a0, a0, Operand(2 * kPointerSize)); -+ // Compute copy end address. Also adjust for return address. -+ __ Add64(a7, fp, kPointerSize); -+ -+ // Copy the arguments (including the receiver) to the new stack frame. -+ // a0: copy start address -+ // a1: function -+ // a2: expected number of arguments -+ // a3: new target (passed through to callee) -+ // a7: copy end address -+ Label copy; -+ __ bind(©); -+ __ Ld(a4, MemOperand(a0)); // Adjusted above for return addr and receiver. -+ __ Sub64(sp, sp, kPointerSize); -+ __ Sub64(a0, a0, kPointerSize); -+ __ Sd(a4, MemOperand(sp)); -+ __ Branch(©, ne, a0, Operand(a7)); -+ -+ // Fill the remaining expected arguments with undefined. -+ // a1: function -+ // a2: expected number of arguments -+ // a3: new target (passed through to callee) -+ __ LoadRoot(a5, RootIndex::kUndefinedValue); -+ __ Sll64(a6, a2, kPointerSizeLog2); -+ __ Sub64(a4, fp, Operand(a6)); -+ // Adjust for frame. -+ __ Sub64(a4, a4, -+ Operand(ArgumentsAdaptorFrameConstants::kFixedFrameSizeFromFp + -+ kPointerSize)); -+ -+ Label fill; -+ __ bind(&fill); -+ __ Sub64(sp, sp, kPointerSize); -+ __ Sd(a5, MemOperand(sp)); -+ __ Branch(&fill, ne, sp, Operand(a4)); -+ } -+ -+ // Call the entry point. -+ __ bind(&invoke); -+ __ Move(a0, a2); -+ // a0 : expected number of arguments -+ // a1 : function (passed through to callee) -+ // a3: new target (passed through to callee) -+ static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch"); -+ __ Ld(a2, FieldMemOperand(a1, JSFunction::kCodeOffset)); -+ __ Add64(a2, a2, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Call(a2); -+ -+ // Store offset of return address for deoptimizer. -+ masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); -+ -+ // Exit frame and return. -+ LeaveArgumentsAdaptorFrame(masm); -+ __ Ret(); -+ -+ // ------------------------------------------- -+ // Don't adapt arguments. -+ // ------------------------------------------- -+ __ bind(&dont_adapt_arguments); -+ static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch"); -+ __ Ld(a2, FieldMemOperand(a1, JSFunction::kCodeOffset)); -+ __ Add64(a2, a2, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Jump(a2); -+ -+ __ bind(&stack_overflow); -+ { -+ FrameScope frame(masm, StackFrame::MANUAL); -+ __ CallRuntime(Runtime::kThrowStackOverflow); -+ __ break_(0xCC); -+ } -+} -+ -+void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { -+ // The function index was put in t0 by the jump table trampoline. -+ // Convert to Smi for the runtime call -+ __ SmiTag(kWasmCompileLazyFuncIndexRegister); -+ { -+ HardAbortScope hard_abort(masm); // Avoid calls to Abort. -+ FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY); -+ -+ // Save all parameter registers (see kGpParamRegisters in wasm-linkage.cc). -+ // They might be overwritten in the runtime call below. We don't have any -+ // callee-saved registers in wasm, so no need to store anything else. -+ constexpr RegList gp_regs = Register::ListOf(a0, a2, a3, a4, a5, a6, a7); -+ constexpr RegList fp_regs = -+ DoubleRegister::ListOf(fa0, fa1, fa2, fa3, fa4, fa5, fa6); -+ static_assert(WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs == -+ arraysize(wasm::kGpParamRegisters), -+ "frame size mismatch"); -+ static_assert(WasmCompileLazyFrameConstants::kNumberOfSavedFpParamRegs == -+ arraysize(wasm::kFpParamRegisters), -+ "frame size mismatch"); -+ __ MultiPush(gp_regs); -+ __ MultiPushFPU(fp_regs); -+ -+ // Pass instance and function index as an explicit arguments to the runtime -+ // function. -+ __ Push(kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister); -+ // Initialize the JavaScript context with 0. CEntry will use it to -+ // set the current context on the isolate. -+ __ Move(kContextRegister, Smi::zero()); -+ __ CallRuntime(Runtime::kWasmCompileLazy, 2); -+ -+ __ Move(s1, a0); // move return value to s1 since a0 will be restored to -+ // the value before the call -+ -+ // Restore registers. -+ __ MultiPopFPU(fp_regs); -+ __ MultiPop(gp_regs); -+ } -+ // Finally, jump to the entrypoint. -+ __ Jump(s1); -+} -+ -+void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { -+ HardAbortScope hard_abort(masm); // Avoid calls to Abort. -+ { -+ FrameScope scope(masm, StackFrame::WASM_DEBUG_BREAK); -+ -+ // Save all parameter registers. They might hold live values, we restore -+ // them after the runtime call. -+ __ MultiPush(WasmDebugBreakFrameConstants::kPushedGpRegs); -+ __ MultiPushFPU(WasmDebugBreakFrameConstants::kPushedFpRegs); -+ -+ // Initialize the JavaScript context with 0. CEntry will use it to -+ // set the current context on the isolate. -+ __ Move(cp, Smi::zero()); -+ __ CallRuntime(Runtime::kWasmDebugBreak, 0); -+ -+ // Restore registers. -+ __ MultiPopFPU(WasmDebugBreakFrameConstants::kPushedFpRegs); -+ __ MultiPop(WasmDebugBreakFrameConstants::kPushedGpRegs); -+ } -+ __ Ret(); -+} -+ -+void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, -+ SaveFPRegsMode save_doubles, ArgvMode argv_mode, -+ bool builtin_exit_frame) { -+ // Called from JavaScript; parameters are on stack as if calling JS function -+ // a0: number of arguments including receiver -+ // a1: pointer to builtin function -+ // fp: frame pointer (restored after C call) -+ // sp: stack pointer (restored as callee's sp after C call) -+ // cp: current context (C callee-saved) -+ // -+ // If argv_mode == kArgvInRegister: -+ // a2: pointer to the first argument -+ -+ if (argv_mode == kArgvInRegister) { -+ // Move argv into the correct register. -+ __ Move(s1, a2); -+ } else { -+ // Compute the argv pointer in a callee-saved register. -+ __ CalcScaledAddress(s1, sp, a0, kPointerSizeLog2); -+ __ Sub64(s1, s1, kPointerSize); -+ } -+ -+ // Enter the exit frame that transitions from JavaScript to C++. -+ FrameScope scope(masm, StackFrame::MANUAL); -+ __ EnterExitFrame( -+ save_doubles == kSaveFPRegs, 0, -+ builtin_exit_frame ? StackFrame::BUILTIN_EXIT : StackFrame::EXIT); -+ -+ // s3: number of arguments including receiver (C callee-saved) -+ // s1: pointer to first argument (C callee-saved) -+ // s2: pointer to builtin function (C callee-saved) -+ -+ // Prepare arguments for C routine. -+ // a0 = argc -+ __ Move(s3, a0); -+ __ Move(s2, a1); -+ -+ // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We -+ // also need to reserve the 4 argument slots on the stack. -+ -+ __ AssertStackIsAligned(); -+ -+ // a0 = argc, a1 = argv, a2 = isolate -+ __ li(a2, ExternalReference::isolate_address(masm->isolate())); -+ __ Move(a1, s1); -+ -+ __ StoreReturnAddressAndCall(s2); -+ -+ // Result returned in a0 or a1:a0 - do not destroy these registers! -+ -+ // Check result for exception sentinel. -+ Label exception_returned; -+ __ LoadRoot(a4, RootIndex::kException); -+ __ Branch(&exception_returned, eq, a4, Operand(a0)); -+ -+ // Check that there is no pending exception, otherwise we -+ // should have returned the exception sentinel. -+ if (FLAG_debug_code) { -+ Label okay; -+ ExternalReference pending_exception_address = ExternalReference::Create( -+ IsolateAddressId::kPendingExceptionAddress, masm->isolate()); -+ __ li(a2, pending_exception_address); -+ __ Ld(a2, MemOperand(a2)); -+ __ LoadRoot(a4, RootIndex::kTheHoleValue); -+ // Cannot use check here as it attempts to generate call into runtime. -+ __ Branch(&okay, eq, a4, Operand(a2)); -+ __ stop(); -+ __ bind(&okay); -+ } -+ -+ // Exit C frame and return. -+ // a0:a1: result -+ // sp: stack pointer -+ // fp: frame pointer -+ Register argc = argv_mode == kArgvInRegister -+ // We don't want to pop arguments so set argc to no_reg. -+ ? no_reg -+ // s3: still holds argc (callee-saved). -+ : s3; -+ __ LeaveExitFrame(save_doubles == kSaveFPRegs, argc, EMIT_RETURN); -+ -+ // Handling of exception. -+ __ bind(&exception_returned); -+ -+ ExternalReference pending_handler_context_address = ExternalReference::Create( -+ IsolateAddressId::kPendingHandlerContextAddress, masm->isolate()); -+ ExternalReference pending_handler_entrypoint_address = -+ ExternalReference::Create( -+ IsolateAddressId::kPendingHandlerEntrypointAddress, masm->isolate()); -+ ExternalReference pending_handler_fp_address = ExternalReference::Create( -+ IsolateAddressId::kPendingHandlerFPAddress, masm->isolate()); -+ ExternalReference pending_handler_sp_address = ExternalReference::Create( -+ IsolateAddressId::kPendingHandlerSPAddress, masm->isolate()); -+ -+ // Ask the runtime for help to determine the handler. This will set a0 to -+ // contain the current pending exception, don't clobber it. -+ ExternalReference find_handler = -+ ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler); -+ { -+ FrameScope scope(masm, StackFrame::MANUAL); -+ __ PrepareCallCFunction(3, 0, a0); -+ __ Move(a0, zero_reg); -+ __ Move(a1, zero_reg); -+ __ li(a2, ExternalReference::isolate_address(masm->isolate())); -+ __ CallCFunction(find_handler, 3); -+ } -+ -+ // Retrieve the handler context, SP and FP. -+ __ li(cp, pending_handler_context_address); -+ __ Ld(cp, MemOperand(cp)); -+ __ li(sp, pending_handler_sp_address); -+ __ Ld(sp, MemOperand(sp)); -+ __ li(fp, pending_handler_fp_address); -+ __ Ld(fp, MemOperand(fp)); -+ -+ // If the handler is a JS frame, restore the context to the frame. Note that -+ // the context will be set to (cp == 0) for non-JS frames. -+ Label zero; -+ __ Branch(&zero, eq, cp, Operand(zero_reg)); -+ __ Sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); -+ __ bind(&zero); -+ -+ // Reset the masking register. This is done independent of the underlying -+ // feature flag {FLAG_untrusted_code_mitigations} to make the snapshot work -+ // with both configurations. It is safe to always do this, because the -+ // underlying register is caller-saved and can be arbitrarily clobbered. -+ __ ResetSpeculationPoisonRegister(); -+ -+ // Compute the handler entry address and jump to it. -+ __ li(t6, pending_handler_entrypoint_address); -+ __ Ld(t6, MemOperand(t6)); -+ __ Jump(t6); -+} -+ -+void Builtins::Generate_DoubleToI(MacroAssembler* masm) { -+ Label done; -+ Register result_reg = t0; -+ -+ Register scratch = GetRegisterThatIsNotOneOf(result_reg); -+ Register scratch2 = GetRegisterThatIsNotOneOf(result_reg, scratch); -+ Register scratch3 = GetRegisterThatIsNotOneOf(result_reg, scratch, scratch2); -+ DoubleRegister double_scratch = kScratchDoubleReg; -+ -+ // Account for saved regs. -+ const int kArgumentOffset = 4 * kPointerSize; -+ -+ __ Push(result_reg); -+ __ Push(scratch, scratch2, scratch3); -+ -+ // Load double input. -+ __ LoadDouble(double_scratch, MemOperand(sp, kArgumentOffset)); -+ -+ // Try a conversion to a signed integer, if exception occurs, scratch is -+ // set to 0 -+ __ Trunc_w_d(scratch3, double_scratch, scratch); -+ -+ // If we had no exceptions then set result_reg and we are done. -+ Label error; -+ __ Branch(&error, eq, scratch, Operand(zero_reg)); -+ __ Move(result_reg, scratch3); -+ __ Branch(&done); -+ __ bind(&error); -+ -+ // Load the double value and perform a manual truncation. -+ Register input_high = scratch2; -+ Register input_low = scratch3; -+ -+ __ Lw(input_low, MemOperand(sp, kArgumentOffset + Register::kMantissaOffset)); -+ __ Lw(input_high, -+ MemOperand(sp, kArgumentOffset + Register::kExponentOffset)); -+ -+ Label normal_exponent; -+ // Extract the biased exponent in result. -+ __ ExtractBits(result_reg, input_high, HeapNumber::kExponentShift, -+ HeapNumber::kExponentBits); -+ -+ // Check for Infinity and NaNs, which should return 0. -+ __ Sub32(scratch, result_reg, HeapNumber::kExponentMask); -+ __ LoadZeroIfConditionZero( -+ result_reg, -+ scratch); // result_reg = scratch == 0 ? 0 : result_reg -+ __ Branch(&done, eq, scratch, Operand(zero_reg)); -+ -+ // Express exponent as delta to (number of mantissa bits + 31). -+ __ Sub32(result_reg, result_reg, -+ Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31)); -+ -+ // If the delta is strictly positive, all bits would be shifted away, -+ // which means that we can return 0. -+ __ Branch(&normal_exponent, le, result_reg, Operand(zero_reg)); -+ __ Move(result_reg, zero_reg); -+ __ Branch(&done); -+ -+ __ bind(&normal_exponent); -+ const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1; -+ // Calculate shift. -+ __ Add32(scratch, result_reg, -+ Operand(kShiftBase + HeapNumber::kMantissaBits)); -+ -+ // Save the sign. -+ Register sign = result_reg; -+ result_reg = no_reg; -+ __ And(sign, input_high, Operand(HeapNumber::kSignMask)); -+ -+ // We must specially handle shifts greater than 31. -+ Label high_shift_needed, high_shift_done; -+ __ Branch(&high_shift_needed, lt, scratch, Operand(32)); -+ __ Move(input_high, zero_reg); -+ __ Branch(&high_shift_done); -+ __ bind(&high_shift_needed); -+ -+ // Set the implicit 1 before the mantissa part in input_high. -+ __ Or(input_high, input_high, -+ Operand(1 << HeapNumber::kMantissaBitsInTopWord)); -+ // Shift the mantissa bits to the correct position. -+ // We don't need to clear non-mantissa bits as they will be shifted away. -+ // If they weren't, it would mean that the answer is in the 32bit range. -+ __ Sll32(input_high, input_high, scratch); -+ -+ __ bind(&high_shift_done); -+ -+ // Replace the shifted bits with bits from the lower mantissa word. -+ Label pos_shift, shift_done, sign_negative; -+ __ li(kScratchReg, 32); -+ __ subw(scratch, kScratchReg, scratch); -+ __ Branch(&pos_shift, ge, scratch, Operand(zero_reg)); -+ -+ // Negate scratch. -+ __ Sub32(scratch, zero_reg, scratch); -+ __ Sll32(input_low, input_low, scratch); -+ __ Branch(&shift_done); -+ -+ __ bind(&pos_shift); -+ __ srlw(input_low, input_low, scratch); -+ -+ __ bind(&shift_done); -+ __ Or(input_high, input_high, Operand(input_low)); -+ // Restore sign if necessary. -+ __ Move(scratch, sign); -+ result_reg = sign; -+ sign = no_reg; -+ __ Sub32(result_reg, zero_reg, input_high); -+ __ Branch(&sign_negative, ne, scratch, Operand(zero_reg)); -+ __ Move(result_reg, input_high); -+ __ bind(&sign_negative); -+ -+ __ bind(&done); -+ -+ __ Sd(result_reg, MemOperand(sp, kArgumentOffset)); -+ __ Pop(scratch, scratch2, scratch3); -+ __ Pop(result_reg); -+ __ Ret(); -+} -+ -+void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) { -+ // TODO(v8:10701): Implement for this platform. -+ __ Trap(); -+} -+ -+namespace { -+ -+int AddressOffset(ExternalReference ref0, ExternalReference ref1) { -+ int64_t offset = (ref0.address() - ref1.address()); -+ DCHECK(static_cast(offset) == offset); -+ return static_cast(offset); -+} -+ -+// Calls an API function. Allocates HandleScope, extracts returned value -+// from handle and propagates exceptions. Restores context. stack_space -+// - space to be unwound on exit (includes the call JS arguments space and -+// the additional space allocated for the fast call). -+void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address, -+ ExternalReference thunk_ref, int stack_space, -+ MemOperand* stack_space_operand, -+ MemOperand return_value_operand) { -+ Isolate* isolate = masm->isolate(); -+ ExternalReference next_address = -+ ExternalReference::handle_scope_next_address(isolate); -+ const int kNextOffset = 0; -+ const int kLimitOffset = AddressOffset( -+ ExternalReference::handle_scope_limit_address(isolate), next_address); -+ const int kLevelOffset = AddressOffset( -+ ExternalReference::handle_scope_level_address(isolate), next_address); -+ -+ DCHECK(function_address == a1 || function_address == a2); -+ -+ Label profiler_enabled, end_profiler_check; -+ __ li(t6, ExternalReference::is_profiling_address(isolate)); -+ __ Lb(t6, MemOperand(t6, 0)); -+ __ Branch(&profiler_enabled, ne, t6, Operand(zero_reg)); -+ __ li(t6, ExternalReference::address_of_runtime_stats_flag()); -+ __ Lw(t6, MemOperand(t6, 0)); -+ __ Branch(&profiler_enabled, ne, t6, Operand(zero_reg)); -+ { -+ // Call the api function directly. -+ __ Move(t6, function_address); -+ __ Branch(&end_profiler_check); -+ } -+ -+ __ bind(&profiler_enabled); -+ { -+ // Additional parameter is the address of the actual callback. -+ __ li(t6, thunk_ref); -+ } -+ __ bind(&end_profiler_check); -+ -+ // Allocate HandleScope in callee-save registers. -+ __ li(s5, next_address); -+ __ Ld(s3, MemOperand(s5, kNextOffset)); -+ __ Ld(s1, MemOperand(s5, kLimitOffset)); -+ __ Lw(s2, MemOperand(s5, kLevelOffset)); -+ __ Add32(s2, s2, Operand(1)); -+ __ Sw(s2, MemOperand(s5, kLevelOffset)); -+ -+ __ StoreReturnAddressAndCall(t6); -+ -+ Label promote_scheduled_exception; -+ Label delete_allocated_handles; -+ Label leave_exit_frame; -+ Label return_value_loaded; -+ -+ // Load value from ReturnValue. -+ __ Ld(a0, return_value_operand); -+ __ bind(&return_value_loaded); -+ -+ // No more valid handles (the result handle was the last one). Restore -+ // previous handle scope. -+ __ Sd(s3, MemOperand(s5, kNextOffset)); -+ if (__ emit_debug_code()) { -+ __ Lw(a1, MemOperand(s5, kLevelOffset)); -+ __ Check(eq, AbortReason::kUnexpectedLevelAfterReturnFromApiCall, a1, -+ Operand(s2)); -+ } -+ __ Sub32(s2, s2, Operand(1)); -+ __ Sw(s2, MemOperand(s5, kLevelOffset)); -+ __ Ld(kScratchReg, MemOperand(s5, kLimitOffset)); -+ __ Branch(&delete_allocated_handles, ne, s1, Operand(kScratchReg)); -+ -+ // Leave the API exit frame. -+ __ bind(&leave_exit_frame); -+ -+ if (stack_space_operand == nullptr) { -+ DCHECK_NE(stack_space, 0); -+ __ li(s3, Operand(stack_space)); -+ } else { -+ DCHECK_EQ(stack_space, 0); -+ STATIC_ASSERT(kCArgSlotCount == 0); -+ __ Ld(s3, *stack_space_operand); -+ } -+ -+ static constexpr bool kDontSaveDoubles = false; -+ static constexpr bool kRegisterContainsSlotCount = false; -+ __ LeaveExitFrame(kDontSaveDoubles, s3, NO_EMIT_RETURN, -+ kRegisterContainsSlotCount); -+ -+ // Check if the function scheduled an exception. -+ __ LoadRoot(a4, RootIndex::kTheHoleValue); -+ __ li(kScratchReg, ExternalReference::scheduled_exception_address(isolate)); -+ __ Ld(a5, MemOperand(kScratchReg)); -+ __ Branch(&promote_scheduled_exception, ne, a4, Operand(a5)); -+ -+ __ Ret(); -+ -+ // Re-throw by promoting a scheduled exception. -+ __ bind(&promote_scheduled_exception); -+ __ TailCallRuntime(Runtime::kPromoteScheduledException); -+ -+ // HandleScope limit has changed. Delete allocated extensions. -+ __ bind(&delete_allocated_handles); -+ __ Sd(s1, MemOperand(s5, kLimitOffset)); -+ __ Move(s3, a0); -+ __ PrepareCallCFunction(1, s1); -+ __ li(a0, ExternalReference::isolate_address(isolate)); -+ __ CallCFunction(ExternalReference::delete_handle_scope_extensions(), 1); -+ __ Move(a0, s3); -+ __ Branch(&leave_exit_frame); -+} -+ -+} // namespace -+ -+void Builtins::Generate_CallApiCallback(MacroAssembler* masm) { -+ // ----------- S t a t e ------------- -+ // -- cp : context -+ // -- a1 : api function address -+ // -- a2 : arguments count (not including the receiver) -+ // -- a3 : call data -+ // -- a0 : holder -+ // -- -+ // -- sp[0] : last argument -+ // -- ... -+ // -- sp[(argc - 1) * 8] : first argument -+ // -- sp[(argc + 0) * 8] : receiver -+ // ----------------------------------- -+ -+ Register api_function_address = a1; -+ Register argc = a2; -+ Register call_data = a3; -+ Register holder = a0; -+ Register scratch = t0; -+ Register base = t1; // For addressing MemOperands on the stack. -+ -+ DCHECK(!AreAliased(api_function_address, argc, call_data, holder, scratch, -+ base)); -+ -+ using FCA = FunctionCallbackArguments; -+ -+ STATIC_ASSERT(FCA::kArgsLength == 6); -+ STATIC_ASSERT(FCA::kNewTargetIndex == 5); -+ STATIC_ASSERT(FCA::kDataIndex == 4); -+ STATIC_ASSERT(FCA::kReturnValueOffset == 3); -+ STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); -+ STATIC_ASSERT(FCA::kIsolateIndex == 1); -+ STATIC_ASSERT(FCA::kHolderIndex == 0); -+ -+ // Set up FunctionCallbackInfo's implicit_args on the stack as follows: -+ // -+ // Target state: -+ // sp[0 * kPointerSize]: kHolder -+ // sp[1 * kPointerSize]: kIsolate -+ // sp[2 * kPointerSize]: undefined (kReturnValueDefaultValue) -+ // sp[3 * kPointerSize]: undefined (kReturnValue) -+ // sp[4 * kPointerSize]: kData -+ // sp[5 * kPointerSize]: undefined (kNewTarget) -+ -+ // Set up the base register for addressing through MemOperands. It will point -+ // at the receiver (located at sp + argc * kPointerSize). -+ __ CalcScaledAddress(base, sp, argc, kPointerSizeLog2); -+ -+ // Reserve space on the stack. -+ __ Sub64(sp, sp, Operand(FCA::kArgsLength * kPointerSize)); -+ -+ // kHolder. -+ __ Sd(holder, MemOperand(sp, 0 * kPointerSize)); -+ -+ // kIsolate. -+ __ li(scratch, ExternalReference::isolate_address(masm->isolate())); -+ __ Sd(scratch, MemOperand(sp, 1 * kPointerSize)); -+ -+ // kReturnValueDefaultValue and kReturnValue. -+ __ LoadRoot(scratch, RootIndex::kUndefinedValue); -+ __ Sd(scratch, MemOperand(sp, 2 * kPointerSize)); -+ __ Sd(scratch, MemOperand(sp, 3 * kPointerSize)); -+ -+ // kData. -+ __ Sd(call_data, MemOperand(sp, 4 * kPointerSize)); -+ -+ // kNewTarget. -+ __ Sd(scratch, MemOperand(sp, 5 * kPointerSize)); -+ -+ // Keep a pointer to kHolder (= implicit_args) in a scratch register. -+ // We use it below to set up the FunctionCallbackInfo object. -+ __ Move(scratch, sp); -+ -+ // Allocate the v8::Arguments structure in the arguments' space since -+ // it's not controlled by GC. -+ static constexpr int kApiStackSpace = 4; -+ static constexpr bool kDontSaveDoubles = false; -+ FrameScope frame_scope(masm, StackFrame::MANUAL); -+ __ EnterExitFrame(kDontSaveDoubles, kApiStackSpace); -+ -+ // EnterExitFrame may align the sp. -+ -+ // FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above). -+ // Arguments are after the return address (pushed by EnterExitFrame()). -+ __ Sd(scratch, MemOperand(sp, 1 * kPointerSize)); -+ -+ // FunctionCallbackInfo::values_ (points at the first varargs argument passed -+ // on the stack). -+ __ Sub64(scratch, base, Operand(1 * kPointerSize)); -+ __ Sd(scratch, MemOperand(sp, 2 * kPointerSize)); -+ -+ // FunctionCallbackInfo::length_. -+ // Stored as int field, 32-bit integers within struct on stack always left -+ // justified by n64 ABI. -+ __ Sw(argc, MemOperand(sp, 3 * kPointerSize)); -+ -+ // We also store the number of bytes to drop from the stack after returning -+ // from the API function here. -+ // Note: Unlike on other architectures, this stores the number of slots to -+ // drop, not the number of bytes. -+ __ Add64(scratch, argc, Operand(FCA::kArgsLength + 1 /* receiver */)); -+ __ Sd(scratch, MemOperand(sp, 4 * kPointerSize)); -+ -+ // v8::InvocationCallback's argument. -+ DCHECK(!AreAliased(api_function_address, scratch, a0)); -+ __ Add64(a0, sp, Operand(1 * kPointerSize)); -+ -+ ExternalReference thunk_ref = ExternalReference::invoke_function_callback(); -+ -+ // There are two stack slots above the arguments we constructed on the stack. -+ // TODO(jgruber): Document what these arguments are. -+ static constexpr int kStackSlotsAboveFCA = 2; -+ MemOperand return_value_operand( -+ fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize); -+ -+ static constexpr int kUseStackSpaceOperand = 0; -+ MemOperand stack_space_operand(sp, 4 * kPointerSize); -+ -+ AllowExternalCallThatCantCauseGC scope(masm); -+ CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, -+ kUseStackSpaceOperand, &stack_space_operand, -+ return_value_operand); -+} -+ -+void Builtins::Generate_CallApiGetter(MacroAssembler* masm) { -+ // Build v8::PropertyCallbackInfo::args_ array on the stack and push property -+ // name below the exit frame to make GC aware of them. -+ STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0); -+ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1); -+ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2); -+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3); -+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4); -+ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5); -+ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6); -+ STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7); -+ -+ Register receiver = ApiGetterDescriptor::ReceiverRegister(); -+ Register holder = ApiGetterDescriptor::HolderRegister(); -+ Register callback = ApiGetterDescriptor::CallbackRegister(); -+ Register scratch = a4; -+ DCHECK(!AreAliased(receiver, holder, callback, scratch)); -+ -+ Register api_function_address = a2; -+ -+ // Here and below +1 is for name() pushed after the args_ array. -+ using PCA = PropertyCallbackArguments; -+ __ Sub64(sp, sp, (PCA::kArgsLength + 1) * kPointerSize); -+ __ Sd(receiver, MemOperand(sp, (PCA::kThisIndex + 1) * kPointerSize)); -+ __ Ld(scratch, FieldMemOperand(callback, AccessorInfo::kDataOffset)); -+ __ Sd(scratch, MemOperand(sp, (PCA::kDataIndex + 1) * kPointerSize)); -+ __ LoadRoot(scratch, RootIndex::kUndefinedValue); -+ __ Sd(scratch, MemOperand(sp, (PCA::kReturnValueOffset + 1) * kPointerSize)); -+ __ Sd(scratch, MemOperand(sp, (PCA::kReturnValueDefaultValueIndex + 1) * -+ kPointerSize)); -+ __ li(scratch, ExternalReference::isolate_address(masm->isolate())); -+ __ Sd(scratch, MemOperand(sp, (PCA::kIsolateIndex + 1) * kPointerSize)); -+ __ Sd(holder, MemOperand(sp, (PCA::kHolderIndex + 1) * kPointerSize)); -+ // should_throw_on_error -> false -+ DCHECK_EQ(0, Smi::zero().ptr()); -+ __ Sd(zero_reg, -+ MemOperand(sp, (PCA::kShouldThrowOnErrorIndex + 1) * kPointerSize)); -+ __ Ld(scratch, FieldMemOperand(callback, AccessorInfo::kNameOffset)); -+ __ Sd(scratch, MemOperand(sp, 0 * kPointerSize)); -+ -+ // v8::PropertyCallbackInfo::args_ array and name handle. -+ const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; -+ -+ // Load address of v8::PropertyAccessorInfo::args_ array and name handle. -+ __ Move(a0, sp); // a0 = Handle -+ __ Add64(a1, a0, Operand(1 * kPointerSize)); // a1 = v8::PCI::args_ -+ -+ const int kApiStackSpace = 1; -+ FrameScope frame_scope(masm, StackFrame::MANUAL); -+ __ EnterExitFrame(false, kApiStackSpace); -+ -+ // Create v8::PropertyCallbackInfo object on the stack and initialize -+ // it's args_ field. -+ __ Sd(a1, MemOperand(sp, 1 * kPointerSize)); -+ __ Add64(a1, sp, Operand(1 * kPointerSize)); -+ // a1 = v8::PropertyCallbackInfo& -+ -+ ExternalReference thunk_ref = -+ ExternalReference::invoke_accessor_getter_callback(); -+ -+ __ Ld(scratch, FieldMemOperand(callback, AccessorInfo::kJsGetterOffset)); -+ __ Ld(api_function_address, -+ FieldMemOperand(scratch, Foreign::kForeignAddressOffset)); -+ -+ // +3 is to skip prolog, return address and name handle. -+ MemOperand return_value_operand( -+ fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize); -+ MemOperand* const kUseStackSpaceConstant = nullptr; -+ CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, -+ kStackUnwindSpace, kUseStackSpaceConstant, -+ return_value_operand); -+} -+ -+void Builtins::Generate_DirectCEntry(MacroAssembler* masm) { -+ // The sole purpose of DirectCEntry is for movable callers (e.g. any general -+ // purpose Code object) to be able to call into C functions that may trigger -+ // GC and thus move the caller. -+ // -+ // DirectCEntry places the return address on the stack (updated by the GC), -+ // making the call GC safe. The irregexp backend relies on this. -+ -+ // Make place for arguments to fit C calling convention. Callers use -+ // EnterExitFrame/LeaveExitFrame so they handle stack restoring and we don't -+ // have to do that here. Any caller must drop kCArgsSlotsSize stack space -+ // after the call. -+ __ Add64(sp, sp, -kCArgsSlotsSize); -+ -+ __ Sd(ra, MemOperand(sp, kCArgsSlotsSize)); // Store the return address. -+ __ Call(t6); // Call the C++ function. -+ __ Ld(t6, MemOperand(sp, kCArgsSlotsSize)); // Return to calling code. -+ -+ if (FLAG_debug_code && FLAG_enable_slow_asserts) { -+ // In case of an error the return address may point to a memory area -+ // filled with kZapValue by the GC. Dereference the address and check for -+ // this. -+ __ Uld(a4, MemOperand(t6)); -+ __ Assert(ne, AbortReason::kReceivedInvalidReturnAddress, a4, -+ Operand(reinterpret_cast(kZapValue))); -+ } -+ -+ __ Jump(t6); -+} -+ -+#undef __ -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/assembler-arch.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/assembler-arch.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/assembler-arch.h -@@ -23,6 +23,10 @@ - #include "src/codegen/mips64/assembler-mips64.h" - #elif V8_TARGET_ARCH_S390 - #include "src/codegen/s390/assembler-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/codegen/riscv64/assembler-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/codegen/riscv/assembler-riscv.h" - #else - #error Unknown architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/assembler-inl.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/assembler-inl.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/assembler-inl.h -@@ -23,6 +23,10 @@ - #include "src/codegen/mips64/assembler-mips64-inl.h" - #elif V8_TARGET_ARCH_S390 - #include "src/codegen/s390/assembler-s390-inl.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/codegen/riscv64/assembler-riscv64-inl.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/codegen/riscv/assembler-riscv-inl.h" - #else - #error Unknown architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/constants-arch.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/constants-arch.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/constants-arch.h -@@ -21,6 +21,10 @@ - #include "src/codegen/s390/constants-s390.h" // NOLINT - #elif V8_TARGET_ARCH_X64 - #include "src/codegen/x64/constants-x64.h" // NOLINT -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/codegen/riscv64/constants-riscv64.h" // NOLINT -+#elif V8_TARGET_ARCH_RISCV -+#include "src/codegen/riscv64/constants-riscv.h" // NOLINT - #else - #error Unsupported target architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/cpu-features.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/cpu-features.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/cpu-features.h -@@ -67,6 +67,12 @@ enum CpuFeature { - VECTOR_ENHANCE_FACILITY_1, - VECTOR_ENHANCE_FACILITY_2, - MISC_INSTR_EXT2, -+ -+// FIXME (RISCV): add features for RISCV -+#elif V8_TARGET_ARCH_RISCV64 -+ FPU, -+ FP64FPU, -+ RISCV_SIMD, - #endif - - NUMBER_OF_CPU_FEATURES -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/external-reference.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/external-reference.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/external-reference.cc -@@ -502,6 +502,8 @@ ExternalReference ExternalReference::inv - #define re_stack_check_func RegExpMacroAssemblerMIPS::CheckStackGuardState - #elif V8_TARGET_ARCH_S390 - #define re_stack_check_func RegExpMacroAssemblerS390::CheckStackGuardState -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+#define re_stack_check_func RegExpMacroAssemblerRISCV::CheckStackGuardState - #else - UNREACHABLE(); - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/interface-descriptors.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/interface-descriptors.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/interface-descriptors.cc -@@ -397,7 +397,9 @@ void WasmFloat64ToNumberDescriptor::Init - } - #endif // !V8_TARGET_ARCH_IA32 - --#if !defined(V8_TARGET_ARCH_MIPS) && !defined(V8_TARGET_ARCH_MIPS64) -+// FIXME(RISCV): Review this once atomics are added -+#if !defined(V8_TARGET_ARCH_MIPS) && !defined(V8_TARGET_ARCH_MIPS64) && \ -+ !defined(V8_TARGET_ARCH_RISCV64) && !defined(V8_TARGET_ARCH_RISCV) - void WasmI32AtomicWait32Descriptor::InitializePlatformSpecific( - CallInterfaceDescriptorData* data) { - DefaultInitializePlatformSpecific(data, kParameterCount); -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/macro-assembler.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/macro-assembler.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/macro-assembler.h -@@ -52,6 +52,12 @@ enum AllocationFlags { - #elif V8_TARGET_ARCH_S390 - #include "src/codegen/s390/constants-s390.h" - #include "src/codegen/s390/macro-assembler-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/codegen/riscv64/macro-assembler-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/codegen/riscv/constants-riscv.h" -+#include "src/codegen/riscv/macro-assembler-riscv.h" - #else - #error Unsupported target architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/register-arch.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/register-arch.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/register-arch.h -@@ -24,6 +24,10 @@ - #include "src/codegen/mips64/register-mips64.h" - #elif V8_TARGET_ARCH_S390 - #include "src/codegen/s390/register-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/codegen/riscv64/register-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/codegen/riscv/register-riscv.h" - #else - #error Unknown architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/register-configuration.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/register-configuration.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/register-configuration.cc -@@ -64,6 +64,8 @@ static int get_num_allocatable_double_re - kMaxAllocatableDoubleRegisterCount; - #elif V8_TARGET_ARCH_S390 - kMaxAllocatableDoubleRegisterCount; -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+ kMaxAllocatableDoubleRegisterCount; - #else - #error Unsupported target architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/reloc-info.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/reloc-info.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/reloc-info.cc -@@ -330,7 +330,8 @@ bool RelocInfo::OffHeapTargetIsCodedSpec - return false; - #elif defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_MIPS) || \ - defined(V8_TARGET_ARCH_MIPS64) || defined(V8_TARGET_ARCH_PPC) || \ -- defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_S390) -+ defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_S390) || \ -+ defined(V8_TARGET_ARCH_RISCV64) || defined(V8_TARGET_ARCH_RISCV) - return true; - #endif - } -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/reloc-info.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/codegen/reloc-info.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/reloc-info.h -@@ -69,7 +69,7 @@ class RelocInfo { - EXTERNAL_REFERENCE, // The address of an external C++ function. - INTERNAL_REFERENCE, // An address inside the same function. - -- // Encoded internal reference, used only on MIPS, MIPS64 and PPC. -+ // Encoded internal reference, used only on RISCV64, MIPS, MIPS64 and PPC. - INTERNAL_REFERENCE_ENCODED, - - // An off-heap instruction stream target. See http://goo.gl/Z2HUiM. -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/assembler-riscv64-inl.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/assembler-riscv64-inl.h -@@ -0,0 +1,247 @@ -+ -+// Copyright (c) 1994-2006 Sun Microsystems Inc. -+// All Rights Reserved. -+// -+// Redistribution and use in source and binary forms, with or without -+// modification, are permitted provided that the following conditions are -+// met: -+// -+// - Redistributions of source code must retain the above copyright notice, -+// this list of conditions and the following disclaimer. -+// -+// - Redistribution in binary form must reproduce the above copyright -+// notice, this list of conditions and the following disclaimer in the -+// documentation and/or other materials provided with the distribution. -+// -+// - Neither the name of Sun Microsystems or the names of contributors may -+// be used to endorse or promote products derived from this software without -+// specific prior written permission. -+// -+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+// The original source code covered by the above license above has been -+// modified significantly by Google Inc. -+// Copyright 2012 the V8 project authors. All rights reserved. -+ -+#ifndef V8_CODEGEN_RISCV_ASSEMBLER_RISCV_INL_H_ -+#define V8_CODEGEN_RISCV_ASSEMBLER_RISCV_INL_H_ -+ -+#include "src/codegen/assembler.h" -+#include "src/codegen/riscv64/assembler-riscv64.h" -+#include "src/debug/debug.h" -+#include "src/objects/objects-inl.h" -+ -+namespace v8 { -+namespace internal { -+ -+bool CpuFeatures::SupportsOptimizer() { return IsSupported(FPU); } -+ -+bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(RISCV_SIMD); } -+ -+// ----------------------------------------------------------------------------- -+// Operand and MemOperand. -+ -+bool Operand::is_reg() const { return rm_.is_valid(); } -+ -+int64_t Operand::immediate() const { -+ DCHECK(!is_reg()); -+ DCHECK(!IsHeapObjectRequest()); -+ return value_.immediate; -+} -+ -+// ----------------------------------------------------------------------------- -+// RelocInfo. -+ -+void RelocInfo::apply(intptr_t delta) { -+ if (IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)) { -+ // Absolute code pointer inside code object moves with the code object. -+ Assembler::RelocateInternalReference(rmode_, pc_, delta); -+ } -+} -+ -+Address RelocInfo::target_address() { -+ DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_)); -+ return Assembler::target_address_at(pc_, constant_pool_); -+} -+ -+Address RelocInfo::target_address_address() { -+ DCHECK(HasTargetAddressAddress()); -+ // Read the address of the word containing the target_address in an -+ // instruction stream. -+ // The only architecture-independent user of this function is the serializer. -+ // The serializer uses it to find out how many raw bytes of instruction to -+ // output before the next target. -+ // For an instruction like LUI/ORI where the target bits are mixed into the -+ // instruction bits, the size of the target will be zero, indicating that the -+ // serializer should not step forward in memory after a target is resolved -+ // and written. In this case the target_address_address function should -+ // return the end of the instructions to be patched, allowing the -+ // deserializer to deserialize the instructions as raw bytes and put them in -+ // place, ready to be patched with the target. After jump optimization, -+ // that is the address of the instruction that follows J/JAL/JR/JALR -+ // instruction. -+ return pc_ + Assembler::kInstructionsFor64BitConstant * kInstrSize; -+} -+ -+Address RelocInfo::constant_pool_entry_address() { UNREACHABLE(); } -+ -+int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; } -+ -+void Assembler::deserialization_set_special_target_at( -+ Address instruction_payload, Code code, Address target) { -+ set_target_address_at(instruction_payload, -+ !code.is_null() ? code.constant_pool() : kNullAddress, -+ target); -+} -+ -+int Assembler::deserialization_special_target_size( -+ Address instruction_payload) { -+ return kSpecialTargetSize; -+} -+ -+void Assembler::set_target_internal_reference_encoded_at(Address pc, -+ Address target) { -+ set_target_value_at(pc, static_cast(target)); -+} -+ -+void Assembler::deserialization_set_target_internal_reference_at( -+ Address pc, Address target, RelocInfo::Mode mode) { -+ if (RelocInfo::IsInternalReferenceEncoded(mode)) { -+ DCHECK(IsLui(instr_at(pc))); -+ set_target_internal_reference_encoded_at(pc, target); -+ } else { -+ DCHECK(RelocInfo::IsInternalReference(mode)); -+ Memory
(pc) = target; -+ } -+} -+ -+HeapObject RelocInfo::target_object() { -+ DCHECK(IsCodeTarget(rmode_) || IsFullEmbeddedObject(rmode_)); -+ return HeapObject::cast( -+ Object(Assembler::target_address_at(pc_, constant_pool_))); -+} -+ -+HeapObject RelocInfo::target_object_no_host(Isolate* isolate) { -+ return target_object(); -+} -+ -+Handle RelocInfo::target_object_handle(Assembler* origin) { -+ DCHECK(IsCodeTarget(rmode_) || IsFullEmbeddedObject(rmode_)); -+ return Handle(reinterpret_cast( -+ Assembler::target_address_at(pc_, constant_pool_))); -+} -+ -+void RelocInfo::set_target_object(Heap* heap, HeapObject target, -+ WriteBarrierMode write_barrier_mode, -+ ICacheFlushMode icache_flush_mode) { -+ DCHECK(IsCodeTarget(rmode_) || IsFullEmbeddedObject(rmode_)); -+ Assembler::set_target_address_at(pc_, constant_pool_, target.ptr(), -+ icache_flush_mode); -+ if (write_barrier_mode == UPDATE_WRITE_BARRIER && !host().is_null() && -+ !FLAG_disable_write_barriers) { -+ WriteBarrierForCode(host(), this, target); -+ } -+} -+ -+Address RelocInfo::target_external_reference() { -+ DCHECK(rmode_ == EXTERNAL_REFERENCE); -+ return Assembler::target_address_at(pc_, constant_pool_); -+} -+ -+void RelocInfo::set_target_external_reference( -+ Address target, ICacheFlushMode icache_flush_mode) { -+ DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); -+ Assembler::set_target_address_at(pc_, constant_pool_, target, -+ icache_flush_mode); -+} -+ -+Address RelocInfo::target_internal_reference() { -+ if (rmode_ == INTERNAL_REFERENCE) { -+ return Memory
(pc_); -+ } else { -+ // Encoded internal references are j/jal instructions. -+ DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED); -+ DCHECK(Assembler::IsLui(Assembler::instr_at(pc_ + 0 * kInstrSize))); -+ Address address = Assembler::target_address_at(pc_); -+ return address; -+ } -+} -+ -+Address RelocInfo::target_internal_reference_address() { -+ DCHECK(rmode_ == INTERNAL_REFERENCE || rmode_ == INTERNAL_REFERENCE_ENCODED); -+ return pc_; -+} -+ -+Address RelocInfo::target_runtime_entry(Assembler* origin) { -+ DCHECK(IsRuntimeEntry(rmode_)); -+ return target_address(); -+} -+ -+void RelocInfo::set_target_runtime_entry(Address target, -+ WriteBarrierMode write_barrier_mode, -+ ICacheFlushMode icache_flush_mode) { -+ DCHECK(IsRuntimeEntry(rmode_)); -+ if (target_address() != target) -+ set_target_address(target, write_barrier_mode, icache_flush_mode); -+} -+ -+Address RelocInfo::target_off_heap_target() { -+ DCHECK(IsOffHeapTarget(rmode_)); -+ return Assembler::target_address_at(pc_, constant_pool_); -+} -+ -+void RelocInfo::WipeOut() { -+ DCHECK(IsFullEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || -+ IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || -+ IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_) || -+ IsOffHeapTarget(rmode_)); -+ if (IsInternalReference(rmode_)) { -+ Memory
(pc_) = kNullAddress; -+ } else if (IsInternalReferenceEncoded(rmode_)) { -+ Assembler::set_target_internal_reference_encoded_at(pc_, kNullAddress); -+ } else { -+ Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress); -+ } -+} -+ -+// ----------------------------------------------------------------------------- -+// Assembler. -+ -+void Assembler::CheckBuffer() { -+ if (buffer_space() <= kGap) { -+ GrowBuffer(); -+ } -+} -+ -+template -+void Assembler::EmitHelper(T x) { -+ DEBUG_PRINTF("%p: ", pc_); -+ disassembleInstr((int)x); -+ *reinterpret_cast(pc_) = x; -+ pc_ += sizeof(x); -+ CheckTrampolinePoolQuick(); -+} -+ -+void Assembler::emit(Instr x) { -+ if (!is_buffer_growth_blocked()) { -+ CheckBuffer(); -+ } -+ EmitHelper(x); -+} -+ -+EnsureSpace::EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); } -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_CODEGEN_RISCV_ASSEMBLER_RISCV_INL_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/assembler-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/assembler-riscv64.cc -@@ -0,0 +1,2342 @@ -+// Copyright (c) 1994-2006 Sun Microsystems Inc. -+// All Rights Reserved. -+// -+// Redistribution and use in source and binary forms, with or without -+// modification, are permitted provided that the following conditions are -+// met: -+// -+// - Redistributions of source code must retain the above copyright notice, -+// this list of conditions and the following disclaimer. -+// -+// - Redistribution in binary form must reproduce the above copyright -+// notice, this list of conditions and the following disclaimer in the -+// documentation and/or other materials provided with the distribution. -+// -+// - Neither the name of Sun Microsystems or the names of contributors may -+// be used to endorse or promote products derived from this software without -+// specific prior written permission. -+// -+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+// The original source code covered by the above license above has been -+// modified significantly by Google Inc. -+// Copyright 2012 the V8 project authors. All rights reserved. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/codegen/riscv64/assembler-riscv64.h" -+ -+#include "src/base/cpu.h" -+#include "src/codegen/riscv64/assembler-riscv64-inl.h" -+#include "src/codegen/safepoint-table.h" -+#include "src/codegen/string-constants.h" -+#include "src/deoptimizer/deoptimizer.h" -+#include "src/diagnostics/disasm.h" -+#include "src/diagnostics/disassembler.h" -+#include "src/objects/heap-number-inl.h" -+ -+namespace v8 { -+namespace internal { -+// Get the CPU features enabled by the build. For cross compilation the -+// preprocessor symbols CAN_USE_FPU_INSTRUCTIONS -+// can be defined to enable FPU instructions when building the -+// snapshot. -+static unsigned CpuFeaturesImpliedByCompiler() { -+ unsigned answer = 0; -+#ifdef CAN_USE_FPU_INSTRUCTIONS -+ answer |= 1u << FPU; -+#endif // def CAN_USE_FPU_INSTRUCTIONS -+ -+ return answer; -+} -+ -+void CpuFeatures::ProbeImpl(bool cross_compile) { -+ supported_ |= CpuFeaturesImpliedByCompiler(); -+ -+ // Only use statically determined features for cross compile (snapshot). -+ if (cross_compile) return; -+ -+ // Probe for additional features at runtime. -+ base::CPU cpu; -+ if (cpu.has_fpu()) supported_ |= 1u << FPU; -+} -+ -+void CpuFeatures::PrintTarget() {} -+void CpuFeatures::PrintFeatures() {} -+ -+int ToNumber(Register reg) { -+ DCHECK(reg.is_valid()); -+ const int kNumbers[] = { -+ 0, // zero_reg -+ 1, // ra -+ 2, // sp -+ 3, // gp -+ 4, // tp -+ 5, // t0 -+ 6, // t1 -+ 7, // t2 -+ 8, // s0/fp -+ 9, // s1 -+ 10, // a0 -+ 11, // a1 -+ 12, // a2 -+ 13, // a3 -+ 14, // a4 -+ 15, // a5 -+ 16, // a6 -+ 17, // a7 -+ 18, // s2 -+ 19, // s3 -+ 20, // s4 -+ 21, // s5 -+ 22, // s6 -+ 23, // s7 -+ 24, // s8 -+ 25, // s9 -+ 26, // s10 -+ 27, // s11 -+ 28, // t3 -+ 29, // t4 -+ 30, // t5 -+ 31, // t6 -+ }; -+ return kNumbers[reg.code()]; -+} -+ -+Register ToRegister(int num) { -+ DCHECK(num >= 0 && num < kNumRegisters); -+ const Register kRegisters[] = { -+ zero_reg, ra, sp, gp, tp, t0, t1, t2, fp, s1, a0, a1, a2, a3, a4, a5, -+ a6, a7, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, t3, t4, t5, t6}; -+ return kRegisters[num]; -+} -+ -+// ----------------------------------------------------------------------------- -+// Implementation of RelocInfo. -+ -+const int RelocInfo::kApplyMask = -+ RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | -+ RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED); -+ -+bool RelocInfo::IsCodedSpecially() { -+ // The deserializer needs to know whether a pointer is specially coded. Being -+ // specially coded on RISC-V means that it is a lui/addi instruction, and that -+ // is always the case inside code objects. -+ return true; -+} -+ -+bool RelocInfo::IsInConstantPool() { return false; } -+ -+uint32_t RelocInfo::wasm_call_tag() const { -+ DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL); -+ return static_cast( -+ Assembler::target_address_at(pc_, constant_pool_)); -+} -+ -+// ----------------------------------------------------------------------------- -+// Implementation of Operand and MemOperand. -+// See assembler-riscv64-inl.h for inlined constructors. -+ -+Operand::Operand(Handle handle) -+ : rm_(no_reg), rmode_(RelocInfo::FULL_EMBEDDED_OBJECT) { -+ value_.immediate = static_cast(handle.address()); -+} -+ -+Operand Operand::EmbeddedNumber(double value) { -+ int32_t smi; -+ if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi)); -+ Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT); -+ result.is_heap_object_request_ = true; -+ result.value_.heap_object_request = HeapObjectRequest(value); -+ return result; -+} -+ -+Operand Operand::EmbeddedStringConstant(const StringConstantBase* str) { -+ Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT); -+ result.is_heap_object_request_ = true; -+ result.value_.heap_object_request = HeapObjectRequest(str); -+ return result; -+} -+ -+MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) { -+ offset_ = offset; -+} -+ -+MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier, -+ OffsetAddend offset_addend) -+ : Operand(rm) { -+ offset_ = unit * multiplier + offset_addend; -+} -+ -+void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { -+ DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty()); -+ for (auto& request : heap_object_requests_) { -+ Handle object; -+ switch (request.kind()) { -+ case HeapObjectRequest::kHeapNumber: -+ object = isolate->factory()->NewHeapNumber( -+ request.heap_number()); -+ break; -+ case HeapObjectRequest::kStringConstant: -+ const StringConstantBase* str = request.string(); -+ CHECK_NOT_NULL(str); -+ object = str->AllocateStringConstant(isolate); -+ break; -+ } -+ Address pc = reinterpret_cast
(buffer_start_) + request.offset(); -+ set_target_value_at(pc, reinterpret_cast(object.location())); -+ } -+} -+ -+// ----------------------------------------------------------------------------- -+// Specific instructions, constants, and masks. -+ -+Assembler::Assembler(const AssemblerOptions& options, -+ std::unique_ptr buffer) -+ : AssemblerBase(options, std::move(buffer)), -+ scratch_register_list_(t3.bit()) { -+ reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_); -+ -+ last_trampoline_pool_end_ = 0; -+ no_trampoline_pool_before_ = 0; -+ trampoline_pool_blocked_nesting_ = 0; -+ // We leave space (16 * kTrampolineSlotsSize) -+ // for BlockTrampolinePoolScope buffer. -+ next_buffer_check_ = FLAG_force_long_branches -+ ? kMaxInt -+ : kMaxBranchOffset - kTrampolineSlotsSize * 16; -+ internal_trampoline_exception_ = false; -+ last_bound_pos_ = 0; -+ -+ trampoline_emitted_ = FLAG_force_long_branches; -+ unbound_labels_count_ = 0; -+ block_buffer_growth_ = false; -+} -+ -+void Assembler::GetCode(Isolate* isolate, CodeDesc* desc, -+ SafepointTableBuilder* safepoint_table_builder, -+ int handler_table_offset) { -+ int code_comments_size = WriteCodeComments(); -+ -+ DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap. -+ -+ AllocateAndInstallRequestedHeapObjects(isolate); -+ -+ // Set up code descriptor. -+ // TODO(jgruber): Reconsider how these offsets and sizes are maintained up to -+ // this point to make CodeDesc initialization less fiddly. -+ -+ static constexpr int kConstantPoolSize = 0; -+ const int instruction_size = pc_offset(); -+ const int code_comments_offset = instruction_size - code_comments_size; -+ const int constant_pool_offset = code_comments_offset - kConstantPoolSize; -+ const int handler_table_offset2 = (handler_table_offset == kNoHandlerTable) -+ ? constant_pool_offset -+ : handler_table_offset; -+ const int safepoint_table_offset = -+ (safepoint_table_builder == kNoSafepointTable) -+ ? handler_table_offset2 -+ : safepoint_table_builder->GetCodeOffset(); -+ const int reloc_info_offset = -+ static_cast(reloc_info_writer.pos() - buffer_->start()); -+ CodeDesc::Initialize(desc, this, safepoint_table_offset, -+ handler_table_offset2, constant_pool_offset, -+ code_comments_offset, reloc_info_offset); -+} -+ -+void Assembler::Align(int m) { -+ DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m)); -+ while ((pc_offset() & (m - 1)) != 0) { -+ nop(); -+ } -+} -+ -+void Assembler::CodeTargetAlign() { -+ // No advantage to aligning branch/call targets to more than -+ // single instruction, that I am aware of. -+ Align(4); -+} -+ -+// Labels refer to positions in the (to be) generated code. -+// There are bound, linked, and unused labels. -+// -+// Bound labels refer to known positions in the already -+// generated code. pos() is the position the label refers to. -+// -+// Linked labels refer to unknown positions in the code -+// to be generated; pos() is the position of the last -+// instruction using the label. -+ -+// The link chain is terminated by a value in the instruction of 0, -+// which is an otherwise illegal value (branch 0 is inf loop). -+ -+const int kEndOfChain = 0; -+ -+// Determines the end of the Jump chain (a subset of the label link chain). -+const int kEndOfJumpChain = 0; -+ -+bool Assembler::IsBranch(Instr instr) { -+ return (instr & kBaseOpcodeMask) == BRANCH; -+} -+ -+bool Assembler::IsJump(Instr instr) { -+ int Op = instr & kBaseOpcodeMask; -+ return Op == JAL || Op == JALR; -+} -+ -+bool Assembler::IsJal(Instr instr) { return (instr & kBaseOpcodeMask) == JAL; } -+ -+bool Assembler::IsJalr(Instr instr) { -+ return (instr & kBaseOpcodeMask) == JALR; -+} -+ -+bool Assembler::IsLui(Instr instr) { return (instr & kBaseOpcodeMask) == LUI; } -+bool Assembler::IsAuipc(Instr instr) { return (instr & kBaseOpcodeMask) == AUIPC; } -+bool Assembler::IsAddiw(Instr instr) { -+ return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ADDIW; -+} -+bool Assembler::IsAddi(Instr instr) { -+ return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ADDI; -+} -+bool Assembler::IsSlli(Instr instr) { -+ return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_SLLI; -+} -+int Assembler::target_at(int pos, bool is_internal) { -+ if (is_internal) { -+ int64_t* p = reinterpret_cast(buffer_start_ + pos); -+ int64_t address = *p; -+ if (address == kEndOfJumpChain) { -+ return kEndOfChain; -+ } else { -+ int64_t instr_address = reinterpret_cast(p); -+ DCHECK(instr_address - address < INT_MAX); -+ int delta = static_cast(instr_address - address); -+ DCHECK(pos > delta); -+ return pos - delta; -+ } -+ } -+ Instr instr = instr_at(pos); -+ DEBUG_PRINTF("target_at: %p (%d)\n\t", -+ reinterpret_cast(buffer_start_ + pos), pos); -+ disassembleInstr(instr); -+ if (IsBranch(instr)) { -+ int32_t imm13 = BranchOffset(instr); -+ if (imm13 == kEndOfJumpChain) { -+ // EndOfChain sentinel is returned directly, not relative to pc or pos. -+ return kEndOfChain; -+ } else { -+ return pos + imm13; -+ } -+ } else if (IsJal(instr)) { -+ int32_t imm21 = JumpOffset(instr); -+ if (imm21 == kEndOfJumpChain) { -+ // EndOfChain sentinel is returned directly, not relative to pc or pos. -+ return kEndOfChain; -+ } else { -+ return pos + imm21; -+ } -+ } else if (IsJalr(instr)) { -+ int32_t imm12 = instr >> 20; -+ if (imm12 == kEndOfJumpChain) { -+ // EndOfChain sentinel is returned directly, not relative to pc or pos. -+ return kEndOfChain; -+ } else { -+ return pos + imm12; -+ } -+ } else if (IsLui(instr)) { -+ Address pc = reinterpret_cast
(buffer_start_ + pos); -+ pc = target_address_at(pc); -+ uint64_t instr_address = reinterpret_cast(buffer_start_ + pos); -+ uint64_t imm = reinterpret_cast(pc); -+ if(imm == kEndOfJumpChain) { -+ return kEndOfChain; -+ } else { -+ DCHECK(instr_address - imm < INT_MAX); -+ int32_t delta = static_cast(instr_address - imm); -+ DCHECK(pos > delta); -+ return pos - delta; -+ } -+ } else if (IsAuipc(instr)) { -+ Instr instr_auipc = instr; -+ Instr instr_jalr = instr_at(pos + 4); -+ DCHECK(IsJalr(instr_jalr)); -+ int32_t offset = BrachlongOffset(instr_auipc, instr_jalr); -+ if(offset == kEndOfJumpChain) -+ return kEndOfChain; -+ return offset + pos; -+ } else { -+ // Emitted label constant, not part of a branch. -+ if (instr == 0) { -+ return kEndOfChain; -+ } else { -+ int32_t imm18 = ((instr & static_cast(kImm16Mask)) << 16) >> 14; -+ return (imm18 + pos); -+ } -+ } -+} -+ -+static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos, -+ Instr instr) { -+ int32_t imm = target_pos - pos; -+ DCHECK_EQ(imm & 1, 0); -+ DCHECK(is_intn(imm, Assembler::kBranchOffsetBits)); -+ -+ instr &= ~kBImm12Mask; -+ int32_t imm12 = ((imm & 0x800) >> 4) | // bit 11 -+ ((imm & 0x1e) << 7) | // bits 4-1 -+ ((imm & 0x7e0) << 20) | // bits 10-5 -+ ((imm & 0x1000) << 19); // bit 12 -+ -+ return instr | (imm12 & kBImm12Mask); -+} -+ -+static inline Instr SetJalOffset(int32_t pos, int32_t target_pos, Instr instr) { -+ int32_t imm = target_pos - pos; -+ DCHECK_EQ(imm & 1, 0); -+ DCHECK(is_intn(imm, Assembler::kJumpOffsetBits)); -+ -+ instr &= ~kImm20Mask; -+ int32_t imm20 = (imm & 0xff000) | // bits 19-12 -+ ((imm & 0x800) << 9) | // bit 11 -+ ((imm & 0x7fe) << 20) | // bits 10-1 -+ ((imm & 0x100000) << 11); // bit 20 -+ -+ return instr | (imm20 & kImm20Mask); -+} -+ -+void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { -+ if (is_internal) { -+ uint64_t imm = reinterpret_cast(buffer_start_) + target_pos; -+ *reinterpret_cast(buffer_start_ + pos) = imm; -+ return; -+ } -+ DEBUG_PRINTF("target_at_put: %p (%d) to %p (%d)\n", -+ reinterpret_cast(buffer_start_ + pos), pos, -+ reinterpret_cast(buffer_start_ + target_pos), -+ target_pos); -+ Instr instr = instr_at(pos); -+ -+ if (IsBranch(instr)) { -+ instr = SetBranchOffset(pos, target_pos, instr); -+ instr_at_put(pos, instr); -+ } else if (IsJal(instr)) { -+ instr = SetJalOffset(pos, target_pos, instr); -+ instr_at_put(pos, instr); -+ } else if (IsLui(instr)) { -+ Address pc = reinterpret_cast
(buffer_start_ + pos); -+ set_target_value_at(pc, reinterpret_cast(buffer_start_ + target_pos)); -+ } else if (IsAuipc(instr)) { -+ Instr instr_auipc = instr; -+ Instr instr_jalr = instr_at(pos + 4); -+ DCHECK(IsJalr(instr_jalr)); -+ -+ int64_t offset = target_pos - pos; -+ DCHECK(is_int32(offset)); -+ -+ int32_t Hi20 = (((int32_t)offset + 0x800) >> 12); -+ int32_t Lo12 = (int32_t)offset << 20 >> 20; -+ -+ const int kImm31_12Mask = ((1 << 20) - 1) << 12; -+ const int kImm19_0Mask = ((1 << 20) - 1); -+ instr_auipc = (instr_auipc & ~kImm31_12Mask) | -+ ((Hi20 & kImm19_0Mask) << 12); -+ instr_at_put(pos, instr_auipc); -+ -+ const int kImm31_20Mask = ((1 << 12) - 1) << 20; -+ const int kImm11_0Mask = ((1 << 12) - 1); -+ instr_jalr = (instr_jalr & ~kImm31_20Mask) | -+ ((Lo12 & kImm11_0Mask) << 20); -+ instr_at_put(pos + 4, instr_jalr); -+ } else { -+ // Emitted label constant, not part of a branch. -+ // Make label relative to Code pointer of generated Code object. -+ instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); -+ } -+ disassembleInstr(instr); -+} -+ -+void Assembler::print(const Label* L) { -+ if (L->is_unused()) { -+ PrintF("unused label\n"); -+ } else if (L->is_bound()) { -+ PrintF("bound label to %d\n", L->pos()); -+ } else if (L->is_linked()) { -+ Label l; -+ l.link_to(L->pos()); -+ PrintF("unbound label"); -+ while (l.is_linked()) { -+ PrintF("@ %d ", l.pos()); -+ Instr instr = instr_at(l.pos()); -+ if ((instr & ~kImm16Mask) == 0) { -+ PrintF("value\n"); -+ } else { -+ PrintF("%d\n", instr); -+ } -+ next(&l, is_internal_reference(&l)); -+ } -+ } else { -+ PrintF("label in inconsistent state (pos = %d)\n", L->pos_); -+ } -+} -+ -+void Assembler::bind_to(Label* L, int pos) { -+ DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position. -+ DEBUG_PRINTF("binding %d to label %p\n", pos, L); -+ int trampoline_pos = kInvalidSlotPos; -+ bool is_internal = false; -+ if (L->is_linked() && !trampoline_emitted_) { -+ unbound_labels_count_--; -+ if (!is_internal_reference(L)) { -+ next_buffer_check_ += kTrampolineSlotsSize; -+ } -+ } -+ -+ while (L->is_linked()) { -+ int fixup_pos = L->pos(); -+ int dist = pos - fixup_pos; -+ is_internal = is_internal_reference(L); -+ next(L, is_internal); // Call next before overwriting link with target -+ // at fixup_pos. -+ Instr instr = instr_at(fixup_pos); -+ DEBUG_PRINTF("\tfixup: %d to %d\n", fixup_pos, dist); -+ if (is_internal) { -+ target_at_put(fixup_pos, pos, is_internal); -+ } else { -+ if (IsBranch(instr)) { -+ if (dist > kMaxBranchOffset) { -+ if (trampoline_pos == kInvalidSlotPos) { -+ trampoline_pos = get_trampoline_entry(fixup_pos); -+ CHECK_NE(trampoline_pos, kInvalidSlotPos); -+ } -+ CHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset); -+ DEBUG_PRINTF("\t\ttrampolining: %d\n", trampoline_pos); -+ target_at_put(fixup_pos, trampoline_pos, false); -+ fixup_pos = trampoline_pos; -+ } -+ target_at_put(fixup_pos, pos, false); -+ } else if (IsJal(instr)) { -+ if (dist > kMaxJumpOffset) { -+ if (trampoline_pos == kInvalidSlotPos) { -+ trampoline_pos = get_trampoline_entry(fixup_pos); -+ CHECK_NE(trampoline_pos, kInvalidSlotPos); -+ } -+ CHECK((trampoline_pos - fixup_pos) <= kMaxJumpOffset); -+ DEBUG_PRINTF("\t\ttrampolining: %d\n", trampoline_pos); -+ target_at_put(fixup_pos, trampoline_pos, false); -+ fixup_pos = trampoline_pos; -+ } -+ target_at_put(fixup_pos, pos, false); -+ } else { -+ target_at_put(fixup_pos, pos, false); -+ } -+ } -+ } -+ L->bind_to(pos); -+ -+ // Keep track of the last bound label so we don't eliminate any instructions -+ // before a bound label. -+ if (pos > last_bound_pos_) last_bound_pos_ = pos; -+} -+ -+void Assembler::bind(Label* L) { -+ DCHECK(!L->is_bound()); // Label can only be bound once. -+ bind_to(L, pc_offset()); -+} -+ -+void Assembler::next(Label* L, bool is_internal) { -+ DCHECK(L->is_linked()); -+ int link = target_at(L->pos(), is_internal); -+ if (link == kEndOfChain) { -+ L->Unuse(); -+ } else { -+ DCHECK_GT(link, 0); -+ DEBUG_PRINTF("next: %p to %p (%d)\n", L, -+ reinterpret_cast(buffer_start_ + link), link); -+ L->link_to(link); -+ } -+} -+ -+bool Assembler::is_near(Label* L) { -+ DCHECK(L->is_bound()); -+ return is_intn((pc_offset() - L->pos()), kJumpOffsetBits); -+} -+ -+bool Assembler::is_near(Label* L, OffsetSize bits) { -+ if (L == nullptr || !L->is_bound()) return true; -+ return is_intn((pc_offset() - L->pos()), bits); -+} -+ -+bool Assembler::is_near_branch(Label* L) { -+ DCHECK(L->is_bound()); -+ return is_intn((pc_offset() - L->pos()), kBranchOffsetBits); -+} -+ -+int Assembler::BranchOffset(Instr instr) { -+ // | imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1|11] | opcode | -+ // 31 25 11 7 -+ int32_t imm13 = ((instr & 0xf00) >> 7) | ((instr & 0x7e000000) >> 20) | -+ ((instr & 0x80) << 4) | ((instr & 0x80000000) >> 19); -+ imm13 = imm13 << 19 >> 19; -+ return imm13; -+} -+ -+int Assembler::JumpOffset(Instr instr) { -+ int32_t imm21 = ((instr & 0x7fe00000) >> 20) | ((instr & 0x100000) >> 9) | -+ (instr & 0xff000) | ((instr & 0x80000000) >> 11); -+ imm21 = imm21 << 11 >> 11; -+ return imm21; -+} -+ -+int Assembler::BrachlongOffset(Instr auipc, Instr jalr) { -+ const int kImm19_0Mask = ((1 << 20) - 1); -+ int32_t imm_auipc = auipc & (kImm19_0Mask << 12); -+ int32_t imm_jalr = jalr >> 20; -+ int32_t offset = imm_jalr + imm_auipc; -+ return offset; -+} -+ -+// We have to use a temporary register for things that can be relocated even -+// if they can be encoded in RISC-V's 12 bits of immediate-offset instruction -+// space. There is no guarantee that the relocated location can be similarly -+// encoded. -+bool Assembler::MustUseReg(RelocInfo::Mode rmode) { -+ return !RelocInfo::IsNone(rmode); -+} -+ -+void Assembler::disassembleInstr(Instr instr) { -+ if (!FLAG_debug_riscv) return; -+ disasm::NameConverter converter; -+ disasm::Disassembler disasm(converter); -+ EmbeddedVector disasm_buffer; -+ -+ disasm.InstructionDecode(disasm_buffer, reinterpret_cast(&instr)); -+ DEBUG_PRINTF("%s\n", disasm_buffer.begin()); -+} -+ -+// ----- Top-level instruction formats match those in the ISA manual -+// (R, I, S, B, U, J). These match the formats defined in the compiler -+void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, -+ Register rd, Register rs1, Register rs2) { -+ DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, -+ FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, -+ Register rd, FPURegister rs1, Register rs2) { -+ DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, -+ FPURegister rd, Register rs1, Register rs2) { -+ DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, -+ FPURegister rd, FPURegister rs1, Register rs2) { -+ DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, -+ Register rd, FPURegister rs1, FPURegister rs2) { -+ DCHECK(is_uint7(funct7) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR4(uint8_t funct2, Opcode opcode, Register rd, -+ Register rs1, Register rs2, Register rs3, -+ RoundingMode frm) { -+ DCHECK(is_uint2(funct2) && rd.is_valid() && rs1.is_valid() && -+ rs2.is_valid() && rs3.is_valid() && is_uint3(frm)); -+ Instr instr = opcode | (rd.code() << kRdShift) | (frm << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct2 << kFunct2Shift) | (rs3.code() << kRs3Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrR4(uint8_t funct2, Opcode opcode, FPURegister rd, -+ FPURegister rs1, FPURegister rs2, FPURegister rs3, -+ RoundingMode frm) { -+ DCHECK(is_uint2(funct2) && rd.is_valid() && rs1.is_valid() && -+ rs2.is_valid() && rs3.is_valid() && is_uint3(frm)); -+ Instr instr = opcode | (rd.code() << kRdShift) | (frm << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct2 << kFunct2Shift) | (rs3.code() << kRs3Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrRAtomic(uint8_t funct5, bool aq, bool rl, -+ uint8_t funct3, Register rd, Register rs1, -+ Register rs2) { -+ DCHECK(is_uint5(funct5) && is_uint3(funct3) && rd.is_valid() && -+ rs1.is_valid() && rs2.is_valid()); -+ Instr instr = AMO | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (rl << kRlShift) | (aq << kAqShift) | (funct5 << kFunct5Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrRFrm(uint8_t funct7, Opcode opcode, Register rd, -+ Register rs1, Register rs2, RoundingMode frm) { -+ DCHECK(rd.is_valid() && rs1.is_valid() && rs2.is_valid() && is_uint3(frm)); -+ Instr instr = opcode | (rd.code() << kRdShift) | (frm << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (rs2.code() << kRs2Shift) | -+ (funct7 << kFunct7Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrI(uint8_t funct3, Opcode opcode, Register rd, -+ Register rs1, int16_t imm12) { -+ DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() && -+ (is_uint12(imm12) || is_int12(imm12))); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (imm12 << kImm12Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrI(uint8_t funct3, Opcode opcode, FPURegister rd, -+ Register rs1, int16_t imm12) { -+ DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() && -+ (is_uint12(imm12) || is_int12(imm12))); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (imm12 << kImm12Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrIShift(bool arithshift, uint8_t funct3, Opcode opcode, -+ Register rd, Register rs1, uint8_t shamt) { -+ DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() && -+ is_uint6(shamt)); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (shamt << kShamtShift) | -+ (arithshift << kArithShiftShift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrIShiftW(bool arithshift, uint8_t funct3, Opcode opcode, -+ Register rd, Register rs1, uint8_t shamt) { -+ DCHECK(is_uint3(funct3) && rd.is_valid() && rs1.is_valid() && -+ is_uint5(shamt)); -+ Instr instr = opcode | (rd.code() << kRdShift) | (funct3 << kFunct3Shift) | -+ (rs1.code() << kRs1Shift) | (shamt << kShamtWShift) | -+ (arithshift << kArithShiftShift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, -+ Register rs2, int16_t imm12) { -+ DCHECK(is_uint3(funct3) && rs1.is_valid() && rs2.is_valid() && -+ is_int12(imm12)); -+ Instr instr = opcode | ((imm12 & 0x1f) << 7) | // bits 4-0 -+ (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) | -+ (rs2.code() << kRs2Shift) | -+ ((imm12 & 0xfe0) << 20); // bits 11-5 -+ emit(instr); -+} -+ -+void Assembler::GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, -+ FPURegister rs2, int16_t imm12) { -+ DCHECK(is_uint3(funct3) && rs1.is_valid() && rs2.is_valid() && -+ is_int12(imm12)); -+ Instr instr = opcode | ((imm12 & 0x1f) << 7) | // bits 4-0 -+ (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) | -+ (rs2.code() << kRs2Shift) | -+ ((imm12 & 0xfe0) << 20); // bits 11-5 -+ emit(instr); -+} -+ -+void Assembler::GenInstrB(uint8_t funct3, Opcode opcode, Register rs1, -+ Register rs2, int16_t imm13) { -+ DCHECK(is_uint3(funct3) && rs1.is_valid() && rs2.is_valid() && -+ is_int13(imm13) && ((imm13 & 1) == 0)); -+ Instr instr = opcode | ((imm13 & 0x800) >> 4) | // bit 11 -+ ((imm13 & 0x1e) << 7) | // bits 4-1 -+ (funct3 << kFunct3Shift) | (rs1.code() << kRs1Shift) | -+ (rs2.code() << kRs2Shift) | -+ ((imm13 & 0x7e0) << 20) | // bits 10-5 -+ ((imm13 & 0x1000) << 19); // bit 12 -+ emit(instr); -+} -+ -+void Assembler::GenInstrU(Opcode opcode, Register rd, int32_t imm20) { -+ DCHECK(rd.is_valid() && (is_int20(imm20) || is_uint20(imm20))); -+ Instr instr = opcode | (rd.code() << kRdShift) | (imm20 << kImm20Shift); -+ emit(instr); -+} -+ -+void Assembler::GenInstrJ(Opcode opcode, Register rd, int32_t imm21) { -+ DCHECK(rd.is_valid() && is_int21(imm21) && ((imm21 & 1) == 0)); -+ Instr instr = opcode | (rd.code() << kRdShift) | -+ (imm21 & 0xff000) | // bits 19-12 -+ ((imm21 & 0x800) << 9) | // bit 11 -+ ((imm21 & 0x7fe) << 20) | // bits 10-1 -+ ((imm21 & 0x100000) << 11); // bit 20 -+ emit(instr); -+} -+ -+// ----- Instruction class templates match those in the compiler -+ -+void Assembler::GenInstrBranchCC_rri(uint8_t funct3, Register rs1, Register rs2, -+ int16_t imm13) { -+ GenInstrB(funct3, BRANCH, rs1, rs2, imm13); -+} -+ -+void Assembler::GenInstrLoad_ri(uint8_t funct3, Register rd, Register rs1, -+ int16_t imm12) { -+ GenInstrI(funct3, LOAD, rd, rs1, imm12); -+} -+ -+void Assembler::GenInstrStore_rri(uint8_t funct3, Register rs1, Register rs2, -+ int16_t imm12) { -+ GenInstrS(funct3, STORE, rs1, rs2, imm12); -+} -+ -+void Assembler::GenInstrALU_ri(uint8_t funct3, Register rd, Register rs1, -+ int16_t imm12) { -+ GenInstrI(funct3, OP_IMM, rd, rs1, imm12); -+} -+ -+void Assembler::GenInstrShift_ri(bool arithshift, uint8_t funct3, Register rd, -+ Register rs1, uint8_t shamt) { -+ DCHECK(is_uint6(shamt)); -+ GenInstrI(funct3, OP_IMM, rd, rs1, (arithshift << 10) | shamt); -+} -+ -+void Assembler::GenInstrALU_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ Register rs1, Register rs2) { -+ GenInstrR(funct7, funct3, OP, rd, rs1, rs2); -+} -+ -+void Assembler::GenInstrCSR_ir(uint8_t funct3, Register rd, -+ ControlStatusReg csr, Register rs1) { -+ GenInstrI(funct3, SYSTEM, rd, rs1, csr); -+} -+ -+void Assembler::GenInstrCSR_ii(uint8_t funct3, Register rd, -+ ControlStatusReg csr, uint8_t imm5) { -+ GenInstrI(funct3, SYSTEM, rd, ToRegister(imm5), csr); -+} -+ -+void Assembler::GenInstrShiftW_ri(bool arithshift, uint8_t funct3, Register rd, -+ Register rs1, uint8_t shamt) { -+ GenInstrIShiftW(arithshift, funct3, OP_IMM_32, rd, rs1, shamt); -+} -+ -+void Assembler::GenInstrALUW_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ Register rs1, Register rs2) { -+ GenInstrR(funct7, funct3, OP_32, rd, rs1, rs2); -+} -+ -+void Assembler::GenInstrPriv(uint8_t funct7, Register rs1, Register rs2) { -+ GenInstrR(funct7, 0b000, SYSTEM, ToRegister(0), rs1, rs2); -+} -+ -+void Assembler::GenInstrLoadFP_ri(uint8_t funct3, FPURegister rd, Register rs1, -+ int16_t imm12) { -+ GenInstrI(funct3, LOAD_FP, rd, rs1, imm12); -+} -+ -+void Assembler::GenInstrStoreFP_rri(uint8_t funct3, Register rs1, -+ FPURegister rs2, int16_t imm12) { -+ GenInstrS(funct3, STORE_FP, rs1, rs2, imm12); -+} -+ -+void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, -+ FPURegister rs1, FPURegister rs2) { -+ GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2); -+} -+ -+void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, -+ Register rs1, Register rs2) { -+ GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2); -+} -+ -+void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, -+ FPURegister rs1, Register rs2) { -+ GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2); -+} -+ -+void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ FPURegister rs1, Register rs2) { -+ GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2); -+} -+ -+void Assembler::GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ FPURegister rs1, FPURegister rs2) { -+ GenInstrR(funct7, funct3, OP_FP, rd, rs1, rs2); -+} -+ -+// Returns the next free trampoline entry. -+int32_t Assembler::get_trampoline_entry(int32_t pos) { -+ int32_t trampoline_entry = kInvalidSlotPos; -+ if (!internal_trampoline_exception_) { -+ if (trampoline_.start() > pos) { -+ trampoline_entry = trampoline_.take_slot(); -+ } -+ -+ if (kInvalidSlotPos == trampoline_entry) { -+ internal_trampoline_exception_ = true; -+ } -+ } -+ return trampoline_entry; -+} -+ -+uint64_t Assembler::jump_address(Label* L) { -+ int64_t target_pos; -+ DEBUG_PRINTF("jump_address: %p to %p (%d)\n", L, -+ reinterpret_cast(buffer_start_ + pc_offset()), -+ pc_offset()); -+ if (L->is_bound()) { -+ target_pos = L->pos(); -+ } else { -+ if (L->is_linked()) { -+ target_pos = L->pos(); // L's link. -+ L->link_to(pc_offset()); -+ } else { -+ L->link_to(pc_offset()); -+ if (!trampoline_emitted_) { -+ unbound_labels_count_++; -+ next_buffer_check_ -= kTrampolineSlotsSize; -+ } -+ DEBUG_PRINTF("\tstarted link\n"); -+ return kEndOfJumpChain; -+ } -+ } -+ uint64_t imm = reinterpret_cast(buffer_start_) + target_pos; -+ DCHECK_EQ(imm & 3, 0); -+ -+ return imm; -+} -+ -+uint64_t Assembler::branch_long_offset(Label* L) { -+ int64_t target_pos; -+ -+ DEBUG_PRINTF("branch_long_offset: %p to %p (%d)\n", L, -+ reinterpret_cast(buffer_start_ + pc_offset()), -+ pc_offset()); -+ if (L->is_bound()) { -+ target_pos = L->pos(); -+ } else { -+ if (L->is_linked()) { -+ target_pos = L->pos(); // L's link. -+ L->link_to(pc_offset()); -+ } else { -+ L->link_to(pc_offset()); -+ if (!trampoline_emitted_) { -+ unbound_labels_count_++; -+ next_buffer_check_ -= kTrampolineSlotsSize; -+ } -+ DEBUG_PRINTF("\tstarted link\n"); -+ return kEndOfJumpChain; -+ } -+ } -+ int64_t offset = target_pos - pc_offset(); -+ DCHECK_EQ(offset & 3, 0); -+ -+ return static_cast(offset); -+} -+ -+int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) { -+ int32_t target_pos; -+ -+ DEBUG_PRINTF("branch_offset_helper: %p to %p (%d)\n", L, -+ reinterpret_cast(buffer_start_ + pc_offset()), -+ pc_offset()); -+ if (L->is_bound()) { -+ target_pos = L->pos(); -+ DEBUG_PRINTF("\tbound: %d", target_pos); -+ } else { -+ if (L->is_linked()) { -+ target_pos = L->pos(); -+ L->link_to(pc_offset()); -+ DEBUG_PRINTF("\tadded to link: %d\n", target_pos); -+ } else { -+ L->link_to(pc_offset()); -+ if (!trampoline_emitted_) { -+ unbound_labels_count_++; -+ next_buffer_check_ -= kTrampolineSlotsSize; -+ } -+ DEBUG_PRINTF("\tstarted link\n"); -+ return kEndOfChain; -+ } -+ } -+ -+ int32_t offset = target_pos - pc_offset(); -+ DCHECK(is_intn(offset, bits)); -+ DCHECK_EQ(offset & 1, 0); -+ DEBUG_PRINTF("\toffset = %d\n", offset); -+ return offset; -+} -+ -+void Assembler::label_at_put(Label* L, int at_offset) { -+ int target_pos; -+ DEBUG_PRINTF("label_at_put: %p @ %p (%d)\n", L, -+ reinterpret_cast(buffer_start_ + at_offset), at_offset); -+ if (L->is_bound()) { -+ target_pos = L->pos(); -+ instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); -+ } else { -+ if (L->is_linked()) { -+ target_pos = L->pos(); // L's link. -+ int32_t imm18 = target_pos - at_offset; -+ DCHECK_EQ(imm18 & 3, 0); -+ int32_t imm16 = imm18 >> 2; -+ DCHECK(is_int16(imm16)); -+ instr_at_put(at_offset, (imm16 & kImm16Mask)); -+ } else { -+ target_pos = kEndOfChain; -+ instr_at_put(at_offset, 0); -+ if (!trampoline_emitted_) { -+ unbound_labels_count_++; -+ next_buffer_check_ -= kTrampolineSlotsSize; -+ } -+ } -+ L->link_to(at_offset); -+ } -+} -+ -+//===----------------------------------------------------------------------===// -+// Instructions -+//===----------------------------------------------------------------------===// -+ -+void Assembler::lui(Register rd, int32_t imm20) { GenInstrU(LUI, rd, imm20); } -+ -+void Assembler::auipc(Register rd, int32_t imm20) { -+ GenInstrU(AUIPC, rd, imm20); -+} -+ -+// Jumps -+ -+void Assembler::jal(Register rd, int32_t imm21) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ GenInstrJ(JAL, rd, imm21); -+ BlockTrampolinePoolFor(1); -+} -+ -+void Assembler::jalr(Register rd, Register rs1, int16_t imm12) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ GenInstrI(0b000, JALR, rd, rs1, imm12); -+ BlockTrampolinePoolFor(1); -+} -+ -+// Branches -+ -+void Assembler::beq(Register rs1, Register rs2, int16_t imm13) { -+ GenInstrBranchCC_rri(0b000, rs1, rs2, imm13); -+} -+ -+void Assembler::bne(Register rs1, Register rs2, int16_t imm13) { -+ GenInstrBranchCC_rri(0b001, rs1, rs2, imm13); -+} -+ -+void Assembler::blt(Register rs1, Register rs2, int16_t imm13) { -+ GenInstrBranchCC_rri(0b100, rs1, rs2, imm13); -+} -+ -+void Assembler::bge(Register rs1, Register rs2, int16_t imm13) { -+ GenInstrBranchCC_rri(0b101, rs1, rs2, imm13); -+} -+ -+void Assembler::bltu(Register rs1, Register rs2, int16_t imm13) { -+ GenInstrBranchCC_rri(0b110, rs1, rs2, imm13); -+} -+ -+void Assembler::bgeu(Register rs1, Register rs2, int16_t imm13) { -+ GenInstrBranchCC_rri(0b111, rs1, rs2, imm13); -+} -+ -+// Loads -+ -+void Assembler::lb(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b000, rd, rs1, imm12); -+} -+ -+void Assembler::lh(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b001, rd, rs1, imm12); -+} -+ -+void Assembler::lw(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b010, rd, rs1, imm12); -+} -+ -+void Assembler::lbu(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b100, rd, rs1, imm12); -+} -+ -+void Assembler::lhu(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b101, rd, rs1, imm12); -+} -+ -+// Stores -+ -+void Assembler::sb(Register source, Register base, int16_t imm12) { -+ GenInstrStore_rri(0b000, base, source, imm12); -+} -+ -+void Assembler::sh(Register source, Register base, int16_t imm12) { -+ GenInstrStore_rri(0b001, base, source, imm12); -+} -+ -+void Assembler::sw(Register source, Register base, int16_t imm12) { -+ GenInstrStore_rri(0b010, base, source, imm12); -+} -+ -+// Arithmetic with immediate -+ -+void Assembler::addi(Register rd, Register rs1, int16_t imm12) { -+ GenInstrALU_ri(0b000, rd, rs1, imm12); -+} -+ -+void Assembler::slti(Register rd, Register rs1, int16_t imm12) { -+ GenInstrALU_ri(0b010, rd, rs1, imm12); -+} -+ -+void Assembler::sltiu(Register rd, Register rs1, int16_t imm12) { -+ GenInstrALU_ri(0b011, rd, rs1, imm12); -+} -+ -+void Assembler::xori(Register rd, Register rs1, int16_t imm12) { -+ GenInstrALU_ri(0b100, rd, rs1, imm12); -+} -+ -+void Assembler::ori(Register rd, Register rs1, int16_t imm12) { -+ GenInstrALU_ri(0b110, rd, rs1, imm12); -+} -+ -+void Assembler::andi(Register rd, Register rs1, int16_t imm12) { -+ GenInstrALU_ri(0b111, rd, rs1, imm12); -+} -+ -+void Assembler::slli(Register rd, Register rs1, uint8_t shamt) { -+ GenInstrShift_ri(0, 0b001, rd, rs1, shamt & 0x3f); -+} -+ -+void Assembler::srli(Register rd, Register rs1, uint8_t shamt) { -+ GenInstrShift_ri(0, 0b101, rd, rs1, shamt & 0x3f); -+} -+ -+void Assembler::srai(Register rd, Register rs1, uint8_t shamt) { -+ GenInstrShift_ri(1, 0b101, rd, rs1, shamt & 0x3f); -+} -+ -+// Arithmetic -+ -+void Assembler::add(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::sub(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0100000, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::sll(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::slt(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::sltu(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::xor_(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b100, rd, rs1, rs2); -+} -+ -+void Assembler::srl(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b101, rd, rs1, rs2); -+} -+ -+void Assembler::sra(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0100000, 0b101, rd, rs1, rs2); -+} -+ -+void Assembler::or_(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b110, rd, rs1, rs2); -+} -+ -+void Assembler::and_(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000000, 0b111, rd, rs1, rs2); -+} -+ -+// Memory fences -+ -+void Assembler::fence(uint8_t pred, uint8_t succ) { -+ DCHECK(is_uint4(pred) && is_uint4(succ)); -+ uint16_t imm12 = succ | (pred << 4) | (0b0000 << 8); -+ GenInstrI(0b000, MISC_MEM, ToRegister(0), ToRegister(0), imm12); -+} -+ -+void Assembler::fence_tso() { -+ uint16_t imm12 = (0b0011) | (0b0011 << 4) | (0b1000 << 8); -+ GenInstrI(0b000, MISC_MEM, ToRegister(0), ToRegister(0), imm12); -+} -+ -+// Environment call / break -+ -+void Assembler::ecall() { -+ GenInstrI(0b000, SYSTEM, ToRegister(0), ToRegister(0), 0); -+} -+ -+void Assembler::ebreak() { -+ GenInstrI(0b000, SYSTEM, ToRegister(0), ToRegister(0), 1); -+} -+ -+// This is a de facto standard (as set by GNU binutils) 32-bit unimplemented -+// instruction (i.e., it should always trap, if your implementation has invalid -+// instruction traps). -+void Assembler::unimp() { -+ GenInstrI(0b001, SYSTEM, ToRegister(0), ToRegister(0), 0b110000000000); -+} -+ -+// CSR -+ -+void Assembler::csrrw(Register rd, ControlStatusReg csr, Register rs1) { -+ GenInstrCSR_ir(0b001, rd, csr, rs1); -+} -+ -+void Assembler::csrrs(Register rd, ControlStatusReg csr, Register rs1) { -+ GenInstrCSR_ir(0b010, rd, csr, rs1); -+} -+ -+void Assembler::csrrc(Register rd, ControlStatusReg csr, Register rs1) { -+ GenInstrCSR_ir(0b011, rd, csr, rs1); -+} -+ -+void Assembler::csrrwi(Register rd, ControlStatusReg csr, uint8_t imm5) { -+ GenInstrCSR_ii(0b101, rd, csr, imm5); -+} -+ -+void Assembler::csrrsi(Register rd, ControlStatusReg csr, uint8_t imm5) { -+ GenInstrCSR_ii(0b110, rd, csr, imm5); -+} -+ -+void Assembler::csrrci(Register rd, ControlStatusReg csr, uint8_t imm5) { -+ GenInstrCSR_ii(0b111, rd, csr, imm5); -+} -+ -+// RV64I -+ -+void Assembler::lwu(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b110, rd, rs1, imm12); -+} -+ -+void Assembler::ld(Register rd, Register rs1, int16_t imm12) { -+ GenInstrLoad_ri(0b011, rd, rs1, imm12); -+} -+ -+void Assembler::sd(Register source, Register base, int16_t imm12) { -+ GenInstrStore_rri(0b011, base, source, imm12); -+} -+ -+void Assembler::addiw(Register rd, Register rs1, int16_t imm12) { -+ GenInstrI(0b000, OP_IMM_32, rd, rs1, imm12); -+} -+ -+void Assembler::slliw(Register rd, Register rs1, uint8_t shamt) { -+ GenInstrShiftW_ri(0, 0b001, rd, rs1, shamt & 0x1f); -+} -+ -+void Assembler::srliw(Register rd, Register rs1, uint8_t shamt) { -+ GenInstrShiftW_ri(0, 0b101, rd, rs1, shamt & 0x1f); -+} -+ -+void Assembler::sraiw(Register rd, Register rs1, uint8_t shamt) { -+ GenInstrShiftW_ri(1, 0b101, rd, rs1, shamt & 0x1f); -+} -+ -+void Assembler::addw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000000, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::subw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0100000, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::sllw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000000, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::srlw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000000, 0b101, rd, rs1, rs2); -+} -+ -+void Assembler::sraw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0100000, 0b101, rd, rs1, rs2); -+} -+ -+// RV32M Standard Extension -+ -+void Assembler::mul(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::mulh(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::mulhsu(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::mulhu(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::div(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b100, rd, rs1, rs2); -+} -+ -+void Assembler::divu(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b101, rd, rs1, rs2); -+} -+ -+void Assembler::rem(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b110, rd, rs1, rs2); -+} -+ -+void Assembler::remu(Register rd, Register rs1, Register rs2) { -+ GenInstrALU_rr(0b0000001, 0b111, rd, rs1, rs2); -+} -+ -+// RV64M Standard Extension (in addition to RV32M) -+ -+void Assembler::mulw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000001, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::divw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000001, 0b100, rd, rs1, rs2); -+} -+ -+void Assembler::divuw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000001, 0b101, rd, rs1, rs2); -+} -+ -+void Assembler::remw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000001, 0b110, rd, rs1, rs2); -+} -+ -+void Assembler::remuw(Register rd, Register rs1, Register rs2) { -+ GenInstrALUW_rr(0b0000001, 0b111, rd, rs1, rs2); -+} -+ -+// RV32A Standard Extension -+ -+void Assembler::lr_w(bool aq, bool rl, Register rd, Register rs1) { -+ GenInstrRAtomic(0b00010, aq, rl, 0b010, rd, rs1, zero_reg); -+} -+ -+void Assembler::sc_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00011, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amoswap_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00001, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amoadd_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00000, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amoxor_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00100, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amoand_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b01100, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amoor_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b01000, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amomin_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b10000, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amomax_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b10100, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amominu_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b11000, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::amomaxu_w(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b11100, aq, rl, 0b010, rd, rs1, rs2); -+} -+ -+// RV64A Standard Extension (in addition to RV32A) -+ -+void Assembler::lr_d(bool aq, bool rl, Register rd, Register rs1) { -+ GenInstrRAtomic(0b00010, aq, rl, 0b011, rd, rs1, zero_reg); -+} -+ -+void Assembler::sc_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00011, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amoswap_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00001, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amoadd_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00000, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amoxor_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b00100, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amoand_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b01100, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amoor_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b01000, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amomin_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b10000, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amomax_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b10100, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amominu_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b11000, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+void Assembler::amomaxu_d(bool aq, bool rl, Register rd, Register rs1, -+ Register rs2) { -+ GenInstrRAtomic(0b11100, aq, rl, 0b011, rd, rs1, rs2); -+} -+ -+// RV32F Standard Extension -+ -+void Assembler::flw(FPURegister rd, Register rs1, int16_t imm12) { -+ GenInstrLoadFP_ri(0b010, rd, rs1, imm12); -+} -+ -+void Assembler::fsw(FPURegister source, Register base, int16_t imm12) { -+ GenInstrStoreFP_rri(0b010, base, source, imm12); -+} -+ -+void Assembler::fmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b00, MADD, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b00, MSUB, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fnmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b00, NMSUB, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fnmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b00, NMADD, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0000000, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0000100, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fmul_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0001000, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fdiv_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0001100, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fsqrt_s(FPURegister rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b0101100, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::fsgnj_s(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010000, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::fsgnjn_s(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010000, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::fsgnjx_s(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010000, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::fmin_s(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010100, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::fmax_s(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010100, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::fcvt_w_s(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100000, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_wu_s(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100000, frm, rd, rs1, ToRegister(1)); -+} -+ -+void Assembler::fmv_x_w(Register rd, FPURegister rs1) { -+ GenInstrALUFP_rr(0b1110000, 0b000, rd, rs1, zero_reg); -+} -+ -+void Assembler::feq_s(Register rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b1010000, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::flt_s(Register rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b1010000, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::fle_s(Register rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b1010000, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::fclass_s(Register rd, FPURegister rs1) { -+ GenInstrALUFP_rr(0b1110000, 0b001, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_s_w(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101000, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_s_wu(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101000, frm, rd, rs1, ToRegister(1)); -+} -+ -+void Assembler::fmv_w_x(FPURegister rd, Register rs1) { -+ GenInstrALUFP_rr(0b1111000, 0b000, rd, rs1, zero_reg); -+} -+ -+// RV64F Standard Extension (in addition to RV32F) -+ -+void Assembler::fcvt_l_s(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100000, frm, rd, rs1, ToRegister(2)); -+} -+ -+void Assembler::fcvt_lu_s(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100000, frm, rd, rs1, ToRegister(3)); -+} -+ -+void Assembler::fcvt_s_l(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101000, frm, rd, rs1, ToRegister(2)); -+} -+ -+void Assembler::fcvt_s_lu(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101000, frm, rd, rs1, ToRegister(3)); -+} -+ -+// RV32D Standard Extension -+ -+void Assembler::fld(FPURegister rd, Register rs1, int16_t imm12) { -+ GenInstrLoadFP_ri(0b011, rd, rs1, imm12); -+} -+ -+void Assembler::fsd(FPURegister source, Register base, int16_t imm12) { -+ GenInstrStoreFP_rri(0b011, base, source, imm12); -+} -+ -+void Assembler::fmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b01, MADD, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b01, MSUB, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fnmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b01, NMSUB, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fnmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm) { -+ GenInstrR4(0b01, NMADD, rd, rs1, rs2, rs3, frm); -+} -+ -+void Assembler::fadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0000001, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0000101, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fmul_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0001001, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fdiv_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm) { -+ GenInstrALUFP_rr(0b0001101, frm, rd, rs1, rs2); -+} -+ -+void Assembler::fsqrt_d(FPURegister rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b0101101, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::fsgnj_d(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010001, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::fsgnjn_d(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010001, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::fsgnjx_d(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010001, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::fmin_d(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010101, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::fmax_d(FPURegister rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b0010101, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::fcvt_s_d(FPURegister rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b0100000, frm, rd, rs1, ToRegister(1)); -+} -+ -+void Assembler::fcvt_d_s(FPURegister rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b0100001, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::feq_d(Register rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b1010001, 0b010, rd, rs1, rs2); -+} -+ -+void Assembler::flt_d(Register rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b1010001, 0b001, rd, rs1, rs2); -+} -+ -+void Assembler::fle_d(Register rd, FPURegister rs1, FPURegister rs2) { -+ GenInstrALUFP_rr(0b1010001, 0b000, rd, rs1, rs2); -+} -+ -+void Assembler::fclass_d(Register rd, FPURegister rs1) { -+ GenInstrALUFP_rr(0b1110001, 0b001, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_w_d(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100001, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_wu_d(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100001, frm, rd, rs1, ToRegister(1)); -+} -+ -+void Assembler::fcvt_d_w(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101001, frm, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_d_wu(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101001, frm, rd, rs1, ToRegister(1)); -+} -+ -+// RV64D Standard Extension (in addition to RV32D) -+ -+void Assembler::fcvt_l_d(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100001, frm, rd, rs1, ToRegister(2)); -+} -+ -+void Assembler::fcvt_lu_d(Register rd, FPURegister rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1100001, frm, rd, rs1, ToRegister(3)); -+} -+ -+void Assembler::fmv_x_d(Register rd, FPURegister rs1) { -+ GenInstrALUFP_rr(0b1110001, 0b000, rd, rs1, zero_reg); -+} -+ -+void Assembler::fcvt_d_l(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101001, frm, rd, rs1, ToRegister(2)); -+} -+ -+void Assembler::fcvt_d_lu(FPURegister rd, Register rs1, RoundingMode frm) { -+ GenInstrALUFP_rr(0b1101001, frm, rd, rs1, ToRegister(3)); -+} -+ -+void Assembler::fmv_d_x(FPURegister rd, Register rs1) { -+ GenInstrALUFP_rr(0b1111001, 0b000, rd, rs1, zero_reg); -+} -+ -+// Privileged -+ -+void Assembler::uret() { -+ GenInstrPriv(0b0000000, ToRegister(0), ToRegister(0b00010)); -+} -+ -+void Assembler::sret() { -+ GenInstrPriv(0b0001000, ToRegister(0), ToRegister(0b00010)); -+} -+ -+void Assembler::mret() { -+ GenInstrPriv(0b0011000, ToRegister(0), ToRegister(0b00010)); -+} -+ -+void Assembler::wfi() { -+ GenInstrPriv(0b0001000, ToRegister(0), ToRegister(0b00101)); -+} -+ -+void Assembler::sfence_vma(Register rs1, Register rs2) { -+ GenInstrR(0b0001001, 0b000, SYSTEM, ToRegister(0), rs1, rs2); -+} -+ -+// Assembler Pseudo Instructions (Tables 25.2 and 25.3, RISC-V Unprivileged ISA) -+ -+void Assembler::nop() { addi(ToRegister(0), ToRegister(0), 0); } -+ -+void Assembler::RV_li(Register rd, int64_t imm) { -+ // 64-bit imm is put in the register rd. -+ // In most cases the imm is 32 bit and 2 instructions are generated. If a -+ // temporary register is available, in the worst case, 6 instructions are -+ // generated for a full 64-bit immediate. If temporay register is not -+ // available the maximum will be 8 instructions. If imm is more than 32 bits -+ // and a temp register is available, imm is divided into two 32-bit parts, -+ // low_32 and up_32. Each part is built in a separate register. low_32 is -+ // built before up_32. If low_32 is negative (upper 32 bits are 1), 0xffffffff -+ // is subtracted from up_32 before up_32 is built. This compensates for 32 -+ // bits of 1's in the lower when the two registers are added. If no temp is -+ // available, the upper 32 bit is built in rd, and the lower 32 bits are -+ // devided to 3 parts (11, 11, and 10 bits). The parts are shifted and added -+ // to the upper part built in rd. -+ if (is_int32(imm + 0x800)) { -+ // 32-bit case. Maximum of 2 instructions generated -+ int64_t high_20 = ((imm + 0x800) >> 12); -+ int64_t low_12 = imm << 52 >> 52; -+ if (high_20) { -+ lui(rd, (int32_t)high_20); -+ if (low_12) { -+ addi(rd, rd, low_12); -+ } -+ } else { -+ addi(rd, zero_reg, low_12); -+ } -+ return; -+ } else { -+ // 64-bit case: divide imm into two 32-bit parts, upper and lower -+ int64_t up_32 = imm >> 32; -+ int64_t low_32 = imm & 0xffffffffull; -+ Register temp_reg = rd; -+ // Check if a temporary register is available -+ if (up_32 == 0 || low_32 == 0) { -+ // No temp register is needed -+ } else { -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ temp_reg = temps.hasAvailable() ? temps.Acquire() : no_reg; -+ } -+ if (temp_reg != no_reg) { -+ // keep track of hardware behavior for lower part in sim_low -+ int64_t sim_low = 0; -+ // Build lower part -+ if (low_32 != 0) { -+ int64_t high_20 = ((low_32 + 0x800) >> 12); -+ int64_t low_12 = low_32 & 0xfff; -+ if (high_20) { -+ // Adjust to 20 bits for the case of overflow -+ high_20 &= 0xfffff; -+ sim_low = ((high_20 << 12) << 32) >> 32; -+ lui(rd, (int32_t)high_20); -+ if (low_12) { -+ sim_low += (low_12 << 52 >> 52) | low_12; -+ addi(rd, rd, low_12); -+ } -+ } else { -+ sim_low = low_12; -+ ori(rd, zero_reg, low_12); -+ } -+ } -+ if (sim_low & 0x100000000) { -+ // Bit 31 is 1. Either an overflow or a negative 64 bit -+ if (up_32 == 0) { -+ // Positive number, but overflow because of the add 0x800 -+ slli(rd, rd, 32); -+ srli(rd, rd, 32); -+ return; -+ } -+ // low_32 is a negative 64 bit after the build -+ up_32 = (up_32 - 0xffffffff) & 0xffffffff; -+ } -+ if (up_32 == 0) { -+ return; -+ } -+ // Build upper part in a temporary register -+ if (low_32 == 0) { -+ // Build upper part in rd -+ temp_reg = rd; -+ } -+ int64_t high_20 = (up_32 + 0x800) >> 12; -+ int64_t low_12 = up_32 & 0xfff; -+ if (high_20) { -+ // Adjust to 20 bits for the case of overflow -+ high_20 &= 0xfffff; -+ lui(temp_reg, (int32_t)high_20); -+ if (low_12) { -+ addi(temp_reg, temp_reg, low_12); -+ } -+ } else { -+ ori(temp_reg, zero_reg, low_12); -+ } -+ // Put it at the bgining of register -+ slli(temp_reg, temp_reg, 32); -+ if (low_32 != 0) { -+ add(rd, rd, temp_reg); -+ } -+ return; -+ } -+ // No temp register. Build imm in rd. -+ // Build upper 32 bits first in rd. Divide lower 32 bits parts and add -+ // parts to the upper part by doing shift and add. -+ // First build upper part in rd. -+ int64_t high_20 = (up_32 + 0x800) >> 12; -+ int64_t low_12 = up_32 & 0xfff; -+ if (high_20) { -+ // Adjust to 20 bits for the case of overflow -+ high_20 &= 0xfffff; -+ lui(rd, (int32_t)high_20); -+ if (low_12) { -+ addi(rd, rd, low_12); -+ } -+ } else { -+ ori(rd, zero_reg, low_12); -+ } -+ // upper part already in rd. Each part to be added to rd, has maximum of 11 -+ // bits, and always starts with a 1. rd is shifted by the size of the part -+ // plus the number of zeros between the parts. Each part is added after the -+ // left shift. -+ uint32_t mask = 0x80000000; -+ int32_t shift_val = 0; -+ int32_t i; -+ for (i = 0; i < 32; i++) { -+ if ((low_32 & mask) == 0) { -+ mask >>= 1; -+ shift_val++; -+ if (i == 31) { -+ // rest is zero -+ slli(rd, rd, shift_val); -+ } -+ continue; -+ } -+ // The first 1 seen -+ int32_t part; -+ if ((i + 11) < 32) { -+ // Pick 11 bits -+ part = ((uint32_t)(low_32 << i) >> i) >> (32 - (i + 11)); -+ slli(rd, rd, shift_val + 11); -+ ori(rd, rd, part); -+ i += 10; -+ mask >>= 11; -+ } else { -+ part = (uint32_t)(low_32 << i) >> i; -+ slli(rd, rd, shift_val + (32 - i)); -+ ori(rd, rd, part); -+ break; -+ } -+ shift_val = 0; -+ } -+ } -+} -+ -+int Assembler::li_count(int64_t imm) { -+ int count = 0; -+ if (is_int32(imm + 0x800)) { -+ int64_t Hi20 = ((imm + 0x800) >> 12); -+ int64_t Lo12 = imm << 52 >> 52; -+ -+ if (Hi20) count++; -+ -+ if (Lo12 || Hi20 == 0) count++; -+ return count; -+ } -+ -+ int64_t Lo12 = imm << 52 >> 52; -+ int64_t Hi52 = ((uint64_t)imm + 0x800ull) >> 12; -+ int FirstBit = 0; -+ uint64_t Val = Hi52; -+ while ((Val & 1) == 0) { -+ Val = Val >> 1; -+ FirstBit++; -+ } -+ int ShiftAmount = 12 + FirstBit; -+ Hi52 = (Hi52 >> (ShiftAmount - 12)) << ShiftAmount >> ShiftAmount; -+ -+ count += li_count(Hi52); -+ -+ count++; -+ if (Lo12) count++; -+ -+ return count; -+} -+ -+void Assembler::li_constant(Register rd, int64_t imm) { -+ DEBUG_PRINTF("li_constant(%d, %lx <%ld>)\n", ToNumber(rd), imm, imm); -+ lui(rd, (imm + (1LL << 47) + (1LL << 35) + (1LL << 23) + (1LL << 11)) >> -+ 48); // Bits 63:48 -+ addiw(rd, rd, -+ (imm + (1LL << 35) + (1LL << 23) + (1LL << 11)) << 16 >> -+ 52); // Bits 47:36 -+ slli(rd, rd, 12); -+ addi(rd, rd, (imm + (1LL << 23) + (1LL << 11)) << 28 >> 52); // Bits 35:24 -+ slli(rd, rd, 12); -+ addi(rd, rd, (imm + (1LL << 11)) << 40 >> 52); // Bits 23:12 -+ slli(rd, rd, 12); -+ addi(rd, rd, imm << 52 >> 52); // Bits 11:0 -+} -+ -+// Break / Trap instructions. -+void Assembler::break_(uint32_t code, bool break_as_stop) { -+ // We need to invalidate breaks that could be stops as well because the -+ // simulator expects a char pointer after the stop instruction. -+ // See constants-mips.h for explanation. -+ DCHECK( -+ (break_as_stop && code <= kMaxStopCode && code > kMaxWatchpointCode) || -+ (!break_as_stop && (code > kMaxStopCode || code <= kMaxWatchpointCode))); -+ -+ // since ebreak does not allow additional immediate field, we use the -+ // immediate field of lui instruction immediately following the ebreak to -+ // encode the "code" info -+ ebreak(); -+ DCHECK(is_uint20(code)); -+ lui(zero_reg, code); -+} -+ -+void Assembler::stop(uint32_t code) { -+ DCHECK_GT(code, kMaxWatchpointCode); -+ DCHECK_LE(code, kMaxStopCode); -+#if defined(V8_HOST_ARCH_RISCV64) -+ // FIXME: does RISCV expect a special value? -+ break_(0x54321); -+#else // V8_HOST_ARCH_RISCV64 -+ break_(code, true); -+#endif -+} -+ -+// Original MIPS Instructions -+ -+// ------------Memory-instructions------------- -+ -+bool Assembler::NeedAdjustBaseAndOffset(const MemOperand& src, -+ OffsetAccessType access_type, -+ int second_access_add_to_offset) { -+ bool two_accesses = static_cast(access_type); -+ DCHECK_LE(second_access_add_to_offset, 7); // Must be <= 7. -+ -+ // is_int12 must be passed a signed value, hence the static cast below. -+ if (is_int12(src.offset()) && -+ (!two_accesses || is_int12(static_cast( -+ src.offset() + second_access_add_to_offset)))) { -+ // Nothing to do: 'offset' (and, if needed, 'offset + 4', or other specified -+ // value) fits into int12. -+ return false; -+ } -+ return true; -+} -+ -+void Assembler::AdjustBaseAndOffset(MemOperand* src, Register scratch, -+ OffsetAccessType access_type, -+ int second_Access_add_to_offset) { -+ // This method is used to adjust the base register and offset pair -+ // for a load/store when the offset doesn't fit into int12. -+ -+ // Must not overwrite the register 'base' while loading 'offset'. -+ DCHECK(src->rm() != scratch); -+ -+ // FIXME(RISC-V): There may be a more optimal way to do this -+ RV_li(scratch, src->offset()); -+ add(scratch, scratch, src->rm()); -+ src->offset_ = 0; -+ src->rm_ = scratch; -+} -+ -+// FIXME (RISCV): not yet ported (or not used?) -+int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, Address pc, -+ intptr_t pc_delta) { -+ if (RelocInfo::IsInternalReference(rmode)) { -+ int64_t* p = reinterpret_cast(pc); -+ if (*p == kEndOfJumpChain) { -+ return 0; // Number of instructions patched. -+ } -+ *p += pc_delta; -+ return 2; // Number of instructions patched. -+ } -+ Instr instr = instr_at(pc); -+ DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode)); -+ if (IsLui(instr)) { -+ uint64_t target_address = target_address_at(pc) + pc_delta; -+ DEBUG_PRINTF("target_address 0x%lx\n", target_address); -+ set_target_value_at(pc, target_address); -+ return 8; // Number of instructions patched. -+ } else { -+ UNIMPLEMENTED(); -+ return 1; -+ } -+} -+ -+void Assembler::GrowBuffer() { -+ DEBUG_PRINTF("GrowBuffer: %p -> ", buffer_start_); -+ // Compute new buffer size. -+ int old_size = buffer_->size(); -+ int new_size = std::min(2 * old_size, old_size + 1 * MB); -+ -+ // Some internal data structures overflow for very large buffers, -+ // they must ensure that kMaximalBufferSize is not too large. -+ if (new_size > kMaximalBufferSize) { -+ V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer"); -+ } -+ -+ // Set up new buffer. -+ std::unique_ptr new_buffer = buffer_->Grow(new_size); -+ DCHECK_EQ(new_size, new_buffer->size()); -+ byte* new_start = new_buffer->start(); -+ -+ // Copy the data. -+ intptr_t pc_delta = new_start - buffer_start_; -+ intptr_t rc_delta = (new_start + new_size) - (buffer_start_ + old_size); -+ size_t reloc_size = (buffer_start_ + old_size) - reloc_info_writer.pos(); -+ MemMove(new_start, buffer_start_, pc_offset()); -+ MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(), -+ reloc_size); -+ -+ // Switch buffers. -+ buffer_ = std::move(new_buffer); -+ buffer_start_ = new_start; -+ DEBUG_PRINTF("%p\n", buffer_start_); -+ pc_ += pc_delta; -+ reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, -+ reloc_info_writer.last_pc() + pc_delta); -+ -+ // Relocate runtime entries. -+ Vector instructions{buffer_start_, (size_t)pc_offset()}; -+ Vector reloc_info{reloc_info_writer.pos(), reloc_size}; -+ for (RelocIterator it(instructions, reloc_info, 0); !it.done(); it.next()) { -+ RelocInfo::Mode rmode = it.rinfo()->rmode(); -+ if (rmode == RelocInfo::INTERNAL_REFERENCE) { -+ RelocateInternalReference(rmode, it.rinfo()->pc(), pc_delta); -+ } -+ } -+ DCHECK(!overflow()); -+} -+ -+void Assembler::db(uint8_t data) { -+ if (!is_buffer_growth_blocked()) CheckBuffer(); -+ EmitHelper(data); -+} -+ -+void Assembler::dd(uint32_t data) { -+ if (!is_buffer_growth_blocked()) CheckBuffer(); -+ EmitHelper(data); -+} -+ -+void Assembler::dq(uint64_t data) { -+ if (!is_buffer_growth_blocked()) CheckBuffer(); -+ EmitHelper(data); -+} -+ -+void Assembler::dd(Label* label) { -+ uint64_t data; -+ if (!is_buffer_growth_blocked()) CheckBuffer(); -+ if (label->is_bound()) { -+ data = reinterpret_cast(buffer_start_ + label->pos()); -+ } else { -+ data = jump_address(label); -+ internal_reference_positions_.insert(label->pos()); -+ } -+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); -+ EmitHelper(data); -+} -+ -+void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { -+ if (!ShouldRecordRelocInfo(rmode)) return; -+ // We do not try to reuse pool constants. -+ RelocInfo rinfo(reinterpret_cast
(pc_), rmode, data, Code()); -+ DCHECK_GE(buffer_space(), kMaxRelocSize); // Too late to grow buffer here. -+ reloc_info_writer.Write(&rinfo); -+} -+ -+void Assembler::BlockTrampolinePoolFor(int instructions) { -+ CheckTrampolinePoolQuick(instructions); -+ BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize); -+} -+ -+void Assembler::CheckTrampolinePool() { -+ // Some small sequences of instructions must not be broken up by the -+ // insertion of a trampoline pool; such sequences are protected by setting -+ // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_, -+ // which are both checked here. Also, recursive calls to CheckTrampolinePool -+ // are blocked by trampoline_pool_blocked_nesting_. -+ if ((trampoline_pool_blocked_nesting_ > 0) || -+ (pc_offset() < no_trampoline_pool_before_)) { -+ // Emission is currently blocked; make sure we try again as soon as -+ // possible. -+ if (trampoline_pool_blocked_nesting_ > 0) { -+ next_buffer_check_ = pc_offset() + kInstrSize; -+ } else { -+ next_buffer_check_ = no_trampoline_pool_before_; -+ } -+ return; -+ } -+ -+ DCHECK(!trampoline_emitted_); -+ DCHECK_GE(unbound_labels_count_, 0); -+ if (unbound_labels_count_ > 0) { -+ // First we emit jump, then we emit trampoline pool. -+ { -+ DEBUG_PRINTF("inserting trampoline pool at %p (%d)\n", -+ reinterpret_cast(buffer_start_ + pc_offset()), -+ pc_offset()); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Label after_pool; -+ j(&after_pool); -+ -+ int pool_start = pc_offset(); -+ for (int i = 0; i < unbound_labels_count_; i++) { -+ int64_t imm64; -+ imm64 = branch_long_offset(&after_pool); -+ DCHECK(is_int32(imm64)); -+ int32_t Hi20 = (((int32_t)imm64 + 0x800) >> 12); -+ int32_t Lo12 = (int32_t)imm64 << 20 >> 20; -+ auipc(t5, Hi20); // Read PC + Hi20 into t5. -+ jr(t5, Lo12); // jump PC + Hi20 + Lo12 -+ } -+ // If unbound_labels_count_ is big enough, label after_pool will -+ // need a trampoline too, so we must create the trampoline before -+ // the bind operation to make sure function 'bind' can get this -+ // information. -+ trampoline_ = Trampoline(pool_start, unbound_labels_count_); -+ bind(&after_pool); -+ -+ trampoline_emitted_ = true; -+ // As we are only going to emit trampoline once, we need to prevent any -+ // further emission. -+ next_buffer_check_ = kMaxInt; -+ } -+ } else { -+ // Number of branches to unbound label at this point is zero, so we can -+ // move next buffer check to maximum. -+ next_buffer_check_ = -+ pc_offset() + kMaxBranchOffset - kTrampolineSlotsSize * 16; -+ } -+ return; -+} -+ -+Address Assembler::target_address_at(Address pc) { -+ DEBUG_PRINTF("target_address_at: pc: %lx\t", pc); -+ Instruction* instr0 = Instruction::At((unsigned char*)pc); -+ Instruction* instr1 = Instruction::At((unsigned char*)(pc + 1 * kInstrSize)); -+ Instruction* instr3 = Instruction::At((unsigned char*)(pc + 3 * kInstrSize)); -+ Instruction* instr5 = Instruction::At((unsigned char*)(pc + 5 * kInstrSize)); -+ Instruction* instr7 = Instruction::At((unsigned char*)(pc + 7 * kInstrSize)); -+ -+ // Interpret 5 instructions for address generated by li: See listing in -+ // Assembler::set_target_address_at() just below. -+ if (IsLui(*reinterpret_cast(instr0)) && -+ IsAddiw(*reinterpret_cast(instr1)) && -+ IsAddi(*reinterpret_cast(instr3)) && -+ IsAddi(*reinterpret_cast(instr5)) && -+ IsAddi(*reinterpret_cast(instr7))) { -+ // Assemble the 64 bit value. -+ int64_t addr = (int64_t)(instr0->Imm20UValue() << kImm20Shift) + -+ (int64_t)instr1->Imm12Value(); -+ addr <<= 12; -+ addr += (int64_t)instr3->Imm12Value(); -+ addr <<= 12; -+ addr += (int64_t)instr5->Imm12Value(); -+ addr <<= 12; -+ addr += (int64_t)instr7->Imm12Value(); -+ -+ DEBUG_PRINTF("addr: %lx\n", addr); -+ return static_cast
(addr); -+ } -+ // We should never get here, force a bad address if we do. -+ UNREACHABLE(); -+} -+ -+// On RISC-V, a 64-bit target address is stored in an 8-instruction sequence: -+// 0: lui(rd, (j.imm64_ + (1LL << 47) + (1LL << 35) + -+// (1LL << 23) + (1LL << 11)) >> 48); -+// 1: addiw(rd, rd, (j.imm64_ + (1LL << 35) + (1LL << 23) + (1LL << 11)) -+// << 16 >> 52); -+// 2: slli(rd, rd, 12); -+// 3: addi(rd, rd, (j.imm64_ + (1LL << 23) + (1LL << 11)) << 28 >> 52); -+// 4: slli(rd, rd, 12); -+// 5: addi(rd, rd, (j.imm64_ + (1 << 11)) << 40 >> 52); -+// 6: slli(rd, rd, 12); -+// 7: addi(rd, rd, j.imm64_ << 52 >> 52); -+// -+// Patching the address must replace all the lui & addi instructions, -+// and flush the i-cache. -+void Assembler::set_target_value_at(Address pc, uint64_t target, -+ ICacheFlushMode icache_flush_mode) { -+ // FIXME(RISC-V): Does the below statement apply to RISC-V? If so, we do not -+ // need all 8 instructions. -+ // There is an optimization where only 4 instructions are used to load address -+ // in code on MIP64 because only 48-bits of address is effectively used. -+ // It relies on fact the upper [63:48] bits are not used for virtual address -+ // translation and they have to be set according to value of bit 47 in order -+ // get canonical address. -+ Instruction* instr0 = Instruction::At((unsigned char*)pc); -+ DEBUG_PRINTF("set_target_value_at: pc: %lx\ttarget: %lx\n", pc, target); -+ int rd_code = instr0->RdValue(); -+ uint32_t* p = reinterpret_cast(pc); -+ -+#ifdef DEBUG -+ // Check we have the result from a li macro-instruction. -+ Instruction* instr1 = Instruction::At((unsigned char*)(pc + 1 * kInstrSize)); -+ Instruction* instr3 = Instruction::At((unsigned char*)(pc + 3 * kInstrSize)); -+ Instruction* instr5 = Instruction::At((unsigned char*)(pc + 5 * kInstrSize)); -+ Instruction* instr7 = Instruction::At((unsigned char*)(pc + 7 * kInstrSize)); -+ DCHECK(IsLui(*reinterpret_cast(instr0)) && -+ IsAddiw(*reinterpret_cast(instr1)) && -+ IsAddi(*reinterpret_cast(instr3)) && -+ IsAddi(*reinterpret_cast(instr5)) && -+ IsAddi(*reinterpret_cast(instr7))); -+#endif -+ -+ // Must use 8 instructions to insure patchable code (see above comment). -+ *p = LUI | (rd_code << kRdShift) | -+ ((uint32_t)( -+ (target + (1LL << 47) + (1LL << 35) + (1LL << 23) + (1LL << 11)) >> -+ 48) -+ << kImm20Shift); -+ *(p + 1) = -+ OP_IMM_32 | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | -+ ((uint32_t)((target + (1LL << 35) + (1LL << 23) + (1LL << 11)) << 16 >> -+ 52) -+ << kImm12Shift); -+ *(p + 2) = OP_IMM | (rd_code << kRdShift) | (0b001 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | (12 << kImm12Shift); -+ *(p + 3) = OP_IMM | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | -+ ((uint32_t)((target + (1LL << 23) + (1LL << 11)) << 28 >> 52) -+ << kImm12Shift); -+ *(p + 4) = OP_IMM | (rd_code << kRdShift) | (0b001 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | (12 << kImm12Shift); -+ *(p + 5) = OP_IMM | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | -+ ((uint32_t)((target + (1LL << 11)) << 40 >> 52) << kImm12Shift); -+ *(p + 6) = OP_IMM | (rd_code << kRdShift) | (0b001 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | (12 << kImm12Shift); -+ *(p + 7) = OP_IMM | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | -+ (rd_code << kRs1Shift) | -+ ((uint32_t)(target << 52 >> 52) << kImm12Shift); -+ -+ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { -+ FlushInstructionCache(pc, 8 * kInstrSize); -+ } -+ DCHECK_EQ(target_address_at(pc), target); -+} -+ -+UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler) -+ : available_(assembler->GetScratchRegisterList()), -+ old_available_(*available_) {} -+ -+UseScratchRegisterScope::~UseScratchRegisterScope() { -+ *available_ = old_available_; -+} -+ -+Register UseScratchRegisterScope::Acquire() { -+ DCHECK_NOT_NULL(available_); -+ DCHECK_NE(*available_, 0); -+ int index = static_cast(base::bits::CountTrailingZeros32(*available_)); -+ *available_ &= ~(1UL << index); -+ -+ return Register::from_code(index); -+} -+ -+bool UseScratchRegisterScope::hasAvailable() const { return *available_ != 0; } -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/assembler-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/assembler-riscv64.h -@@ -0,0 +1,1110 @@ -+// Copyright (c) 1994-2006 Sun Microsystems Inc. -+// All Rights Reserved. -+// -+// Redistribution and use in source and binary forms, with or without -+// modification, are permitted provided that the following conditions are -+// met: -+// -+// - Redistributions of source code must retain the above copyright notice, -+// this list of conditions and the following disclaimer. -+// -+// - Redistribution in binary form must reproduce the above copyright -+// notice, this list of conditions and the following disclaimer in the -+// documentation and/or other materials provided with the distribution. -+// -+// - Neither the name of Sun Microsystems or the names of contributors may -+// be used to endorse or promote products derived from this software without -+// specific prior written permission. -+// -+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+// The original source code covered by the above license above has been -+// modified significantly by Google Inc. -+// Copyright 2012 the V8 project authors. All rights reserved. -+ -+#ifndef V8_CODEGEN_RISCV_ASSEMBLER_RISCV_H_ -+#define V8_CODEGEN_RISCV_ASSEMBLER_RISCV_H_ -+ -+#include -+ -+#include -+#include -+ -+#include "src/codegen/assembler.h" -+#include "src/codegen/external-reference.h" -+#include "src/codegen/label.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/codegen/riscv64/register-riscv64.h" -+#include "src/objects/contexts.h" -+#include "src/objects/smi.h" -+ -+namespace v8 { -+namespace internal { -+ -+class SafepointTableBuilder; -+ -+// ----------------------------------------------------------------------------- -+// Machine instruction Operands. -+constexpr int kSmiShift = kSmiTagSize + kSmiShiftSize; -+constexpr uint64_t kSmiShiftMask = (1UL << kSmiShift) - 1; -+// Class Operand represents a shifter operand in data processing instructions. -+class Operand { -+ public: -+ // Immediate. -+ V8_INLINE explicit Operand(int64_t immediate, -+ RelocInfo::Mode rmode = RelocInfo::NONE) -+ : rm_(no_reg), rmode_(rmode) { -+ value_.immediate = immediate; -+ } -+ V8_INLINE explicit Operand(const ExternalReference& f) -+ : rm_(no_reg), rmode_(RelocInfo::EXTERNAL_REFERENCE) { -+ value_.immediate = static_cast(f.address()); -+ } -+ V8_INLINE explicit Operand(const char* s); -+ explicit Operand(Handle handle); -+ V8_INLINE explicit Operand(Smi value) : rm_(no_reg), rmode_(RelocInfo::NONE) { -+ value_.immediate = static_cast(value.ptr()); -+ } -+ -+ static Operand EmbeddedNumber(double number); // Smi or HeapNumber. -+ static Operand EmbeddedStringConstant(const StringConstantBase* str); -+ -+ // Register. -+ V8_INLINE explicit Operand(Register rm) : rm_(rm) {} -+ -+ // Return true if this is a register operand. -+ V8_INLINE bool is_reg() const; -+ -+ inline int64_t immediate() const; -+ -+ bool IsImmediate() const { return !rm_.is_valid(); } -+ -+ HeapObjectRequest heap_object_request() const { -+ DCHECK(IsHeapObjectRequest()); -+ return value_.heap_object_request; -+ } -+ -+ bool IsHeapObjectRequest() const { -+ DCHECK_IMPLIES(is_heap_object_request_, IsImmediate()); -+ DCHECK_IMPLIES(is_heap_object_request_, -+ rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT || -+ rmode_ == RelocInfo::CODE_TARGET); -+ return is_heap_object_request_; -+ } -+ -+ Register rm() const { return rm_; } -+ -+ RelocInfo::Mode rmode() const { return rmode_; } -+ -+ private: -+ Register rm_; -+ union Value { -+ Value() {} -+ HeapObjectRequest heap_object_request; // if is_heap_object_request_ -+ int64_t immediate; // otherwise -+ } value_; // valid if rm_ == no_reg -+ bool is_heap_object_request_ = false; -+ RelocInfo::Mode rmode_; -+ -+ friend class Assembler; -+ friend class MacroAssembler; -+}; -+ -+// On RISC-V we have only one addressing mode with base_reg + offset. -+// Class MemOperand represents a memory operand in load and store instructions. -+class V8_EXPORT_PRIVATE MemOperand : public Operand { -+ public: -+ // Immediate value attached to offset. -+ enum OffsetAddend { offset_minus_one = -1, offset_zero = 0 }; -+ -+ explicit MemOperand(Register rn, int32_t offset = 0); -+ explicit MemOperand(Register rn, int32_t unit, int32_t multiplier, -+ OffsetAddend offset_addend = offset_zero); -+ int32_t offset() const { return offset_; } -+ -+ bool OffsetIsInt12Encodable() const { return is_int12(offset_); } -+ -+ private: -+ int32_t offset_; -+ -+ friend class Assembler; -+}; -+ -+class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { -+ public: -+ // Create an assembler. Instructions and relocation information are emitted -+ // into a buffer, with the instructions starting from the beginning and the -+ // relocation information starting from the end of the buffer. See CodeDesc -+ // for a detailed comment on the layout (globals.h). -+ // -+ // If the provided buffer is nullptr, the assembler allocates and grows its -+ // own buffer. Otherwise it takes ownership of the provided buffer. -+ explicit Assembler(const AssemblerOptions&, -+ std::unique_ptr = {}); -+ -+ virtual ~Assembler() {} -+ -+ // GetCode emits any pending (non-emitted) code and fills the descriptor desc. -+ static constexpr int kNoHandlerTable = 0; -+ static constexpr SafepointTableBuilder* kNoSafepointTable = nullptr; -+ void GetCode(Isolate* isolate, CodeDesc* desc, -+ SafepointTableBuilder* safepoint_table_builder, -+ int handler_table_offset); -+ -+ // Convenience wrapper for code without safepoint or handler tables. -+ void GetCode(Isolate* isolate, CodeDesc* desc) { -+ GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable); -+ } -+ -+ // Unused on this architecture. -+ void MaybeEmitOutOfLineConstantPool() {} -+ -+ // Label operations & relative jumps (PPUM Appendix D). -+ // -+ // Takes a branch opcode (cc) and a label (L) and generates -+ // either a backward branch or a forward branch and links it -+ // to the label fixup chain. Usage: -+ // -+ // Label L; // unbound label -+ // j(cc, &L); // forward branch to unbound label -+ // bind(&L); // bind label to the current pc -+ // j(cc, &L); // backward branch to bound label -+ // bind(&L); // illegal: a label may be bound only once -+ // -+ // Note: The same Label can be used for forward and backward branches -+ // but it may be bound only once. -+ void bind(Label* L); // Binds an unbound label L to current code position. -+ -+ enum OffsetSize : int { -+ kOffset21 = 21, // RISCV jal -+ kOffset12 = 12, // RISCV imm12 -+ kOffset20 = 20, // RISCV imm20 -+ kOffset13 = 13 // RISCV branch -+ }; -+ -+ // Determines if Label is bound and near enough so that branch instruction -+ // can be used to reach it, instead of jump instruction. -+ bool is_near(Label* L); -+ bool is_near(Label* L, OffsetSize bits); -+ bool is_near_branch(Label* L); -+ -+ //Get offset from instr. -+ int BranchOffset(Instr instr); -+ int BrachlongOffset(Instr auipc, Instr jalr); -+ int JumpOffset(Instr instr); -+ -+ // Returns the branch offset to the given label from the current code -+ // position. Links the label to the current position if it is still unbound. -+ // Manages the jump elimination optimization if the second parameter is true. -+ int32_t branch_offset_helper(Label* L, OffsetSize bits); -+ inline int32_t branch_offset(Label* L) { -+ return branch_offset_helper(L, OffsetSize::kOffset13); -+ } -+ inline int32_t jump_offset(Label* L) { -+ return branch_offset_helper(L, OffsetSize::kOffset21); -+ } -+ -+ uint64_t jump_address(Label* L); -+ uint64_t branch_long_offset(Label* L); -+ -+ // Puts a labels target address at the given position. -+ // The high 8 bits are set to zero. -+ void label_at_put(Label* L, int at_offset); -+ -+ // Read/Modify the code target address in the branch/call instruction at pc. -+ // The isolate argument is unused (and may be nullptr) when skipping flushing. -+ static Address target_address_at(Address pc); -+ V8_INLINE static void set_target_address_at( -+ Address pc, Address target, -+ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) { -+ set_target_value_at(pc, target, icache_flush_mode); -+ } -+ // On RISC-V there is no Constant Pool so we skip that parameter. -+ V8_INLINE static Address target_address_at(Address pc, -+ Address constant_pool) { -+ return target_address_at(pc); -+ } -+ V8_INLINE static void set_target_address_at( -+ Address pc, Address constant_pool, Address target, -+ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED) { -+ set_target_address_at(pc, target, icache_flush_mode); -+ } -+ -+ static void set_target_value_at( -+ Address pc, uint64_t target, -+ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); -+ -+ static void JumpLabelToJumpRegister(Address pc); -+ -+ // This sets the branch destination (which gets loaded at the call address). -+ // This is for calls and branches within generated code. The serializer -+ // has already deserialized the lui/ori instructions etc. -+ inline static void deserialization_set_special_target_at( -+ Address instruction_payload, Code code, Address target); -+ -+ // Get the size of the special target encoded at 'instruction_payload'. -+ inline static int deserialization_special_target_size( -+ Address instruction_payload); -+ -+ // This sets the internal reference at the pc. -+ inline static void deserialization_set_target_internal_reference_at( -+ Address pc, Address target, -+ RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE); -+ -+ // Difference between address of current opcode and target address offset. -+ static constexpr int kBranchPCOffset = kInstrSize; -+ -+ // Difference between address of current opcode and target address offset, -+ // when we are generatinga sequence of instructions for long relative PC -+ // branches -+ static constexpr int kLongBranchPCOffset = 3 * kInstrSize; -+ -+ // Adjust ra register in branch delay slot of bal instruction so to skip -+ // instructions not needed after optimization of PIC in -+ // TurboAssembler::BranchAndLink method. -+ -+ static constexpr int kOptimizedBranchAndLinkLongReturnOffset = 4 * kInstrSize; -+ -+ // Here we are patching the address in the LUI/ADDI instruction pair. -+ // These values are used in the serialization process and must be zero for -+ // RISC-V platform, as Code, Embedded Object or External-reference pointers -+ // are split across two consecutive instructions and don't exist separately -+ // in the code, so the serializer should not step forwards in memory after -+ // a target is resolved and written. -+ static constexpr int kSpecialTargetSize = 0; -+ -+ // Number of consecutive instructions used to store 32bit/64bit constant. -+ // This constant was used in RelocInfo::target_address_address() function -+ // to tell serializer address of the instruction that follows -+ // LUI/ADDI instruction pair. -+ static constexpr int kInstructionsFor32BitConstant = 2; -+ static constexpr int kInstructionsFor64BitConstant = 8; -+ -+ // Difference between address of current opcode and value read from pc -+ // register. -+ static constexpr int kPcLoadDelta = 4; -+ -+ // Bits available for offset field in branches -+ static constexpr int kBranchOffsetBits = 13; -+ -+ // Bits available for offset field in jump -+ static constexpr int kJumpOffsetBits = 21; -+ -+ // Max offset for b instructions with 12-bit offset field (multiple of 2) -+ static constexpr int kMaxBranchOffset = (1 << (13 - 1)) - 1; -+ -+ // Max offset for jal instruction with 20-bit offset field (multiple of 2) -+ static constexpr int kMaxJumpOffset = (1 << (21 - 1)) - 1; -+ -+ static constexpr int kTrampolineSlotsSize = 2 * kInstrSize; -+ -+ RegList* GetScratchRegisterList() { return &scratch_register_list_; } -+ -+ // --------------------------------------------------------------------------- -+ // Code generation. -+ -+ // Insert the smallest number of nop instructions -+ // possible to align the pc offset to a multiple -+ // of m. m must be a power of 2 (>= 4). -+ void Align(int m); -+ // Insert the smallest number of zero bytes possible to align the pc offset -+ // to a mulitple of m. m must be a power of 2 (>= 2). -+ void DataAlign(int m); -+ // Aligns code to something that's optimal for a jump target for the platform. -+ void CodeTargetAlign(); -+ -+ // Different nop operations are used by the code generator to detect certain -+ // states of the generated code. -+ enum NopMarkerTypes { -+ NON_MARKING_NOP = 0, -+ DEBUG_BREAK_NOP, -+ // IC markers. -+ PROPERTY_ACCESS_INLINED, -+ PROPERTY_ACCESS_INLINED_CONTEXT, -+ PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, -+ // Helper values. -+ LAST_CODE_MARKER, -+ FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED, -+ }; -+ -+ // RISC-V Instructions Emited to a buffer -+ -+ void lui(Register rd, int32_t imm20); -+ void auipc(Register rd, int32_t imm20); -+ -+ // Jumps -+ void jal(Register rd, int32_t imm20); -+ void jalr(Register rd, Register rs1, int16_t imm12); -+ -+ // Branches -+ void beq(Register rs1, Register rs2, int16_t imm12); -+ inline void beq(Register rs1, Register rs2, Label* L) { -+ beq(rs1, rs2, branch_offset(L)); -+ } -+ void bne(Register rs1, Register rs2, int16_t imm12); -+ inline void bne(Register rs1, Register rs2, Label* L) { -+ bne(rs1, rs2, branch_offset(L)); -+ } -+ void blt(Register rs1, Register rs2, int16_t imm12); -+ inline void blt(Register rs1, Register rs2, Label* L) { -+ blt(rs1, rs2, branch_offset(L)); -+ } -+ void bge(Register rs1, Register rs2, int16_t imm12); -+ inline void bge(Register rs1, Register rs2, Label* L) { -+ bge(rs1, rs2, branch_offset(L)); -+ } -+ void bltu(Register rs1, Register rs2, int16_t imm12); -+ inline void bltu(Register rs1, Register rs2, Label* L) { -+ bltu(rs1, rs2, branch_offset(L)); -+ } -+ void bgeu(Register rs1, Register rs2, int16_t imm12); -+ inline void bgeu(Register rs1, Register rs2, Label* L) { -+ bgeu(rs1, rs2, branch_offset(L)); -+ } -+ -+ // Loads -+ void lb(Register rd, Register rs1, int16_t imm12); -+ void lh(Register rd, Register rs1, int16_t imm12); -+ void lw(Register rd, Register rs1, int16_t imm12); -+ void lbu(Register rd, Register rs1, int16_t imm12); -+ void lhu(Register rd, Register rs1, int16_t imm12); -+ -+ // Stores -+ void sb(Register source, Register base, int16_t imm12); -+ void sh(Register source, Register base, int16_t imm12); -+ void sw(Register source, Register base, int16_t imm12); -+ -+ // Arithmetic with immediate -+ void addi(Register rd, Register rs1, int16_t imm12); -+ void slti(Register rd, Register rs1, int16_t imm12); -+ void sltiu(Register rd, Register rs1, int16_t imm12); -+ void xori(Register rd, Register rs1, int16_t imm12); -+ void ori(Register rd, Register rs1, int16_t imm12); -+ void andi(Register rd, Register rs1, int16_t imm12); -+ void slli(Register rd, Register rs1, uint8_t shamt); -+ void srli(Register rd, Register rs1, uint8_t shamt); -+ void srai(Register rd, Register rs1, uint8_t shamt); -+ -+ // Arithmetic -+ void add(Register rd, Register rs1, Register rs2); -+ void sub(Register rd, Register rs1, Register rs2); -+ void sll(Register rd, Register rs1, Register rs2); -+ void slt(Register rd, Register rs1, Register rs2); -+ void sltu(Register rd, Register rs1, Register rs2); -+ void xor_(Register rd, Register rs1, Register rs2); -+ void srl(Register rd, Register rs1, Register rs2); -+ void sra(Register rd, Register rs1, Register rs2); -+ void or_(Register rd, Register rs1, Register rs2); -+ void and_(Register rd, Register rs1, Register rs2); -+ -+ // Memory fences -+ void fence(uint8_t pred, uint8_t succ); -+ void fence_tso(); -+ -+ // Environment call / break -+ void ecall(); -+ void ebreak(); -+ -+ // This is a de facto standard (as set by GNU binutils) 32-bit unimplemented -+ // instruction (i.e., it should always trap, if your implementation has -+ // invalid instruction traps). -+ void unimp(); -+ -+ // CSR -+ void csrrw(Register rd, ControlStatusReg csr, Register rs1); -+ void csrrs(Register rd, ControlStatusReg csr, Register rs1); -+ void csrrc(Register rd, ControlStatusReg csr, Register rs1); -+ void csrrwi(Register rd, ControlStatusReg csr, uint8_t imm5); -+ void csrrsi(Register rd, ControlStatusReg csr, uint8_t imm5); -+ void csrrci(Register rd, ControlStatusReg csr, uint8_t imm5); -+ -+ // RV64I -+ void lwu(Register rd, Register rs1, int16_t imm12); -+ void ld(Register rd, Register rs1, int16_t imm12); -+ void sd(Register source, Register base, int16_t imm12); -+ void addiw(Register rd, Register rs1, int16_t imm12); -+ void slliw(Register rd, Register rs1, uint8_t shamt); -+ void srliw(Register rd, Register rs1, uint8_t shamt); -+ void sraiw(Register rd, Register rs1, uint8_t shamt); -+ void addw(Register rd, Register rs1, Register rs2); -+ void subw(Register rd, Register rs1, Register rs2); -+ void sllw(Register rd, Register rs1, Register rs2); -+ void srlw(Register rd, Register rs1, Register rs2); -+ void sraw(Register rd, Register rs1, Register rs2); -+ -+ // RV32M Standard Extension -+ void mul(Register rd, Register rs1, Register rs2); -+ void mulh(Register rd, Register rs1, Register rs2); -+ void mulhsu(Register rd, Register rs1, Register rs2); -+ void mulhu(Register rd, Register rs1, Register rs2); -+ void div(Register rd, Register rs1, Register rs2); -+ void divu(Register rd, Register rs1, Register rs2); -+ void rem(Register rd, Register rs1, Register rs2); -+ void remu(Register rd, Register rs1, Register rs2); -+ -+ // RV64M Standard Extension (in addition to RV32M) -+ void mulw(Register rd, Register rs1, Register rs2); -+ void divw(Register rd, Register rs1, Register rs2); -+ void divuw(Register rd, Register rs1, Register rs2); -+ void remw(Register rd, Register rs1, Register rs2); -+ void remuw(Register rd, Register rs1, Register rs2); -+ -+ // RV32A Standard Extension -+ void lr_w(bool aq, bool rl, Register rd, Register rs1); -+ void sc_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoswap_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoadd_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoxor_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoand_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoor_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amomin_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amomax_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amominu_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amomaxu_w(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ -+ // RV64A Standard Extension (in addition to RV32A) -+ void lr_d(bool aq, bool rl, Register rd, Register rs1); -+ void sc_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoswap_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoadd_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoxor_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoand_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amoor_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amomin_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amomax_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amominu_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ void amomaxu_d(bool aq, bool rl, Register rd, Register rs1, Register rs2); -+ -+ // RV32F Standard Extension -+ void flw(FPURegister rd, Register rs1, int16_t imm12); -+ void fsw(FPURegister source, Register base, int16_t imm12); -+ void fmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fnmsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fnmadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fadd_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fsub_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fmul_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fdiv_s(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fsqrt_s(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fsgnj_s(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fsgnjn_s(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fsgnjx_s(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fmin_s(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fmax_s(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fcvt_w_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_wu_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fmv_x_w(Register rd, FPURegister rs1); -+ void feq_s(Register rd, FPURegister rs1, FPURegister rs2); -+ void flt_s(Register rd, FPURegister rs1, FPURegister rs2); -+ void fle_s(Register rd, FPURegister rs1, FPURegister rs2); -+ void fclass_s(Register rd, FPURegister rs1); -+ void fcvt_s_w(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ void fcvt_s_wu(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ void fmv_w_x(FPURegister rd, Register rs1); -+ -+ // RV64F Standard Extension (in addition to RV32F) -+ void fcvt_l_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_lu_s(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_s_l(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ void fcvt_s_lu(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ -+ // RV32D Standard Extension -+ void fld(FPURegister rd, Register rs1, int16_t imm12); -+ void fsd(FPURegister source, Register base, int16_t imm12); -+ void fmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fnmsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fnmadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ FPURegister rs3, RoundingMode frm = RNE); -+ void fadd_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fsub_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fmul_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fdiv_d(FPURegister rd, FPURegister rs1, FPURegister rs2, -+ RoundingMode frm = RNE); -+ void fsqrt_d(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fsgnj_d(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fsgnjn_d(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fsgnjx_d(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fmin_d(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fmax_d(FPURegister rd, FPURegister rs1, FPURegister rs2); -+ void fcvt_s_d(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_d_s(FPURegister rd, FPURegister rs1, RoundingMode frm = RNE); -+ void feq_d(Register rd, FPURegister rs1, FPURegister rs2); -+ void flt_d(Register rd, FPURegister rs1, FPURegister rs2); -+ void fle_d(Register rd, FPURegister rs1, FPURegister rs2); -+ void fclass_d(Register rd, FPURegister rs1); -+ void fcvt_w_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_wu_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_d_w(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ void fcvt_d_wu(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ -+ // RV64D Standard Extension (in addition to RV32D) -+ void fcvt_l_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fcvt_lu_d(Register rd, FPURegister rs1, RoundingMode frm = RNE); -+ void fmv_x_d(Register rd, FPURegister rs1); -+ void fcvt_d_l(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ void fcvt_d_lu(FPURegister rd, Register rs1, RoundingMode frm = RNE); -+ void fmv_d_x(FPURegister rd, Register rs1); -+ -+ // Privileged -+ void uret(); -+ void sret(); -+ void mret(); -+ void wfi(); -+ void sfence_vma(Register rs1, Register rs2); -+ -+ // Assembler Pseudo Instructions (Tables 25.2, 25.3, RISC-V Unprivileged ISA) -+ void nop(); -+ void RV_li(Register rd, int64_t imm); -+ // Returns the number of instructions required to load the immediate -+ static int li_count(int64_t imm); -+ // Loads an immediate, always using 8 instructions, regardless of the value, -+ // so that it can be modified later. -+ void li_constant(Register rd, int64_t imm); -+ -+ void mv(Register rd, Register rs) { addi(rd, rs, 0); } -+ void not_(Register rd, Register rs) { xori(rd, rs, -1); } -+ void neg(Register rd, Register rs) { sub(rd, zero_reg, rs); } -+ void negw(Register rd, Register rs) { subw(rd, zero_reg, rs); } -+ void sext_w(Register rd, Register rs) { addiw(rd, rs, 0); } -+ void seqz(Register rd, Register rs) { sltiu(rd, rs, 1); } -+ void snez(Register rd, Register rs) { sltu(rd, zero_reg, rs); } -+ void sltz(Register rd, Register rs) { slt(rd, rs, zero_reg); } -+ void sgtz(Register rd, Register rs) { slt(rd, zero_reg, rs); } -+ -+ void fmv_s(FPURegister rd, FPURegister rs) { fsgnj_s(rd, rs, rs); } -+ void fabs_s(FPURegister rd, FPURegister rs) { fsgnjx_s(rd, rs, rs); } -+ void fneg_s(FPURegister rd, FPURegister rs) { fsgnjn_s(rd, rs, rs); } -+ void fmv_d(FPURegister rd, FPURegister rs) { fsgnj_d(rd, rs, rs); } -+ void fabs_d(FPURegister rd, FPURegister rs) { fsgnjx_d(rd, rs, rs); } -+ void fneg_d(FPURegister rd, FPURegister rs) { fsgnjn_d(rd, rs, rs); } -+ -+ void beqz(Register rs, int16_t imm13) { beq(rs, zero_reg, imm13); } -+ inline void beqz(Register rs1, Label* L) { beqz(rs1, branch_offset(L)); } -+ void bnez(Register rs, int16_t imm13) { bne(rs, zero_reg, imm13); } -+ inline void bnez(Register rs1, Label* L) { bnez(rs1, branch_offset(L)); } -+ void blez(Register rs, int16_t imm13) { bge(zero_reg, rs, imm13); } -+ inline void blez(Register rs1, Label* L) { blez(rs1, branch_offset(L)); } -+ void bgez(Register rs, int16_t imm13) { bge(rs, zero_reg, imm13); } -+ inline void bgez(Register rs1, Label* L) { bgez(rs1, branch_offset(L)); } -+ void bltz(Register rs, int16_t imm13) { blt(rs, zero_reg, imm13); } -+ inline void bltz(Register rs1, Label* L) { bltz(rs1, branch_offset(L)); } -+ void bgtz(Register rs, int16_t imm13) { blt(zero_reg, rs, imm13); } -+ -+ inline void bgtz(Register rs1, Label* L) { bgtz(rs1, branch_offset(L)); } -+ void bgt(Register rs1, Register rs2, int16_t imm13) { blt(rs2, rs1, imm13); } -+ inline void bgt(Register rs1, Register rs2, Label* L) { -+ bgt(rs1, rs2, branch_offset(L)); -+ } -+ void ble(Register rs1, Register rs2, int16_t imm13) { bge(rs2, rs1, imm13); } -+ inline void ble(Register rs1, Register rs2, Label* L) { -+ ble(rs1, rs2, branch_offset(L)); -+ } -+ void bgtu(Register rs1, Register rs2, int16_t imm13) { -+ bltu(rs2, rs1, imm13); -+ } -+ inline void bgtu(Register rs1, Register rs2, Label* L) { -+ bgtu(rs1, rs2, branch_offset(L)); -+ } -+ void bleu(Register rs1, Register rs2, int16_t imm13) { -+ bgeu(rs2, rs1, imm13); -+ } -+ inline void bleu(Register rs1, Register rs2, Label* L) { -+ bleu(rs1, rs2, branch_offset(L)); -+ } -+ -+ // TODO: Replace uses of ToRegister with names once they are properly defined -+ void j(int32_t imm21) { jal(zero_reg, imm21); } -+ inline void j(Label* L) { j(jump_offset(L)); } -+ void jal(int32_t imm21) { jal(ToRegister(1), imm21); } -+ inline void jal(Label* L) { jal(jump_offset(L)); } -+ void jr(Register rs) { jalr(zero_reg, rs, 0); } -+ void jr(Register rs, int32_t imm12) { jalr(zero_reg, rs, imm12); } -+ void jalr(Register rs, int32_t imm12) { jalr(ToRegister(1), rs, imm12); } -+ void jalr(Register rs) { jalr(ToRegister(1), rs, 0); } -+ void ret() { jalr(zero_reg, ToRegister(1), 0); } -+ void call(int32_t offset) { -+ auipc(ToRegister(1), (offset >> 12) + ((offset & 0x800) >> 11)); -+ jalr(ToRegister(1), ToRegister(1), offset << 20 >> 20); -+ } -+ -+ // Read instructions-retired counter -+ void rdinstret(Register rd) { csrrs(rd, csr_instret, zero_reg); } -+ void rdinstreth(Register rd) { csrrs(rd, csr_instreth, zero_reg); } -+ void rdcycle(Register rd) { csrrs(rd, csr_cycle, zero_reg); } -+ void rdcycleh(Register rd) { csrrs(rd, csr_cycleh, zero_reg); } -+ void rdtime(Register rd) { csrrs(rd, csr_time, zero_reg); } -+ void rdtimeh(Register rd) { csrrs(rd, csr_timeh, zero_reg); } -+ -+ void csrr(Register rd, ControlStatusReg csr) { csrrs(rd, csr, zero_reg); } -+ void csrw(ControlStatusReg csr, Register rs) { csrrw(zero_reg, csr, rs); } -+ void csrs(ControlStatusReg csr, Register rs) { csrrs(zero_reg, csr, rs); } -+ void csrc(ControlStatusReg csr, Register rs) { csrrc(zero_reg, csr, rs); } -+ -+ void csrwi(ControlStatusReg csr, uint8_t imm) { csrrwi(zero_reg, csr, imm); } -+ void csrsi(ControlStatusReg csr, uint8_t imm) { csrrsi(zero_reg, csr, imm); } -+ void csrci(ControlStatusReg csr, uint8_t imm) { csrrci(zero_reg, csr, imm); } -+ -+ void frcsr(Register rd) { csrrs(rd, csr_fcsr, zero_reg); } -+ void fscsr(Register rd, Register rs) { csrrw(rd, csr_fcsr, rs); } -+ void fscsr(Register rs) { csrrw(zero_reg, csr_fcsr, rs); } -+ -+ void frrm(Register rd) { csrrs(rd, csr_frm, zero_reg); } -+ void fsrm(Register rd, Register rs) { csrrw(rd, csr_frm, rs); } -+ void fsrm(Register rs) { csrrw(zero_reg, csr_frm, rs); } -+ -+ void frflags(Register rd) { csrrs(rd, csr_fflags, zero_reg); } -+ void fsflags(Register rd, Register rs) { csrrw(rd, csr_fflags, rs); } -+ void fsflags(Register rs) { csrrw(zero_reg, csr_fflags, rs); } -+ -+ // Other pseudo instructions that are not part of RISCV pseudo assemly -+ void nor(Register rd, Register rs, Register rt) { -+ or_(rd, rs, rt); -+ not_(rd, rd); -+ } -+ -+ void sync() { fence(0b1111, 0b1111); } -+ void break_(uint32_t code, bool break_as_stop = false); -+ void stop(uint32_t code = kMaxStopCode); -+ -+ // Check the code size generated from label to here. -+ int SizeOfCodeGeneratedSince(Label* label) { -+ return pc_offset() - label->pos(); -+ } -+ -+ // Check the number of instructions generated from label to here. -+ int InstructionsGeneratedSince(Label* label) { -+ return SizeOfCodeGeneratedSince(label) / kInstrSize; -+ } -+ -+ // Class for scoping postponing the trampoline pool generation. -+ class BlockTrampolinePoolScope { -+ public: -+ explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) { -+ assem_->StartBlockTrampolinePool(); -+ } -+ ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); } -+ -+ private: -+ Assembler* assem_; -+ -+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope); -+ }; -+ -+ // Class for postponing the assembly buffer growth. Typically used for -+ // sequences of instructions that must be emitted as a unit, before -+ // buffer growth (and relocation) can occur. -+ // This blocking scope is not nestable. -+ class BlockGrowBufferScope { -+ public: -+ explicit BlockGrowBufferScope(Assembler* assem) : assem_(assem) { -+ assem_->StartBlockGrowBuffer(); -+ } -+ ~BlockGrowBufferScope() { assem_->EndBlockGrowBuffer(); } -+ -+ private: -+ Assembler* assem_; -+ -+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope); -+ }; -+ -+ // Record a deoptimization reason that can be used by a log or cpu profiler. -+ // Use --trace-deopt to enable. -+ void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position, -+ int id); -+ -+ static int RelocateInternalReference(RelocInfo::Mode rmode, Address pc, -+ intptr_t pc_delta); -+ -+ // Writes a single byte or word of data in the code stream. Used for -+ // inline tables, e.g., jump-tables. -+ void db(uint8_t data); -+ void dd(uint32_t data); -+ void dq(uint64_t data); -+ void dp(uintptr_t data) { dq(data); } -+ void dd(Label* label); -+ -+ // Postpone the generation of the trampoline pool for the specified number of -+ // instructions. -+ void BlockTrampolinePoolFor(int instructions); -+ -+ // Check if there is less than kGap bytes available in the buffer. -+ // If this is the case, we need to grow the buffer before emitting -+ // an instruction or relocation information. -+ inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } -+ -+ // Get the number of bytes available in the buffer. -+ inline intptr_t available_space() const { -+ return reloc_info_writer.pos() - pc_; -+ } -+ -+ // Read/patch instructions. -+ static Instr instr_at(Address pc) { return *reinterpret_cast(pc); } -+ static void instr_at_put(Address pc, Instr instr) { -+ *reinterpret_cast(pc) = instr; -+ } -+ Instr instr_at(int pos) { -+ return *reinterpret_cast(buffer_start_ + pos); -+ } -+ void instr_at_put(int pos, Instr instr) { -+ *reinterpret_cast(buffer_start_ + pos) = instr; -+ } -+ -+ // Check if an instruction is a branch of some kind. -+ static bool IsBranch(Instr instr); -+ static bool IsJump(Instr instr); -+ static bool IsJal(Instr instr); -+ static bool IsJalr(Instr instr); -+ static bool IsLui(Instr instr); -+ static bool IsAuipc(Instr instr); -+ static bool IsAddiw(Instr instr); -+ static bool IsAddi(Instr instr); -+ static bool IsSlli(Instr instr); -+ -+ void CheckTrampolinePool(); -+ -+ inline int UnboundLabelsCount() { return unbound_labels_count_; } -+ -+ protected: -+ // Readable constants for base and offset adjustment helper, these indicate if -+ // aside from offset, another value like offset + 4 should fit into int16. -+ enum class OffsetAccessType : bool { -+ SINGLE_ACCESS = false, -+ TWO_ACCESSES = true -+ }; -+ -+ // Determine whether need to adjust base and offset of memroy load/store -+ bool NeedAdjustBaseAndOffset( -+ const MemOperand& src, OffsetAccessType = OffsetAccessType::SINGLE_ACCESS, -+ int second_Access_add_to_offset = 4); -+ -+ // Helper function for memory load/store using base register and offset. -+ void AdjustBaseAndOffset( -+ MemOperand* src, Register scratch, -+ OffsetAccessType access_type = OffsetAccessType::SINGLE_ACCESS, -+ int second_access_add_to_offset = 4); -+ -+ inline static void set_target_internal_reference_encoded_at(Address pc, -+ Address target); -+ -+ int64_t buffer_space() const { return reloc_info_writer.pos() - pc_; } -+ -+ // Decode branch instruction at pos and return branch target pos. -+ int target_at(int pos, bool is_internal); -+ -+ // Patch branch instruction at pos to branch to given branch target pos. -+ void target_at_put(int pos, int target_pos, bool is_internal); -+ -+ // Say if we need to relocate with this mode. -+ bool MustUseReg(RelocInfo::Mode rmode); -+ -+ // Record reloc info for current pc_. -+ void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); -+ -+ // Block the emission of the trampoline pool before pc_offset. -+ void BlockTrampolinePoolBefore(int pc_offset) { -+ if (no_trampoline_pool_before_ < pc_offset) -+ no_trampoline_pool_before_ = pc_offset; -+ } -+ -+ void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; } -+ -+ void EndBlockTrampolinePool() { -+ trampoline_pool_blocked_nesting_--; -+ if (trampoline_pool_blocked_nesting_ == 0) { -+ CheckTrampolinePoolQuick(1); -+ } -+ } -+ -+ bool is_trampoline_pool_blocked() const { -+ return trampoline_pool_blocked_nesting_ > 0; -+ } -+ -+ bool has_exception() const { return internal_trampoline_exception_; } -+ -+ bool is_trampoline_emitted() const { return trampoline_emitted_; } -+ -+ // Temporarily block automatic assembly buffer growth. -+ void StartBlockGrowBuffer() { -+ DCHECK(!block_buffer_growth_); -+ block_buffer_growth_ = true; -+ } -+ -+ void EndBlockGrowBuffer() { -+ DCHECK(block_buffer_growth_); -+ block_buffer_growth_ = false; -+ } -+ -+ bool is_buffer_growth_blocked() const { return block_buffer_growth_; } -+ -+ void CheckTrampolinePoolQuick(int extra_instructions = 0) { -+ if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) { -+ CheckTrampolinePool(); -+ } -+ } -+ -+ private: -+ // Avoid overflows for displacements etc. -+ static const int kMaximalBufferSize = 512 * MB; -+ -+ // Buffer size and constant pool distance are checked together at regular -+ // intervals of kBufferCheckInterval emitted bytes. -+ static constexpr int kBufferCheckInterval = 1 * KB / 2; -+ -+ // Code generation. -+ // The relocation writer's position is at least kGap bytes below the end of -+ // the generated instructions. This is so that multi-instruction sequences do -+ // not have to check for overflow. The same is true for writes of large -+ // relocation info entries. -+ static constexpr int kGap = 64; -+ STATIC_ASSERT(AssemblerBase::kMinimalBufferSize >= 2 * kGap); -+ -+ // Repeated checking whether the trampoline pool should be emitted is rather -+ // expensive. By default we only check again once a number of instructions -+ // has been generated. -+ static constexpr int kCheckConstIntervalInst = 32; -+ static constexpr int kCheckConstInterval = -+ kCheckConstIntervalInst * kInstrSize; -+ -+ int next_buffer_check_; // pc offset of next buffer check. -+ -+ // Emission of the trampoline pool may be blocked in some code sequences. -+ int trampoline_pool_blocked_nesting_; // Block emission if this is not zero. -+ int no_trampoline_pool_before_; // Block emission before this pc offset. -+ -+ // Keep track of the last emitted pool to guarantee a maximal distance. -+ int last_trampoline_pool_end_; // pc offset of the end of the last pool. -+ -+ // Automatic growth of the assembly buffer may be blocked for some sequences. -+ bool block_buffer_growth_; // Block growth when true. -+ -+ // Relocation information generation. -+ // Each relocation is encoded as a variable size value. -+ static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize; -+ RelocInfoWriter reloc_info_writer; -+ -+ // The bound position, before this we cannot do instruction elimination. -+ int last_bound_pos_; -+ -+ // Code emission. -+ inline void CheckBuffer(); -+ void GrowBuffer(); -+ inline void emit(Instr x); -+ inline void emit(uint64_t x); -+ template -+ inline void EmitHelper(T x); -+ -+ static void disassembleInstr(Instr instr); -+ -+ // Instruction generation. -+ -+ // ----- Top-level instruction formats match those in the ISA manual -+ // (R, I, S, B, U, J). These match the formats defined in LLVM's -+ // RISCVInstrFormats.td. -+ void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd, -+ Register rs1, Register rs2); -+ void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd, -+ FPURegister rs1, FPURegister rs2); -+ void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd, -+ FPURegister rs1, Register rs2); -+ void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd, -+ Register rs1, Register rs2); -+ void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, FPURegister rd, -+ FPURegister rs1, Register rs2); -+ void GenInstrR(uint8_t funct7, uint8_t funct3, Opcode opcode, Register rd, -+ FPURegister rs1, FPURegister rs2); -+ void GenInstrR4(uint8_t funct2, Opcode opcode, Register rd, Register rs1, -+ Register rs2, Register rs3, RoundingMode frm); -+ void GenInstrR4(uint8_t funct2, Opcode opcode, FPURegister rd, -+ FPURegister rs1, FPURegister rs2, FPURegister rs3, -+ RoundingMode frm); -+ void GenInstrRAtomic(uint8_t funct5, bool aq, bool rl, uint8_t funct3, -+ Register rd, Register rs1, Register rs2); -+ void GenInstrRFrm(uint8_t funct7, Opcode opcode, Register rd, Register rs1, -+ Register rs2, RoundingMode frm); -+ void GenInstrI(uint8_t funct3, Opcode opcode, Register rd, Register rs1, -+ int16_t imm12); -+ void GenInstrI(uint8_t funct3, Opcode opcode, FPURegister rd, Register rs1, -+ int16_t imm12); -+ void GenInstrIShift(bool arithshift, uint8_t funct3, Opcode opcode, -+ Register rd, Register rs1, uint8_t shamt); -+ void GenInstrIShiftW(bool arithshift, uint8_t funct3, Opcode opcode, -+ Register rd, Register rs1, uint8_t shamt); -+ void GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, Register rs2, -+ int16_t imm12); -+ void GenInstrS(uint8_t funct3, Opcode opcode, Register rs1, FPURegister rs2, -+ int16_t imm12); -+ void GenInstrB(uint8_t funct3, Opcode opcode, Register rs1, Register rs2, -+ int16_t imm12); -+ void GenInstrU(Opcode opcode, Register rd, int32_t imm20); -+ void GenInstrJ(Opcode opcode, Register rd, int32_t imm20); -+ -+ // ----- Instruction class templates match those in LLVM's RISCVInstrInfo.td -+ void GenInstrBranchCC_rri(uint8_t funct3, Register rs1, Register rs2, -+ int16_t imm12); -+ void GenInstrLoad_ri(uint8_t funct3, Register rd, Register rs1, -+ int16_t imm12); -+ void GenInstrStore_rri(uint8_t funct3, Register rs1, Register rs2, -+ int16_t imm12); -+ void GenInstrALU_ri(uint8_t funct3, Register rd, Register rs1, int16_t imm12); -+ void GenInstrShift_ri(bool arithshift, uint8_t funct3, Register rd, -+ Register rs1, uint8_t shamt); -+ void GenInstrALU_rr(uint8_t funct7, uint8_t funct3, Register rd, Register rs1, -+ Register rs2); -+ void GenInstrCSR_ir(uint8_t funct3, Register rd, ControlStatusReg csr, -+ Register rs1); -+ void GenInstrCSR_ii(uint8_t funct3, Register rd, ControlStatusReg csr, -+ uint8_t rs1); -+ void GenInstrShiftW_ri(bool arithshift, uint8_t funct3, Register rd, -+ Register rs1, uint8_t shamt); -+ void GenInstrALUW_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ Register rs1, Register rs2); -+ void GenInstrPriv(uint8_t funct7, Register rs1, Register rs2); -+ void GenInstrLoadFP_ri(uint8_t funct3, FPURegister rd, Register rs1, -+ int16_t imm12); -+ void GenInstrStoreFP_rri(uint8_t funct3, Register rs1, FPURegister rs2, -+ int16_t imm12); -+ void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, -+ FPURegister rs1, FPURegister rs2); -+ void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, -+ Register rs1, Register rs2); -+ void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, FPURegister rd, -+ FPURegister rs1, Register rs2); -+ void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ FPURegister rs1, Register rs2); -+ void GenInstrALUFP_rr(uint8_t funct7, uint8_t funct3, Register rd, -+ FPURegister rs1, FPURegister rs2); -+ -+ // Labels. -+ void print(const Label* L); -+ void bind_to(Label* L, int pos); -+ void next(Label* L, bool is_internal); -+ -+ // One trampoline consists of: -+ // - space for trampoline slots, -+ // - space for labels. -+ // -+ // Space for trampoline slots is equal to slot_count * 2 * kInstrSize. -+ // Space for trampoline slots precedes space for labels. Each label is of one -+ // instruction size, so total amount for labels is equal to -+ // label_count * kInstrSize. -+ class Trampoline { -+ public: -+ Trampoline() { -+ start_ = 0; -+ next_slot_ = 0; -+ free_slot_count_ = 0; -+ end_ = 0; -+ } -+ Trampoline(int start, int slot_count) { -+ start_ = start; -+ next_slot_ = start; -+ free_slot_count_ = slot_count; -+ end_ = start + slot_count * kTrampolineSlotsSize; -+ } -+ int start() { return start_; } -+ int end() { return end_; } -+ int take_slot() { -+ int trampoline_slot = kInvalidSlotPos; -+ if (free_slot_count_ <= 0) { -+ // We have run out of space on trampolines. -+ // Make sure we fail in debug mode, so we become aware of each case -+ // when this happens. -+ DCHECK(0); -+ // Internal exception will be caught. -+ } else { -+ trampoline_slot = next_slot_; -+ free_slot_count_--; -+ next_slot_ += kTrampolineSlotsSize; -+ } -+ return trampoline_slot; -+ } -+ -+ private: -+ int start_; -+ int end_; -+ int next_slot_; -+ int free_slot_count_; -+ }; -+ -+ int32_t get_trampoline_entry(int32_t pos); -+ int unbound_labels_count_; -+ // After trampoline is emitted, long branches are used in generated code for -+ // the forward branches whose target offsets could be beyond reach of branch -+ // instruction. We use this information to trigger different mode of -+ // branch instruction generation, where we use jump instructions rather -+ // than regular branch instructions. -+ bool trampoline_emitted_ = false; -+ static constexpr int kInvalidSlotPos = -1; -+ -+ // Internal reference positions, required for unbounded internal reference -+ // labels. -+ std::set internal_reference_positions_; -+ bool is_internal_reference(Label* L) { -+ return internal_reference_positions_.find(L->pos()) != -+ internal_reference_positions_.end(); -+ } -+ -+ Trampoline trampoline_; -+ bool internal_trampoline_exception_; -+ -+ RegList scratch_register_list_; -+ -+ private: -+ void AllocateAndInstallRequestedHeapObjects(Isolate* isolate); -+ -+ int WriteCodeComments(); -+ -+ friend class RegExpMacroAssemblerRISCV; -+ friend class RelocInfo; -+ friend class BlockTrampolinePoolScope; -+ friend class EnsureSpace; -+}; -+ -+class EnsureSpace { -+ public: -+ explicit inline EnsureSpace(Assembler* assembler); -+}; -+ -+class V8_EXPORT_PRIVATE UseScratchRegisterScope { -+ public: -+ explicit UseScratchRegisterScope(Assembler* assembler); -+ ~UseScratchRegisterScope(); -+ -+ Register Acquire(); -+ bool hasAvailable() const; -+ -+ private: -+ RegList* available_; -+ RegList old_available_; -+}; -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_CODEGEN_RISCV_ASSEMBLER_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/constants-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/constants-riscv64.cc -@@ -0,0 +1,111 @@ -+// Copyright 2011 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. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/codegen/riscv64/constants-riscv64.h" -+ -+namespace v8 { -+namespace internal { -+ -+// ----------------------------------------------------------------------------- -+// Registers. -+ -+// These register names are defined in a way to match the native disassembler -+// formatting. See for example the command "objdump -d ". -+const char* Registers::names_[kNumSimuRegisters] = { -+ "zero_reg", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0", -+ "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", -+ "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}; -+ -+// List of alias names which can be used when referring to RISC-V registers. -+const Registers::RegisterAlias Registers::aliases_[] = { -+ {0, "zero"}, -+ {33, "pc"}, -+ {8, "s0"}, -+ {8, "s0_fp"}, -+ {kInvalidRegister, nullptr}}; -+ -+const char* Registers::Name(int reg) { -+ const char* result; -+ if ((0 <= reg) && (reg < kNumSimuRegisters)) { -+ result = names_[reg]; -+ } else { -+ result = "noreg"; -+ } -+ return result; -+} -+ -+int Registers::Number(const char* name) { -+ // Look through the canonical names. -+ for (int i = 0; i < kNumSimuRegisters; i++) { -+ if (strcmp(names_[i], name) == 0) { -+ return i; -+ } -+ } -+ -+ // Look through the alias names. -+ int i = 0; -+ while (aliases_[i].reg != kInvalidRegister) { -+ if (strcmp(aliases_[i].name, name) == 0) { -+ return aliases_[i].reg; -+ } -+ i++; -+ } -+ -+ // No register with the reguested name found. -+ return kInvalidRegister; -+} -+ -+/* -+const char* FPURegisters::names_[kNumFPURegisters] = { -+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", -+ "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", -+ "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; -+*/ -+const char* FPURegisters::names_[kNumFPURegisters] = { -+ "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", -+ "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", -+ "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", -+ "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"}; -+ -+// List of alias names which can be used when referring to RISC-V FP registers. -+const FPURegisters::RegisterAlias FPURegisters::aliases_[] = { -+ {kInvalidRegister, nullptr}}; -+ -+const char* FPURegisters::Name(int creg) { -+ const char* result; -+ if ((0 <= creg) && (creg < kNumFPURegisters)) { -+ result = names_[creg]; -+ } else { -+ result = "nocreg"; -+ } -+ return result; -+} -+ -+int FPURegisters::Number(const char* name) { -+ // Look through the canonical names. -+ for (int i = 0; i < kNumFPURegisters; i++) { -+ if (strcmp(names_[i], name) == 0) { -+ return i; -+ } -+ } -+ -+ // Look through the alias names. -+ int i = 0; -+ while (aliases_[i].creg != kInvalidRegister) { -+ if (strcmp(aliases_[i].name, name) == 0) { -+ return aliases_[i].creg; -+ } -+ i++; -+ } -+ -+ // No Cregister with the reguested name found. -+ return kInvalidFPURegister; -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/constants-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/constants-riscv64.h -@@ -0,0 +1,947 @@ -+// Copyright 2012 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. -+ -+#ifndef V8_CODEGEN_RISCV_CONSTANTS_RISCV_H_ -+#define V8_CODEGEN_RISCV_CONSTANTS_RISCV_H_ -+ -+#include "src/base/logging.h" -+#include "src/base/macros.h" -+#include "src/common/globals.h" -+ -+// UNIMPLEMENTED_ macro for RISCV. -+#ifdef DEBUG -+#define UNIMPLEMENTED_RISCV() \ -+ v8::internal::PrintF("%s, \tline %d: \tfunction %s not implemented. \n", \ -+ __FILE__, __LINE__, __func__) -+#else -+#define UNIMPLEMENTED_RISCV() -+#endif -+ -+#define UNSUPPORTED_RISCV() v8::internal::PrintF("Unsupported instruction.\n") -+ -+enum Endianness { kLittle, kBig }; -+ -+#if defined(V8_TARGET_LITTLE_ENDIAN) -+static const Endianness kArchEndian = kLittle; -+#elif defined(V8_TARGET_BIG_ENDIAN) -+static const Endianness kArchEndian = kBig; -+#else -+#error Unknown endianness -+#endif -+ -+#if defined(V8_TARGET_LITTLE_ENDIAN) -+const uint32_t kLeastSignificantByteInInt32Offset = 0; -+const uint32_t kLessSignificantWordInDoublewordOffset = 0; -+#elif defined(V8_TARGET_BIG_ENDIAN) -+const uint32_t kLeastSignificantByteInInt32Offset = 3; -+const uint32_t kLessSignificantWordInDoublewordOffset = 4; -+#else -+#error Unknown endianness -+#endif -+ -+#ifndef __STDC_FORMAT_MACROS -+#define __STDC_FORMAT_MACROS -+#endif -+#include -+ -+// Defines constants and accessor classes to assemble, disassemble and -+// simulate RISC-V instructions. -+// -+// See: The RISC-V Instruction Set Manual -+// Volume I: User-Level ISA -+// Try https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf. -+ -+namespace v8 { -+namespace internal { -+ -+// TODO(sigurds): Change this value once we use relative jumps. -+constexpr size_t kMaxPCRelativeCodeRangeInMB = 0; -+ -+// ----------------------------------------------------------------------------- -+// Registers and FPURegisters. -+ -+// Number of general purpose registers. -+const int kNumRegisters = 32; -+const int kInvalidRegister = -1; -+ -+// Number of registers with pc. -+const int kNumSimuRegisters = 33; -+ -+// In the simulator, the PC register is simulated as the 34th register. -+const int kPCRegister = 34; -+ -+// Number coprocessor registers. -+const int kNumFPURegisters = 32; -+const int kInvalidFPURegister = -1; -+ -+// 'pref' instruction hints -+const int32_t kPrefHintLoad = 0; -+const int32_t kPrefHintStore = 1; -+const int32_t kPrefHintLoadStreamed = 4; -+const int32_t kPrefHintStoreStreamed = 5; -+const int32_t kPrefHintLoadRetained = 6; -+const int32_t kPrefHintStoreRetained = 7; -+const int32_t kPrefHintWritebackInvalidate = 25; -+const int32_t kPrefHintPrepareForStore = 30; -+ -+// Actual value of root register is offset from the root array's start -+// to take advantage of negative displacement values. -+// TODO(sigurds): Choose best value. -+constexpr int kRootRegisterBias = 256; -+ -+// Helper functions for converting between register numbers and names. -+class Registers { -+ public: -+ // Return the name of the register. -+ static const char* Name(int reg); -+ -+ // Lookup the register number for the name provided. -+ static int Number(const char* name); -+ -+ struct RegisterAlias { -+ int reg; -+ const char* name; -+ }; -+ -+ static const int64_t kMaxValue = 0x7fffffffffffffffl; -+ static const int64_t kMinValue = 0x8000000000000000l; -+ -+ private: -+ static const char* names_[kNumSimuRegisters]; -+ static const RegisterAlias aliases_[]; -+}; -+ -+// Helper functions for converting between register numbers and names. -+class FPURegisters { -+ public: -+ // Return the name of the register. -+ static const char* Name(int reg); -+ -+ // Lookup the register number for the name provided. -+ static int Number(const char* name); -+ -+ struct RegisterAlias { -+ int creg; -+ const char* name; -+ }; -+ -+ private: -+ static const char* names_[kNumFPURegisters]; -+ static const RegisterAlias aliases_[]; -+}; -+ -+// ----------------------------------------------------------------------------- -+// Instructions encoding constants. -+ -+// On RISCV all instructions are 32 bits. -+using Instr = int32_t; -+ -+// Special Software Interrupt codes when used in the presence of the RISC-V -+// simulator. -+enum SoftwareInterruptCodes { -+ // Transition to C code. -+ call_rt_redirected = 0xfffff -+}; -+ -+// On RISC-V Simulator breakpoints can have different codes: -+// - Breaks between 0 and kMaxWatchpointCode are treated as simple watchpoints, -+// the simulator will run through them and print the registers. -+// - Breaks between kMaxWatchpointCode and kMaxStopCode are treated as stop() -+// instructions (see Assembler::stop()). -+// - Breaks larger than kMaxStopCode are simple breaks, dropping you into the -+// debugger. -+const uint32_t kMaxWatchpointCode = 31; -+const uint32_t kMaxStopCode = 127; -+STATIC_ASSERT(kMaxWatchpointCode < kMaxStopCode); -+ -+// ----- Fields offset and length. -+// RISCV constants -+const int kBaseOpcodeShift = 0; -+const int kBaseOpcodeBits = 7; -+const int kFunct7Shift = 25; -+const int kFunct7Bits = 7; -+const int kFunct5Shift = 27; -+const int kFunct5Bits = 5; -+const int kFunct3Shift = 12; -+const int kFunct3Bits = 3; -+const int kFunct2Shift = 25; -+const int kFunct2Bits = 2; -+const int kRs1Shift = 15; -+const int kRs1Bits = 5; -+const int kRs2Shift = 20; -+const int kRs2Bits = 5; -+const int kRs3Shift = 27; -+const int kRs3Bits = 5; -+const int kRdShift = 7; -+const int kRdBits = 5; -+const int kRlShift = 25; -+const int kAqShift = 26; -+const int kImm12Shift = 20; -+const int kImm12Bits = 12; -+const int kShamtShift = 20; -+const int kShamtBits = 5; -+const int kShamtWShift = 20; -+const int kShamtWBits = 6; -+const int kArithShiftShift = 30; -+const int kImm20Shift = 12; -+const int kImm20Bits = 20; -+const int kCsrShift = 20; -+const int kCsrBits = 12; -+const int kMemOrderBits = 4; -+const int kPredOrderShift = 24; -+const int kSuccOrderShift = 20; -+ -+// RISCV Instruction bit masks -+const uint32_t kBaseOpcodeMask = ((1 << kBaseOpcodeBits) - 1) << kBaseOpcodeShift; -+const uint32_t kFunct3Mask = ((1 << kFunct3Bits) - 1) << kFunct3Shift; -+const uint32_t kFunct5Mask = ((1 << kFunct5Bits) - 1) << kFunct5Shift; -+const uint32_t kFunct7Mask = ((1 << kFunct7Bits) - 1) << kFunct7Shift; -+const uint32_t kFunct2Mask = 0b11 << kFunct7Shift; -+const uint32_t kRTypeMask = kBaseOpcodeMask | kFunct3Mask | kFunct7Mask; -+const uint32_t kRATypeMask = kBaseOpcodeMask | kFunct3Mask | kFunct5Mask; -+const uint32_t kRFPTypeMask = kBaseOpcodeMask | kFunct7Mask; -+const uint32_t kR4TypeMask = kBaseOpcodeMask | kFunct3Mask | kFunct2Mask; -+const uint32_t kITypeMask = kBaseOpcodeMask | kFunct3Mask; -+const uint32_t kSTypeMask = kBaseOpcodeMask | kFunct3Mask; -+const uint32_t kBTypeMask = kBaseOpcodeMask | kFunct3Mask; -+const uint32_t kUTypeMask = kBaseOpcodeMask; -+const uint32_t kJTypeMask = kBaseOpcodeMask; -+const uint32_t kRs1FieldMask = ((1 << kRs1Bits) - 1) << kRs1Shift; -+const uint32_t kRs2FieldMask = ((1 << kRs2Bits) - 1) << kRs2Shift; -+const uint32_t kRs3FieldMask = ((1 << kRs3Bits) - 1) << kRs3Shift; -+const uint32_t kRdFieldMask = ((1 << kRdBits) - 1) << kRdShift; -+const uint32_t kBImm12Mask = kFunct7Mask | kRdFieldMask; -+const uint32_t kImm20Mask = ((1 << kImm20Bits) - 1) << kImm20Shift; -+const uint32_t kImm12Mask = ((1 << kImm12Bits) - 1) << kImm12Shift; -+ -+// RISCV CSR related bit mask and shift -+const uint32_t kFcsrFlagsBits = 5; -+const uint32_t kFcsrFlagsMask = (1 << kFcsrFlagsBits) - 1; -+const uint32_t kFcsrFrmBits = 3; -+const uint32_t kFcsrFrmShift = kFcsrFlagsBits; -+const uint32_t kFcsrFrmMask = ((1 << kFcsrFrmBits) - 1) << kFcsrFrmShift; -+const uint32_t kFcsrBits = kFcsrFlagsBits + kFcsrFrmBits; -+const uint32_t kFcsrMask = kFcsrFlagsMask | kFcsrFrmMask; -+ -+// Original MIPS constants -+// FIXME (RISCV): to be cleaned up -+const uint32_t kImm16Shift = 0; -+const uint32_t kImm16Bits = 16; -+const uint32_t kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift; -+// end of FIXME (RISCV): to be cleaned up -+ -+// ----- RISCV Base Opcodes -+ -+enum BaseOpcode : uint32_t { -+ -+}; -+ -+// ----- RISC-V Opcodes and Function Fields. -+enum Opcode : uint32_t { -+ LOAD = 0b0000011, // I form: LB LH LW LBU LHU -+ LOAD_FP = 0b0000111, // I form: FLW FLD FLQ -+ MISC_MEM = 0b0001111, // I special form: FENCE FENCE.I -+ OP_IMM = 0b0010011, // I form: ADDI SLTI SLTIU XORI ORI ANDI SLLI SRLI SARI -+ // Note: SLLI/SRLI/SRAI I form first, then func3 001/101 => R type -+ AUIPC = 0b0010111, // U form: AUIPC -+ OP_IMM_32 = 0b0011011, // I form: ADDIW SLLIW SRLIW SRAIW -+ // Note: SRLIW SRAIW I form first, then func3 101 special shift encoding -+ STORE = 0b0100011, // S form: SB SH SW SD -+ STORE_FP = 0b0100111, // S form: FSW FSD FSQ -+ AMO = 0b0101111, // R form: All A instructions -+ OP = 0b0110011, // R: ADD SUB SLL SLT SLTU XOR SRL SRA OR AND and 32M set -+ LUI = 0b0110111, // U form: LUI -+ OP_32 = 0b0111011, // R: ADDW SUBW SLLW SRLW SRAW MULW DIVW DIVUW REMW REMUW -+ MADD = 0b1000011, // R4 type: FMADD.S FMADD.D FMADD.Q -+ MSUB = 0b1000111, // R4 type: FMSUB.S FMSUB.D FMSUB.Q -+ NMSUB = 0b1001011, // R4 type: FNMSUB.S FNMSUB.D FNMSUB.Q -+ NMADD = 0b1001111, // R4 type: FNMADD.S FNMADD.D FNMADD.Q -+ OP_FP = 0b1010011, // R type: Q ext -+ BRANCH = 0b1100011, // B form: BEQ BNE, BLT, BGE, BLTU BGEU -+ JALR = 0b1100111, // I form: JALR -+ JAL = 0b1101111, // J form: JAL -+ SYSTEM = 0b1110011, // I form: ECALL EBREAK Zicsr ext -+ -+ // Note use RO (RiscV Opcode) prefix -+ // RV32I Base Instruction Set -+ RO_LUI = LUI, -+ RO_AUIPC = AUIPC, -+ RO_JAL = JAL, -+ RO_JALR = JALR | (0b000 << kFunct3Shift), -+ RO_BEQ = BRANCH | (0b000 << kFunct3Shift), -+ RO_BNE = BRANCH | (0b001 << kFunct3Shift), -+ RO_BLT = BRANCH | (0b100 << kFunct3Shift), -+ RO_BGE = BRANCH | (0b101 << kFunct3Shift), -+ RO_BLTU = BRANCH | (0b110 << kFunct3Shift), -+ RO_BGEU = BRANCH | (0b111 << kFunct3Shift), -+ RO_LB = LOAD | (0b000 << kFunct3Shift), -+ RO_LH = LOAD | (0b001 << kFunct3Shift), -+ RO_LW = LOAD | (0b010 << kFunct3Shift), -+ RO_LBU = LOAD | (0b100 << kFunct3Shift), -+ RO_LHU = LOAD | (0b101 << kFunct3Shift), -+ RO_SB = STORE | (0b000 << kFunct3Shift), -+ RO_SH = STORE | (0b001 << kFunct3Shift), -+ RO_SW = STORE | (0b010 << kFunct3Shift), -+ RO_ADDI = OP_IMM | (0b000 << kFunct3Shift), -+ RO_SLTI = OP_IMM | (0b010 << kFunct3Shift), -+ RO_SLTIU = OP_IMM | (0b011 << kFunct3Shift), -+ RO_XORI = OP_IMM | (0b100 << kFunct3Shift), -+ RO_ORI = OP_IMM | (0b110 << kFunct3Shift), -+ RO_ANDI = OP_IMM | (0b111 << kFunct3Shift), -+ RO_SLLI = OP_IMM | (0b001 << kFunct3Shift), -+ RO_SRLI = OP_IMM | (0b101 << kFunct3Shift), -+ // RO_SRAI = OP_IMM | (0b101 << kFunct3Shift), // Same as SRLI, use func7 -+ RO_ADD = OP | (0b000 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SUB = OP | (0b000 << kFunct3Shift) | (0b0100000 << kFunct7Shift), -+ RO_SLL = OP | (0b001 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SLT = OP | (0b010 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SLTU = OP | (0b011 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_XOR = OP | (0b100 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SRL = OP | (0b101 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SRA = OP | (0b101 << kFunct3Shift) | (0b0100000 << kFunct7Shift), -+ RO_OR = OP | (0b110 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_AND = OP | (0b111 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_FENCE = MISC_MEM | (0b000 << kFunct3Shift), -+ RO_ECALL = SYSTEM | (0b000 << kFunct3Shift), -+ // RO_EBREAK = SYSTEM | (0b000 << kFunct3Shift), // Same as ECALL, use imm12 -+ -+ // RV64I Base Instruction Set (in addition to RV32I) -+ RO_LWU = LOAD | (0b110 << kFunct3Shift), -+ RO_LD = LOAD | (0b011 << kFunct3Shift), -+ RO_SD = STORE | (0b011 << kFunct3Shift), -+ RO_ADDIW = OP_IMM_32 | (0b000 << kFunct3Shift), -+ RO_SLLIW = OP_IMM_32 | (0b001 << kFunct3Shift), -+ RO_SRLIW = OP_IMM_32 | (0b101 << kFunct3Shift), -+ // RO_SRAIW = OP_IMM_32 | (0b101 << kFunct3Shift), // Same as SRLIW, use func7 -+ RO_ADDW = OP_32 | (0b000 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SUBW = OP_32 | (0b000 << kFunct3Shift) | (0b0100000 << kFunct7Shift), -+ RO_SLLW = OP_32 | (0b001 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SRLW = OP_32 | (0b101 << kFunct3Shift) | (0b0000000 << kFunct7Shift), -+ RO_SRAW = OP_32 | (0b101 << kFunct3Shift) | (0b0100000 << kFunct7Shift), -+ -+ // RV32/RV64 Zifencei Standard Extension -+ RO_FENCE_I = MISC_MEM | (0b001 << kFunct3Shift), -+ -+ // RV32/RV64 Zicsr Standard Extension -+ RO_CSRRW = SYSTEM | (0b001 << kFunct3Shift), -+ RO_CSRRS = SYSTEM | (0b010 << kFunct3Shift), -+ RO_CSRRC = SYSTEM | (0b011 << kFunct3Shift), -+ RO_CSRRWI = SYSTEM | (0b101 << kFunct3Shift), -+ RO_CSRRSI = SYSTEM | (0b110 << kFunct3Shift), -+ RO_CSRRCI = SYSTEM | (0b111 << kFunct3Shift), -+ -+ // RV32M Standard Extension -+ RO_MUL = OP | (0b000 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_MULH = OP | (0b001 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_MULHSU = OP | (0b010 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_MULHU = OP | (0b011 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_DIV = OP | (0b100 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_DIVU = OP | (0b101 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_REM = OP | (0b110 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_REMU = OP | (0b111 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ -+ // RV64M Standard Extension (in addition to RV32M) -+ RO_MULW = OP_32 | (0b000 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_DIVW = OP_32 | (0b100 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_DIVUW = OP_32 | (0b101 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_REMW = OP_32 | (0b110 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ RO_REMUW = OP_32 | (0b111 << kFunct3Shift) | (0b0000001 << kFunct7Shift), -+ -+ // RV32A Standard Extension -+ RO_LR_W = AMO | (0b010 << kFunct3Shift) | (0b00010 << kFunct5Shift), -+ RO_SC_W = AMO | (0b010 << kFunct3Shift) | (0b00011 << kFunct5Shift), -+ RO_AMOSWAP_W = AMO | (0b010 << kFunct3Shift) | (0b00001 << kFunct5Shift), -+ RO_AMOADD_W = AMO | (0b010 << kFunct3Shift) | (0b00000 << kFunct5Shift), -+ RO_AMOXOR_W = AMO | (0b010 << kFunct3Shift) | (0b00100 << kFunct5Shift), -+ RO_AMOAND_W = AMO | (0b010 << kFunct3Shift) | (0b01100 << kFunct5Shift), -+ RO_AMOOR_W = AMO | (0b010 << kFunct3Shift) | (0b01000 << kFunct5Shift), -+ RO_AMOMIN_W = AMO | (0b010 << kFunct3Shift) | (0b10000 << kFunct5Shift), -+ RO_AMOMAX_W = AMO | (0b010 << kFunct3Shift) | (0b10100 << kFunct5Shift), -+ RO_AMOMINU_W = AMO | (0b010 << kFunct3Shift) | (0b11000 << kFunct5Shift), -+ RO_AMOMAXU_W = AMO | (0b010 << kFunct3Shift) | (0b11100 << kFunct5Shift), -+ -+ // RV64A Standard Extension (in addition to RV32A) -+ RO_LR_D = AMO | (0b011 << kFunct3Shift) | (0b00010 << kFunct5Shift), -+ RO_SC_D = AMO | (0b011 << kFunct3Shift) | (0b00011 << kFunct5Shift), -+ RO_AMOSWAP_D = AMO | (0b011 << kFunct3Shift) | (0b00001 << kFunct5Shift), -+ RO_AMOADD_D = AMO | (0b011 << kFunct3Shift) | (0b00000 << kFunct5Shift), -+ RO_AMOXOR_D = AMO | (0b011 << kFunct3Shift) | (0b00100 << kFunct5Shift), -+ RO_AMOAND_D = AMO | (0b011 << kFunct3Shift) | (0b01100 << kFunct5Shift), -+ RO_AMOOR_D = AMO | (0b011 << kFunct3Shift) | (0b01000 << kFunct5Shift), -+ RO_AMOMIN_D = AMO | (0b011 << kFunct3Shift) | (0b10000 << kFunct5Shift), -+ RO_AMOMAX_D = AMO | (0b011 << kFunct3Shift) | (0b10100 << kFunct5Shift), -+ RO_AMOMINU_D = AMO | (0b011 << kFunct3Shift) | (0b11000 << kFunct5Shift), -+ RO_AMOMAXU_D = AMO | (0b011 << kFunct3Shift) | (0b11100 << kFunct5Shift), -+ -+ // RV32F Standard Extension -+ RO_FLW = LOAD_FP | (0b010 << kFunct3Shift), -+ RO_FSW = STORE_FP | (0b010 << kFunct3Shift), -+ RO_FMADD_S = MADD | (0b00 << kFunct2Shift), -+ RO_FMSUB_S = MSUB | (0b00 << kFunct2Shift), -+ RO_FNMSUB_S = NMSUB | (0b00 << kFunct2Shift), -+ RO_FNMADD_S = NMADD | (0b00 << kFunct2Shift), -+ RO_FADD_S = OP_FP | (0b0000000 << kFunct7Shift), -+ RO_FSUB_S = OP_FP | (0b0000100 << kFunct7Shift), -+ RO_FMUL_S = OP_FP | (0b0001000 << kFunct7Shift), -+ RO_FDIV_S = OP_FP | (0b0001100 << kFunct7Shift), -+ RO_FSQRT_S = OP_FP | (0b0101100 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FSGNJ_S = OP_FP | (0b000 << kFunct3Shift) | (0b0010000 << kFunct7Shift), -+ RO_FSGNJN_S = OP_FP | (0b001 << kFunct3Shift) | (0b0010000 << kFunct7Shift), -+ RO_FSQNJX_S = OP_FP | (0b010 << kFunct3Shift) | (0b0010000 << kFunct7Shift), -+ RO_FMIN_S = OP_FP | (0b000 << kFunct3Shift) | (0b0010100 << kFunct7Shift), -+ RO_FMAX_S = OP_FP | (0b001 << kFunct3Shift) | (0b0010100 << kFunct7Shift), -+ RO_FCVT_W_S = OP_FP | (0b1100000 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FCVT_WU_S = OP_FP | (0b1100000 << kFunct7Shift) | (0b00001 << kRs2Shift), -+ RO_FMV = OP_FP | (0b1110000 << kFunct7Shift) | (0b000 << kFunct3Shift) | -+ (0b00000 << kRs2Shift), -+ RO_FEQ_S = OP_FP | (0b010 << kFunct3Shift) | (0b1010000 << kFunct7Shift), -+ RO_FLT_S = OP_FP | (0b001 << kFunct3Shift) | (0b1010000 << kFunct7Shift), -+ RO_FLE_S = OP_FP | (0b000 << kFunct3Shift) | (0b1010000 << kFunct7Shift), -+ RO_FCLASS_S = OP_FP | (0b001 << kFunct3Shift) | (0b1110000 << kFunct7Shift), -+ RO_FCVT_S_W = OP_FP | (0b1101000 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FCVT_S_WU = OP_FP | (0b1101000 << kFunct7Shift) | (0b00001 << kRs2Shift), -+ RO_FMV_W_X = OP_FP | (0b000 << kFunct3Shift) | (0b1111000 << kFunct7Shift), -+ -+ // RV64F Standard Extension (in addition to RV32F) -+ RO_FCVT_L_S = OP_FP | (0b1100000 << kFunct7Shift) | (0b00010 << kRs2Shift), -+ RO_FCVT_LU_S = OP_FP | (0b1100000 << kFunct7Shift) | (0b00011 << kRs2Shift), -+ RO_FCVT_S_L = OP_FP | (0b1101000 << kFunct7Shift) | (0b00010 << kRs2Shift), -+ RO_FCVT_S_LU = OP_FP | (0b1101000 << kFunct7Shift) | (0b00011 << kRs2Shift), -+ -+ // RV32D Standard Extension -+ RO_FLD = LOAD_FP | (0b011 << kFunct3Shift), -+ RO_FSD = STORE_FP | (0b011 << kFunct3Shift), -+ RO_FMADD_D = MADD | (0b01 << kFunct2Shift), -+ RO_FMSUB_D = MSUB | (0b01 << kFunct2Shift), -+ RO_FNMSUB_D = NMSUB | (0b01 << kFunct2Shift), -+ RO_FNMADD_D = NMADD | (0b01 << kFunct2Shift), -+ RO_FADD_D = OP_FP | (0b0000001 << kFunct7Shift), -+ RO_FSUB_D = OP_FP | (0b0000101 << kFunct7Shift), -+ RO_FMUL_D = OP_FP | (0b0001001 << kFunct7Shift), -+ RO_FDIV_D = OP_FP | (0b0001101 << kFunct7Shift), -+ RO_FSQRT_D = OP_FP | (0b0101101 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FSGNJ_D = OP_FP | (0b000 << kFunct3Shift) | (0b0010001 << kFunct7Shift), -+ RO_FSGNJN_D = OP_FP | (0b001 << kFunct3Shift) | (0b0010001 << kFunct7Shift), -+ RO_FSQNJX_D = OP_FP | (0b010 << kFunct3Shift) | (0b0010001 << kFunct7Shift), -+ RO_FMIN_D = OP_FP | (0b000 << kFunct3Shift) | (0b0010101 << kFunct7Shift), -+ RO_FMAX_D = OP_FP | (0b001 << kFunct3Shift) | (0b0010101 << kFunct7Shift), -+ RO_FCVT_S_D = OP_FP | (0b0100000 << kFunct7Shift) | (0b00001 << kRs2Shift), -+ RO_FCVT_D_S = OP_FP | (0b0100001 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FEQ_D = OP_FP | (0b010 << kFunct3Shift) | (0b1010001 << kFunct7Shift), -+ RO_FLT_D = OP_FP | (0b001 << kFunct3Shift) | (0b1010001 << kFunct7Shift), -+ RO_FLE_D = OP_FP | (0b000 << kFunct3Shift) | (0b1010001 << kFunct7Shift), -+ RO_FCLASS_D = OP_FP | (0b001 << kFunct3Shift) | (0b1110001 << kFunct7Shift) | -+ (0b00000 << kRs2Shift), -+ RO_FCVT_W_D = OP_FP | (0b1100001 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FCVT_WU_D = OP_FP | (0b1100001 << kFunct7Shift) | (0b00001 << kRs2Shift), -+ RO_FCVT_D_W = OP_FP | (0b1101001 << kFunct7Shift) | (0b00000 << kRs2Shift), -+ RO_FCVT_D_WU = OP_FP | (0b1101001 << kFunct7Shift) | (0b00001 << kRs2Shift), -+ -+ // RV64D Standard Extension (in addition to RV32D) -+ RO_FCVT_L_D = OP_FP | (0b1100001 << kFunct7Shift) | (0b00010 << kRs2Shift), -+ RO_FCVT_LU_D = OP_FP | (0b1100001 << kFunct7Shift) | (0b00011 << kRs2Shift), -+ RO_FMV_X_D = OP_FP | (0b000 << kFunct3Shift) | (0b1110001 << kFunct7Shift) | -+ (0b00000 << kRs2Shift), -+ RO_FCVT_D_L = OP_FP | (0b1101001 << kFunct7Shift) | (0b00010 << kRs2Shift), -+ RO_FCVT_D_LU = OP_FP | (0b1101001 << kFunct7Shift) | (0b00011 << kRs2Shift), -+ RO_FMV_D_X = OP_FP | (0b000 << kFunct3Shift) | (0b1111001 << kFunct7Shift) | -+ (0b00000 << kRs2Shift), -+}; -+ -+// ----- Emulated conditions. -+// On RISC-V we use this enum to abstract from conditional branch instructions. -+// The 'U' prefix is used to specify unsigned comparisons. -+// Opposite conditions must be paired as odd/even numbers -+// because 'NegateCondition' function flips LSB to negate condition. -+enum Condition { // Any value < 0 is considered no_condition. -+ kNoCondition = -1, -+ overflow = 0, -+ no_overflow = 1, -+ Uless = 2, -+ Ugreater_equal = 3, -+ Uless_equal = 4, -+ Ugreater = 5, -+ equal = 6, -+ not_equal = 7, // Unordered or Not Equal. -+ less = 8, -+ greater_equal = 9, -+ less_equal = 10, -+ greater = 11, -+ cc_always = 12, -+ -+ // Aliases. -+ eq = equal, -+ ne = not_equal, -+ ge = greater_equal, -+ lt = less, -+ gt = greater, -+ le = less_equal, -+ al = cc_always, -+ ult = Uless, -+ uge = Ugreater_equal, -+ ule = Uless_equal, -+ ugt = Ugreater, -+}; -+ -+// Returns the equivalent of !cc. -+// Negation of the default kNoCondition (-1) results in a non-default -+// no_condition value (-2). As long as tests for no_condition check -+// for condition < 0, this will work as expected. -+inline Condition NegateCondition(Condition cc) { -+ DCHECK(cc != cc_always); -+ return static_cast(cc ^ 1); -+} -+ -+inline Condition NegateFpuCondition(Condition cc) { -+ DCHECK(cc != cc_always); -+ switch (cc) { -+ case ult: -+ return ge; -+ case ugt: -+ return le; -+ case uge: -+ return lt; -+ case ule: -+ return gt; -+ case lt: -+ return uge; -+ case gt: -+ return ule; -+ case ge: -+ return ult; -+ case le: -+ return ugt; -+ case eq: -+ return ne; -+ case ne: -+ return eq; -+ default: -+ return cc; -+ } -+} -+ -+// ----- Coprocessor conditions. -+enum FPUCondition { -+ kNoFPUCondition = -1, -+ EQ = 0x02, // Ordered and Equal -+ NE = 0x03, // Unordered or Not Equal -+ LT = 0x04, // Ordered and Less Than -+ GE = 0x05, // Ordered and Greater Than or Equal -+ LE = 0x06, // Ordered and Less Than or Equal -+ GT = 0x07, // Ordered and Greater Than -+}; -+ -+enum CheckForInexactConversion { -+ kCheckForInexactConversion, -+ kDontCheckForInexactConversion -+}; -+ -+enum class MaxMinKind : int { kMin = 0, kMax = 1 }; -+ -+// ---------------------------------------------------------------------------- -+// RISCV flags -+ -+enum ControlStatusReg { -+ csr_fflags = 0x001, // Floating-Point Accrued Exceptions (RW) -+ csr_frm = 0x002, // Floating-Point Dynamic Rounding Mode (RW) -+ csr_fcsr = 0x003, // Floating-Point Control and Status Register (RW) -+ csr_cycle = 0xc00, // Cycle counter for RDCYCLE instruction (RO) -+ csr_time = 0xc01, // Timer for RDTIME instruction (RO) -+ csr_instret = 0xc02, // Insns-retired counter for RDINSTRET instruction (RO) -+ csr_cycleh = 0xc80, // Upper 32 bits of cycle, RV32I only (RO) -+ csr_timeh = 0xc81, // Upper 32 bits of time, RV32I only (RO) -+ csr_instreth = 0xc82 // Upper 32 bits of instret, RV32I only (RO) -+}; -+ -+enum FFlagsMask { -+ kInvalidOperation = 0b10000, // NV: Invalid -+ kDivideByZero = 0b1000, // DZ: Divide by Zero -+ kOverflow = 0b100, // OF: Overflow -+ kUnderflow = 0b10, // UF: Underflow -+ kInexact = 0b1 // NX: Inexact -+}; -+ -+enum RoundingMode { -+ RNE = 0b000, // Round to Nearest, ties to Even -+ RTZ = 0b001, // Round towards Zero -+ RDN = 0b010, // Round Down (towards -infinity) -+ RUP = 0b011, // Round Up (towards +infinity) -+ RMM = 0b100, // Round to Nearest, tiest to Max Magnitude -+ DYN = 0b111 // In instruction's rm field, selects dynamic rounding mode; -+ // In Rounding Mode register, Invalid -+}; -+ -+enum MemoryOdering { -+ PSI = 0b1000, // PI or SI -+ PSO = 0b0100, // PO or SO -+ PSR = 0b0010, // PR or SR -+ PSW = 0b0001, // PW or SW -+ PSIORW = PSI | PSO | PSR | PSW -+}; -+ -+enum FClassFlag { -+ kNegativeInfinity = 1, -+ kNegativeNormalNumber = 1 << 1, -+ kNegativeSubnormalNumber = 1 << 2, -+ kNegativeZero = 1 << 3, -+ kPositiveZero = 1 << 4, -+ kPositiveSubnormalNumber = 1 << 5, -+ kPositiveNormalNumber = 1 << 6, -+ kPositiveInfinity = 1 << 7, -+ kSignalingNaN = 1 << 8, -+ kQuietNaN = 1 << 9 -+}; -+ -+// ----------------------------------------------------------------------------- -+// Hints. -+ -+// Branch hints are not used on RISC-V. They are defined so that they can -+// appear in shared function signatures, but will be ignored in RISC-V -+// implementations. -+enum Hint { no_hint = 0 }; -+ -+inline Hint NegateHint(Hint hint) { return no_hint; } -+ -+// ----------------------------------------------------------------------------- -+// Specific instructions, constants, and masks. -+// These constants are declared in assembler-riscv64.cc, as they use named -+// registers and other constants. -+ -+// An ECALL instruction, used for redirected real time call -+const Instr rtCallRedirInstr = SYSTEM; // All other bits are 0s (i.e., ecall) -+// An EBreak instruction, used for debugging and semi-hosting -+const Instr kBreakInstr = SYSTEM | 1 << kImm12Shift; // ebreak -+ -+constexpr uint8_t kInstrSize = 4; -+constexpr uint8_t kInstrSizeLog2 = 2; -+ -+class InstructionBase { -+ public: -+ enum { -+ // On RISC-V, PC cannot actually be directly accessed. We behave as if PC -+ // was always the value of the current instruction being executed. -+ kPCReadOffset = 0 -+ }; -+ -+ // Instruction type. -+ enum Type { -+ kRType, -+ kR4Type, // Special R4 for Q extension -+ kIType, -+ kSType, -+ kBType, -+ kUType, -+ kJType, -+ kUnsupported = -1 -+ }; -+ -+ // Get the raw instruction bits. -+ inline Instr InstructionBits() const { -+ return *reinterpret_cast(this); -+ } -+ -+ // Set the raw instruction bits to value. -+ inline void SetInstructionBits(Instr value) { -+ *reinterpret_cast(this) = value; -+ } -+ -+ // Read one particular bit out of the instruction bits. -+ inline int Bit(int nr) const { return (InstructionBits() >> nr) & 1; } -+ -+ // Read a bit field out of the instruction bits. -+ inline int Bits(int hi, int lo) const { -+ return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1); -+ } -+ -+ // Accessors for the different named fields used in the RISC-V encoding. -+ inline Opcode BaseOpcodeValue() const { -+ return static_cast( -+ Bits(kBaseOpcodeShift + kBaseOpcodeBits - 1, kBaseOpcodeShift)); -+ } -+ -+ // Return the fields at their original place in the instruction encoding. -+ inline Opcode BaseOpcodeFieldRaw() const { -+ return static_cast(InstructionBits() & kBaseOpcodeMask); -+ } -+ -+ // Safe to call within R-type instructions -+ inline int Funct7FieldRaw() const { return InstructionBits() & kFunct7Mask; } -+ -+ // Safe to call within R-, I-, S-, or B-type instructions -+ inline int Funct3FieldRaw() const { return InstructionBits() & kFunct3Mask; } -+ -+ // Safe to call within R-, I-, S-, or B-type instructions -+ inline int Rs1FieldRawNoAssert() const { -+ return InstructionBits() & kRs1FieldMask; -+ } -+ -+ // Safe to call within R-, S-, or B-type instructions -+ inline int Rs2FieldRawNoAssert() const { -+ return InstructionBits() & kRs2FieldMask; -+ } -+ -+ // Safe to call within R4-type instructions -+ inline int Rs3FieldRawNoAssert() const { -+ return InstructionBits() & kRs3FieldMask; -+ } -+ -+ inline int32_t ITypeBits() const { return InstructionBits() & kITypeMask; } -+ -+ // Get the encoding type of the instruction. -+ inline Type InstructionType() const; -+ -+ protected: -+ InstructionBase() {} -+}; -+ -+template -+class InstructionGetters : public T { -+ public: -+ inline int BaseOpcode() const { -+ return this->InstructionBits() & kBaseOpcodeMask; -+ } -+ -+ inline int Rs1Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kRType || -+ this->InstructionType() == InstructionBase::kR4Type || -+ this->InstructionType() == InstructionBase::kIType || -+ this->InstructionType() == InstructionBase::kSType || -+ this->InstructionType() == InstructionBase::kBType); -+ return this->Bits(kRs1Shift + kRs1Bits - 1, kRs1Shift); -+ } -+ -+ inline int Rs2Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kRType || -+ this->InstructionType() == InstructionBase::kR4Type || -+ this->InstructionType() == InstructionBase::kSType || -+ this->InstructionType() == InstructionBase::kBType); -+ return this->Bits(kRs2Shift + kRs2Bits - 1, kRs2Shift); -+ } -+ -+ inline int Rs3Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kR4Type); -+ return this->Bits(kRs3Shift + kRs3Bits - 1, kRs3Shift); -+ } -+ -+ inline int RdValue() const { -+ DCHECK(this->InstructionType() == InstructionBase::kRType || -+ this->InstructionType() == InstructionBase::kR4Type || -+ this->InstructionType() == InstructionBase::kIType || -+ this->InstructionType() == InstructionBase::kUType || -+ this->InstructionType() == InstructionBase::kJType); -+ return this->Bits(kRdShift + kRdBits - 1, kRdShift); -+ } -+ -+ inline int Funct7Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kRType); -+ return this->Bits(kFunct7Shift + kFunct7Bits - 1, kFunct7Shift); -+ } -+ -+ inline int Funct3Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kRType || -+ this->InstructionType() == InstructionBase::kIType || -+ this->InstructionType() == InstructionBase::kSType || -+ this->InstructionType() == InstructionBase::kBType); -+ return this->Bits(kFunct3Shift + kFunct3Bits - 1, kFunct3Shift); -+ } -+ -+ inline int Funct5Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kRType && -+ this->BaseOpcode() == OP_FP); -+ return this->Bits(kFunct5Shift + kFunct5Bits - 1, kFunct5Shift); -+ } -+ -+ inline int CsrValue() const { -+ DCHECK(this->InstructionType() == InstructionBase::kIType && -+ this->BaseOpcode() == SYSTEM); -+ return (this->Bits(kCsrShift + kCsrBits - 1, kCsrShift)); -+ } -+ -+ inline int RoundMode() const { -+ DCHECK((this->InstructionType() == InstructionBase::kRType || -+ this->InstructionType() == InstructionBase::kR4Type) && -+ this->BaseOpcode() == OP_FP); -+ return this->Bits(kFunct3Shift + kFunct3Bits - 1, kFunct3Shift); -+ } -+ -+ inline int MemoryOrder(bool is_pred) const { -+ DCHECK((this->InstructionType() == InstructionBase::kIType && -+ this->BaseOpcode() == MISC_MEM)); -+ if (is_pred) { -+ return this->Bits(kPredOrderShift + kMemOrderBits - 1, kPredOrderShift); -+ } else { -+ return this->Bits(kSuccOrderShift + kMemOrderBits - 1, kSuccOrderShift); -+ } -+ } -+ -+ inline int Imm12Value() const { -+ DCHECK(this->InstructionType() == InstructionBase::kIType); -+ int Value = this->Bits(kImm12Shift + kImm12Bits - 1, kImm12Shift); -+ return Value << 20 >> 20; -+ } -+ -+ inline int32_t Imm12SExtValue() const { -+ int32_t Value = this->Imm12Value() << 20 >> 20; -+ return Value; -+ } -+ -+ inline int BranchOffset() const { -+ DCHECK(this->InstructionType() == InstructionBase::kBType); -+ // | imm[12|10:5] | rs2 | rs1 | funct3 | imm[4:1|11] | opcode | -+ // 31 25 11 7 -+ uint32_t Bits = this->InstructionBits(); -+ int16_t imm13 = ((Bits & 0xf00) >> 7) | ((Bits & 0x7e000000) >> 20) | -+ ((Bits & 0x80) << 4) | ((Bits & 0x80000000) >> 19); -+ return imm13 << 19 >> 19; -+ } -+ -+ inline int StoreOffset() const { -+ DCHECK(this->InstructionType() == InstructionBase::kSType); -+ // | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | -+ // 31 25 11 7 -+ uint32_t Bits = this->InstructionBits(); -+ int16_t imm12 = ((Bits & 0xf80) >> 7) | ((Bits & 0xfe000000) >> 20); -+ return imm12 << 20 >> 20; -+ } -+ -+ inline int Imm20UValue() const { -+ DCHECK(this->InstructionType() == InstructionBase::kUType); -+ // | imm[31:12] | rd | opcode | -+ // 31 12 -+ int32_t Bits = this->InstructionBits(); -+ return Bits >> 12; -+ } -+ -+ inline int Imm20JValue() const { -+ DCHECK(this->InstructionType() == InstructionBase::kJType); -+ // | imm[20|10:1|11|19:12] | rd | opcode | -+ // 31 12 -+ uint32_t Bits = this->InstructionBits(); -+ int32_t imm20 = ((Bits & 0x7fe00000) >> 20) | ((Bits & 0x100000) >> 9) | -+ (Bits & 0xff000) | ((Bits & 0x80000000) >> 11); -+ return imm20 << 11 >> 11; -+ } -+ -+ inline bool IsArithShift() const { -+ // Valid only for right shift operations -+ DCHECK((this->BaseOpcode() == OP || this->BaseOpcode() == OP_32 || -+ this->BaseOpcode() == OP_IMM || this->BaseOpcode() == OP_IMM_32) && -+ this->Funct3Value() == 0b101); -+ return this->InstructionBits() & 0x40000000; -+ } -+ -+ inline int Shamt() const { -+ // Valid only for shift instructions (SLLI, SRLI, SRAI) -+ DCHECK((this->InstructionBits() & kBaseOpcodeMask) == OP_IMM && -+ (this->Funct3Value() == 0b001 || this->Funct3Value() == 0b101)); -+ // | 0A0000 | shamt | rs1 | funct3 | rd | opcode | -+ // 31 25 20 -+ return this->Bits(kImm12Shift + 5, kImm12Shift); -+ } -+ -+ inline int Shamt32() const { -+ // Valid only for shift instructions (SLLIW, SRLIW, SRAIW) -+ DCHECK((this->InstructionBits() & kBaseOpcodeMask) == OP_IMM_32 && -+ (this->Funct3Value() == 0b001 || this->Funct3Value() == 0b101)); -+ // | 0A00000 | shamt | rs1 | funct3 | rd | opcode | -+ // 31 24 20 -+ return this->Bits(kImm12Shift + 4, kImm12Shift); -+ } -+ -+ inline bool AqValue() const { return this->Bits(kAqShift, kAqShift); } -+ -+ inline bool RlValue() const { return this->Bits(kRlShift, kRlShift); } -+ -+ // Say if the instruction is a break or a trap. -+ bool IsTrap() const; -+}; -+ -+class Instruction : public InstructionGetters { -+ public: -+ // Instructions are read of out a code stream. The only way to get a -+ // reference to an instruction is to convert a pointer. There is no way -+ // to allocate or create instances of class Instruction. -+ // Use the At(pc) function to create references to Instruction. -+ static Instruction* At(byte* pc) { -+ return reinterpret_cast(pc); -+ } -+ -+ private: -+ // We need to prevent the creation of instances of class Instruction. -+ DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); -+}; -+ -+// ----------------------------------------------------------------------------- -+// RISC-V assembly various constants. -+ -+// C/C++ argument slots size. -+const int kCArgSlotCount = 0; -+ -+// TODO(plind): below should be based on kPointerSize -+// TODO(plind): find all usages and remove the needless instructions for n64. -+const int kCArgsSlotsSize = kCArgSlotCount * kInstrSize * 2; -+ -+const int kInvalidStackOffset = -1; -+const int kBranchReturnOffset = 2 * kInstrSize; -+ -+static const int kNegOffset = 0x00008000; -+ -+InstructionBase::Type InstructionBase::InstructionType() const { -+ // RISCV routine -+ switch (InstructionBits() & kBaseOpcodeMask) { -+ case LOAD: -+ return kIType; -+ case LOAD_FP: -+ return kIType; -+ case MISC_MEM: -+ return kIType; -+ case OP_IMM: -+ return kIType; -+ case AUIPC: -+ return kUType; -+ case OP_IMM_32: -+ return kIType; -+ case STORE: -+ return kSType; -+ case STORE_FP: -+ return kSType; -+ case AMO: -+ return kRType; -+ case OP: -+ return kRType; -+ case LUI: -+ return kUType; -+ case OP_32: -+ return kRType; -+ case MADD: -+ case MSUB: -+ case NMSUB: -+ case NMADD: -+ return kR4Type; -+ case OP_FP: -+ return kRType; -+ case BRANCH: -+ return kBType; -+ case JALR: -+ return kIType; -+ case JAL: -+ return kJType; -+ case SYSTEM: -+ return kIType; -+ } -+ return kUnsupported; -+} -+ -+// ----------------------------------------------------------------------------- -+// Instructions. -+ -+template -+bool InstructionGetters

::IsTrap() const { -+ return (this->InstructionBits() == kBreakInstr); -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_CODEGEN_RISCV_CONSTANTS_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/cpu-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/cpu-riscv64.cc -@@ -0,0 +1,32 @@ -+// Copyright 2012 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. -+ -+// CPU specific code for arm independent of OS goes here. -+ -+#include -+#include -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/codegen/cpu-features.h" -+ -+namespace v8 { -+namespace internal { -+ -+void CpuFeatures::FlushICache(void* start, size_t size) { -+#if !defined(USE_SIMULATOR) -+ char* end = reinterpret_cast(start) + size; -+ // The definition of this syscall is -+ // SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, -+ // uintptr_t, end, uintptr_t, flags) -+ // The flag here is set to be SYS_RISCV_FLUSH_ICACHE_LOCAL, which is -+ // defined as 1 in the Linux kernel. -+ syscall(SYS_riscv_flush_icache, start, end, 1); -+#endif // !USE_SIMULATOR. -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/interface-descriptors-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/interface-descriptors-riscv64.cc -@@ -0,0 +1,348 @@ -+// Copyright 2012 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. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/codegen/interface-descriptors.h" -+#include "src/execution/frames.h" -+ -+namespace v8 { -+namespace internal { -+ -+const Register CallInterfaceDescriptor::ContextRegister() { return cp; } -+ -+void CallInterfaceDescriptor::DefaultInitializePlatformSpecific( -+ CallInterfaceDescriptorData* data, int register_parameter_count) { -+ const Register default_stub_registers[] = {a0, a1, a2, a3, a4}; -+ CHECK_LE(static_cast(register_parameter_count), -+ arraysize(default_stub_registers)); -+ data->InitializePlatformSpecific(register_parameter_count, -+ default_stub_registers); -+} -+ -+void WasmI32AtomicWait32Descriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ const Register default_stub_registers[] = {a0, a1, a2, a3}; -+ CHECK_EQ(static_cast(kParameterCount), -+ arraysize(default_stub_registers)); -+ data->InitializePlatformSpecific(kParameterCount, default_stub_registers); -+} -+ -+void WasmI64AtomicWait32Descriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ const Register default_stub_registers[] = {a0, a1, a2, a3, a4}; -+ CHECK_EQ(static_cast(kParameterCount - kStackArgumentsCount), -+ arraysize(default_stub_registers)); -+ data->InitializePlatformSpecific(kParameterCount - kStackArgumentsCount, -+ default_stub_registers); -+} -+ -+void RecordWriteDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ const Register default_stub_registers[] = {a0, a1, a2, a3, kReturnRegister0}; -+ -+ data->RestrictAllocatableRegisters(default_stub_registers, -+ arraysize(default_stub_registers)); -+ -+ CHECK_LE(static_cast(kParameterCount), -+ arraysize(default_stub_registers)); -+ data->InitializePlatformSpecific(kParameterCount, default_stub_registers); -+} -+ -+void EphemeronKeyBarrierDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ const Register default_stub_registers[] = {a0, a1, a2, a3, kReturnRegister0}; -+ -+ data->RestrictAllocatableRegisters(default_stub_registers, -+ arraysize(default_stub_registers)); -+ -+ CHECK_LE(static_cast(kParameterCount), -+ arraysize(default_stub_registers)); -+ data->InitializePlatformSpecific(kParameterCount, default_stub_registers); -+} -+ -+const Register LoadDescriptor::ReceiverRegister() { return a1; } -+const Register LoadDescriptor::NameRegister() { return a2; } -+const Register LoadDescriptor::SlotRegister() { return a0; } -+ -+const Register LoadWithVectorDescriptor::VectorRegister() { return a3; } -+ -+const Register -+LoadWithReceiverAndVectorDescriptor::LookupStartObjectRegister() { -+ return a4; -+} -+ -+const Register StoreDescriptor::ReceiverRegister() { return a1; } -+const Register StoreDescriptor::NameRegister() { return a2; } -+const Register StoreDescriptor::ValueRegister() { return a0; } -+const Register StoreDescriptor::SlotRegister() { return a4; } -+ -+const Register StoreWithVectorDescriptor::VectorRegister() { return a3; } -+ -+const Register StoreTransitionDescriptor::SlotRegister() { return a4; } -+const Register StoreTransitionDescriptor::VectorRegister() { return a3; } -+const Register StoreTransitionDescriptor::MapRegister() { return a5; } -+ -+const Register ApiGetterDescriptor::HolderRegister() { return a0; } -+const Register ApiGetterDescriptor::CallbackRegister() { return a3; } -+ -+const Register GrowArrayElementsDescriptor::ObjectRegister() { return a0; } -+const Register GrowArrayElementsDescriptor::KeyRegister() { return a3; } -+ -+// static -+const Register TypeConversionDescriptor::ArgumentRegister() { return a0; } -+ -+void TypeofDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = {a3}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CallTrampolineDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1: target -+ // a0: number of arguments -+ Register registers[] = {a1, a0}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CallVarargsDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a0 : number of arguments (on the stack, not including receiver) -+ // a1 : the target to call -+ // a4 : arguments list length (untagged) -+ // a2 : arguments list (FixedArray) -+ Register registers[] = {a1, a0, a4, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CallForwardVarargsDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1: the target to call -+ // a0: number of arguments -+ // a2: start index (to support rest parameters) -+ Register registers[] = {a1, a0, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CallFunctionTemplateDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1 : function template info -+ // a0 : number of arguments (on the stack, not including receiver) -+ Register registers[] = {a1, a0}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CallWithSpreadDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a0 : number of arguments (on the stack, not including receiver) -+ // a1 : the target to call -+ // a2 : the object to spread -+ Register registers[] = {a1, a0, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CallWithArrayLikeDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1 : the target to call -+ // a2 : the arguments list -+ Register registers[] = {a1, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ConstructVarargsDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a0 : number of arguments (on the stack, not including receiver) -+ // a1 : the target to call -+ // a3 : the new target -+ // a4 : arguments list length (untagged) -+ // a2 : arguments list (FixedArray) -+ Register registers[] = {a1, a3, a0, a4, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ConstructForwardVarargsDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1: the target to call -+ // a3: new target -+ // a0: number of arguments -+ // a2: start index (to support rest parameters) -+ Register registers[] = {a1, a3, a0, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ConstructWithSpreadDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a0 : number of arguments (on the stack, not including receiver) -+ // a1 : the target to call -+ // a3 : the new target -+ // a2 : the object to spread -+ Register registers[] = {a1, a3, a0, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ConstructWithArrayLikeDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1 : the target to call -+ // a3 : the new target -+ // a2 : the arguments list -+ Register registers[] = {a1, a3, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ConstructStubDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // a1: target -+ // a3: new target -+ // a0: number of arguments -+ // a2: allocation site or undefined -+ Register registers[] = {a1, a3, a0, a2}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void AbortDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = {a0}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void CompareDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = {a1, a0}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void BinaryOpDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = {a1, a0}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ArgumentsAdaptorDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ a1, // JSFunction -+ a3, // the new target -+ a0, // actual number of arguments -+ a2, // expected number of arguments -+ }; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ApiCallbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ a1, // kApiFunctionAddress -+ a2, // kArgc -+ a3, // kCallData -+ a0, // kHolder -+ }; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void InterpreterDispatchDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ kInterpreterAccumulatorRegister, kInterpreterBytecodeOffsetRegister, -+ kInterpreterBytecodeArrayRegister, kInterpreterDispatchTableRegister}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ a0, // argument count (not including receiver) -+ a2, // address of first argument -+ a1 // the target callable to be call -+ }; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ a0, // argument count (not including receiver) -+ a4, // address of the first argument -+ a1, // constructor to call -+ a3, // new target -+ a2, // allocation site feedback if available, undefined otherwise -+ }; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void ResumeGeneratorDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ a0, // the value to pass to the generator -+ a1 // the JSGeneratorObject to resume -+ }; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void FrameDropperTrampolineDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = { -+ a1, // loaded new FP -+ }; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void RunMicrotasksEntryDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ Register registers[] = {a0, a1}; -+ data->InitializePlatformSpecific(arraysize(registers), registers); -+} -+ -+void BinaryOp_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void CallTrampoline_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void CallWithArrayLike_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void CallWithSpread_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void ConstructWithArrayLike_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void ConstructWithSpread_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void Compare_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 4); -+} -+ -+void UnaryOp_WithFeedbackDescriptor::InitializePlatformSpecific( -+ CallInterfaceDescriptorData* data) { -+ // TODO(v8:8888): Implement on this platform. -+ DefaultInitializePlatformSpecific(data, 3); -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/macro-assembler-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/macro-assembler-riscv64.cc -@@ -0,0 +1,4336 @@ -+// Copyright 2012 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. -+ -+#include // For LONG_MIN, LONG_MAX. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/base/bits.h" -+#include "src/base/division-by-constant.h" -+#include "src/codegen/assembler-inl.h" -+#include "src/codegen/callable.h" -+#include "src/codegen/code-factory.h" -+#include "src/codegen/external-reference-table.h" -+#include "src/codegen/macro-assembler.h" -+#include "src/codegen/register-configuration.h" -+#include "src/debug/debug.h" -+#include "src/execution/frames-inl.h" -+#include "src/heap/memory-chunk.h" -+#include "src/init/bootstrapper.h" -+#include "src/logging/counters.h" -+#include "src/objects/heap-number.h" -+#include "src/runtime/runtime.h" -+#include "src/snapshot/embedded/embedded-data.h" -+#include "src/snapshot/snapshot.h" -+#include "src/wasm/wasm-code-manager.h" -+ -+// Satisfy cpplint check, but don't include platform-specific header. It is -+// included recursively via macro-assembler.h. -+#if 0 -+#include "src/codegen/riscv64/macro-assembler-riscv64.h" -+#endif -+ -+namespace v8 { -+namespace internal { -+ -+static inline bool IsZero(const Operand& rt) { -+ if (rt.is_reg()) { -+ return rt.rm() == zero_reg; -+ } else { -+ return rt.immediate() == 0; -+ } -+} -+ -+int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode, -+ Register exclusion1, -+ Register exclusion2, -+ Register exclusion3) const { -+ int bytes = 0; -+ RegList exclusions = 0; -+ if (exclusion1 != no_reg) { -+ exclusions |= exclusion1.bit(); -+ if (exclusion2 != no_reg) { -+ exclusions |= exclusion2.bit(); -+ if (exclusion3 != no_reg) { -+ exclusions |= exclusion3.bit(); -+ } -+ } -+ } -+ -+ RegList list = kJSCallerSaved & ~exclusions; -+ bytes += NumRegs(list) * kPointerSize; -+ -+ if (fp_mode == kSaveFPRegs) { -+ bytes += NumRegs(kCallerSavedFPU) * kDoubleSize; -+ } -+ -+ return bytes; -+} -+ -+int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, -+ Register exclusion2, Register exclusion3) { -+ int bytes = 0; -+ RegList exclusions = 0; -+ if (exclusion1 != no_reg) { -+ exclusions |= exclusion1.bit(); -+ if (exclusion2 != no_reg) { -+ exclusions |= exclusion2.bit(); -+ if (exclusion3 != no_reg) { -+ exclusions |= exclusion3.bit(); -+ } -+ } -+ } -+ -+ RegList list = kJSCallerSaved & ~exclusions; -+ MultiPush(list); -+ bytes += NumRegs(list) * kPointerSize; -+ -+ if (fp_mode == kSaveFPRegs) { -+ MultiPushFPU(kCallerSavedFPU); -+ bytes += NumRegs(kCallerSavedFPU) * kDoubleSize; -+ } -+ -+ return bytes; -+} -+ -+int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, -+ Register exclusion2, Register exclusion3) { -+ int bytes = 0; -+ if (fp_mode == kSaveFPRegs) { -+ MultiPopFPU(kCallerSavedFPU); -+ bytes += NumRegs(kCallerSavedFPU) * kDoubleSize; -+ } -+ -+ RegList exclusions = 0; -+ if (exclusion1 != no_reg) { -+ exclusions |= exclusion1.bit(); -+ if (exclusion2 != no_reg) { -+ exclusions |= exclusion2.bit(); -+ if (exclusion3 != no_reg) { -+ exclusions |= exclusion3.bit(); -+ } -+ } -+ } -+ -+ RegList list = kJSCallerSaved & ~exclusions; -+ MultiPop(list); -+ bytes += NumRegs(list) * kPointerSize; -+ -+ return bytes; -+} -+ -+void TurboAssembler::LoadRoot(Register destination, RootIndex index) { -+ Ld(destination, MemOperand(s6, RootRegisterOffsetForRootIndex(index))); -+} -+ -+void TurboAssembler::LoadRoot(Register destination, RootIndex index, -+ Condition cond, Register src1, -+ const Operand& src2) { -+ Label skip; -+ Branch(&skip, NegateCondition(cond), src1, src2); -+ Ld(destination, MemOperand(s6, RootRegisterOffsetForRootIndex(index))); -+ bind(&skip); -+} -+ -+void TurboAssembler::PushCommonFrame(Register marker_reg) { -+ if (marker_reg.is_valid()) { -+ Push(ra, fp, marker_reg); -+ Add64(fp, sp, Operand(kPointerSize)); -+ } else { -+ Push(ra, fp); -+ mv(fp, sp); -+ } -+} -+ -+void TurboAssembler::PushStandardFrame(Register function_reg) { -+ int offset = -StandardFrameConstants::kContextOffset; -+ if (function_reg.is_valid()) { -+ Push(ra, fp, cp, function_reg); -+ offset += kPointerSize; -+ } else { -+ Push(ra, fp, cp); -+ } -+ Add64(fp, sp, Operand(offset)); -+} -+ -+int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { -+ // The registers are pushed starting with the highest encoding, -+ // which means that lowest encodings are closest to the stack pointer. -+ return kSafepointRegisterStackIndexMap[reg_code]; -+} -+ -+// Clobbers object, dst, value, and ra, if (ra_status == kRAHasBeenSaved) -+// The register 'object' contains a heap object pointer. The heap object -+// tag is shifted away. -+void MacroAssembler::RecordWriteField(Register object, int offset, -+ Register value, Register dst, -+ RAStatus ra_status, -+ SaveFPRegsMode save_fp, -+ RememberedSetAction remembered_set_action, -+ SmiCheck smi_check) { -+ DCHECK(!AreAliased(value, dst, t5, object)); -+ // First, check if a write barrier is even needed. The tests below -+ // catch stores of Smis. -+ Label done; -+ -+ // Skip barrier if writing a smi. -+ if (smi_check == INLINE_SMI_CHECK) { -+ JumpIfSmi(value, &done); -+ } -+ -+ // Although the object register is tagged, the offset is relative to the start -+ // of the object, so so offset must be a multiple of kPointerSize. -+ DCHECK(IsAligned(offset, kPointerSize)); -+ -+ Add64(dst, object, Operand(offset - kHeapObjectTag)); -+ if (emit_debug_code()) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Label ok; -+ And(t5, dst, Operand(kPointerSize - 1)); -+ Branch(&ok, eq, t5, Operand(zero_reg)); -+ ebreak(); -+ bind(&ok); -+ } -+ -+ RecordWrite(object, dst, value, ra_status, save_fp, remembered_set_action, -+ OMIT_SMI_CHECK); -+ -+ bind(&done); -+ -+ // Clobber clobbered input registers when running with the debug-code flag -+ // turned on to provoke errors. -+ if (emit_debug_code()) { -+ li(value, Operand(bit_cast(kZapValue + 4))); -+ li(dst, Operand(bit_cast(kZapValue + 8))); -+ } -+} -+ -+void TurboAssembler::SaveRegisters(RegList registers) { -+ DCHECK_GT(NumRegs(registers), 0); -+ RegList regs = 0; -+ for (int i = 0; i < Register::kNumRegisters; ++i) { -+ if ((registers >> i) & 1u) { -+ regs |= Register::from_code(i).bit(); -+ } -+ } -+ MultiPush(regs); -+} -+ -+void TurboAssembler::RestoreRegisters(RegList registers) { -+ DCHECK_GT(NumRegs(registers), 0); -+ RegList regs = 0; -+ for (int i = 0; i < Register::kNumRegisters; ++i) { -+ if ((registers >> i) & 1u) { -+ regs |= Register::from_code(i).bit(); -+ } -+ } -+ MultiPop(regs); -+} -+ -+void TurboAssembler::CallEphemeronKeyBarrier(Register object, Register address, -+ SaveFPRegsMode fp_mode) { -+ EphemeronKeyBarrierDescriptor descriptor; -+ RegList registers = descriptor.allocatable_registers(); -+ -+ SaveRegisters(registers); -+ -+ Register object_parameter( -+ descriptor.GetRegisterParameter(EphemeronKeyBarrierDescriptor::kObject)); -+ Register slot_parameter(descriptor.GetRegisterParameter( -+ EphemeronKeyBarrierDescriptor::kSlotAddress)); -+ Register fp_mode_parameter( -+ descriptor.GetRegisterParameter(EphemeronKeyBarrierDescriptor::kFPMode)); -+ -+ Push(object); -+ Push(address); -+ -+ Pop(slot_parameter); -+ Pop(object_parameter); -+ -+ Move(fp_mode_parameter, Smi::FromEnum(fp_mode)); -+ Call(isolate()->builtins()->builtin_handle(Builtins::kEphemeronKeyBarrier), -+ RelocInfo::CODE_TARGET); -+ RestoreRegisters(registers); -+} -+ -+void TurboAssembler::CallRecordWriteStub( -+ Register object, Register address, -+ RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode) { -+ CallRecordWriteStub( -+ object, address, remembered_set_action, fp_mode, -+ isolate()->builtins()->builtin_handle(Builtins::kRecordWrite), -+ kNullAddress); -+} -+ -+void TurboAssembler::CallRecordWriteStub( -+ Register object, Register address, -+ RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode, -+ Address wasm_target) { -+ CallRecordWriteStub(object, address, remembered_set_action, fp_mode, -+ Handle::null(), wasm_target); -+} -+ -+void TurboAssembler::CallRecordWriteStub( -+ Register object, Register address, -+ RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode, -+ Handle code_target, Address wasm_target) { -+ DCHECK_NE(code_target.is_null(), wasm_target == kNullAddress); -+ // TODO(albertnetymk): For now we ignore remembered_set_action and fp_mode, -+ // i.e. always emit remember set and save FP registers in RecordWriteStub. If -+ // large performance regression is observed, we should use these values to -+ // avoid unnecessary work. -+ -+ RecordWriteDescriptor descriptor; -+ RegList registers = descriptor.allocatable_registers(); -+ -+ SaveRegisters(registers); -+ Register object_parameter( -+ descriptor.GetRegisterParameter(RecordWriteDescriptor::kObject)); -+ Register slot_parameter( -+ descriptor.GetRegisterParameter(RecordWriteDescriptor::kSlot)); -+ Register remembered_set_parameter( -+ descriptor.GetRegisterParameter(RecordWriteDescriptor::kRememberedSet)); -+ Register fp_mode_parameter( -+ descriptor.GetRegisterParameter(RecordWriteDescriptor::kFPMode)); -+ -+ Push(object); -+ Push(address); -+ -+ Pop(slot_parameter); -+ Pop(object_parameter); -+ -+ Move(remembered_set_parameter, Smi::FromEnum(remembered_set_action)); -+ Move(fp_mode_parameter, Smi::FromEnum(fp_mode)); -+ if (code_target.is_null()) { -+ Call(wasm_target, RelocInfo::WASM_STUB_CALL); -+ } else { -+ Call(code_target, RelocInfo::CODE_TARGET); -+ } -+ -+ RestoreRegisters(registers); -+} -+ -+// Clobbers object, address, value, and ra, if (ra_status == kRAHasBeenSaved) -+// The register 'object' contains a heap object pointer. The heap object -+// tag is shifted away. -+void MacroAssembler::RecordWrite(Register object, Register address, -+ Register value, RAStatus ra_status, -+ SaveFPRegsMode fp_mode, -+ RememberedSetAction remembered_set_action, -+ SmiCheck smi_check) { -+ DCHECK(!AreAliased(object, address, value, t5)); -+ DCHECK(!AreAliased(object, address, value, t6)); -+ -+ if (emit_debug_code()) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Ld(scratch, MemOperand(address)); -+ Assert(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite, scratch, -+ Operand(value)); -+ } -+ -+ if ((remembered_set_action == OMIT_REMEMBERED_SET && -+ !FLAG_incremental_marking) || -+ FLAG_disable_write_barriers) { -+ return; -+ } -+ -+ // First, check if a write barrier is even needed. The tests below -+ // catch stores of smis and stores into the young generation. -+ Label done; -+ -+ if (smi_check == INLINE_SMI_CHECK) { -+ DCHECK_EQ(0, kSmiTag); -+ JumpIfSmi(value, &done); -+ } -+ -+ CheckPageFlag(value, -+ value, // Used as scratch. -+ MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); -+ CheckPageFlag(object, -+ value, // Used as scratch. -+ MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); -+ -+ // Record the actual write. -+ if (ra_status == kRAHasNotBeenSaved) { -+ push(ra); -+ } -+ CallRecordWriteStub(object, address, remembered_set_action, fp_mode); -+ if (ra_status == kRAHasNotBeenSaved) { -+ pop(ra); -+ } -+ -+ bind(&done); -+ -+ // Clobber clobbered registers when running with the debug-code flag -+ // turned on to provoke errors. -+ if (emit_debug_code()) { -+ li(address, Operand(bit_cast(kZapValue + 12))); -+ li(value, Operand(bit_cast(kZapValue + 16))); -+ } -+} -+ -+// --------------------------------------------------------------------------- -+// Instruction macros. -+ -+void TurboAssembler::Add32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ addw(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ addiw(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ addw(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Add64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ add(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ addi(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ // Register scratch = temps.Acquire(); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ add(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Sub32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ subw(rd, rs, rt.rm()); -+ } else { -+ DCHECK(is_int32(rt.immediate())); -+ if (is_int12(-rt.immediate()) && !MustUseReg(rt.rmode())) { -+ addiw(rd, rs, -+ static_cast( -+ -rt.immediate())); // No subiw instr, use addiw(x, y, -imm). -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ if (-rt.immediate() >> 12 == 0 && !MustUseReg(rt.rmode())) { -+ // Use load -imm and addu when loading -imm generates one instruction. -+ RV_li(scratch, -rt.immediate()); -+ addw(rd, rs, scratch); -+ } else { -+ // li handles the relocation. -+ RV_li(scratch, rt.immediate()); -+ subw(rd, rs, scratch); -+ } -+ } -+ } -+} -+ -+void TurboAssembler::Sub64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ sub(rd, rs, rt.rm()); -+ } else if (is_int12(-rt.immediate()) && !MustUseReg(rt.rmode())) { -+ addi(rd, rs, -+ static_cast( -+ -rt.immediate())); // No subi instr, use addi(x, y, -imm). -+ } else { -+ DCHECK(rs != t3); -+ int li_count = InstrCountForLi64Bit(rt.immediate()); -+ int li_neg_count = InstrCountForLi64Bit(-rt.immediate()); -+ if (li_neg_count < li_count && !MustUseReg(rt.rmode())) { -+ // Use load -imm and add when loading -imm generates one instruction. -+ DCHECK(rt.immediate() != std::numeric_limits::min()); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ RV_li(scratch, -rt.immediate()); -+ add(rd, rs, scratch); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ RV_li(scratch, rt.immediate()); -+ sub(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Mul32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ mulw(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ mulw(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Mulh32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ mul(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ mul(rd, rs, scratch); -+ } -+ srai(rd, rd, 32); -+} -+ -+void TurboAssembler::Mulhu32(Register rd, Register rs, const Operand& rt, -+ Register rsz, Register rtz) { -+ slli(rsz, rs, 32); -+ if (rt.is_reg()) -+ slli(rtz, rt.rm(), 32); -+ else -+ RV_li(rtz, rt.immediate() << 32); -+ mulhu(rd, rsz, rtz); -+ srai(rd, rd, 32); -+} -+ -+void TurboAssembler::Mul64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ mul(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ mul(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Mulh64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ mulh(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ mulh(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Div32(Register res, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ divw(res, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ divw(res, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Mod32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ remw(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ remw(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Modu32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ remuw(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ remuw(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Div64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ div(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ div(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Divu32(Register res, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ divuw(res, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ divuw(res, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Divu64(Register res, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ divu(res, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ divu(res, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Mod64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ rem(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ rem(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::Modu64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ remu(rd, rs, rt.rm()); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ remu(rd, rs, scratch); -+ } -+} -+ -+void TurboAssembler::And(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ and_(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ andi(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ and_(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Or(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ or_(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ ori(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ or_(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Xor(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ xor_(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ xori(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ xor_(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Nor(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ or_(rd, rs, rt.rm()); -+ not_(rd, rd); -+ } else { -+ Or(rd, rs, rt); -+ not_(rd, rd); -+ } -+} -+ -+void TurboAssembler::Neg(Register rs, const Operand& rt) { -+ DCHECK(rt.is_reg()); -+ neg(rs, rt.rm()); -+} -+ -+void TurboAssembler::Seqz(Register rd, const Operand& rt) { -+ if (rt.is_reg()) { -+ seqz(rd, rt.rm()); -+ } else { -+ li(rd, rt.immediate() == 0); -+ } -+} -+ -+void TurboAssembler::Snez(Register rd, const Operand& rt) { -+ if (rt.is_reg()) { -+ snez(rd, rt.rm()); -+ } else { -+ li(rd, rt.immediate() != 0); -+ } -+} -+ -+void TurboAssembler::Seq(Register rd, Register rs, const Operand& rt) { -+ if (rs == zero_reg) { -+ Seqz(rd, rt); -+ } else if (IsZero(rt)) { -+ seqz(rd, rs); -+ } else { -+ Sub64(rd, rs, rt); -+ seqz(rd, rd); -+ } -+} -+ -+void TurboAssembler::Sne(Register rd, Register rs, const Operand& rt) { -+ if (rs == zero_reg) { -+ Snez(rd, rt); -+ } else if (IsZero(rt)) { -+ snez(rd, rs); -+ } else { -+ Sub64(rd, rs, rt); -+ snez(rd, rd); -+ } -+} -+ -+void TurboAssembler::Slt(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ slt(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ slti(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ slt(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Sltu(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ sltu(rd, rs, rt.rm()); -+ } else { -+ if (is_int12(rt.immediate()) && !MustUseReg(rt.rmode())) { -+ sltiu(rd, rs, static_cast(rt.immediate())); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ sltu(rd, rs, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::Sle(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ slt(rd, rt.rm(), rs); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ slt(rd, scratch, rs); -+ } -+ xori(rd, rd, 1); -+} -+ -+void TurboAssembler::Sleu(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ sltu(rd, rt.rm(), rs); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ sltu(rd, scratch, rs); -+ } -+ xori(rd, rd, 1); -+} -+ -+void TurboAssembler::Sge(Register rd, Register rs, const Operand& rt) { -+ Slt(rd, rs, rt); -+ xori(rd, rd, 1); -+} -+ -+void TurboAssembler::Sgeu(Register rd, Register rs, const Operand& rt) { -+ Sltu(rd, rs, rt); -+ xori(rd, rd, 1); -+} -+ -+void TurboAssembler::Sgt(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ slt(rd, rt.rm(), rs); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ slt(rd, scratch, rs); -+ } -+} -+ -+void TurboAssembler::Sgtu(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) { -+ sltu(rd, rt.rm(), rs); -+ } else { -+ // li handles the relocation. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ DCHECK(rs != scratch); -+ RV_li(scratch, rt.immediate()); -+ sltu(rd, scratch, rs); -+ } -+} -+ -+void TurboAssembler::Sll32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) -+ sllw(rd, rs, rt.rm()); -+ else { -+ uint8_t shamt = static_cast(rt.immediate()); -+ slliw(rd, rs, shamt); -+ } -+} -+ -+void TurboAssembler::Sra32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) -+ sraw(rd, rs, rt.rm()); -+ else { -+ uint8_t shamt = static_cast(rt.immediate()); -+ sraiw(rd, rs, shamt); -+ } -+} -+ -+void TurboAssembler::Srl32(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) -+ srlw(rd, rs, rt.rm()); -+ else { -+ uint8_t shamt = static_cast(rt.immediate()); -+ srliw(rd, rs, shamt); -+ } -+} -+ -+void TurboAssembler::Sra64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) -+ sra(rd, rs, rt.rm()); -+ else { -+ uint8_t shamt = static_cast(rt.immediate()); -+ srai(rd, rs, shamt); -+ } -+} -+ -+void TurboAssembler::Srl64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) -+ srl(rd, rs, rt.rm()); -+ else { -+ uint8_t shamt = static_cast(rt.immediate()); -+ srli(rd, rs, shamt); -+ } -+} -+ -+void TurboAssembler::Sll64(Register rd, Register rs, const Operand& rt) { -+ if (rt.is_reg()) -+ sll(rd, rs, rt.rm()); -+ else { -+ uint8_t shamt = static_cast(rt.immediate()); -+ slli(rd, rs, shamt); -+ } -+} -+ -+void TurboAssembler::Ror(Register rd, Register rs, const Operand& rt) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ if (rt.is_reg()) { -+ negw(scratch, rt.rm()); -+ sllw(scratch, rs, scratch); -+ srlw(rd, rs, rt.rm()); -+ or_(rd, scratch, rd); -+ sext_w(rd, rd); -+ } else { -+ int64_t ror_value = rt.immediate() % 32; -+ if (ror_value == 0) { -+ mv(rd, rs); -+ return; -+ } else if (ror_value < 0) { -+ ror_value += 32; -+ } -+ srliw(scratch, rs, ror_value); -+ slliw(rd, rs, 32 - ror_value); -+ or_(rd, scratch, rd); -+ sext_w(rd, rd); -+ } -+} -+ -+void TurboAssembler::Dror(Register rd, Register rs, const Operand& rt) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ DCHECK(rs != scratch); -+ if (rt.is_reg()) { -+ negw(scratch, rt.rm()); -+ sll(scratch, rs, scratch); -+ srl(rd, rs, rt.rm()); -+ or_(rd, scratch, rd); -+ } else { -+ int64_t dror_value = rt.immediate() % 64; -+ if (dror_value == 0) { -+ mv(rd, rs); -+ return; -+ } else if (dror_value < 0) { -+ dror_value += 64; -+ } -+ srli(scratch, rs, dror_value); -+ slli(rd, rs, 64 - dror_value); -+ or_(rd, scratch, rd); -+ } -+} -+ -+void TurboAssembler::CalcScaledAddress(Register rd, Register rt, Register rs, -+ uint8_t sa, Register scratch) { -+ DCHECK(sa >= 1 && sa <= 31); -+ Register tmp = rd == rt ? scratch : rd; -+ DCHECK(tmp != rt); -+ slli(tmp, rs, sa); -+ Add64(rd, rt, tmp); -+} -+ -+// ------------Pseudo-instructions------------- -+// Change endianness -+void TurboAssembler::ByteSwap(Register rd, Register rs, int operand_size) { -+ DCHECK(operand_size == 4 || operand_size == 8); -+ DCHECK(rd != t5 && rd != t6); -+ if (operand_size == 4) { -+ // Uint32_t t5 = 0x00FF00FF; -+ // x = (x << 16 | x >> 16); -+ // x = (((x & t5) << 8) | ((x & (t5 << 8)) >> 8)); -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register x = temps.Acquire(); -+ li(t5, 0x00FF00FF); -+ slliw(x, rs, 16); -+ srliw(rd, rs, 16); -+ or_(x, rd, x); // x <- x << 16 | x >> 16 -+ and_(t6, x, t5); // t <- x & 0x00FF00FF -+ slliw(t6, t6, 8); // t <- (x & t5) << 8 -+ slliw(t5, t5, 8); // t5 <- 0xFF00FF00 -+ and_(rd, x, t5); // x & 0xFF00FF00 -+ srliw(rd, rd, 8); -+ or_(rd, rd, t6); // (((x & t5) << 8) | ((x & (t5 << 8)) >> 8)) -+ } else { -+ // uint64_t t5 = 0x0000FFFF0000FFFFl; -+ // uint64_t t5 = 0x00FF00FF00FF00FFl; -+ // x = (x << 32 | x >> 32); -+ // x = (x & t5) << 16 | (x & (t5 << 16)) >> 16; -+ // x = (x & t5) << 8 | (x & (t5 << 8)) >> 8; -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register x = temps.Acquire(); -+ li(t5, 0x0000FFFF0000FFFFl); -+ slli(x, rs, 32); -+ srli(rd, rs, 32); -+ or_(x, rd, x); // x <- x << 32 | x >> 32 -+ and_(t6, x, t5); // t <- x & 0x0000FFFF0000FFFF -+ slli(t6, t6, 16); // t <- (x & 0x0000FFFF0000FFFF) << 16 -+ slli(t5, t5, 16); // t5 <- 0xFFFF0000FFFF0000 -+ and_(rd, x, t5); // rd <- x & 0xFFFF0000FFFF0000 -+ srli(rd, rd, 16); // rd <- x & (t5 << 16)) >> 16 -+ or_(x, rd, t6); // (x & t5) << 16 | (x & (t5 << 16)) >> 16; -+ li(t5, 0x00FF00FF00FF00FFl); -+ and_(t6, x, t5); // t <- x & 0x00FF00FF00FF00FF -+ slli(t6, t6, 8); // t <- (x & t5) << 8 -+ slli(t5, t5, 8); // t5 <- 0xFF00FF00FF00FF00 -+ and_(rd, x, t5); -+ srli(rd, rd, 8); // rd <- (x & (t5 << 8)) >> 8 -+ or_(rd, rd, t6); // (((x & t5) << 8) | ((x & (t5 << 8)) >> 8)) -+ } -+} -+ -+template -+void TurboAssembler::LoadNBytes(Register rd, const MemOperand& rs, -+ Register scratch) { -+ DCHECK(rd != rs.rm() && rd != scratch); -+ DCHECK(NBYTES <= 8); -+ -+ // load the most significant byte -+ if (LOAD_SIGNED) { -+ lb(rd, rs.rm(), rs.offset() + (NBYTES - 1)); -+ } else { -+ lbu(rd, rs.rm(), rs.offset() + (NBYTES - 1)); -+ } -+ -+ // load remaining (nbytes-1) bytes from higher to lower -+ slli(rd, rd, 8 * (NBYTES - 1)); -+ for (int i = (NBYTES - 2); i >= 0; i--) { -+ lbu(scratch, rs.rm(), rs.offset() + i); -+ if (i) slli(scratch, scratch, i * 8); -+ or_(rd, rd, scratch); -+ } -+} -+ -+template -+void TurboAssembler::LoadNBytesOverwritingBaseReg(const MemOperand& rs, -+ Register scratch0, -+ Register scratch1) { -+ // This function loads nbytes from memory specified by rs and into rs.rm() -+ DCHECK(rs.rm() != scratch0 && rs.rm() != scratch1 && scratch0 != scratch1); -+ DCHECK(NBYTES <= 8); -+ -+ // load the most significant byte -+ if (LOAD_SIGNED) { -+ lb(scratch0, rs.rm(), rs.offset() + (NBYTES - 1)); -+ } else { -+ lbu(scratch0, rs.rm(), rs.offset() + (NBYTES - 1)); -+ } -+ -+ // load remaining (nbytes-1) bytes from higher to lower -+ slli(scratch0, scratch0, 8 * (NBYTES - 1)); -+ for (int i = (NBYTES - 2); i >= 0; i--) { -+ lbu(scratch1, rs.rm(), rs.offset() + i); -+ if (i) { -+ slli(scratch1, scratch1, i * 8); -+ or_(scratch0, scratch0, scratch1); -+ } else { -+ // write to rs.rm() when processing the last byte -+ or_(rs.rm(), scratch0, scratch1); -+ } -+ } -+} -+ -+template -+void TurboAssembler::UnalignedLoadHelper(Register rd, const MemOperand& rs) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ UseScratchRegisterScope temps(this); -+ -+ if (NeedAdjustBaseAndOffset(rs, OffsetAccessType::TWO_ACCESSES, NBYTES - 1)) { -+ // Adjust offset for two accesses and check if offset + 3 fits into int12. -+ MemOperand source = rs; -+ Register scratch_base = temps.Acquire(); -+ DCHECK(scratch_base != rs.rm()); -+ AdjustBaseAndOffset(&source, scratch_base, OffsetAccessType::TWO_ACCESSES, -+ NBYTES - 1); -+ -+ // Since source.rm() is scratch_base, assume rd != source.rm() -+ DCHECK(rd != source.rm()); -+ Register scratch_other = t5; -+ LoadNBytes(rd, source, scratch_other); -+ } else { -+ // no need to adjust base-and-offset -+ if (rd != rs.rm()) { -+ Register scratch = temps.Acquire(); -+ LoadNBytes(rd, rs, scratch); -+ } else { // rd == rs.rm() -+ Register scratch0 = temps.Acquire(); -+ Register scratch1 = t5; -+ LoadNBytesOverwritingBaseReg(rs, scratch0, scratch1); -+ } -+ } -+} -+ -+template -+void TurboAssembler::UnalignedFLoadHelper(FPURegister frd, const MemOperand& rs, -+ Register scratch) { -+ DCHECK(scratch != rs.rm()); -+ DCHECK(NBYTES == 4 || NBYTES == 8); -+ -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ UseScratchRegisterScope temps(this); -+ MemOperand source = rs; -+ if (NeedAdjustBaseAndOffset(rs, OffsetAccessType::TWO_ACCESSES, NBYTES - 1)) { -+ // Adjust offset for two accesses and check if offset + 3 fits into int12. -+ Register scratch_base = temps.Acquire(); -+ DCHECK(scratch_base != scratch && scratch_base != rs.rm()); -+ AdjustBaseAndOffset(&source, scratch_base, OffsetAccessType::TWO_ACCESSES, -+ NBYTES - 1); -+ } -+ -+ Register scratch_other = temps.hasAvailable() ? temps.Acquire() : t5; -+ DCHECK(scratch_other != scratch && scratch_other != rs.rm()); -+ LoadNBytes(scratch, source, scratch_other); -+ if (NBYTES == 4) -+ fmv_w_x(frd, scratch); -+ else -+ fmv_d_x(frd, scratch); -+} -+ -+template -+void TurboAssembler::UnalignedStoreHelper(Register rd, const MemOperand& rs, -+ Register scratch_other) { -+ DCHECK(scratch_other != rs.rm()); -+ DCHECK(NBYTES <= 8); -+ -+ UseScratchRegisterScope temps(this); -+ MemOperand source = rs; -+ // Adjust offset for two accesses and check if offset + 3 fits into int12. -+ if (NeedAdjustBaseAndOffset(rs, OffsetAccessType::TWO_ACCESSES, NBYTES - 1)) { -+ Register scratch_base = temps.Acquire(); -+ DCHECK(scratch_base != rd && scratch_base != rs.rm()); -+ AdjustBaseAndOffset(&source, scratch_base, OffsetAccessType::TWO_ACCESSES, -+ NBYTES - 1); -+ } -+ -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (scratch_other == no_reg) -+ scratch_other = temps.hasAvailable() ? temps.Acquire() : t5; -+ -+ DCHECK(scratch_other != rd && scratch_other != rs.rm() && -+ scratch_other != source.rm()); -+ -+ sb(rd, source.rm(), source.offset()); -+ for (size_t i = 1; i <= (NBYTES - 1); i++) { -+ srli(scratch_other, rd, i * 8); -+ sb(scratch_other, source.rm(), source.offset() + i); -+ } -+} -+ -+template -+void TurboAssembler::UnalignedFStoreHelper(FPURegister frd, -+ const MemOperand& rs, -+ Register scratch) { -+ DCHECK(scratch != rs.rm()); -+ DCHECK(NBYTES == 8 || NBYTES == 4); -+ -+ if (NBYTES == 4) { -+ fmv_x_w(scratch, frd); -+ } else { -+ fmv_x_d(scratch, frd); -+ } -+ UnalignedStoreHelper(scratch, rs); -+} -+ -+template -+void TurboAssembler::AlignedLoadHelper(Reg_T target, const MemOperand& rs, -+ Func generator) { -+ MemOperand source = rs; -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (NeedAdjustBaseAndOffset(source)) { -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ DCHECK(scratch != rs.rm()); -+ AdjustBaseAndOffset(&source, scratch); -+ } -+ generator(target, source); -+} -+ -+template -+void TurboAssembler::AlignedStoreHelper(Reg_T value, const MemOperand& rs, -+ Func generator) { -+ MemOperand source = rs; -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (NeedAdjustBaseAndOffset(source)) { -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ // make sure scratch does not overwrite value -+ if (std::is_same::value) -+ DCHECK(scratch.code() != value.code()); -+ DCHECK(scratch != rs.rm()); -+ AdjustBaseAndOffset(&source, scratch); -+ } -+ generator(value, source); -+} -+ -+void TurboAssembler::Ulw(Register rd, const MemOperand& rs) { -+ UnalignedLoadHelper<4, true>(rd, rs); -+} -+ -+void TurboAssembler::Ulwu(Register rd, const MemOperand& rs) { -+ UnalignedLoadHelper<4, false>(rd, rs); -+} -+ -+void TurboAssembler::Usw(Register rd, const MemOperand& rs) { -+ UnalignedStoreHelper<4>(rd, rs); -+} -+ -+void TurboAssembler::Ulh(Register rd, const MemOperand& rs) { -+ UnalignedLoadHelper<2, true>(rd, rs); -+} -+ -+void TurboAssembler::Ulhu(Register rd, const MemOperand& rs) { -+ UnalignedLoadHelper<2, false>(rd, rs); -+} -+ -+void TurboAssembler::Ush(Register rd, const MemOperand& rs) { -+ UnalignedStoreHelper<2>(rd, rs); -+} -+ -+void TurboAssembler::Uld(Register rd, const MemOperand& rs) { -+ UnalignedLoadHelper<8, true>(rd, rs); -+} -+ -+// Load consequent 32-bit word pair in 64-bit reg. and put first word in low -+// bits, -+// second word in high bits. -+void MacroAssembler::LoadWordPair(Register rd, const MemOperand& rs, -+ Register scratch) { -+ Lwu(rd, rs); -+ Lw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2)); -+ slli(scratch, scratch, 32); -+ Add64(rd, rd, scratch); -+} -+ -+void TurboAssembler::Usd(Register rd, const MemOperand& rs) { -+ UnalignedStoreHelper<8>(rd, rs); -+} -+ -+// Do 64-bit store as two consequent 32-bit stores to unaligned address. -+void MacroAssembler::StoreWordPair(Register rd, const MemOperand& rs, -+ Register scratch) { -+ Sw(rd, rs); -+ srai(scratch, rd, 32); -+ Sw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2)); -+} -+ -+void TurboAssembler::ULoadFloat(FPURegister fd, const MemOperand& rs, -+ Register scratch) { -+ UnalignedFLoadHelper<4>(fd, rs, scratch); -+} -+ -+void TurboAssembler::UStoreFloat(FPURegister fd, const MemOperand& rs, -+ Register scratch) { -+ UnalignedFStoreHelper<4>(fd, rs, scratch); -+} -+ -+void TurboAssembler::ULoadDouble(FPURegister fd, const MemOperand& rs, -+ Register scratch) { -+ UnalignedFLoadHelper<8>(fd, rs, scratch); -+} -+ -+void TurboAssembler::UStoreDouble(FPURegister fd, const MemOperand& rs, -+ Register scratch) { -+ UnalignedFStoreHelper<8>(fd, rs, scratch); -+} -+ -+void TurboAssembler::Lb(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->lb(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Lbu(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->lbu(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Sb(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register value, const MemOperand& source) { -+ this->sb(value, source.rm(), source.offset()); -+ }; -+ AlignedStoreHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Lh(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->lh(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Lhu(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->lhu(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Sh(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register value, const MemOperand& source) { -+ this->sh(value, source.rm(), source.offset()); -+ }; -+ AlignedStoreHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Lw(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->lw(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Lwu(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->lwu(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Sw(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register value, const MemOperand& source) { -+ this->sw(value, source.rm(), source.offset()); -+ }; -+ AlignedStoreHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Ld(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register target, const MemOperand& source) { -+ this->ld(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::Sd(Register rd, const MemOperand& rs) { -+ auto fn = [this](Register value, const MemOperand& source) { -+ this->sd(value, source.rm(), source.offset()); -+ }; -+ AlignedStoreHelper(rd, rs, fn); -+} -+ -+void TurboAssembler::LoadFloat(FPURegister fd, const MemOperand& src) { -+ auto fn = [this](FPURegister target, const MemOperand& source) { -+ this->flw(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(fd, src, fn); -+} -+ -+void TurboAssembler::StoreFloat(FPURegister fs, const MemOperand& src) { -+ auto fn = [this](FPURegister value, const MemOperand& source) { -+ this->fsw(value, source.rm(), source.offset()); -+ }; -+ AlignedStoreHelper(fs, src, fn); -+} -+ -+void TurboAssembler::LoadDouble(FPURegister fd, const MemOperand& src) { -+ auto fn = [this](FPURegister target, const MemOperand& source) { -+ this->fld(target, source.rm(), source.offset()); -+ }; -+ AlignedLoadHelper(fd, src, fn); -+} -+ -+void TurboAssembler::StoreDouble(FPURegister fs, const MemOperand& src) { -+ auto fn = [this](FPURegister value, const MemOperand& source) { -+ this->fsd(value, source.rm(), source.offset()); -+ }; -+ AlignedStoreHelper(fs, src, fn); -+} -+ -+void TurboAssembler::Ll(Register rd, const MemOperand& rs) { -+ bool is_one_instruction = rs.offset() == 0; -+ if (is_one_instruction) { -+ lr_w(false, false, rd, rs.rm()); -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Add64(scratch, rs.rm(), rs.offset()); -+ lr_w(false, false, rd, scratch); -+ } -+} -+ -+void TurboAssembler::Lld(Register rd, const MemOperand& rs) { -+ bool is_one_instruction = rs.offset() == 0; -+ if (is_one_instruction) { -+ lr_d(false, false, rd, rs.rm()); -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Add64(scratch, rs.rm(), rs.offset()); -+ lr_d(false, false, rd, scratch); -+ } -+} -+ -+void TurboAssembler::Sc(Register rd, const MemOperand& rs) { -+ bool is_one_instruction = rs.offset() == 0; -+ if (is_one_instruction) { -+ sc_w(false, false, rd, rs.rm(), rd); -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Add64(scratch, rs.rm(), rs.offset()); -+ sc_w(false, false, rd, scratch, rd); -+ } -+} -+ -+void TurboAssembler::Scd(Register rd, const MemOperand& rs) { -+ bool is_one_instruction = rs.offset() == 0; -+ if (is_one_instruction) { -+ sc_d(false, false, rd, rs.rm(), rd); -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Add64(scratch, rs.rm(), rs.offset()); -+ sc_d(false, false, rd, scratch, rd); -+ } -+} -+ -+void TurboAssembler::li(Register dst, Handle value, LiFlags mode) { -+ // TODO(jgruber,v8:8887): Also consider a root-relative load when generating -+ // non-isolate-independent code. In many cases it might be cheaper than -+ // embedding the relocatable value. -+ if (root_array_available_ && options().isolate_independent_code) { -+ IndirectLoadConstant(dst, value); -+ return; -+ } -+ li(dst, Operand(value), mode); -+} -+ -+void TurboAssembler::li(Register dst, ExternalReference value, LiFlags mode) { -+ // TODO(jgruber,v8:8887): Also consider a root-relative load when generating -+ // non-isolate-independent code. In many cases it might be cheaper than -+ // embedding the relocatable value. -+ if (root_array_available_ && options().isolate_independent_code) { -+ IndirectLoadExternalReference(dst, value); -+ return; -+ } -+ li(dst, Operand(value), mode); -+} -+ -+void TurboAssembler::li(Register dst, const StringConstantBase* string, -+ LiFlags mode) { -+ li(dst, Operand::EmbeddedStringConstant(string), mode); -+} -+ -+static inline int InstrCountForLiLower32Bit(int64_t value) { -+ int64_t Hi20 = ((value + 0x800) >> 12); -+ int64_t Lo12 = value << 52 >> 52; -+ if (Hi20 == 0 || Lo12 == 0) { -+ return 1; -+ } -+ return 2; -+} -+ -+int TurboAssembler::InstrCountForLi64Bit(int64_t value) { -+ if (is_int32(value)) { -+ return InstrCountForLiLower32Bit(value); -+ } else { -+ return li_count(value); -+ } -+ UNREACHABLE(); -+ return INT_MAX; -+} -+ -+void TurboAssembler::li_optimized(Register rd, Operand j, LiFlags mode) { -+ DCHECK(!j.is_reg()); -+ DCHECK(!MustUseReg(j.rmode())); -+ DCHECK(mode == OPTIMIZE_SIZE); -+ RV_li(rd, j.immediate()); -+} -+ -+void TurboAssembler::li(Register rd, Operand j, LiFlags mode) { -+ DCHECK(!j.is_reg()); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (!MustUseReg(j.rmode()) && mode == OPTIMIZE_SIZE) { -+ RV_li(rd, j.immediate()); -+ } else if (MustUseReg(j.rmode())) { -+ int64_t immediate; -+ if (j.IsHeapObjectRequest()) { -+ RequestHeapObject(j.heap_object_request()); -+ immediate = 0; -+ } else { -+ immediate = j.immediate(); -+ } -+ -+ RecordRelocInfo(j.rmode(), immediate); -+ // FIXME(RISC_V): Does this case need to be constant size? -+ li_constant(rd, immediate); -+ } else if (mode == ADDRESS_LOAD) { -+ // We always need the same number of instructions as we may need to patch -+ // this code to load another value which may need all 8 instructions. -+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); -+ li_constant(rd, j.immediate()); -+ } else { // mode == CONSTANT_SIZE - always emit the same instruction -+ // sequence. -+ li_constant(rd, j.immediate()); -+ } -+} -+ -+static RegList t_regs = Register::ListOf(t0, t1, t2, t3, t4, t5, t6); -+static RegList a_regs = Register::ListOf(a0, a1, a2, a3, a4, a5, a6, a7); -+static RegList s_regs = -+ Register::ListOf(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11); -+ -+void TurboAssembler::MultiPush(RegList regs) { -+ int16_t num_to_push = base::bits::CountPopulation(regs); -+ int16_t stack_offset = num_to_push * kPointerSize; -+ -+#define TEST_AND_PUSH_REG(reg) \ -+ if ((regs & reg.bit()) != 0) { \ -+ stack_offset -= kPointerSize; \ -+ Sd(reg, MemOperand(sp, stack_offset)); \ -+ regs &= ~reg.bit(); \ -+ } -+ -+#define T_REGS(V) V(t6) V(t5) V(t4) V(t3) V(t2) V(t1) V(t0) -+#define A_REGS(V) V(a7) V(a6) V(a5) V(a4) V(a3) V(a2) V(a1) V(a0) -+#define S_REGS(V) \ -+ V(s11) V(s10) V(s9) V(s8) V(s7) V(s6) V(s5) V(s4) V(s3) V(s2) V(s1) -+ -+ Sub64(sp, sp, Operand(stack_offset)); -+ -+ // Certain usage of MultiPush requires that registers are pushed onto the -+ // stack in a particular: ra, fp, sp, gp, .... (basically in the decreasing -+ // order of register numbers according to MIPS register numbers) -+ TEST_AND_PUSH_REG(ra); -+ TEST_AND_PUSH_REG(fp); -+ TEST_AND_PUSH_REG(sp); -+ TEST_AND_PUSH_REG(gp); -+ TEST_AND_PUSH_REG(tp); -+ if ((regs & s_regs) != 0) { -+ S_REGS(TEST_AND_PUSH_REG) -+ } -+ if ((regs & a_regs) != 0) { -+ A_REGS(TEST_AND_PUSH_REG) -+ } -+ if ((regs & t_regs) != 0) { -+ T_REGS(TEST_AND_PUSH_REG) -+ } -+ -+ DCHECK(regs == 0); -+ -+#undef TEST_AND_PUSH_REG -+#undef T_REGS -+#undef A_REGS -+#undef S_REGS -+} -+ -+void TurboAssembler::MultiPop(RegList regs) { -+ int16_t stack_offset = 0; -+ -+#define TEST_AND_POP_REG(reg) \ -+ if ((regs & reg.bit()) != 0) { \ -+ Ld(reg, MemOperand(sp, stack_offset)); \ -+ stack_offset += kPointerSize; \ -+ regs &= ~reg.bit(); \ -+ } -+ -+#define T_REGS(V) V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) -+#define A_REGS(V) V(a0) V(a1) V(a2) V(a3) V(a4) V(a5) V(a6) V(a7) -+#define S_REGS(V) \ -+ V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(s8) V(s9) V(s10) V(s11) -+ -+ // MultiPop pops from the stack in reverse order as MultiPush -+ if ((regs & t_regs) != 0) { -+ T_REGS(TEST_AND_POP_REG) -+ } -+ if ((regs & a_regs) != 0) { -+ A_REGS(TEST_AND_POP_REG) -+ } -+ if ((regs & s_regs) != 0) { -+ S_REGS(TEST_AND_POP_REG) -+ } -+ TEST_AND_POP_REG(tp); -+ TEST_AND_POP_REG(gp); -+ TEST_AND_POP_REG(sp); -+ TEST_AND_POP_REG(fp); -+ TEST_AND_POP_REG(ra); -+ -+ DCHECK(regs == 0); -+ -+ addi(sp, sp, stack_offset); -+ -+#undef TEST_AND_POP_REG -+#undef T_REGS -+#undef S_REGS -+#undef A_REGS -+} -+ -+void TurboAssembler::MultiPushFPU(RegList regs) { -+ int16_t num_to_push = base::bits::CountPopulation(regs); -+ int16_t stack_offset = num_to_push * kDoubleSize; -+ -+ Sub64(sp, sp, Operand(stack_offset)); -+ for (int16_t i = kNumRegisters - 1; i >= 0; i--) { -+ if ((regs & (1 << i)) != 0) { -+ stack_offset -= kDoubleSize; -+ StoreDouble(FPURegister::from_code(i), MemOperand(sp, stack_offset)); -+ } -+ } -+} -+ -+void TurboAssembler::MultiPopFPU(RegList regs) { -+ int16_t stack_offset = 0; -+ -+ for (int16_t i = 0; i < kNumRegisters; i++) { -+ if ((regs & (1 << i)) != 0) { -+ LoadDouble(FPURegister::from_code(i), MemOperand(sp, stack_offset)); -+ stack_offset += kDoubleSize; -+ } -+ } -+ addi(sp, sp, stack_offset); -+} -+ -+void TurboAssembler::ExtractBits(Register rt, Register rs, uint16_t pos, -+ uint16_t size, bool sign_extend) { -+ DCHECK(pos < 64 && 0 < size && size <= 64 && 0 < pos + size && -+ pos + size <= 64); -+ slli(rt, rs, 64 - (pos + size)); -+ if (sign_extend) { -+ srai(rt, rt, 64 - size); -+ } else { -+ srli(rt, rt, 64 - size); -+ } -+} -+ -+void TurboAssembler::InsertBits(Register dest, Register source, Register pos, -+ int size) { -+ DCHECK(size < 64); -+ UseScratchRegisterScope temps(this); -+ Register mask = temps.Acquire(); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register source_ = temps.hasAvailable() ? temps.Acquire() : t5; -+ // Create a mask of the length=size. -+ li(mask, 1); -+ slli(mask, mask, size); -+ addi(mask, mask, -1); -+ and_(source_, mask, source); -+ sll(source_, source_, pos); -+ // Make a mask containing 0's. 0's start at "pos" with length=size. -+ sll(mask, mask, pos); -+ not_(mask, mask); -+ // cut area for insertion of source. -+ and_(dest, mask, dest); -+ // insert source -+ or_(dest, dest, source_); -+} -+ -+void TurboAssembler::Neg_s(FPURegister fd, FPURegister fs) { fneg_s(fd, fs); } -+ -+void TurboAssembler::Neg_d(FPURegister fd, FPURegister fs) { fneg_d(fd, fs); } -+ -+void TurboAssembler::Cvt_d_uw(FPURegister fd, Register rs) { -+ // Convert rs to a FP value in fd. -+ fcvt_d_wu(fd, rs); -+} -+ -+void TurboAssembler::Cvt_d_w(FPURegister fd, Register rs) { -+ // Convert rs to a FP value in fd. -+ fcvt_d_w(fd, rs); -+} -+ -+void TurboAssembler::Cvt_d_ul(FPURegister fd, Register rs) { -+ // Convert rs to a FP value in fd. -+ fcvt_d_lu(fd, rs); -+} -+ -+void TurboAssembler::Cvt_s_uw(FPURegister fd, Register rs) { -+ // Convert rs to a FP value in fd. -+ fcvt_s_wu(fd, rs); -+} -+ -+void TurboAssembler::Cvt_s_w(FPURegister fd, Register rs) { -+ // Convert rs to a FP value in fd. -+ fcvt_s_w(fd, rs); -+} -+ -+void TurboAssembler::Cvt_s_ul(FPURegister fd, Register rs) { -+ // Convert rs to a FP value in fd. -+ fcvt_s_lu(fd, rs); -+} -+ -+template -+void TurboAssembler::RoundFloatingPointToInteger(Register rd, FPURegister fs, -+ Register result, -+ CvtFunc fcvt_generator) { -+ // Save csr_fflags to scratch & clear exception flags -+ if (result.is_valid()) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ -+ int exception_flags = kInvalidOperation; -+ csrrci(scratch, csr_fflags, exception_flags); -+ -+ // actual conversion instruction -+ fcvt_generator(this, rd, fs); -+ -+ // check kInvalidOperation flag (out-of-range, NaN) -+ // set result to 1 if normal, otherwise set result to 0 for abnormal -+ frflags(result); -+ andi(result, result, exception_flags); -+ seqz(result, result); // result <-- 1 (normal), result <-- 0 (abnormal) -+ -+ // restore csr_fflags -+ csrw(csr_fflags, scratch); -+ } else { -+ // actual conversion instruction -+ fcvt_generator(this, rd, fs); -+ } -+} -+ -+void TurboAssembler::Trunc_uw_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_wu_d(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_w_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_d(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_uw_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_wu_s(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_w_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_s(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_ul_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_lu_d(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_l_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_l_d(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_ul_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_lu_s(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Trunc_l_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_l_s(dst, src, RTZ); -+ }); -+} -+ -+void TurboAssembler::Round_w_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_s(dst, src, RNE); -+ }); -+} -+ -+void TurboAssembler::Round_w_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_d(dst, src, RNE); -+ }); -+} -+ -+void TurboAssembler::Ceil_w_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_s(dst, src, RUP); -+ }); -+} -+ -+void TurboAssembler::Ceil_w_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_d(dst, src, RUP); -+ }); -+} -+ -+void TurboAssembler::Floor_w_s(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_s(dst, src, RDN); -+ }); -+} -+ -+void TurboAssembler::Floor_w_d(Register rd, FPURegister fs, Register result) { -+ RoundFloatingPointToInteger( -+ rd, fs, result, [](TurboAssembler* tasm, Register dst, FPURegister src) { -+ tasm->fcvt_w_d(dst, src, RDN); -+ }); -+} -+ -+// According to JS ECMA specification, for floating-point round operations, if -+// the input is NaN, +/-infinity, or +/-0, the same input is returned as the -+// rounded result; this differs from behavior of RISCV fcvt instructions (which -+// round out-of-range values to the nearest max or min value), therefore special -+// handling is needed by NaN, +/-Infinity, +/-0 -+template -+void TurboAssembler::RoundHelper(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch, RoundingMode frm) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ -+ DCHECK((std::is_same::value) || (std::is_same::value)); -+ // Need at least two FPRs, so check against dst == src == fpu_scratch -+ DCHECK(!(dst == src && dst == fpu_scratch)); -+ -+ const int kFloat32ExponentBias = 127; -+ const int kFloat32MantissaBits = 23; -+ const int kFloat32ExponentBits = 8; -+ const int kFloat64ExponentBias = 1023; -+ const int kFloat64MantissaBits = 52; -+ const int kFloat64ExponentBits = 11; -+ const int kFloatMantissaBits = -+ sizeof(F) == 4 ? kFloat32MantissaBits : kFloat64MantissaBits; -+ const int kFloatExponentBits = -+ sizeof(F) == 4 ? kFloat32ExponentBits : kFloat64ExponentBits; -+ const int kFloatExponentBias = -+ sizeof(F) == 4 ? kFloat32ExponentBias : kFloat64ExponentBias; -+ -+ Label done; -+ -+ // extract exponent value of the source floating-point to t6 -+ if (std::is_same::value) { -+ fmv_x_d(scratch, src); -+ } else { -+ fmv_x_w(scratch, src); -+ } -+ ExtractBits(t6, scratch, kFloatMantissaBits, kFloatExponentBits); -+ -+ // if src is NaN/+-Infinity/+-Zero or if the exponent is larger than # of bits -+ // in mantissa, the result is the same as src, so move src to dest (to avoid -+ // generating another branch) -+ if (dst != src) { -+ if (std::is_same::value) { -+ fmv_d(dst, src); -+ } else { -+ fmv_s(dst, src); -+ } -+ } -+ -+ // If real exponent (i.e., t6 - kFloatExponentBias) is greater than -+ // kFloat32MantissaBits, it means the floating-point value has no fractional -+ // part, thus the input is already rounded, jump to done. Note that, NaN and -+ // Infinity in floating-point representation sets maximal exponent value, so -+ // they also satisfy (t6-kFloatExponentBias >= kFloatMantissaBits), and JS -+ // round semantics specify that rounding of NaN (Infinity) returns NaN -+ // (Infinity), so NaN and Infinity are considered rounded value too. -+ Branch(&done, greater_equal, t6, -+ Operand(kFloatExponentBias + kFloatMantissaBits)); -+ -+ // Actual rounding is needed along this path -+ -+ // old_src holds the original input, needed for the case of src == dst -+ FPURegister old_src = src; -+ if (src == dst) { -+ DCHECK(fpu_scratch != dst); -+ Move(fpu_scratch, src); -+ old_src = fpu_scratch; -+ } -+ -+ // Since only input whose real exponent value is less than kMantissaBits -+ // (i.e., 23 or 52-bits) falls into this path, the value range of the input -+ // falls into that of 23- or 53-bit integers. So we round the input to integer -+ // values, then convert them back to floating-point. -+ if (std::is_same::value) { -+ fcvt_l_d(scratch, src, frm); -+ fcvt_d_l(dst, scratch, frm); -+ } else { -+ fcvt_w_s(scratch, src, frm); -+ fcvt_s_w(dst, scratch, frm); -+ } -+ -+ // A special handling is needed if the input is a very small positive/negative -+ // number that rounds to zero. JS semantics requires that the rounded result -+ // retains the sign of the input, so a very small positive (negative) -+ // floating-point number should be rounded to positive (negative) 0. -+ // Therefore, we use sign-bit injection to produce +/-0 correctly. Instead of -+ // testing for zero w/ a branch, we just insert sign-bit for everyone on this -+ // path (this is where old_src is needed) -+ if (std::is_same::value) { -+ fsgnj_d(dst, dst, old_src); -+ } else { -+ fsgnj_s(dst, dst, old_src); -+ } -+ -+ bind(&done); -+} -+ -+void TurboAssembler::Floor_d_d(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RDN); -+} -+ -+void TurboAssembler::Ceil_d_d(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RUP); -+} -+ -+void TurboAssembler::Trunc_d_d(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RTZ); -+} -+ -+void TurboAssembler::Round_d_d(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RNE); -+} -+ -+void TurboAssembler::Floor_s_s(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RDN); -+} -+ -+void TurboAssembler::Ceil_s_s(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RUP); -+} -+ -+void TurboAssembler::Trunc_s_s(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RTZ); -+} -+ -+void TurboAssembler::Round_s_s(FPURegister dst, FPURegister src, -+ FPURegister fpu_scratch) { -+ RoundHelper(dst, src, fpu_scratch, RNE); -+} -+ -+void MacroAssembler::Madd_s(FPURegister fd, FPURegister fr, FPURegister fs, -+ FPURegister ft) { -+ fmadd_s(fd, fs, ft, fr); -+} -+ -+void MacroAssembler::Madd_d(FPURegister fd, FPURegister fr, FPURegister fs, -+ FPURegister ft) { -+ fmadd_d(fd, fs, ft, fr); -+} -+ -+void MacroAssembler::Msub_s(FPURegister fd, FPURegister fr, FPURegister fs, -+ FPURegister ft) { -+ fmsub_s(fd, fs, ft, fr); -+} -+ -+void MacroAssembler::Msub_d(FPURegister fd, FPURegister fr, FPURegister fs, -+ FPURegister ft) { -+ fmsub_d(fd, fs, ft, fr); -+} -+ -+void TurboAssembler::CompareF32(Register rd, FPUCondition cc, FPURegister cmp1, -+ FPURegister cmp2) { -+ switch (cc) { -+ case EQ: -+ feq_s(rd, cmp1, cmp2); -+ break; -+ case NE: -+ feq_s(rd, cmp1, cmp2); -+ NegateBool(rd, rd); -+ break; -+ case LT: -+ flt_s(rd, cmp1, cmp2); -+ break; -+ case GE: -+ fle_s(rd, cmp2, cmp1); -+ break; -+ case LE: -+ fle_s(rd, cmp1, cmp2); -+ break; -+ case GT: -+ flt_s(rd, cmp2, cmp1); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+void TurboAssembler::CompareF64(Register rd, FPUCondition cc, FPURegister cmp1, -+ FPURegister cmp2) { -+ switch (cc) { -+ case EQ: -+ feq_d(rd, cmp1, cmp2); -+ break; -+ case NE: -+ feq_d(rd, cmp1, cmp2); -+ NegateBool(rd, rd); -+ break; -+ case LT: -+ flt_d(rd, cmp1, cmp2); -+ break; -+ case GE: -+ fle_d(rd, cmp2, cmp1); -+ break; -+ case LE: -+ fle_d(rd, cmp1, cmp2); -+ break; -+ case GT: -+ flt_d(rd, cmp2, cmp1); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+void TurboAssembler::CompareIsNanF32(Register rd, FPURegister cmp1, -+ FPURegister cmp2) { -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ -+ feq_s(rd, cmp1, cmp1); // rd <- !isNan(cmp1) -+ feq_s(scratch, cmp2, cmp2); // scratch <- !isNaN(cmp2) -+ And(rd, rd, scratch); // rd <- !isNan(cmp1) && !isNan(cmp2) -+ Xor(rd, rd, 1); // rd <- isNan(cmp1) || isNan(cmp2) -+} -+ -+void TurboAssembler::CompareIsNanF64(Register rd, FPURegister cmp1, -+ FPURegister cmp2) { -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ -+ feq_d(rd, cmp1, cmp1); // rd <- !isNan(cmp1) -+ feq_d(scratch, cmp2, cmp2); // scratch <- !isNaN(cmp2) -+ And(rd, rd, scratch); // rd <- !isNan(cmp1) && !isNan(cmp2) -+ Xor(rd, rd, 1); // rd <- isNan(cmp1) || isNan(cmp2) -+} -+ -+void TurboAssembler::BranchTrueShortF(Register rs, Label* target) { -+ Branch(target, not_equal, rs, Operand(zero_reg)); -+} -+ -+void TurboAssembler::BranchFalseShortF(Register rs, Label* target) { -+ Branch(target, equal, rs, Operand(zero_reg)); -+} -+ -+void TurboAssembler::BranchTrueF(Register rs, Label* target) { -+ bool long_branch = -+ target->is_bound() ? !is_near(target) : is_trampoline_emitted(); -+ if (long_branch) { -+ Label skip; -+ BranchFalseShortF(rs, &skip); -+ BranchLong(target); -+ bind(&skip); -+ } else { -+ BranchTrueShortF(rs, target); -+ } -+} -+ -+void TurboAssembler::BranchFalseF(Register rs, Label* target) { -+ bool long_branch = -+ target->is_bound() ? !is_near(target) : is_trampoline_emitted(); -+ if (long_branch) { -+ Label skip; -+ BranchTrueShortF(rs, &skip); -+ BranchLong(target); -+ bind(&skip); -+ } else { -+ BranchFalseShortF(rs, target); -+ } -+} -+ -+void TurboAssembler::InsertHighWordF64(FPURegister dst, Register src_high) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ -+ DCHECK(src_high != t5 && src_high != scratch); -+ -+ fmv_x_d(scratch, dst); -+ slli(t5, src_high, 32); -+ slli(scratch, scratch, 32); -+ srli(scratch, scratch, 32); -+ or_(scratch, scratch, t5); -+ fmv_d_x(dst, scratch); -+} -+ -+void TurboAssembler::InsertLowWordF64(FPURegister dst, Register src_low) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ UseScratchRegisterScope block_trampoline_pool(this); -+ -+ DCHECK(src_low != scratch && src_low != t5); -+ fmv_x_d(scratch, dst); -+ slli(t5, src_low, 32); -+ srli(t5, t5, 32); -+ srli(scratch, scratch, 32); -+ slli(scratch, scratch, 32); -+ or_(scratch, scratch, t5); -+ fmv_d_x(dst, scratch); -+} -+ -+void TurboAssembler::LoadFPRImmediate(FPURegister dst, uint32_t src) { -+ // Handle special values first. -+ if (src == bit_cast(0.0f) && has_single_zero_reg_set_) { -+ if (dst != kDoubleRegZero) fmv_s(dst, kDoubleRegZero); -+ } else if (src == bit_cast(-0.0f) && has_single_zero_reg_set_) { -+ Neg_s(dst, kDoubleRegZero); -+ } else { -+ if (dst == kDoubleRegZero) { -+ DCHECK(src == bit_cast(0.0f)); -+ fmv_w_x(dst, zero_reg); -+ has_single_zero_reg_set_ = true; -+ has_double_zero_reg_set_ = false; -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, Operand(static_cast(src))); -+ fmv_w_x(dst, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::LoadFPRImmediate(FPURegister dst, uint64_t src) { -+ // Handle special values first. -+ if (src == bit_cast(0.0) && has_double_zero_reg_set_) { -+ if (dst != kDoubleRegZero) fmv_d(dst, kDoubleRegZero); -+ } else if (src == bit_cast(-0.0) && has_double_zero_reg_set_) { -+ Neg_d(dst, kDoubleRegZero); -+ } else { -+ if (dst == kDoubleRegZero) { -+ DCHECK(src == bit_cast(0.0)); -+ fmv_d_x(dst, zero_reg); -+ has_double_zero_reg_set_ = true; -+ has_single_zero_reg_set_ = false; -+ } else { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, Operand(src)); -+ fmv_d_x(dst, scratch); -+ } -+ } -+} -+ -+void TurboAssembler::CompareI(Register rd, Register rs, const Operand& rt, -+ Condition cond) { -+ switch (cond) { -+ case eq: -+ Seq(rd, rs, rt); -+ break; -+ case ne: -+ Sne(rd, rs, rt); -+ break; -+ -+ // Signed comparison. -+ case greater: -+ Sgt(rd, rs, rt); -+ break; -+ case greater_equal: -+ Sge(rd, rs, rt); // rs >= rt -+ break; -+ case less: -+ Slt(rd, rs, rt); // rs < rt -+ break; -+ case less_equal: -+ Sle(rd, rs, rt); // rs <= rt -+ break; -+ -+ // Unsigned comparison. -+ case Ugreater: -+ Sgtu(rd, rs, rt); // rs > rt -+ break; -+ case Ugreater_equal: -+ Sgeu(rd, rs, rt); // rs >= rt -+ break; -+ case Uless: -+ Sltu(rd, rs, rt); // rs < rt -+ break; -+ case Uless_equal: -+ Sleu(rd, rs, rt); // rs <= rt -+ break; -+ case cc_always: -+ UNREACHABLE(); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+// dest <- (condition != 0 ? zero : dest) -+void TurboAssembler::LoadZeroIfConditionNotZero(Register dest, -+ Register condition) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ seqz(scratch, condition); -+ // neg + and may be more efficient than mul(dest, dest, scratch) -+ neg(scratch, scratch); // 0 is still 0, 1 becomes all 1s -+ and_(dest, dest, scratch); -+} -+ -+// dest <- (condition == 0 ? 0 : dest) -+void TurboAssembler::LoadZeroIfConditionZero(Register dest, -+ Register condition) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ snez(scratch, condition); -+ // neg + and may be more efficient than mul(dest, dest, scratch); -+ neg(scratch, scratch); // 0 is still 0, 1 becomes all 1s -+ and_(dest, dest, scratch); -+} -+ -+void TurboAssembler::Clz32(Register rd, Register xx) { -+ // 32 bit unsigned in lower word: count number of leading zeros. -+ // int n = 32; -+ // unsigned y; -+ -+ // y = x >>16; if (y != 0) { n = n -16; x = y; } -+ // y = x >> 8; if (y != 0) { n = n - 8; x = y; } -+ // y = x >> 4; if (y != 0) { n = n - 4; x = y; } -+ // y = x >> 2; if (y != 0) { n = n - 2; x = y; } -+ // y = x >> 1; if (y != 0) {rd = n - 2; return;} -+ // rd = n - x; -+ -+ Label L0, L1, L2, L3, L4; -+ DCHECK(xx != t5 && xx != t6); -+ UseScratchRegisterScope temps(this); -+ UseScratchRegisterScope block_trampoline_pool(this); -+ Register x = rd; -+ Register y = t5; -+ Register n = t6; -+ Move(x, xx); -+ li(n, Operand(32)); -+ srliw(y, x, 16); -+ Branch(&L0, eq, y, Operand(zero_reg)); -+ Move(x, y); -+ addiw(n, n, -16); -+ bind(&L0); -+ srliw(y, x, 8); -+ Branch(&L1, eq, y, Operand(zero_reg)); -+ addiw(n, n, -8); -+ Move(x, y); -+ bind(&L1); -+ srliw(y, x, 4); -+ Branch(&L2, eq, y, Operand(zero_reg)); -+ addiw(n, n, -4); -+ Move(x, y); -+ bind(&L2); -+ srliw(y, x, 2); -+ Branch(&L3, eq, y, Operand(zero_reg)); -+ addiw(n, n, -2); -+ Move(x, y); -+ bind(&L3); -+ srliw(y, x, 1); -+ subw(rd, n, x); -+ Branch(&L4, eq, y, Operand(zero_reg)); -+ addiw(rd, n, -2); -+ bind(&L4); -+} -+ -+void TurboAssembler::Clz64(Register rd, Register xx) { -+ // 64 bit: count number of leading zeros. -+ // int n = 64; -+ // unsigned y; -+ -+ // y = x >>32; if (y != 0) { n = n - 32; x = y; } -+ // y = x >>16; if (y != 0) { n = n - 16; x = y; } -+ // y = x >> 8; if (y != 0) { n = n - 8; x = y; } -+ // y = x >> 4; if (y != 0) { n = n - 4; x = y; } -+ // y = x >> 2; if (y != 0) { n = n - 2; x = y; } -+ // y = x >> 1; if (y != 0) {rd = n - 2; return;} -+ // rd = n - x; -+ -+ DCHECK(xx != t5 && xx != t6); -+ Label L0, L1, L2, L3, L4, L5; -+ UseScratchRegisterScope temps(this); -+ UseScratchRegisterScope block_trampoline_pool(this); -+ Register x = rd; -+ Register y = t5; -+ Register n = t6; -+ Move(x, xx); -+ li(n, Operand(64)); -+ srli(y, x, 32); -+ Branch(&L0, eq, y, Operand(zero_reg)); -+ addiw(n, n, -32); -+ Move(x, y); -+ bind(&L0); -+ srli(y, x, 16); -+ Branch(&L1, eq, y, Operand(zero_reg)); -+ addiw(n, n, -16); -+ Move(x, y); -+ bind(&L1); -+ srli(y, x, 8); -+ Branch(&L2, eq, y, Operand(zero_reg)); -+ addiw(n, n, -8); -+ Move(x, y); -+ bind(&L2); -+ srli(y, x, 4); -+ Branch(&L3, eq, y, Operand(zero_reg)); -+ addiw(n, n, -4); -+ Move(x, y); -+ bind(&L3); -+ srli(y, x, 2); -+ Branch(&L4, eq, y, Operand(zero_reg)); -+ addiw(n, n, -2); -+ Move(x, y); -+ bind(&L4); -+ srli(y, x, 1); -+ subw(rd, n, x); -+ Branch(&L5, eq, y, Operand(zero_reg)); -+ addiw(rd, n, -2); -+ bind(&L5); -+} -+ -+void TurboAssembler::Ctz32(Register rd, Register rs) { -+ // Convert trailing zeroes to trailing ones, and bits to their left -+ // to zeroes. -+ UseScratchRegisterScope temps(this); -+ UseScratchRegisterScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ Add64(scratch, rs, -1); -+ Xor(rd, scratch, rs); -+ And(rd, rd, scratch); -+ // Count number of leading zeroes. -+ Clz32(rd, rd); -+ // Subtract number of leading zeroes from 32 to get number of trailing -+ // ones. Remember that the trailing ones were formerly trailing zeroes. -+ li(scratch, 32); -+ Sub32(rd, scratch, rd); -+} -+ -+void TurboAssembler::Ctz64(Register rd, Register rs) { -+ // Convert trailing zeroes to trailing ones, and bits to their left -+ // to zeroes. -+ UseScratchRegisterScope temps(this); -+ UseScratchRegisterScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ Add64(scratch, rs, -1); -+ Xor(rd, scratch, rs); -+ And(rd, rd, scratch); -+ // Count number of leading zeroes. -+ Clz64(rd, rd); -+ // Subtract number of leading zeroes from 64 to get number of trailing -+ // ones. Remember that the trailing ones were formerly trailing zeroes. -+ li(scratch, 64); -+ Sub64(rd, scratch, rd); -+} -+ -+void TurboAssembler::Popcnt32(Register rd, Register rs) { -+ // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel -+ // -+ // A generalization of the best bit counting method to integers of -+ // bit-widths up to 128 (parameterized by type T) is this: -+ // -+ // v = v - ((v >> 1) & (T)~(T)0/3); // temp -+ // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp -+ // v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp -+ // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; //count -+ // -+ // There are algorithms which are faster in the cases where very few -+ // bits are set but the algorithm here attempts to minimize the total -+ // number of instructions executed even when a large number of bits -+ // are set. -+ // The number of instruction is 20. -+ // uint32_t B0 = 0x55555555; // (T)~(T)0/3 -+ // uint32_t B1 = 0x33333333; // (T)~(T)0/15*3 -+ // uint32_t B2 = 0x0F0F0F0F; // (T)~(T)0/255*15 -+ // uint32_t value = 0x01010101; // (T)~(T)0/255 -+ -+ DCHECK(rd != t5 && rd != t6 && rs != t5 && rs != t6); -+ uint32_t shift = 24; -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.Acquire(); -+ Register scratch2 = t5; -+ Register value = t6; -+ li(value, 0x01010101); // value = 0x01010101; -+ li(scratch2, 0x55555555); // B0 = 0x55555555; -+ Srl32(scratch, rs, 1); -+ And(scratch, scratch, scratch2); -+ Sub32(scratch, rs, scratch); -+ li(scratch2, 0x33333333); // B1 = 0x33333333; -+ slli(rd, scratch2, 4); -+ or_(scratch2, scratch2, rd); -+ And(rd, scratch, scratch2); -+ Srl32(scratch, scratch, 2); -+ And(scratch, scratch, scratch2); -+ Add32(scratch, rd, scratch); -+ srliw(rd, scratch, 4); -+ Add32(rd, rd, scratch); -+ li(scratch2, 0xF); -+ Mul32(scratch2, value, scratch2); // B2 = 0x0F0F0F0F; -+ And(rd, rd, scratch2); -+ Mul32(rd, rd, value); -+ Srl32(rd, rd, shift); -+} -+ -+void TurboAssembler::Popcnt64(Register rd, Register rs) { -+ // uint64_t B0 = 0x5555555555555555l; // (T)~(T)0/3 -+ // uint64_t B1 = 0x3333333333333333l; // (T)~(T)0/15*3 -+ // uint64_t B2 = 0x0F0F0F0F0F0F0F0Fl; // (T)~(T)0/255*15 -+ // uint64_t value = 0x0101010101010101l; // (T)~(T)0/255 -+ // uint64_t shift = 24; // (sizeof(T) - 1) * BITS_PER_BYTE -+ -+ DCHECK(rd != t5 && rd != t6 && rs != t5 && rs != t6); -+ uint64_t shift = 24; -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.Acquire(); -+ Register scratch2 = t5; -+ Register value = t6; -+ li(value, 0x1111111111111111l); // value = 0x1111111111111111l; -+ li(scratch2, 5); -+ Mul64(scratch2, value, scratch2); // B0 = 0x5555555555555555l; -+ Srl64(scratch, rs, 1); -+ And(scratch, scratch, scratch2); -+ Sub64(scratch, rs, scratch); -+ li(scratch2, 3); -+ Mul64(scratch2, value, scratch2); // B1 = 0x3333333333333333l; -+ And(rd, scratch, scratch2); -+ Srl64(scratch, scratch, 2); -+ And(scratch, scratch, scratch2); -+ Add64(scratch, rd, scratch); -+ Srl64(rd, scratch, 4); -+ Add64(rd, rd, scratch); -+ li(scratch2, 0xF); -+ li(value, 0x0101010101010101l); // value = 0x0101010101010101l; -+ Mul64(scratch2, value, scratch2); // B2 = 0x0F0F0F0F0F0F0F0Fl; -+ And(rd, rd, scratch2); -+ Mul64(rd, rd, value); -+ srli(rd, rd, 32 + shift); -+} -+ -+void TurboAssembler::TryInlineTruncateDoubleToI(Register result, -+ DoubleRegister double_input, -+ Label* done) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ // if scratch == 1, exception happens during truncation -+ Trunc_w_d(result, double_input, scratch); -+ // If we had no exceptions (i.e., scratch==1) we are done. -+ Branch(done, eq, scratch, Operand(1)); -+} -+ -+void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone, -+ Register result, -+ DoubleRegister double_input, -+ StubCallMode stub_mode) { -+ Label done; -+ -+ TryInlineTruncateDoubleToI(result, double_input, &done); -+ -+ // If we fell through then inline version didn't succeed - call stub -+ // instead. -+ push(ra); -+ Sub64(sp, sp, Operand(kDoubleSize)); // Put input on stack. -+ fsd(double_input, sp, 0); -+ -+ if (stub_mode == StubCallMode::kCallWasmRuntimeStub) { -+ Call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL); -+ } else { -+ Call(BUILTIN_CODE(isolate, DoubleToI), RelocInfo::CODE_TARGET); -+ } -+ ld(result, sp, 0); -+ -+ Add64(sp, sp, Operand(kDoubleSize)); -+ pop(ra); -+ -+ bind(&done); -+} -+ -+// BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. -+#define BRANCH_ARGS_CHECK(cond, rs, rt) \ -+ DCHECK((cond == cc_always && rs == zero_reg && rt.rm() == zero_reg) || \ -+ (cond != cc_always && (rs != zero_reg || rt.rm() != zero_reg))) -+ -+void TurboAssembler::Branch(int32_t offset) { -+ DCHECK(is_int21(offset)); -+ BranchShort(offset); -+} -+ -+void TurboAssembler::Branch(int32_t offset, Condition cond, Register rs, -+ const Operand& rt) { -+ bool is_near = BranchShortCheck(offset, nullptr, cond, rs, rt); -+ DCHECK(is_near); -+ USE(is_near); -+} -+ -+void TurboAssembler::Branch(Label* L) { -+ if (L->is_bound()) { -+ if (is_near(L)) { -+ BranchShort(L); -+ } else { -+ BranchLong(L); -+ } -+ } else { -+ if (is_trampoline_emitted()) { -+ BranchLong(L); -+ } else { -+ BranchShort(L); -+ } -+ } -+} -+ -+void TurboAssembler::Branch(Label* L, Condition cond, Register rs, -+ const Operand& rt) { -+ if (L->is_bound()) { -+ if (!BranchShortCheck(0, L, cond, rs, rt)) { -+ if (cond != cc_always) { -+ Label skip; -+ Condition neg_cond = NegateCondition(cond); -+ BranchShort(&skip, neg_cond, rs, rt); -+ BranchLong(L); -+ bind(&skip); -+ } else { -+ BranchLong(L); -+ } -+ } -+ } else { -+ if (is_trampoline_emitted()) { -+ if (cond != cc_always) { -+ Label skip; -+ Condition neg_cond = NegateCondition(cond); -+ BranchShort(&skip, neg_cond, rs, rt); -+ BranchLong(L); -+ bind(&skip); -+ } else { -+ BranchLong(L); -+ } -+ } else { -+ BranchShort(L, cond, rs, rt); -+ } -+ } -+} -+ -+void TurboAssembler::Branch(Label* L, Condition cond, Register rs, -+ RootIndex index) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ LoadRoot(scratch, index); -+ Branch(L, cond, rs, Operand(scratch)); -+} -+ -+void TurboAssembler::BranchShortHelper(int32_t offset, Label* L) { -+ DCHECK(L == nullptr || offset == 0); -+ offset = GetOffset(offset, L, OffsetSize::kOffset21); -+ j(offset); -+} -+ -+void TurboAssembler::BranchShort(int32_t offset) { -+ DCHECK(is_int21(offset)); -+ BranchShortHelper(offset, nullptr); -+} -+ -+void TurboAssembler::BranchShort(Label* L) { BranchShortHelper(0, L); } -+ -+int32_t TurboAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) { -+ if (L) { -+ offset = branch_offset_helper(L, bits); -+ } else { -+ DCHECK(is_intn(offset, bits)); -+ } -+ return offset; -+} -+ -+Register TurboAssembler::GetRtAsRegisterHelper(const Operand& rt, -+ Register scratch) { -+ Register r2 = no_reg; -+ if (rt.is_reg()) { -+ r2 = rt.rm(); -+ } else { -+ r2 = scratch; -+ li(r2, rt); -+ } -+ -+ return r2; -+} -+ -+bool TurboAssembler::CalculateOffset(Label* L, int32_t* offset, -+ OffsetSize bits) { -+ if (!is_near(L, bits)) return false; -+ *offset = GetOffset(*offset, L, bits); -+ return true; -+} -+ -+bool TurboAssembler::CalculateOffset(Label* L, int32_t* offset, OffsetSize bits, -+ Register* scratch, const Operand& rt) { -+ if (!is_near(L, bits)) return false; -+ *scratch = GetRtAsRegisterHelper(rt, *scratch); -+ *offset = GetOffset(*offset, L, bits); -+ return true; -+} -+ -+bool TurboAssembler::BranchShortHelper(int32_t offset, Label* L, Condition cond, -+ Register rs, const Operand& rt) { -+ DCHECK(L == nullptr || offset == 0); -+ UseScratchRegisterScope temps(this); -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register scratch = temps.hasAvailable() ? temps.Acquire() : t5; -+ -+ { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ switch (cond) { -+ case cc_always: -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; -+ j(offset); -+ break; -+ case eq: -+ // rs == rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; -+ j(offset); -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ beq(rs, scratch, offset); -+ } -+ break; -+ case ne: -+ // rs != rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ break; // No code needs to be emitted -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bne(rs, scratch, offset); -+ } -+ break; -+ -+ // Signed comparison. -+ case greater: -+ // rs > rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ break; // No code needs to be emitted. -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bgt(rs, scratch, offset); -+ } -+ break; -+ case greater_equal: -+ // rs >= rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; -+ j(offset); -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bge(rs, scratch, offset); -+ } -+ break; -+ case less: -+ // rs < rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ break; // No code needs to be emitted. -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ blt(rs, scratch, offset); -+ } -+ break; -+ case less_equal: -+ // rs <= rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; -+ j(offset); -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ ble(rs, scratch, offset); -+ } -+ break; -+ -+ // Unsigned comparison. -+ case Ugreater: -+ // rs > rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ break; // No code needs to be emitted. -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bgtu(rs, scratch, offset); -+ } -+ break; -+ case Ugreater_equal: -+ // rs >= rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; -+ j(offset); -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bgeu(rs, scratch, offset); -+ } -+ break; -+ case Uless: -+ // rs < rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ break; // No code needs to be emitted. -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bltu(rs, scratch, offset); -+ } -+ break; -+ case Uless_equal: -+ // rs <= rt -+ if (rt.is_reg() && rs == rt.rm()) { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; -+ j(offset); -+ } else { -+ if (!CalculateOffset(L, &offset, OffsetSize::kOffset13, &scratch, rt)) -+ return false; -+ DCHECK(rs != scratch); -+ bleu(rs, scratch, offset); -+ } -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+ -+ CheckTrampolinePoolQuick(1); -+ return true; -+} -+ -+bool TurboAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond, -+ Register rs, const Operand& rt) { -+ BRANCH_ARGS_CHECK(cond, rs, rt); -+ -+ if (!L) { -+ DCHECK(is_int13(offset)); -+ return BranchShortHelper(offset, nullptr, cond, rs, rt); -+ } else { -+ DCHECK_EQ(offset, 0); -+ return BranchShortHelper(0, L, cond, rs, rt); -+ } -+ return false; -+} -+ -+void TurboAssembler::BranchShort(int32_t offset, Condition cond, Register rs, -+ const Operand& rt) { -+ BranchShortCheck(offset, nullptr, cond, rs, rt); -+} -+ -+void TurboAssembler::BranchShort(Label* L, Condition cond, Register rs, -+ const Operand& rt) { -+ BranchShortCheck(0, L, cond, rs, rt); -+} -+ -+void TurboAssembler::BranchAndLink(int32_t offset) { -+ BranchAndLinkShort(offset); -+} -+ -+void TurboAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs, -+ const Operand& rt) { -+ bool is_near = BranchAndLinkShortCheck(offset, nullptr, cond, rs, rt); -+ DCHECK(is_near); -+ USE(is_near); -+} -+ -+void TurboAssembler::BranchAndLink(Label* L) { -+ if (L->is_bound()) { -+ if (is_near(L)) { -+ BranchAndLinkShort(L); -+ } else { -+ BranchAndLinkLong(L); -+ } -+ } else { -+ if (is_trampoline_emitted()) { -+ BranchAndLinkLong(L); -+ } else { -+ BranchAndLinkShort(L); -+ } -+ } -+} -+ -+void TurboAssembler::BranchAndLink(Label* L, Condition cond, Register rs, -+ const Operand& rt) { -+ if (L->is_bound()) { -+ if (!BranchAndLinkShortCheck(0, L, cond, rs, rt)) { -+ Label skip; -+ Condition neg_cond = NegateCondition(cond); -+ BranchShort(&skip, neg_cond, rs, rt); -+ BranchAndLinkLong(L); -+ bind(&skip); -+ } -+ } else { -+ if (is_trampoline_emitted()) { -+ Label skip; -+ Condition neg_cond = NegateCondition(cond); -+ BranchShort(&skip, neg_cond, rs, rt); -+ BranchAndLinkLong(L); -+ bind(&skip); -+ } else { -+ BranchAndLinkShortCheck(0, L, cond, rs, rt); -+ } -+ } -+} -+ -+void TurboAssembler::BranchAndLinkShortHelper(int32_t offset, Label* L) { -+ DCHECK(L == nullptr || offset == 0); -+ offset = GetOffset(offset, L, OffsetSize::kOffset21); -+ jal(offset); -+} -+ -+void TurboAssembler::BranchAndLinkShort(int32_t offset) { -+ DCHECK(is_int21(offset)); -+ BranchAndLinkShortHelper(offset, nullptr); -+} -+ -+void TurboAssembler::BranchAndLinkShort(Label* L) { -+ BranchAndLinkShortHelper(0, L); -+} -+ -+// Pre r6 we need to use a bgezal or bltzal, but they can't be used directly -+// with the slt instructions. We could use sub or add instead but we would miss -+// overflow cases, so we keep slt and add an intermediate third instruction. -+bool TurboAssembler::BranchAndLinkShortHelper(int32_t offset, Label* L, -+ Condition cond, Register rs, -+ const Operand& rt) { -+ DCHECK(L == nullptr || offset == 0); -+ if (!is_near(L, OffsetSize::kOffset21)) return false; -+ -+ Register scratch = t5; -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ -+ if (cond == cc_always) { -+ offset = GetOffset(offset, L, OffsetSize::kOffset21); -+ jal(offset); -+ } else { -+ Branch(kInstrSize * 2, NegateCondition(cond), rs, -+ Operand(GetRtAsRegisterHelper(rt, scratch))); -+ offset = GetOffset(offset, L, OffsetSize::kOffset21); -+ jal(offset); -+ } -+ -+ return true; -+} -+ -+bool TurboAssembler::BranchAndLinkShortCheck(int32_t offset, Label* L, -+ Condition cond, Register rs, -+ const Operand& rt) { -+ BRANCH_ARGS_CHECK(cond, rs, rt); -+ -+ if (!L) { -+ DCHECK(is_int21(offset)); -+ return BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt); -+ } else { -+ DCHECK_EQ(offset, 0); -+ return BranchAndLinkShortHelper(0, L, cond, rs, rt); -+ } -+ return false; -+} -+ -+void TurboAssembler::LoadFromConstantsTable(Register destination, -+ int constant_index) { -+ DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable)); -+ LoadRoot(destination, RootIndex::kBuiltinsConstantsTable); -+ Ld(destination, -+ FieldMemOperand(destination, -+ FixedArray::kHeaderSize + constant_index * kPointerSize)); -+} -+ -+void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) { -+ Ld(destination, MemOperand(kRootRegister, offset)); -+} -+ -+void TurboAssembler::LoadRootRegisterOffset(Register destination, -+ intptr_t offset) { -+ if (offset == 0) { -+ Move(destination, kRootRegister); -+ } else { -+ Add64(destination, kRootRegister, Operand(offset)); -+ } -+} -+ -+void TurboAssembler::Jump(Register target, Condition cond, Register rs, -+ const Operand& rt) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (cond == cc_always) { -+ jr(target); -+ } else { -+ BRANCH_ARGS_CHECK(cond, rs, rt); -+ Branch(kInstrSize * 2, NegateCondition(cond), rs, rt); -+ jr(target); -+ } -+} -+ -+void TurboAssembler::Jump(intptr_t target, RelocInfo::Mode rmode, -+ Condition cond, Register rs, const Operand& rt) { -+ Label skip; -+ if (cond != cc_always) { -+ Branch(&skip, NegateCondition(cond), rs, rt); -+ } -+ { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ li(t6, Operand(target, rmode)); -+ Jump(t6, al, zero_reg, Operand(zero_reg)); -+ bind(&skip); -+ } -+} -+ -+void TurboAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond, -+ Register rs, const Operand& rt) { -+ DCHECK(!RelocInfo::IsCodeTarget(rmode)); -+ Jump(static_cast(target), rmode, cond, rs, rt); -+} -+ -+void TurboAssembler::Jump(Handle code, RelocInfo::Mode rmode, -+ Condition cond, Register rs, const Operand& rt) { -+ DCHECK(RelocInfo::IsCodeTarget(rmode)); -+ -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (root_array_available_ && options().isolate_independent_code) { -+ IndirectLoadConstant(t6, code); -+ Add64(t6, t6, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ Jump(t6, cond, rs, rt); -+ return; -+ } else if (options().inline_offheap_trampolines) { -+ int builtin_index = Builtins::kNoBuiltinId; -+ if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) && -+ Builtins::IsIsolateIndependent(builtin_index)) { -+ // Inline the trampoline. -+ RecordCommentForOffHeapTrampoline(builtin_index); -+ CHECK_NE(builtin_index, Builtins::kNoBuiltinId); -+ EmbeddedData d = EmbeddedData::FromBlob(); -+ Address entry = d.InstructionStartOfBuiltin(builtin_index); -+ li(t6, Operand(entry, RelocInfo::OFF_HEAP_TARGET)); -+ Jump(t6, cond, rs, rt); -+ return; -+ } -+ } -+ -+ Jump(static_cast(code.address()), rmode, cond, rs, rt); -+} -+ -+void TurboAssembler::Jump(const ExternalReference& reference) { -+ li(t6, reference); -+ Jump(t6); -+} -+ -+// FIXME (RISCV): the comment does not make sense, where is t6 used? -+// Note: To call gcc-compiled C code on riscv64, you must call through t6. -+void TurboAssembler::Call(Register target, Condition cond, Register rs, -+ const Operand& rt) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (cond == cc_always) { -+ jalr(ra, target, 0); -+ } else { -+ BRANCH_ARGS_CHECK(cond, rs, rt); -+ Branch(kInstrSize * 2, NegateCondition(cond), rs, rt); -+ jalr(ra, target, 0); -+ } -+} -+ -+void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit, -+ unsigned higher_limit, -+ Label* on_in_range) { -+ if (lower_limit != 0) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Sub64(scratch, value, Operand(lower_limit)); -+ Branch(on_in_range, Uless_equal, scratch, -+ Operand(higher_limit - lower_limit)); -+ } else { -+ Branch(on_in_range, Uless_equal, value, -+ Operand(higher_limit - lower_limit)); -+ } -+} -+ -+void TurboAssembler::Call(Address target, RelocInfo::Mode rmode, Condition cond, -+ Register rs, const Operand& rt) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ li(t6, Operand(static_cast(target), rmode), ADDRESS_LOAD); -+ Call(t6, cond, rs, rt); -+} -+ -+void TurboAssembler::Call(Handle code, RelocInfo::Mode rmode, -+ Condition cond, Register rs, const Operand& rt) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ -+ if (root_array_available_ && options().isolate_independent_code) { -+ IndirectLoadConstant(t6, code); -+ Add64(t6, t6, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ Call(t6, cond, rs, rt); -+ return; -+ } else if (options().inline_offheap_trampolines) { -+ int builtin_index = Builtins::kNoBuiltinId; -+ if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) && -+ Builtins::IsIsolateIndependent(builtin_index)) { -+ // Inline the trampoline. -+ RecordCommentForOffHeapTrampoline(builtin_index); -+ CHECK_NE(builtin_index, Builtins::kNoBuiltinId); -+ EmbeddedData d = EmbeddedData::FromBlob(); -+ Address entry = d.InstructionStartOfBuiltin(builtin_index); -+ li(t6, Operand(entry, RelocInfo::OFF_HEAP_TARGET)); -+ Call(t6, cond, rs, rt); -+ return; -+ } -+ } -+ -+ DCHECK(RelocInfo::IsCodeTarget(rmode)); -+ DCHECK(code->IsExecutable()); -+ Call(code.address(), rmode, cond, rs, rt); -+} -+ -+void TurboAssembler::LoadEntryFromBuiltinIndex(Register builtin_index) { -+ STATIC_ASSERT(kSystemPointerSize == 8); -+ STATIC_ASSERT(kSmiTagSize == 1); -+ STATIC_ASSERT(kSmiTag == 0); -+ -+ // The builtin_index register contains the builtin index as a Smi. -+ SmiUntag(builtin_index, builtin_index); -+ CalcScaledAddress(builtin_index, kRootRegister, builtin_index, -+ kSystemPointerSizeLog2); -+ Ld(builtin_index, -+ MemOperand(builtin_index, IsolateData::builtin_entry_table_offset())); -+} -+ -+void TurboAssembler::CallBuiltinByIndex(Register builtin_index) { -+ LoadEntryFromBuiltinIndex(builtin_index); -+ Call(builtin_index); -+} -+ -+void TurboAssembler::PatchAndJump(Address target) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ auipc(scratch, 0); // Load PC into scratch -+ Ld(t6, MemOperand(scratch, kInstrSize * 4)); -+ jr(t6); -+ nop(); // For alignment -+ DCHECK_EQ(reinterpret_cast(pc_) % 8, 0); -+ *reinterpret_cast(pc_) = target; // pc_ should be align. -+ pc_ += sizeof(uint64_t); -+} -+ -+void TurboAssembler::StoreReturnAddressAndCall(Register target) { -+ // This generates the final instruction sequence for calls to C functions -+ // once an exit frame has been constructed. -+ // -+ // Note that this assumes the caller code (i.e. the Code object currently -+ // being generated) is immovable or that the callee function cannot trigger -+ // GC, since the callee function will return to it. -+ -+ // Compute the return address in lr to return to after the jump below. The -+ // pc is already at '+ 8' from the current instruction; but return is after -+ // three instructions, so add another 4 to pc to get the return address. -+ -+ Assembler::BlockTrampolinePoolScope block_trampoline_pool(this); -+ static constexpr int kNumInstructionsToJump = 5; -+ Label find_ra; -+ // Adjust the value in ra to point to the correct return location, one -+ // instruction past the real call into C code (the jalr(t6)), and push it. -+ // This is the return address of the exit frame. -+ auipc(ra, 0); // Set ra the current PC -+ bind(&find_ra); -+ addi(ra, ra, -+ (kNumInstructionsToJump + 1) * -+ kInstrSize); // Set ra to insn after the call -+ -+ // This spot was reserved in EnterExitFrame. -+ Sd(ra, MemOperand(sp)); -+ addi(sp, sp, -kCArgsSlotsSize); -+ // Stack is still aligned. -+ -+ // Call the C routine. -+ mv(t6, target); // Function pointer to t6 to conform to ABI for PIC. -+ jalr(t6); -+ // Make sure the stored 'ra' points to this position. -+ DCHECK_EQ(kNumInstructionsToJump, InstructionsGeneratedSince(&find_ra)); -+} -+ -+void TurboAssembler::Ret(Condition cond, Register rs, const Operand& rt) { -+ Jump(ra, cond, rs, rt); -+} -+ -+void TurboAssembler::BranchLong(Label* L) { -+ // Generate position independent long branch. -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ int64_t imm64; -+ imm64 = branch_long_offset(L); -+ DCHECK(is_int32(imm64)); -+ int32_t Hi20 = (((int32_t)imm64 + 0x800) >> 12); -+ int32_t Lo12 = (int32_t)imm64 << 20 >> 20; -+ auipc(t5, Hi20); // Read PC + Hi20 into t5. -+ jr(t5, Lo12); // jump PC + Hi20 + Lo12 -+} -+ -+void TurboAssembler::BranchAndLinkLong(Label* L) { -+ // Generate position independent long branch and link. -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ int64_t imm64; -+ imm64 = branch_long_offset(L); -+ DCHECK(is_int32(imm64)); -+ int32_t Hi20 = (((int32_t)imm64 + 0x800) >> 12); -+ int32_t Lo12 = (int32_t)imm64 << 20 >> 20; -+ auipc(t5, Hi20); // Read PC + Hi20 into t5. -+ jalr(t5, Lo12); // jump PC + Hi20 + Lo12 and read PC + 4 to ra -+} -+ -+void TurboAssembler::DropAndRet(int drop) { -+ Add64(sp, sp, drop * kPointerSize); -+ Ret(); -+} -+ -+void TurboAssembler::DropAndRet(int drop, Condition cond, Register r1, -+ const Operand& r2) { -+ // Both Drop and Ret need to be conditional. -+ Label skip; -+ if (cond != cc_always) { -+ Branch(&skip, NegateCondition(cond), r1, r2); -+ } -+ -+ Drop(drop); -+ Ret(); -+ -+ if (cond != cc_always) { -+ bind(&skip); -+ } -+} -+ -+void TurboAssembler::Drop(int count, Condition cond, Register reg, -+ const Operand& op) { -+ if (count <= 0) { -+ return; -+ } -+ -+ Label skip; -+ -+ if (cond != al) { -+ Branch(&skip, NegateCondition(cond), reg, op); -+ } -+ -+ Add64(sp, sp, Operand(count * kPointerSize)); -+ -+ if (cond != al) { -+ bind(&skip); -+ } -+} -+ -+void MacroAssembler::Swap(Register reg1, Register reg2, Register scratch) { -+ if (scratch == no_reg) { -+ Xor(reg1, reg1, Operand(reg2)); -+ Xor(reg2, reg2, Operand(reg1)); -+ Xor(reg1, reg1, Operand(reg2)); -+ } else { -+ mv(scratch, reg1); -+ mv(reg1, reg2); -+ mv(reg2, scratch); -+ } -+} -+ -+void TurboAssembler::Call(Label* target) { BranchAndLink(target); } -+ -+void TurboAssembler::LoadAddress(Register dst, Label* target) { -+ uint64_t address = jump_address(target); -+ li(dst, address, ADDRESS_LOAD); -+} -+ -+void TurboAssembler::Push(Smi smi) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, Operand(smi)); -+ push(scratch); -+} -+ -+void TurboAssembler::Push(Handle handle) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, Operand(handle)); -+ push(scratch); -+} -+ -+void MacroAssembler::MaybeDropFrames() { -+ // Check whether we need to drop frames to restart a function on the stack. -+ li(a1, ExternalReference::debug_restart_fp_address(isolate())); -+ Ld(a1, MemOperand(a1)); -+ Jump(BUILTIN_CODE(isolate(), FrameDropperTrampoline), RelocInfo::CODE_TARGET, -+ ne, a1, Operand(zero_reg)); -+} -+ -+// --------------------------------------------------------------------------- -+// Exception handling. -+ -+void MacroAssembler::PushStackHandler() { -+ // Adjust this code if not the case. -+ STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kPointerSize); -+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); -+ -+ Push(Smi::zero()); // Padding. -+ -+ // Link the current handler as the next handler. -+ li(t2, -+ ExternalReference::Create(IsolateAddressId::kHandlerAddress, isolate())); -+ Ld(t1, MemOperand(t2)); -+ push(t1); -+ -+ // Set this new handler as the current one. -+ Sd(sp, MemOperand(t2)); -+} -+ -+void MacroAssembler::PopStackHandler() { -+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); -+ pop(a1); -+ Add64(sp, sp, -+ Operand( -+ static_cast(StackHandlerConstants::kSize - kPointerSize))); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, -+ ExternalReference::Create(IsolateAddressId::kHandlerAddress, isolate())); -+ Sd(a1, MemOperand(scratch)); -+} -+ -+void TurboAssembler::FPUCanonicalizeNaN(const DoubleRegister dst, -+ const DoubleRegister src) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ Label NotNaN; -+ -+ fmv_d(dst, src); -+ feq_d(scratch, src, src); -+ bne(scratch, zero_reg, &NotNaN); -+ RV_li(scratch, 0x7ff8000000000000ULL); // This is the canonical NaN -+ fmv_d_x(dst, scratch); -+ bind(&NotNaN); -+} -+ -+void TurboAssembler::MovFromFloatResult(const DoubleRegister dst) { -+ Move(dst, fa0); // Reg fa0 is FP return value. -+} -+ -+void TurboAssembler::MovFromFloatParameter(const DoubleRegister dst) { -+ Move(dst, fa0); // Reg fa0 is FP first argument value. -+} -+ -+void TurboAssembler::MovToFloatParameter(DoubleRegister src) { Move(fa0, src); } -+ -+void TurboAssembler::MovToFloatResult(DoubleRegister src) { Move(fa0, src); } -+ -+void TurboAssembler::MovToFloatParameters(DoubleRegister src1, -+ DoubleRegister src2) { -+ const DoubleRegister fparg2 = fa1; -+ if (src2 == fa0) { -+ DCHECK(src1 != fparg2); -+ Move(fparg2, src2); -+ Move(fa0, src1); -+ } else { -+ Move(fa0, src1); -+ Move(fparg2, src2); -+ } -+} -+ -+// ----------------------------------------------------------------------------- -+// JavaScript invokes. -+ -+void TurboAssembler::PrepareForTailCall(Register callee_args_count, -+ Register caller_args_count, -+ Register scratch0, Register scratch1) { -+ // Calculate the end of destination area where we will put the arguments -+ // after we drop current frame. We add kPointerSize to count the receiver -+ // argument which is not included into formal parameters count. -+ Register dst_reg = scratch0; -+ CalcScaledAddress(dst_reg, fp, caller_args_count, kPointerSizeLog2); -+ Add64(dst_reg, dst_reg, -+ Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize)); -+ -+ Register src_reg = caller_args_count; -+ // Calculate the end of source area. +kPointerSize is for the receiver. -+ CalcScaledAddress(src_reg, sp, callee_args_count, kPointerSizeLog2); -+ Add64(src_reg, src_reg, Operand(kPointerSize)); -+ -+ if (FLAG_debug_code) { -+ Check(Uless, AbortReason::kStackAccessBelowStackPointer, src_reg, -+ Operand(dst_reg)); -+ } -+ -+ // Restore caller's frame pointer and return address now as they will be -+ // overwritten by the copying loop. -+ Ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); -+ Ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); -+ -+ // Now copy callee arguments to the caller frame going backwards to avoid -+ // callee arguments corruption (source and destination areas could overlap). -+ -+ // Both src_reg and dst_reg are pointing to the word after the one to copy, -+ // so they must be pre-decremented in the loop. -+ Register tmp_reg = scratch1; -+ Label loop, entry; -+ Branch(&entry); -+ bind(&loop); -+ Sub64(src_reg, src_reg, Operand(kPointerSize)); -+ Sub64(dst_reg, dst_reg, Operand(kPointerSize)); -+ Ld(tmp_reg, MemOperand(src_reg)); -+ Sd(tmp_reg, MemOperand(dst_reg)); -+ bind(&entry); -+ Branch(&loop, ne, sp, Operand(src_reg)); -+ -+ // Leave current frame. -+ mv(sp, dst_reg); -+} -+ -+void MacroAssembler::InvokePrologue(Register expected_parameter_count, -+ Register actual_parameter_count, -+ Label* done, InvokeFlag flag) { -+ Label regular_invoke; -+ -+ // Check whether the expected and actual arguments count match. The -+ // registers are set up according to contract with -+ // ArgumentsAdaptorTrampoline: -+ // a0: actual arguments count -+ // a1: function (passed through to callee) -+ // a2: expected arguments count -+ -+ // The code below is made a lot easier because the calling code already sets -+ // up actual and expected registers according to the contract. -+ -+ DCHECK_EQ(actual_parameter_count, a0); -+ DCHECK_EQ(expected_parameter_count, a2); -+ -+ Branch(®ular_invoke, eq, expected_parameter_count, -+ Operand(actual_parameter_count)); -+ -+ Handle adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline); -+ if (flag == CALL_FUNCTION) { -+ Call(adaptor); -+ Branch(done); -+ } else { -+ Jump(adaptor, RelocInfo::CODE_TARGET); -+ } -+ -+ bind(®ular_invoke); -+} -+ -+void MacroAssembler::CheckDebugHook(Register fun, Register new_target, -+ Register expected_parameter_count, -+ Register actual_parameter_count) { -+ Label skip_hook; -+ -+ li(t0, ExternalReference::debug_hook_on_function_call_address(isolate())); -+ Lb(t0, MemOperand(t0)); -+ Branch(&skip_hook, eq, t0, Operand(zero_reg)); -+ -+ { -+ // Load receiver to pass it later to DebugOnFunctionCall hook. -+ CalcScaledAddress(t0, sp, actual_parameter_count, kPointerSizeLog2); -+ Ld(t0, MemOperand(t0)); -+ FrameScope frame(this, -+ has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); -+ SmiTag(expected_parameter_count); -+ Push(expected_parameter_count); -+ -+ SmiTag(actual_parameter_count); -+ Push(actual_parameter_count); -+ -+ if (new_target.is_valid()) { -+ Push(new_target); -+ } -+ Push(fun); -+ Push(fun); -+ Push(t0); -+ CallRuntime(Runtime::kDebugOnFunctionCall); -+ Pop(fun); -+ if (new_target.is_valid()) { -+ Pop(new_target); -+ } -+ -+ Pop(actual_parameter_count); -+ SmiUntag(actual_parameter_count); -+ -+ Pop(expected_parameter_count); -+ SmiUntag(expected_parameter_count); -+ } -+ bind(&skip_hook); -+} -+ -+void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, -+ Register expected_parameter_count, -+ Register actual_parameter_count, -+ InvokeFlag flag) { -+ // You can't call a function without a valid frame. -+ DCHECK_IMPLIES(flag == CALL_FUNCTION, has_frame()); -+ DCHECK_EQ(function, a1); -+ DCHECK_IMPLIES(new_target.is_valid(), new_target == a3); -+ -+ // On function call, call into the debugger if necessary. -+ CheckDebugHook(function, new_target, expected_parameter_count, -+ actual_parameter_count); -+ -+ // Clear the new.target register if not given. -+ if (!new_target.is_valid()) { -+ LoadRoot(a3, RootIndex::kUndefinedValue); -+ } -+ -+ Label done; -+ InvokePrologue(expected_parameter_count, actual_parameter_count, &done, flag); -+ // We call indirectly through the code field in the function to -+ // allow recompilation to take effect without changing any of the -+ // call sites. -+ Register code = kJavaScriptCallCodeStartRegister; -+ Ld(code, FieldMemOperand(function, JSFunction::kCodeOffset)); -+ if (flag == CALL_FUNCTION) { -+ Add64(code, code, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ Call(code); -+ } else { -+ DCHECK(flag == JUMP_FUNCTION); -+ Add64(code, code, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ Jump(code); -+ } -+ -+ // Continue here if InvokePrologue does handle the invocation due to -+ // mismatched parameter counts. -+ bind(&done); -+} -+ -+void MacroAssembler::InvokeFunctionWithNewTarget( -+ Register function, Register new_target, Register actual_parameter_count, -+ InvokeFlag flag) { -+ // You can't call a function without a valid frame. -+ DCHECK_IMPLIES(flag == CALL_FUNCTION, has_frame()); -+ -+ // Contract with called JS functions requires that function is passed in a1. -+ DCHECK_EQ(function, a1); -+ Register expected_parameter_count = a2; -+ Register temp_reg = t0; -+ Ld(temp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); -+ Ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); -+ // The argument count is stored as uint16_t -+ Lhu(expected_parameter_count, -+ FieldMemOperand(temp_reg, -+ SharedFunctionInfo::kFormalParameterCountOffset)); -+ -+ InvokeFunctionCode(a1, new_target, expected_parameter_count, -+ actual_parameter_count, flag); -+} -+ -+void MacroAssembler::InvokeFunction(Register function, -+ Register expected_parameter_count, -+ Register actual_parameter_count, -+ InvokeFlag flag) { -+ // You can't call a function without a valid frame. -+ DCHECK_IMPLIES(flag == CALL_FUNCTION, has_frame()); -+ -+ // Contract with called JS functions requires that function is passed in a1. -+ DCHECK_EQ(function, a1); -+ -+ // Get the function and setup the context. -+ Ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); -+ -+ InvokeFunctionCode(a1, no_reg, expected_parameter_count, -+ actual_parameter_count, flag); -+} -+ -+// --------------------------------------------------------------------------- -+// Support functions. -+ -+void MacroAssembler::GetObjectType(Register object, Register map, -+ Register type_reg) { -+ LoadMap(map, object); -+ Lhu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); -+} -+ -+// ----------------------------------------------------------------------------- -+// Runtime calls. -+ -+void TurboAssembler::AddOverflow64(Register dst, Register left, -+ const Operand& right, Register overflow) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register right_reg = no_reg; -+ Register scratch = t5; -+ if (!right.is_reg()) { -+ li(t3, Operand(right)); -+ right_reg = t3; -+ } else { -+ right_reg = right.rm(); -+ } -+ DCHECK(left != scratch && right_reg != scratch && dst != scratch && -+ overflow != scratch); -+ DCHECK(overflow != left && overflow != right_reg); -+ if (dst == left || dst == right_reg) { -+ add(scratch, left, right_reg); -+ xor_(overflow, scratch, left); -+ xor_(t3, scratch, right_reg); -+ and_(overflow, overflow, t3); -+ mv(dst, scratch); -+ } else { -+ add(dst, left, right_reg); -+ xor_(overflow, dst, left); -+ xor_(t3, dst, right_reg); -+ and_(overflow, overflow, t3); -+ } -+} -+ -+void TurboAssembler::SubOverflow64(Register dst, Register left, -+ const Operand& right, Register overflow) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register right_reg = no_reg; -+ Register scratch = t5; -+ if (!right.is_reg()) { -+ li(t3, Operand(right)); -+ right_reg = t3; -+ } else { -+ right_reg = right.rm(); -+ } -+ -+ DCHECK(left != scratch && right_reg != scratch && dst != scratch && -+ overflow != scratch); -+ DCHECK(overflow != left && overflow != right_reg); -+ -+ if (dst == left || dst == right_reg) { -+ sub(scratch, left, right_reg); -+ xor_(overflow, left, scratch); -+ xor_(t3, left, right_reg); -+ and_(overflow, overflow, t3); -+ mv(dst, scratch); -+ } else { -+ sub(dst, left, right_reg); -+ xor_(overflow, left, dst); -+ xor_(t3, left, right_reg); -+ and_(overflow, overflow, t3); -+ } -+} -+ -+void TurboAssembler::MulOverflow32(Register dst, Register left, -+ const Operand& right, Register overflow) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ Register right_reg = no_reg; -+ Register scratch = t5; -+ if (!right.is_reg()) { -+ li(t3, Operand(right)); -+ right_reg = t3; -+ } else { -+ right_reg = right.rm(); -+ } -+ -+ DCHECK(left != scratch && right_reg != scratch && dst != scratch && -+ overflow != scratch); -+ DCHECK(overflow != left && overflow != right_reg); -+ sext_w(overflow, left); -+ sext_w(scratch, right_reg); -+ -+ mul(overflow, overflow, scratch); -+ sext_w(dst, overflow); -+ xor_(overflow, overflow, dst); -+} -+ -+void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, -+ SaveFPRegsMode save_doubles) { -+ // All parameters are on the stack. a0 has the return value after call. -+ -+ // If the expected number of arguments of the runtime function is -+ // constant, we check that the actual number of arguments match the -+ // expectation. -+ CHECK(f->nargs < 0 || f->nargs == num_arguments); -+ -+ // TODO(1236192): Most runtime routines don't need the number of -+ // arguments passed in because it is constant. At some point we -+ // should remove this need and make the runtime routine entry code -+ // smarter. -+ PrepareCEntryArgs(num_arguments); -+ PrepareCEntryFunction(ExternalReference::Create(f)); -+ Handle code = -+ CodeFactory::CEntry(isolate(), f->result_size, save_doubles); -+ Call(code, RelocInfo::CODE_TARGET); -+} -+ -+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { -+ const Runtime::Function* function = Runtime::FunctionForId(fid); -+ DCHECK_EQ(1, function->result_size); -+ if (function->nargs >= 0) { -+ PrepareCEntryArgs(function->nargs); -+ } -+ JumpToExternalReference(ExternalReference::Create(fid)); -+} -+ -+void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin, -+ bool builtin_exit_frame) { -+ PrepareCEntryFunction(builtin); -+ Handle code = CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, -+ kArgvOnStack, builtin_exit_frame); -+ Jump(code, RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg)); -+} -+ -+void MacroAssembler::JumpToInstructionStream(Address entry) { -+ li(kOffHeapTrampolineRegister, Operand(entry, RelocInfo::OFF_HEAP_TARGET)); -+ Jump(kOffHeapTrampolineRegister); -+} -+ -+void MacroAssembler::LoadWeakValue(Register out, Register in, -+ Label* target_if_cleared) { -+ Branch(target_if_cleared, eq, in, Operand(kClearedWeakHeapObjectLower32)); -+ -+ And(out, in, Operand(~kWeakHeapObjectMask)); -+} -+ -+void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, -+ Register scratch1, Register scratch2) { -+ DCHECK_GT(value, 0); -+ if (FLAG_native_code_counters && counter->Enabled()) { -+ // This operation has to be exactly 32-bit wide in case the external -+ // reference table redirects the counter to a uint32_t -+ // dummy_stats_counter_ field. -+ li(scratch2, ExternalReference::Create(counter)); -+ Lw(scratch1, MemOperand(scratch2)); -+ Add32(scratch1, scratch1, Operand(value)); -+ Sw(scratch1, MemOperand(scratch2)); -+ } -+} -+ -+void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, -+ Register scratch1, Register scratch2) { -+ DCHECK_GT(value, 0); -+ if (FLAG_native_code_counters && counter->Enabled()) { -+ // This operation has to be exactly 32-bit wide in case the external -+ // reference table redirects the counter to a uint32_t -+ // dummy_stats_counter_ field. -+ li(scratch2, ExternalReference::Create(counter)); -+ Lw(scratch1, MemOperand(scratch2)); -+ Sub32(scratch1, scratch1, Operand(value)); -+ Sw(scratch1, MemOperand(scratch2)); -+ } -+} -+ -+// ----------------------------------------------------------------------------- -+// Debugging. -+ -+void TurboAssembler::Trap() { stop(); } -+void TurboAssembler::DebugBreak() { stop(); } -+ -+void TurboAssembler::Assert(Condition cc, AbortReason reason, Register rs, -+ Operand rt) { -+ if (emit_debug_code()) Check(cc, reason, rs, rt); -+} -+ -+void TurboAssembler::Check(Condition cc, AbortReason reason, Register rs, -+ Operand rt) { -+ Label L; -+ Branch(&L, cc, rs, rt); -+ Abort(reason); -+ // Will not return here. -+ bind(&L); -+} -+ -+void TurboAssembler::Abort(AbortReason reason) { -+ Label abort_start; -+ bind(&abort_start); -+#ifdef DEBUG -+ const char* msg = GetAbortReason(reason); -+ RecordComment("Abort message: "); -+ RecordComment(msg); -+#endif -+ -+ // Avoid emitting call to builtin if requested. -+ if (trap_on_abort()) { -+ ebreak(); -+ return; -+ } -+ -+ if (should_abort_hard()) { -+ // We don't care if we constructed a frame. Just pretend we did. -+ FrameScope assume_frame(this, StackFrame::NONE); -+ PrepareCallCFunction(0, a0); -+ li(a0, Operand(static_cast(reason))); -+ CallCFunction(ExternalReference::abort_with_reason(), 1); -+ return; -+ } -+ -+ Move(a0, Smi::FromInt(static_cast(reason))); -+ -+ // Disable stub call restrictions to always allow calls to abort. -+ if (!has_frame()) { -+ // We don't actually want to generate a pile of code for this, so just -+ // claim there is a stack frame, without generating one. -+ FrameScope scope(this, StackFrame::NONE); -+ Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET); -+ } else { -+ Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET); -+ } -+ // Will not return here. -+ if (is_trampoline_pool_blocked()) { -+ // If the calling code cares about the exact number of -+ // instructions generated, we insert padding here to keep the size -+ // of the Abort macro constant. -+ // Currently in debug mode with debug_code enabled the number of -+ // generated instructions is 10, so we use this as a maximum value. -+ static const int kExpectedAbortInstructions = 10; -+ int abort_instructions = InstructionsGeneratedSince(&abort_start); -+ DCHECK_LE(abort_instructions, kExpectedAbortInstructions); -+ while (abort_instructions++ < kExpectedAbortInstructions) { -+ nop(); -+ } -+ } -+} -+ -+void MacroAssembler::LoadMap(Register destination, Register object) { -+ Ld(destination, FieldMemOperand(object, HeapObject::kMapOffset)); -+} -+ -+void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { -+ LoadMap(dst, cp); -+ Ld(dst, -+ FieldMemOperand(dst, Map::kConstructorOrBackPointerOrNativeContextOffset)); -+ Ld(dst, MemOperand(dst, Context::SlotOffset(index))); -+} -+ -+void TurboAssembler::StubPrologue(StackFrame::Type type) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, Operand(StackFrame::TypeToMarker(type))); -+ PushCommonFrame(scratch); -+} -+ -+void TurboAssembler::Prologue() { PushStandardFrame(a1); } -+ -+void TurboAssembler::EnterFrame(StackFrame::Type type) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ int stack_offset = -3 * kPointerSize; -+ const int fp_offset = 1 * kPointerSize; -+ addi(sp, sp, stack_offset); -+ stack_offset = -stack_offset - kPointerSize; -+ Sd(ra, MemOperand(sp, stack_offset)); -+ stack_offset -= kPointerSize; -+ Sd(fp, MemOperand(sp, stack_offset)); -+ stack_offset -= kPointerSize; -+ li(t6, Operand(StackFrame::TypeToMarker(type))); -+ Sd(t6, MemOperand(sp, stack_offset)); -+ // Adjust FP to point to saved FP. -+ DCHECK_EQ(stack_offset, 0); -+ Add64(fp, sp, Operand(fp_offset)); -+} -+ -+void TurboAssembler::LeaveFrame(StackFrame::Type type) { -+ addi(sp, fp, 2 * kPointerSize); -+ Ld(ra, MemOperand(fp, 1 * kPointerSize)); -+ Ld(fp, MemOperand(fp, 0 * kPointerSize)); -+} -+ -+void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space, -+ StackFrame::Type frame_type) { -+ DCHECK(frame_type == StackFrame::EXIT || -+ frame_type == StackFrame::BUILTIN_EXIT); -+ -+ // Set up the frame structure on the stack. -+ STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement); -+ STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset); -+ STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset); -+ -+ // This is how the stack will look: -+ // fp + 2 (==kCallerSPDisplacement) - old stack's end -+ // [fp + 1 (==kCallerPCOffset)] - saved old ra -+ // [fp + 0 (==kCallerFPOffset)] - saved old fp -+ // [fp - 1 StackFrame::EXIT Smi -+ // [fp - 2 (==kSPOffset)] - sp of the called function -+ // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the -+ // new stack (will contain saved ra) -+ -+ // Save registers and reserve room for saved entry sp. -+ addi(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp); -+ Sd(ra, MemOperand(sp, 3 * kPointerSize)); -+ Sd(fp, MemOperand(sp, 2 * kPointerSize)); -+ { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ li(scratch, Operand(StackFrame::TypeToMarker(frame_type))); -+ Sd(scratch, MemOperand(sp, 1 * kPointerSize)); -+ } -+ // Set up new frame pointer. -+ addi(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp); -+ -+ if (emit_debug_code()) { -+ Sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset)); -+ } -+ -+ { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ // Save the frame pointer and the context in top. -+ li(t5, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, -+ isolate())); -+ Sd(fp, MemOperand(t5)); -+ li(t5, -+ ExternalReference::Create(IsolateAddressId::kContextAddress, isolate())); -+ Sd(cp, MemOperand(t5)); -+ } -+ -+ const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); -+ if (save_doubles) { -+ // The stack is already aligned to 0 modulo 8 for stores with sdc1. -+ int kNumOfSavedRegisters = FPURegister::kNumRegisters; -+ int space = kNumOfSavedRegisters * kDoubleSize; -+ Sub64(sp, sp, Operand(space)); -+ for (int i = 0; i < kNumOfSavedRegisters; i++) { -+ FPURegister reg = FPURegister::from_code(i); -+ StoreDouble(reg, MemOperand(sp, i * kDoubleSize)); -+ } -+ } -+ -+ // Reserve place for the return address, stack space and an optional slot -+ // (used by DirectCEntry to hold the return value if a struct is -+ // returned) and align the frame preparing for calling the runtime function. -+ DCHECK_GE(stack_space, 0); -+ Sub64(sp, sp, Operand((stack_space + 2) * kPointerSize)); -+ if (frame_alignment > 0) { -+ DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); -+ And(sp, sp, Operand(-frame_alignment)); // Align stack. -+ } -+ -+ // Set the exit frame sp value to point just before the return address -+ // location. -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ addi(scratch, sp, kPointerSize); -+ Sd(scratch, MemOperand(fp, ExitFrameConstants::kSPOffset)); -+} -+ -+void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, -+ bool do_return, -+ bool argument_count_is_length) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ // Optionally restore all double registers. -+ if (save_doubles) { -+ // Remember: we only need to restore every 2nd double FPU value. -+ int kNumOfSavedRegisters = FPURegister::kNumRegisters / 2; -+ Sub64(t5, fp, -+ Operand(ExitFrameConstants::kFixedFrameSizeFromFp + -+ kNumOfSavedRegisters * kDoubleSize)); -+ for (int i = 0; i < kNumOfSavedRegisters; i++) { -+ FPURegister reg = FPURegister::from_code(2 * i); -+ LoadDouble(reg, MemOperand(t5, i * kDoubleSize)); -+ } -+ } -+ -+ // Clear top frame. -+ li(t5, -+ ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate())); -+ Sd(zero_reg, MemOperand(t5)); -+ -+ // Restore current context from top and clear it in debug mode. -+ li(t5, -+ ExternalReference::Create(IsolateAddressId::kContextAddress, isolate())); -+ Ld(cp, MemOperand(t5)); -+ -+#ifdef DEBUG -+ li(t5, -+ ExternalReference::Create(IsolateAddressId::kContextAddress, isolate())); -+ Sd(a3, MemOperand(t5)); -+#endif -+ -+ // Pop the arguments, restore registers, and return. -+ mv(sp, fp); // Respect ABI stack constraint. -+ Ld(fp, MemOperand(sp, ExitFrameConstants::kCallerFPOffset)); -+ Ld(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset)); -+ -+ if (argument_count.is_valid()) { -+ if (argument_count_is_length) { -+ add(sp, sp, argument_count); -+ } else { -+ CalcScaledAddress(sp, sp, argument_count, kPointerSizeLog2, t5); -+ } -+ } -+ -+ addi(sp, sp, 2 * kPointerSize); -+ -+ if (do_return) { -+ Ret(); -+ } -+} -+ -+int TurboAssembler::ActivationFrameAlignment() { -+#if V8_HOST_ARCH_RISCV64 -+ // Running on the real platform. Use the alignment as mandated by the local -+ // environment. -+ // Note: This will break if we ever start generating snapshots on one RISC-V -+ // platform for another RISC-V platform with a different alignment. -+ return base::OS::ActivationFrameAlignment(); -+#else // V8_HOST_ARCH_RISCV64 -+ // If we are using the simulator then we should always align to the expected -+ // alignment. As the simulator is used to generate snapshots we do not know -+ // if the target platform will need alignment, so this is controlled from a -+ // flag. -+ return FLAG_sim_stack_alignment; -+#endif // V8_HOST_ARCH_RISCV64 -+} -+ -+void MacroAssembler::AssertStackIsAligned() { -+ if (emit_debug_code()) { -+ const int frame_alignment = ActivationFrameAlignment(); -+ const int frame_alignment_mask = frame_alignment - 1; -+ -+ if (frame_alignment > kPointerSize) { -+ Label alignment_as_expected; -+ DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); -+ { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ andi(scratch, sp, frame_alignment_mask); -+ Branch(&alignment_as_expected, eq, scratch, Operand(zero_reg)); -+ } -+ // Don't use Check here, as it will call Runtime_Abort re-entering here. -+ ebreak(); -+ bind(&alignment_as_expected); -+ } -+ } -+} -+ -+void TurboAssembler::SmiUntag(Register dst, const MemOperand& src) { -+ if (SmiValuesAre32Bits()) { -+ Lw(dst, MemOperand(src.rm(), SmiWordOffset(src.offset()))); -+ } else { -+ DCHECK(SmiValuesAre31Bits()); -+ Lw(dst, src); -+ SmiUntag(dst); -+ } -+} -+ -+void TurboAssembler::JumpIfSmi(Register value, Label* smi_label, -+ Register scratch) { -+ DCHECK_EQ(0, kSmiTag); -+ andi(scratch, value, kSmiTagMask); -+ Branch(smi_label, eq, scratch, Operand(zero_reg)); -+} -+ -+void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label, -+ Register scratch) { -+ DCHECK_EQ(0, kSmiTag); -+ andi(scratch, value, kSmiTagMask); -+ Branch(not_smi_label, ne, scratch, Operand(zero_reg)); -+} -+ -+void MacroAssembler::AssertNotSmi(Register object) { -+ if (emit_debug_code()) { -+ STATIC_ASSERT(kSmiTag == 0); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ andi(scratch, object, kSmiTagMask); -+ Check(ne, AbortReason::kOperandIsASmi, scratch, Operand(zero_reg)); -+ } -+} -+ -+void MacroAssembler::AssertSmi(Register object) { -+ if (emit_debug_code()) { -+ STATIC_ASSERT(kSmiTag == 0); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ andi(scratch, object, kSmiTagMask); -+ Check(eq, AbortReason::kOperandIsASmi, scratch, Operand(zero_reg)); -+ } -+} -+ -+void MacroAssembler::AssertConstructor(Register object) { -+ if (emit_debug_code()) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ STATIC_ASSERT(kSmiTag == 0); -+ SmiTst(object, t5); -+ Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, t5, -+ Operand(zero_reg)); -+ -+ LoadMap(t5, object); -+ Lbu(t5, FieldMemOperand(t5, Map::kBitFieldOffset)); -+ And(t5, t5, Operand(Map::Bits1::IsConstructorBit::kMask)); -+ Check(ne, AbortReason::kOperandIsNotAConstructor, t5, Operand(zero_reg)); -+ } -+} -+ -+void MacroAssembler::AssertFunction(Register object) { -+ if (emit_debug_code()) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ STATIC_ASSERT(kSmiTag == 0); -+ SmiTst(object, t5); -+ Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, t5, -+ Operand(zero_reg)); -+ GetObjectType(object, t5, t5); -+ Check(eq, AbortReason::kOperandIsNotAFunction, t5, -+ Operand(JS_FUNCTION_TYPE)); -+ } -+} -+ -+void MacroAssembler::AssertBoundFunction(Register object) { -+ if (emit_debug_code()) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ STATIC_ASSERT(kSmiTag == 0); -+ SmiTst(object, t5); -+ Check(ne, AbortReason::kOperandIsASmiAndNotABoundFunction, t5, -+ Operand(zero_reg)); -+ GetObjectType(object, t5, t5); -+ Check(eq, AbortReason::kOperandIsNotABoundFunction, t5, -+ Operand(JS_BOUND_FUNCTION_TYPE)); -+ } -+} -+ -+void MacroAssembler::AssertGeneratorObject(Register object) { -+ if (!emit_debug_code()) return; -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ STATIC_ASSERT(kSmiTag == 0); -+ SmiTst(object, t5); -+ Check(ne, AbortReason::kOperandIsASmiAndNotAGeneratorObject, t5, -+ Operand(zero_reg)); -+ -+ GetObjectType(object, t5, t5); -+ -+ Label done; -+ -+ // Check if JSGeneratorObject -+ Branch(&done, eq, t5, Operand(JS_GENERATOR_OBJECT_TYPE)); -+ -+ // Check if JSAsyncFunctionObject (See MacroAssembler::CompareInstanceType) -+ Branch(&done, eq, t5, Operand(JS_ASYNC_FUNCTION_OBJECT_TYPE)); -+ -+ // Check if JSAsyncGeneratorObject -+ Branch(&done, eq, t5, Operand(JS_ASYNC_GENERATOR_OBJECT_TYPE)); -+ -+ Abort(AbortReason::kOperandIsNotAGeneratorObject); -+ -+ bind(&done); -+} -+ -+void MacroAssembler::AssertUndefinedOrAllocationSite(Register object, -+ Register scratch) { -+ if (emit_debug_code()) { -+ Label done_checking; -+ AssertNotSmi(object); -+ LoadRoot(scratch, RootIndex::kUndefinedValue); -+ Branch(&done_checking, eq, object, Operand(scratch)); -+ GetObjectType(object, scratch, scratch); -+ Assert(eq, AbortReason::kExpectedUndefinedOrCell, scratch, -+ Operand(ALLOCATION_SITE_TYPE)); -+ bind(&done_checking); -+ } -+} -+ -+template -+void TurboAssembler::FloatMinMaxHelper(FPURegister dst, FPURegister src1, -+ FPURegister src2, MaxMinKind kind) { -+ DCHECK((std::is_same::value) || -+ (std::is_same::value)); -+ -+ if (src1 == src2 && dst != src1) { -+ if (std::is_same::value) { -+ fmv_s(dst, src1); -+ } else { -+ fmv_d(dst, src1); -+ } -+ return; -+ } -+ -+ Label done, nan; -+ -+ // For RISCV, fmin_s returns the other non-NaN operand as result if only one -+ // operand is NaN; but for JS, if any operand is NaN, result is Nan. The -+ // following handles the discrepency between handling of NaN between ISA and -+ // JS semantics -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ if (std::is_same::value) { -+ CompareIsNanF32(scratch, src1, src2); -+ } else { -+ CompareIsNanF64(scratch, src1, src2); -+ } -+ BranchTrueF(scratch, &nan); -+ -+ if (kind == MaxMinKind::kMax) { -+ if (std::is_same::value) { -+ fmax_s(dst, src1, src2); -+ } else { -+ fmax_d(dst, src1, src2); -+ } -+ } else { -+ if (std::is_same::value) { -+ fmin_s(dst, src1, src2); -+ } else { -+ fmin_d(dst, src1, src2); -+ } -+ } -+ j(&done); -+ -+ bind(&nan); -+ // if any operand is NaN, return NaN (fadd returns NaN if any operand is NaN) -+ if (std::is_same::value) { -+ fadd_s(dst, src1, src2); -+ } else { -+ fadd_d(dst, src1, src2); -+ } -+ -+ bind(&done); -+} -+ -+void TurboAssembler::Float32Max(FPURegister dst, FPURegister src1, -+ FPURegister src2) { -+ FloatMinMaxHelper(dst, src1, src2, MaxMinKind::kMax); -+} -+ -+void TurboAssembler::Float32Min(FPURegister dst, FPURegister src1, -+ FPURegister src2) { -+ FloatMinMaxHelper(dst, src1, src2, MaxMinKind::kMin); -+} -+ -+void TurboAssembler::Float64Max(FPURegister dst, FPURegister src1, -+ FPURegister src2) { -+ FloatMinMaxHelper(dst, src1, src2, MaxMinKind::kMax); -+} -+ -+void TurboAssembler::Float64Min(FPURegister dst, FPURegister src1, -+ FPURegister src2) { -+ FloatMinMaxHelper(dst, src1, src2, MaxMinKind::kMin); -+} -+ -+static const int kRegisterPassedArguments = 8; -+ -+int TurboAssembler::CalculateStackPassedDWords(int num_gp_arguments, -+ int num_fp_arguments) { -+ int stack_passed_dwords = 0; -+ -+ // Up to eight integer arguments are passed in registers a0..a7 and -+ // up to eight floating point arguments are passed in registers fa0..fa7 -+ if (num_gp_arguments > kRegisterPassedArguments) { -+ stack_passed_dwords += num_gp_arguments - kRegisterPassedArguments; -+ } -+ if (num_fp_arguments > kRegisterPassedArguments) { -+ stack_passed_dwords += num_fp_arguments - kRegisterPassedArguments; -+ } -+ stack_passed_dwords += kCArgSlotCount; -+ return stack_passed_dwords; -+} -+ -+void TurboAssembler::PrepareCallCFunction(int num_reg_arguments, -+ int num_double_arguments, -+ Register scratch) { -+ int frame_alignment = ActivationFrameAlignment(); -+ -+ // Up to eight simple arguments in a0..a7, fa0..fa7. -+ // Remaining arguments are pushed on the stack (arg slot calculation handled -+ // by CalculateStackPassedDWords()). -+ int stack_passed_arguments = -+ CalculateStackPassedDWords(num_reg_arguments, num_double_arguments); -+ if (frame_alignment > kPointerSize) { -+ // Make stack end at alignment and make room for stack arguments and the -+ // original value of sp. -+ mv(scratch, sp); -+ Sub64(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); -+ DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); -+ And(sp, sp, Operand(-frame_alignment)); -+ Sd(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); -+ } else { -+ Sub64(sp, sp, Operand(stack_passed_arguments * kPointerSize)); -+ } -+} -+ -+void TurboAssembler::PrepareCallCFunction(int num_reg_arguments, -+ Register scratch) { -+ PrepareCallCFunction(num_reg_arguments, 0, scratch); -+} -+ -+void TurboAssembler::CallCFunction(ExternalReference function, -+ int num_reg_arguments, -+ int num_double_arguments) { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ li(t6, function); -+ CallCFunctionHelper(t6, num_reg_arguments, num_double_arguments); -+} -+ -+void TurboAssembler::CallCFunction(Register function, int num_reg_arguments, -+ int num_double_arguments) { -+ CallCFunctionHelper(function, num_reg_arguments, num_double_arguments); -+} -+ -+void TurboAssembler::CallCFunction(ExternalReference function, -+ int num_arguments) { -+ CallCFunction(function, num_arguments, 0); -+} -+ -+void TurboAssembler::CallCFunction(Register function, int num_arguments) { -+ CallCFunction(function, num_arguments, 0); -+} -+ -+void TurboAssembler::CallCFunctionHelper(Register function, -+ int num_reg_arguments, -+ int num_double_arguments) { -+ DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters); -+ DCHECK(has_frame()); -+ // Make sure that the stack is aligned before calling a C function unless -+ // running in the simulator. The simulator has its own alignment check which -+ // provides more information. -+ // The argument stots are presumed to have been set up by -+ // PrepareCallCFunction. -+ -+#if V8_HOST_ARCH_RISCV64 -+ if (emit_debug_code()) { -+ int frame_alignment = base::OS::ActivationFrameAlignment(); -+ int frame_alignment_mask = frame_alignment - 1; -+ if (frame_alignment > kPointerSize) { -+ DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); -+ Label alignment_as_expected; -+ { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ And(scratch, sp, Operand(frame_alignment_mask)); -+ Branch(&alignment_as_expected, eq, scratch, Operand(zero_reg)); -+ } -+ // Don't use Check here, as it will call Runtime_Abort possibly -+ // re-entering here. -+ ebreak(); -+ bind(&alignment_as_expected); -+ } -+ } -+#endif // V8_HOST_ARCH_RISCV64 -+ -+ // Just call directly. The function called cannot cause a GC, or -+ // allow preemption, so the return address in the link register -+ // stays correct. -+ { -+ BlockTrampolinePoolScope block_trampoline_pool(this); -+ if (function != t6) { -+ mv(t6, function); -+ function = t6; -+ } -+ -+ // Save the frame pointer and PC so that the stack layout remains -+ // iterable, even without an ExitFrame which normally exists between JS -+ // and C frames. -+ // 't' registers are caller-saved so this is safe as a scratch register. -+ Register pc_scratch = t1; -+ Register scratch = t2; -+ DCHECK(!AreAliased(pc_scratch, scratch, function)); -+ -+ auipc(pc_scratch, 0); -+ // FIXME(RISCV): Does this need an offset? It seems like this should be the -+ // PC of the call, but MIPS does not seem to do that. -+ -+ // See x64 code for reasoning about how to address the isolate data fields. -+ if (root_array_available()) { -+ Sd(pc_scratch, MemOperand(kRootRegister, -+ IsolateData::fast_c_call_caller_pc_offset())); -+ Sd(fp, MemOperand(kRootRegister, -+ IsolateData::fast_c_call_caller_fp_offset())); -+ } else { -+ DCHECK_NOT_NULL(isolate()); -+ li(scratch, ExternalReference::fast_c_call_caller_pc_address(isolate())); -+ Sd(pc_scratch, MemOperand(scratch)); -+ li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate())); -+ Sd(fp, MemOperand(scratch)); -+ } -+ -+ Call(function); -+ -+ if (isolate() != nullptr) { -+ // We don't unset the PC; the FP is the source of truth. -+ Register scratch = t1; -+ li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate())); -+ Sd(zero_reg, MemOperand(scratch)); -+ } -+ } -+ -+ int stack_passed_arguments = -+ CalculateStackPassedDWords(num_reg_arguments, num_double_arguments); -+ -+ if (base::OS::ActivationFrameAlignment() > kPointerSize) { -+ Ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); -+ } else { -+ Add64(sp, sp, Operand(stack_passed_arguments * kPointerSize)); -+ } -+} -+ -+#undef BRANCH_ARGS_CHECK -+ -+void TurboAssembler::CheckPageFlag(Register object, Register scratch, int mask, -+ Condition cc, Label* condition_met) { -+ And(scratch, object, Operand(~kPageAlignmentMask)); -+ Ld(scratch, MemOperand(scratch, BasicMemoryChunk::kFlagsOffset)); -+ And(scratch, scratch, Operand(mask)); -+ Branch(condition_met, cc, scratch, Operand(zero_reg)); -+} -+ -+Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3, -+ Register reg4, Register reg5, -+ Register reg6) { -+ RegList regs = 0; -+ if (reg1.is_valid()) regs |= reg1.bit(); -+ if (reg2.is_valid()) regs |= reg2.bit(); -+ if (reg3.is_valid()) regs |= reg3.bit(); -+ if (reg4.is_valid()) regs |= reg4.bit(); -+ if (reg5.is_valid()) regs |= reg5.bit(); -+ if (reg6.is_valid()) regs |= reg6.bit(); -+ -+ const RegisterConfiguration* config = RegisterConfiguration::Default(); -+ for (int i = 0; i < config->num_allocatable_general_registers(); ++i) { -+ int code = config->GetAllocatableGeneralCode(i); -+ Register candidate = Register::from_code(code); -+ if (regs & candidate.bit()) continue; -+ return candidate; -+ } -+ UNREACHABLE(); -+} -+ -+void TurboAssembler::ComputeCodeStartAddress(Register dst) { -+ // This push on ra and the pop below together ensure that we restore the -+ // register ra, which is needed while computing the code start address. -+ push(ra); -+ -+ auipc(ra, 0); -+ addi(ra, ra, kInstrSize * 2); // ra = address of li -+ int pc = pc_offset(); -+ li(dst, Operand(pc)); -+ Sub64(dst, ra, dst); -+ -+ pop(ra); // Restore ra -+} -+ -+void TurboAssembler::ResetSpeculationPoisonRegister() { -+ li(kSpeculationPoisonRegister, -1); -+} -+ -+void TurboAssembler::CallForDeoptimization(Address target, int deopt_id, -+ Label* exit, DeoptimizeKind kind) { -+ USE(exit, kind); -+ NoRootArrayScope no_root_array(this); -+ -+ // Save the deopt id in kRootRegister (we don't need the roots array from -+ // now on). -+ DCHECK_LE(deopt_id, 0xFFFF); -+ li(kRootRegister, deopt_id); -+ Call(target, RelocInfo::RUNTIME_ENTRY); -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/macro-assembler-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/macro-assembler-riscv64.h -@@ -0,0 +1,1181 @@ -+// Copyright 2012 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. -+ -+#ifndef INCLUDED_FROM_MACRO_ASSEMBLER_H -+#error This header must be included via macro-assembler.h -+#endif -+ -+#ifndef V8_CODEGEN_RISCV_MACRO_ASSEMBLER_RISCV_H_ -+#define V8_CODEGEN_RISCV_MACRO_ASSEMBLER_RISCV_H_ -+ -+#include "src/codegen/assembler.h" -+#include "src/codegen/riscv64/assembler-riscv64.h" -+#include "src/common/globals.h" -+ -+namespace v8 { -+namespace internal { -+ -+// Forward declarations. -+enum class AbortReason : uint8_t; -+ -+// Reserved Register Usage Summary. -+// -+// Registers t5, t6, and t3 are reserved for use by the MacroAssembler. -+// -+// The programmer should know that the MacroAssembler may clobber these three, -+// but won't touch other registers except in special cases. -+// -+// FIXME(RISCV): Cannot find info about this ABI. We chose t6 for now. -+// Per the RISC-V ABI, register t6 must be used for indirect function call -+// via 'jalr t6' or 'jr t6' instructions. This is relied upon by gcc when -+// trying to update gp register for position-independent-code. Whenever -+// RISC-V generated code calls C code, it must be via t6 register. -+ -+// Flags used for LeaveExitFrame function. -+enum LeaveExitFrameMode { EMIT_RETURN = true, NO_EMIT_RETURN = false }; -+ -+// Flags used for the li macro-assembler function. -+enum LiFlags { -+ // If the constant value can be represented in just 16 bits, then -+ // optimize the li to use a single instruction, rather than lui/ori/slli -+ // sequence. A number of other optimizations that emits less than -+ // maximum number of instructions exists. -+ OPTIMIZE_SIZE = 0, -+ // Always use 8 instructions (lui/addi/slliw sequence), even if the -+ // constant -+ // could be loaded with just one, so that this value is patchable later. -+ CONSTANT_SIZE = 1, -+ // For address loads 8 instruction are required. Used to mark -+ // constant load that will be used as address without relocation -+ // information. It ensures predictable code size, so specific sites -+ // in code are patchable. -+ ADDRESS_LOAD = 2 -+}; -+ -+enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; -+enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; -+enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved }; -+ -+Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg, -+ Register reg3 = no_reg, -+ Register reg4 = no_reg, -+ Register reg5 = no_reg, -+ Register reg6 = no_reg); -+ -+// ----------------------------------------------------------------------------- -+// Static helper functions. -+ -+#if defined(V8_TARGET_LITTLE_ENDIAN) -+#define SmiWordOffset(offset) (offset + kPointerSize / 2) -+#else -+#define SmiWordOffset(offset) offset -+#endif -+ -+// Generate a MemOperand for loading a field from an object. -+inline MemOperand FieldMemOperand(Register object, int offset) { -+ return MemOperand(object, offset - kHeapObjectTag); -+} -+ -+// Generate a MemOperand for storing arguments 5..N on the stack -+// when calling CallCFunction(). -+// TODO(plind): Currently ONLY used for O32. Should be fixed for -+// n64, and used in RegExp code, and other places -+// with more than 8 arguments. -+inline MemOperand CFunctionArgumentOperand(int index) { -+ DCHECK_GT(index, kCArgSlotCount); -+ // Argument 5 takes the slot just past the four Arg-slots. -+ int offset = (index - 5) * kPointerSize + kCArgsSlotsSize; -+ return MemOperand(sp, offset); -+} -+ -+class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { -+ public: -+ using TurboAssemblerBase::TurboAssemblerBase; -+ -+ // Activation support. -+ void EnterFrame(StackFrame::Type type); -+ void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg) { -+ // Out-of-line constant pool not implemented on RISC-V. -+ UNREACHABLE(); -+ } -+ void LeaveFrame(StackFrame::Type type); -+ -+ // Generates function and stub prologue code. -+ void StubPrologue(StackFrame::Type type); -+ void Prologue(); -+ -+ void InitializeRootRegister() { -+ ExternalReference isolate_root = ExternalReference::isolate_root(isolate()); -+ li(kRootRegister, Operand(isolate_root)); -+ } -+ -+ // Jump unconditionally to given label. -+ void jmp(Label* L) { Branch(L); } -+ -+ // ------------------------------------------------------------------------- -+ // Debugging. -+ -+ void Trap() override; -+ void DebugBreak() override; -+ -+ // Calls Abort(msg) if the condition cc is not satisfied. -+ // Use --debug_code to enable. -+ void Assert(Condition cc, AbortReason reason, Register rs, Operand rt); -+ -+ // Like Assert(), but always enabled. -+ void Check(Condition cc, AbortReason reason, Register rs, Operand rt); -+ -+ // Print a message to stdout and abort execution. -+ void Abort(AbortReason msg); -+ -+ // Arguments macros. -+#define COND_TYPED_ARGS Condition cond, Register r1, const Operand &r2 -+#define COND_ARGS cond, r1, r2 -+ -+ // Cases when relocation is not needed. -+#define DECLARE_NORELOC_PROTOTYPE(Name, target_type) \ -+ void Name(target_type target); \ -+ void Name(target_type target, COND_TYPED_ARGS); -+ -+#define DECLARE_BRANCH_PROTOTYPES(Name) \ -+ DECLARE_NORELOC_PROTOTYPE(Name, Label*) \ -+ DECLARE_NORELOC_PROTOTYPE(Name, int32_t) -+ -+ DECLARE_BRANCH_PROTOTYPES(Branch) -+ DECLARE_BRANCH_PROTOTYPES(BranchAndLink) -+ DECLARE_BRANCH_PROTOTYPES(BranchShort) -+ -+#undef DECLARE_BRANCH_PROTOTYPES -+#undef COND_TYPED_ARGS -+#undef COND_ARGS -+ -+ inline void NegateBool(Register rd, Register rs) { Xor(rd, rs, 1); } -+ -+ // Compare float, if any operand is NaN, result is false except for NE -+ void CompareF32(Register rd, FPUCondition cc, FPURegister cmp1, -+ FPURegister cmp2); -+ // Compare double, if any operand is NaN, result is false except for NE -+ void CompareF64(Register rd, FPUCondition cc, FPURegister cmp1, -+ FPURegister cmp2); -+ void CompareIsNanF32(Register rd, FPURegister cmp1, FPURegister cmp2); -+ void CompareIsNanF64(Register rd, FPURegister cmp1, FPURegister cmp2); -+ -+ // Floating point branches -+ void BranchTrueShortF(Register rs, Label* target); -+ void BranchFalseShortF(Register rs, Label* target); -+ -+ void BranchTrueF(Register rs, Label* target); -+ void BranchFalseF(Register rs, Label* target); -+ -+ void Branch(Label* L, Condition cond, Register rs, RootIndex index); -+ -+ static int InstrCountForLi64Bit(int64_t value); -+ inline void LiLower32BitHelper(Register rd, Operand j); -+ void li_optimized(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE); -+ // Load int32 in the rd register. -+ void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE); -+ inline void li(Register rd, int64_t j, LiFlags mode = OPTIMIZE_SIZE) { -+ li(rd, Operand(j), mode); -+ } -+ -+ void li(Register dst, Handle value, LiFlags mode = OPTIMIZE_SIZE); -+ void li(Register dst, ExternalReference value, LiFlags mode = OPTIMIZE_SIZE); -+ void li(Register dst, const StringConstantBase* string, -+ LiFlags mode = OPTIMIZE_SIZE); -+ -+ void LoadFromConstantsTable(Register destination, -+ int constant_index) override; -+ void LoadRootRegisterOffset(Register destination, intptr_t offset) override; -+ void LoadRootRelative(Register destination, int32_t offset) override; -+ -+// Jump, Call, and Ret pseudo instructions implementing inter-working. -+#define COND_ARGS \ -+ Condition cond = al, Register rs = zero_reg, \ -+ const Operand &rt = Operand(zero_reg) -+ -+ void Jump(Register target, COND_ARGS); -+ void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS); -+ void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS); -+ // Deffer from li, this method save target to the memory, and then load -+ // it to register use ld, it can be used in wasm jump table for concurrent -+ // patching. -+ void PatchAndJump(Address target); -+ void Jump(Handle code, RelocInfo::Mode rmode, COND_ARGS); -+ void Jump(const ExternalReference& reference) override; -+ void Call(Register target, COND_ARGS); -+ void Call(Address target, RelocInfo::Mode rmode, COND_ARGS); -+ void Call(Handle code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, -+ COND_ARGS); -+ void Call(Label* target); -+ void LoadAddress(Register dst, Label* target); -+ -+ // Load the builtin given by the Smi in |builtin_index| into the same -+ // register. -+ void LoadEntryFromBuiltinIndex(Register builtin_index); -+ void CallBuiltinByIndex(Register builtin_index) override; -+ -+ void LoadCodeObjectEntry(Register destination, -+ Register code_object) override { -+ // TODO(RISCV): Implement. -+ UNIMPLEMENTED(); -+ } -+ void CallCodeObject(Register code_object) override { -+ // TODO(RISCV): Implement. -+ UNIMPLEMENTED(); -+ } -+ void JumpCodeObject(Register code_object) override { -+ // TODO(RISCV): Implement. -+ UNIMPLEMENTED(); -+ } -+ -+ // Generates an instruction sequence s.t. the return address points to the -+ // instruction following the call. -+ // The return address on the stack is used by frame iteration. -+ void StoreReturnAddressAndCall(Register target); -+ -+ void CallForDeoptimization(Address target, int deopt_id, Label* exit, -+ DeoptimizeKind kind); -+ -+ void Ret(COND_ARGS); -+ -+ // Emit code to discard a non-negative number of pointer-sized elements -+ // from the stack, clobbering only the sp register. -+ void Drop(int count, Condition cond = cc_always, Register reg = no_reg, -+ const Operand& op = Operand(no_reg)); -+ -+ // Trivial case of DropAndRet that only emits 2 instructions. -+ void DropAndRet(int drop); -+ -+ void DropAndRet(int drop, Condition cond, Register reg, const Operand& op); -+ -+ void Ld(Register rd, const MemOperand& rs); -+ void Sd(Register rd, const MemOperand& rs); -+ -+ void push(Register src) { -+ Add64(sp, sp, Operand(-kPointerSize)); -+ Sd(src, MemOperand(sp, 0)); -+ } -+ void Push(Register src) { push(src); } -+ void Push(Handle handle); -+ void Push(Smi smi); -+ -+ // Push two registers. Pushes leftmost register first (to highest address). -+ void Push(Register src1, Register src2) { -+ Sub64(sp, sp, Operand(2 * kPointerSize)); -+ Sd(src1, MemOperand(sp, 1 * kPointerSize)); -+ Sd(src2, MemOperand(sp, 0 * kPointerSize)); -+ } -+ -+ // Push three registers. Pushes leftmost register first (to highest address). -+ void Push(Register src1, Register src2, Register src3) { -+ Sub64(sp, sp, Operand(3 * kPointerSize)); -+ Sd(src1, MemOperand(sp, 2 * kPointerSize)); -+ Sd(src2, MemOperand(sp, 1 * kPointerSize)); -+ Sd(src3, MemOperand(sp, 0 * kPointerSize)); -+ } -+ -+ // Push four registers. Pushes leftmost register first (to highest address). -+ void Push(Register src1, Register src2, Register src3, Register src4) { -+ Sub64(sp, sp, Operand(4 * kPointerSize)); -+ Sd(src1, MemOperand(sp, 3 * kPointerSize)); -+ Sd(src2, MemOperand(sp, 2 * kPointerSize)); -+ Sd(src3, MemOperand(sp, 1 * kPointerSize)); -+ Sd(src4, MemOperand(sp, 0 * kPointerSize)); -+ } -+ -+ // Push five registers. Pushes leftmost register first (to highest address). -+ void Push(Register src1, Register src2, Register src3, Register src4, -+ Register src5) { -+ Sub64(sp, sp, Operand(5 * kPointerSize)); -+ Sd(src1, MemOperand(sp, 4 * kPointerSize)); -+ Sd(src2, MemOperand(sp, 3 * kPointerSize)); -+ Sd(src3, MemOperand(sp, 2 * kPointerSize)); -+ Sd(src4, MemOperand(sp, 1 * kPointerSize)); -+ Sd(src5, MemOperand(sp, 0 * kPointerSize)); -+ } -+ -+ void Push(Register src, Condition cond, Register tst1, Register tst2) { -+ // Since we don't have conditional execution we use a Branch. -+ Branch(3, cond, tst1, Operand(tst2)); -+ Sub64(sp, sp, Operand(kPointerSize)); -+ Sd(src, MemOperand(sp, 0)); -+ } -+ -+ void SaveRegisters(RegList registers); -+ void RestoreRegisters(RegList registers); -+ -+ void CallRecordWriteStub(Register object, Register address, -+ RememberedSetAction remembered_set_action, -+ SaveFPRegsMode fp_mode); -+ void CallRecordWriteStub(Register object, Register address, -+ RememberedSetAction remembered_set_action, -+ SaveFPRegsMode fp_mode, Address wasm_target); -+ void CallEphemeronKeyBarrier(Register object, Register address, -+ SaveFPRegsMode fp_mode); -+ -+ // Push multiple registers on the stack. -+ // Registers are saved in numerical order, with higher numbered registers -+ // saved in higher memory addresses. -+ void MultiPush(RegList regs); -+ void MultiPushFPU(RegList regs); -+ -+ // Calculate how much stack space (in bytes) are required to store caller -+ // registers excluding those specified in the arguments. -+ int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode, -+ Register exclusion1 = no_reg, -+ Register exclusion2 = no_reg, -+ Register exclusion3 = no_reg) const; -+ -+ // Push caller saved registers on the stack, and return the number of bytes -+ // stack pointer is adjusted. -+ int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, -+ Register exclusion2 = no_reg, -+ Register exclusion3 = no_reg); -+ // Restore caller saved registers from the stack, and return the number of -+ // bytes stack pointer is adjusted. -+ int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, -+ Register exclusion2 = no_reg, -+ Register exclusion3 = no_reg); -+ -+ void pop(Register dst) { -+ Ld(dst, MemOperand(sp, 0)); -+ Add64(sp, sp, Operand(kPointerSize)); -+ } -+ void Pop(Register dst) { pop(dst); } -+ -+ // Pop two registers. Pops rightmost register first (from lower address). -+ void Pop(Register src1, Register src2) { -+ DCHECK(src1 != src2); -+ Ld(src2, MemOperand(sp, 0 * kPointerSize)); -+ Ld(src1, MemOperand(sp, 1 * kPointerSize)); -+ Add64(sp, sp, 2 * kPointerSize); -+ } -+ -+ // Pop three registers. Pops rightmost register first (from lower address). -+ void Pop(Register src1, Register src2, Register src3) { -+ Ld(src3, MemOperand(sp, 0 * kPointerSize)); -+ Ld(src2, MemOperand(sp, 1 * kPointerSize)); -+ Ld(src1, MemOperand(sp, 2 * kPointerSize)); -+ Add64(sp, sp, 3 * kPointerSize); -+ } -+ -+ void Pop(uint32_t count = 1) { Add64(sp, sp, Operand(count * kPointerSize)); } -+ -+ // Pops multiple values from the stack and load them in the -+ // registers specified in regs. Pop order is the opposite as in MultiPush. -+ void MultiPop(RegList regs); -+ void MultiPopFPU(RegList regs); -+ -+#define DEFINE_INSTRUCTION(instr) \ -+ void instr(Register rd, Register rs, const Operand& rt); \ -+ void instr(Register rd, Register rs, Register rt) { \ -+ instr(rd, rs, Operand(rt)); \ -+ } \ -+ void instr(Register rs, Register rt, int32_t j) { instr(rs, rt, Operand(j)); } -+ -+#define DEFINE_INSTRUCTION2(instr) \ -+ void instr(Register rs, const Operand& rt); \ -+ void instr(Register rs, Register rt) { instr(rs, Operand(rt)); } \ -+ void instr(Register rs, int32_t j) { instr(rs, Operand(j)); } -+ -+ DEFINE_INSTRUCTION(Add32) -+ DEFINE_INSTRUCTION(Add64) -+ DEFINE_INSTRUCTION(Div32) -+ DEFINE_INSTRUCTION(Divu32) -+ DEFINE_INSTRUCTION(Divu64) -+ DEFINE_INSTRUCTION(Mod32) -+ DEFINE_INSTRUCTION(Modu32) -+ DEFINE_INSTRUCTION(Div64) -+ DEFINE_INSTRUCTION(Sub32) -+ DEFINE_INSTRUCTION(Sub64) -+ DEFINE_INSTRUCTION(Mod64) -+ DEFINE_INSTRUCTION(Modu64) -+ DEFINE_INSTRUCTION(Mul32) -+ DEFINE_INSTRUCTION(Mulh32) -+ DEFINE_INSTRUCTION(Mul64) -+ DEFINE_INSTRUCTION(Mulh64) -+ DEFINE_INSTRUCTION2(Div32) -+ DEFINE_INSTRUCTION2(Div64) -+ DEFINE_INSTRUCTION2(Divu32) -+ DEFINE_INSTRUCTION2(Divu64) -+ -+ DEFINE_INSTRUCTION(And) -+ DEFINE_INSTRUCTION(Or) -+ DEFINE_INSTRUCTION(Xor) -+ DEFINE_INSTRUCTION(Nor) -+ DEFINE_INSTRUCTION2(Neg) -+ -+ DEFINE_INSTRUCTION(Slt) -+ DEFINE_INSTRUCTION(Sltu) -+ DEFINE_INSTRUCTION(Sle) -+ DEFINE_INSTRUCTION(Sleu) -+ DEFINE_INSTRUCTION(Sgt) -+ DEFINE_INSTRUCTION(Sgtu) -+ DEFINE_INSTRUCTION(Sge) -+ DEFINE_INSTRUCTION(Sgeu) -+ DEFINE_INSTRUCTION(Seq) -+ DEFINE_INSTRUCTION(Sne) -+ -+ DEFINE_INSTRUCTION(Sll64) -+ DEFINE_INSTRUCTION(Sra64) -+ DEFINE_INSTRUCTION(Srl64) -+ DEFINE_INSTRUCTION(Sll32) -+ DEFINE_INSTRUCTION(Sra32) -+ DEFINE_INSTRUCTION(Srl32) -+ -+ DEFINE_INSTRUCTION2(Seqz) -+ DEFINE_INSTRUCTION2(Snez) -+ -+ DEFINE_INSTRUCTION(Ror) -+ DEFINE_INSTRUCTION(Dror) -+#undef DEFINE_INSTRUCTION -+#undef DEFINE_INSTRUCTION2 -+#undef DEFINE_INSTRUCTION3 -+ -+ void SmiUntag(Register dst, const MemOperand& src); -+ void SmiUntag(Register dst, Register src) { -+ if (SmiValuesAre32Bits()) { -+ srai(dst, src, kSmiShift); -+ } else { -+ DCHECK(SmiValuesAre31Bits()); -+ sraiw(dst, src, kSmiShift); -+ } -+ } -+ -+ void SmiUntag(Register reg) { SmiUntag(reg, reg); } -+ -+ // Removes current frame and its arguments from the stack preserving -+ // the arguments and a return address pushed to the stack for the next call. -+ // Both |callee_args_count| and |caller_args_count| do not include -+ // receiver. |callee_args_count| is not modified. |caller_args_count| -+ // is trashed. -+ void PrepareForTailCall(Register callee_args_count, -+ Register caller_args_count, Register scratch0, -+ Register scratch1); -+ -+ int CalculateStackPassedDWords(int num_gp_arguments, int num_fp_arguments); -+ -+ // Before calling a C-function from generated code, align arguments on stack. -+ // After aligning the frame, non-register arguments must be stored on the -+ // stack, using helper: CFunctionArgumentOperand(). -+ // The argument count assumes all arguments are word sized. -+ // Some compilers/platforms require the stack to be aligned when calling -+ // C++ code. -+ // Needs a scratch register to do some arithmetic. This register will be -+ // trashed. -+ void PrepareCallCFunction(int num_reg_arguments, int num_double_registers, -+ Register scratch); -+ void PrepareCallCFunction(int num_reg_arguments, Register scratch); -+ -+ // Arguments 1-8 are placed in registers a0 through a7 respectively. -+ // Arguments 9..n are stored to stack -+ -+ // Calls a C function and cleans up the space for arguments allocated -+ // by PrepareCallCFunction. The called function is not allowed to trigger a -+ // garbage collection, since that might move the code and invalidate the -+ // return address (unless this is somehow accounted for by the called -+ // function). -+ void CallCFunction(ExternalReference function, int num_arguments); -+ void CallCFunction(Register function, int num_arguments); -+ void CallCFunction(ExternalReference function, int num_reg_arguments, -+ int num_double_arguments); -+ void CallCFunction(Register function, int num_reg_arguments, -+ int num_double_arguments); -+ void MovFromFloatResult(DoubleRegister dst); -+ void MovFromFloatParameter(DoubleRegister dst); -+ -+ // These functions abstract parameter passing for the three different ways -+ // we call C functions from generated code. -+ void MovToFloatParameter(DoubleRegister src); -+ void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2); -+ void MovToFloatResult(DoubleRegister src); -+ -+ // See comments at the beginning of Builtins::Generate_CEntry. -+ inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); } -+ inline void PrepareCEntryFunction(const ExternalReference& ref) { -+ li(a1, ref); -+ } -+ -+ void CheckPageFlag(Register object, Register scratch, int mask, Condition cc, -+ Label* condition_met); -+#undef COND_ARGS -+ -+ // Performs a truncating conversion of a floating point number as used by -+ // the JS bitwise operations. See ECMA-262 9.5: ToInt32. -+ // Exits with 'result' holding the answer. -+ void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result, -+ DoubleRegister double_input, StubCallMode stub_mode); -+ -+ void CompareI(Register rd, Register rs, const Operand& rt, Condition cond); -+ -+ void LoadZeroIfConditionNotZero(Register dest, Register condition); -+ void LoadZeroIfConditionZero(Register dest, Register condition); -+ -+ void SignExtendByte(Register rd, Register rs) { -+ slli(rd, rs, 64 - 8); -+ srai(rd, rd, 64 - 8); -+ } -+ -+ void SignExtendShort(Register rd, Register rs) { -+ slli(rd, rs, 64 - 16); -+ srai(rd, rd, 64 - 16); -+ } -+ -+ void SignExtendWord(Register rd, Register rs) { sext_w(rd, rs); } -+ void ZeroExtendWord(Register rd, Register rs) { -+ slli(rd, rs, 32); -+ srli(rd, rd, 32); -+ } -+ -+ void Clz32(Register rd, Register rs); -+ void Clz64(Register rd, Register rs); -+ void Ctz32(Register rd, Register rs); -+ void Ctz64(Register rd, Register rs); -+ void Popcnt32(Register rd, Register rs); -+ void Popcnt64(Register rd, Register rs); -+ -+ // Bit field starts at bit pos and extending for size bits is extracted from -+ // rs and stored zero/sign-extended and right-justified in rt -+ void ExtractBits(Register rt, Register rs, uint16_t pos, uint16_t size, -+ bool sign_extend = false); -+ void ExtractBits(Register dest, Register source, Register pos, int size, -+ bool sign_extend = false) { -+ sra(dest, source, pos); -+ ExtractBits(dest, dest, 0, size, sign_extend); -+ } -+ -+ // Insert bits [0, size) of source to bits [pos, pos+size) of dest -+ void InsertBits(Register dest, Register source, Register pos, int size); -+ -+ void Neg_s(FPURegister fd, FPURegister fs); -+ void Neg_d(FPURegister fd, FPURegister fs); -+ -+ // Change endianness -+ void ByteSwap(Register dest, Register src, int operand_size); -+ -+ // Convert single to unsigned word. -+ void Trunc_uw_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // helper functions for unaligned load/store -+ template -+ void UnalignedLoadHelper(Register rd, const MemOperand& rs); -+ template -+ void UnalignedStoreHelper(Register rd, const MemOperand& rs, -+ Register scratch_other = no_reg); -+ -+ template -+ void UnalignedFLoadHelper(FPURegister frd, const MemOperand& rs, -+ Register scratch); -+ template -+ void UnalignedFStoreHelper(FPURegister frd, const MemOperand& rs, -+ Register scratch); -+ -+ template -+ void AlignedLoadHelper(Reg_T target, const MemOperand& rs, Func generator); -+ template -+ void AlignedStoreHelper(Reg_T value, const MemOperand& rs, Func generator); -+ -+ template -+ void LoadNBytes(Register rd, const MemOperand& rs, Register scratch); -+ template -+ void LoadNBytesOverwritingBaseReg(const MemOperand& rs, Register scratch0, -+ Register scratch1); -+ // load/store macros -+ void Ulh(Register rd, const MemOperand& rs); -+ void Ulhu(Register rd, const MemOperand& rs); -+ void Ush(Register rd, const MemOperand& rs); -+ -+ void Ulw(Register rd, const MemOperand& rs); -+ void Ulwu(Register rd, const MemOperand& rs); -+ void Usw(Register rd, const MemOperand& rs); -+ -+ void Uld(Register rd, const MemOperand& rs); -+ void Usd(Register rd, const MemOperand& rs); -+ -+ void ULoadFloat(FPURegister fd, const MemOperand& rs, Register scratch); -+ void UStoreFloat(FPURegister fd, const MemOperand& rs, Register scratch); -+ -+ void ULoadDouble(FPURegister fd, const MemOperand& rs, Register scratch); -+ void UStoreDouble(FPURegister fd, const MemOperand& rs, Register scratch); -+ -+ void Lb(Register rd, const MemOperand& rs); -+ void Lbu(Register rd, const MemOperand& rs); -+ void Sb(Register rd, const MemOperand& rs); -+ -+ void Lh(Register rd, const MemOperand& rs); -+ void Lhu(Register rd, const MemOperand& rs); -+ void Sh(Register rd, const MemOperand& rs); -+ -+ void Lw(Register rd, const MemOperand& rs); -+ void Lwu(Register rd, const MemOperand& rs); -+ void Sw(Register rd, const MemOperand& rs); -+ -+ void LoadFloat(FPURegister fd, const MemOperand& src); -+ void StoreFloat(FPURegister fs, const MemOperand& dst); -+ -+ void LoadDouble(FPURegister fd, const MemOperand& src); -+ void StoreDouble(FPURegister fs, const MemOperand& dst); -+ -+ void Ll(Register rd, const MemOperand& rs); -+ void Sc(Register rd, const MemOperand& rs); -+ -+ void Lld(Register rd, const MemOperand& rs); -+ void Scd(Register rd, const MemOperand& rs); -+ -+ void Float32Max(FPURegister dst, FPURegister src1, FPURegister src2); -+ void Float32Min(FPURegister dst, FPURegister src1, FPURegister src2); -+ void Float64Max(FPURegister dst, FPURegister src1, FPURegister src2); -+ void Float64Min(FPURegister dst, FPURegister src1, FPURegister src2); -+ template -+ void FloatMinMaxHelper(FPURegister dst, FPURegister src1, FPURegister src2, -+ MaxMinKind kind); -+ -+ bool IsDoubleZeroRegSet() { return has_double_zero_reg_set_; } -+ bool IsSingleZeroRegSet() { return has_single_zero_reg_set_; } -+ -+ inline void Move(Register dst, Smi smi) { li(dst, Operand(smi)); } -+ -+ inline void Move(Register dst, Register src) { -+ if (dst != src) { -+ mv(dst, src); -+ } -+ } -+ -+ inline void Move(FPURegister dst, FPURegister src) { -+ if (dst != src) fmv_d(dst, src); -+ } -+ -+ inline void Move(Register dst_low, Register dst_high, FPURegister src) { -+ fmv_x_d(dst_high, src); -+ fmv_x_w(dst_low, src); -+ srli(dst_high, dst_high, 32); -+ } -+ -+ inline void Move(Register dst, FPURegister src) { fmv_x_d(dst, src); } -+ -+ inline void Move(FPURegister dst, Register src) { fmv_d_x(dst, src); } -+ -+ // Extract sign-extended word from high-half of FPR to GPR -+ inline void ExtractHighWordFromF64(Register dst_high, FPURegister src) { -+ fmv_x_d(dst_high, src); -+ srai(dst_high, dst_high, 32); -+ } -+ -+ // Insert low-word from GPR (src_high) to the high-half of FPR (dst) -+ void InsertHighWordF64(FPURegister dst, Register src_high); -+ -+ // Extract sign-extended word from low-half of FPR to GPR -+ inline void ExtractLowWordFromF64(Register dst_low, FPURegister src) { -+ fmv_x_w(dst_low, src); -+ } -+ -+ // Insert low-word from GPR (src_high) to the low-half of FPR (dst) -+ void InsertLowWordF64(FPURegister dst, Register src_low); -+ -+ void LoadFPRImmediate(FPURegister dst, float imm) { -+ LoadFPRImmediate(dst, bit_cast(imm)); -+ } -+ void LoadFPRImmediate(FPURegister dst, double imm) { -+ LoadFPRImmediate(dst, bit_cast(imm)); -+ } -+ void LoadFPRImmediate(FPURegister dst, uint32_t src); -+ void LoadFPRImmediate(FPURegister dst, uint64_t src); -+ -+ // AddOverflow64 sets overflow register to a negative value if -+ // overflow occured, otherwise it is zero or positive -+ void AddOverflow64(Register dst, Register left, const Operand& right, -+ Register overflow); -+ // SubOverflow64 sets overflow register to a negative value if -+ // overflow occured, otherwise it is zero or positive -+ void SubOverflow64(Register dst, Register left, const Operand& right, -+ Register overflow); -+ // MulOverflow32 sets overflow register to zero if no overflow occured -+ void MulOverflow32(Register dst, Register left, const Operand& right, -+ Register overflow); -+ -+ // MIPS-style 32-bit unsigned mulh -+ void Mulhu32(Register dst, Register left, const Operand& right, -+ Register left_zero, Register right_zero); -+ -+ // Number of instructions needed for calculation of switch table entry address -+ static const int kSwitchTablePrologueSize = 6; -+ -+ // GetLabelFunction must be lambda '[](size_t index) -> Label*' or a -+ // functor/function with 'Label *func(size_t index)' declaration. -+ template -+ void GenerateSwitchTable(Register index, size_t case_count, -+ Func GetLabelFunction); -+ -+ // Load an object from the root table. -+ void LoadRoot(Register destination, RootIndex index) override; -+ void LoadRoot(Register destination, RootIndex index, Condition cond, -+ Register src1, const Operand& src2); -+ -+ // If the value is a NaN, canonicalize the value else, do nothing. -+ void FPUCanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src); -+ -+ // --------------------------------------------------------------------------- -+ // FPU macros. These do not handle special cases like NaN or +- inf. -+ -+ // Convert unsigned word to double. -+ void Cvt_d_uw(FPURegister fd, Register rs); -+ -+ // convert signed word to double. -+ void Cvt_d_w(FPURegister fd, Register rs); -+ -+ // Convert unsigned long to double. -+ void Cvt_d_ul(FPURegister fd, Register rs); -+ -+ // Convert unsigned word to float. -+ void Cvt_s_uw(FPURegister fd, Register rs); -+ -+ // convert signed word to float. -+ void Cvt_s_w(FPURegister fd, Register rs); -+ -+ // Convert unsigned long to float. -+ void Cvt_s_ul(FPURegister fd, Register rs); -+ -+ // Convert double to unsigned word. -+ void Trunc_uw_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Convert double to signed word. -+ void Trunc_w_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Convert single to signed word. -+ void Trunc_w_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Convert double to unsigned long. -+ void Trunc_ul_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Convert singled to signed long. -+ void Trunc_l_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Convert single to unsigned long. -+ void Trunc_ul_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Convert singled to signed long. -+ void Trunc_l_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Round single to signed word. -+ void Round_w_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Round double to signed word. -+ void Round_w_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Ceil single to signed word. -+ void Ceil_w_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Ceil double to signed word. -+ void Ceil_w_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Floor single to signed word. -+ void Floor_w_s(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Floor double to signed word. -+ void Floor_w_d(Register rd, FPURegister fs, Register result = no_reg); -+ -+ // Round double functions -+ void Trunc_d_d(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ void Round_d_d(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ void Floor_d_d(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ void Ceil_d_d(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ -+ // Round float functions -+ void Trunc_s_s(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ void Round_s_s(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ void Floor_s_s(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ void Ceil_s_s(FPURegister fd, FPURegister fs, FPURegister fpu_scratch); -+ -+ // Jump the register contains a smi. -+ void JumpIfSmi(Register value, Label* smi_label, Register scratch = t3); -+ -+ void JumpIfEqual(Register a, int32_t b, Label* dest) { -+ Branch(dest, eq, a, Operand(b)); -+ } -+ -+ void JumpIfLessThan(Register a, int32_t b, Label* dest) { -+ Branch(dest, lt, a, Operand(b)); -+ } -+ -+ // Push a standard frame, consisting of ra, fp, context and JS function. -+ void PushStandardFrame(Register function_reg); -+ -+ // Get the actual activation frame alignment for target environment. -+ static int ActivationFrameAlignment(); -+ -+ // Calculated scaled address (rd) as rt + rs << sa -+ void CalcScaledAddress(Register rd, Register rs, Register rt, uint8_t sa, -+ Register scratch = t3); -+ -+ // Compute the start of the generated instruction stream from the current PC. -+ // This is an alternative to embedding the {CodeObject} handle as a reference. -+ void ComputeCodeStartAddress(Register dst); -+ -+ void ResetSpeculationPoisonRegister(); -+ -+ // Control-flow integrity: -+ -+ // Define a function entrypoint. This doesn't emit any code for this -+ // architecture, as control-flow integrity is not supported for it. -+ void CodeEntry() {} -+ // Define an exception handler. -+ void ExceptionHandler() {} -+ // Define an exception handler and bind a label. -+ void BindExceptionHandler(Label* label) { bind(label); } -+ -+ protected: -+ inline Register GetRtAsRegisterHelper(const Operand& rt, Register scratch); -+ inline int32_t GetOffset(int32_t offset, Label* L, OffsetSize bits); -+ -+ private: -+ bool has_double_zero_reg_set_ = false; -+ bool has_single_zero_reg_set_ = false; -+ -+ // Performs a truncating conversion of a floating point number as used by -+ // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it -+ // succeeds, otherwise falls through if result is saturated. On return -+ // 'result' either holds answer, or is clobbered on fall through. -+ void TryInlineTruncateDoubleToI(Register result, DoubleRegister input, -+ Label* done); -+ -+ void CallCFunctionHelper(Register function, int num_reg_arguments, -+ int num_double_arguments); -+ -+ // TODO(RISCV) Reorder parameters so out parameters come last. -+ bool CalculateOffset(Label* L, int32_t* offset, OffsetSize bits); -+ bool CalculateOffset(Label* L, int32_t* offset, OffsetSize bits, -+ Register* scratch, const Operand& rt); -+ -+ void BranchShortHelper(int32_t offset, Label* L); -+ bool BranchShortHelper(int32_t offset, Label* L, Condition cond, Register rs, -+ const Operand& rt); -+ bool BranchShortCheck(int32_t offset, Label* L, Condition cond, Register rs, -+ const Operand& rt); -+ -+ void BranchAndLinkShortHelper(int32_t offset, Label* L); -+ void BranchAndLinkShort(int32_t offset); -+ void BranchAndLinkShort(Label* L); -+ bool BranchAndLinkShortHelper(int32_t offset, Label* L, Condition cond, -+ Register rs, const Operand& rt); -+ bool BranchAndLinkShortCheck(int32_t offset, Label* L, Condition cond, -+ Register rs, const Operand& rt); -+ void BranchLong(Label* L); -+ void BranchAndLinkLong(Label* L); -+ -+ template -+ void RoundHelper(FPURegister dst, FPURegister src, FPURegister fpu_scratch, -+ RoundingMode mode); -+ -+ template -+ void RoundFloatingPointToInteger(Register rd, FPURegister fs, Register result, -+ TruncFunc trunc); -+ -+ // Push a fixed frame, consisting of ra, fp. -+ void PushCommonFrame(Register marker_reg = no_reg); -+ -+ void CallRecordWriteStub(Register object, Register address, -+ RememberedSetAction remembered_set_action, -+ SaveFPRegsMode fp_mode, Handle code_target, -+ Address wasm_target); -+}; -+ -+// MacroAssembler implements a collection of frequently used macros. -+class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { -+ public: -+ using TurboAssembler::TurboAssembler; -+ -+ bool IsNear(Label* L, Condition cond, int rs_reg); -+ -+ // Swap two registers. If the scratch register is omitted then a slightly -+ // less efficient form using xor instead of mov is emitted. -+ void Swap(Register reg1, Register reg2, Register scratch = no_reg); -+ -+ void PushRoot(RootIndex index) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ LoadRoot(scratch, index); -+ Push(scratch); -+ } -+ -+ // Compare the object in a register to a value and jump if they are equal. -+ void JumpIfRoot(Register with, RootIndex index, Label* if_equal) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ LoadRoot(scratch, index); -+ Branch(if_equal, eq, with, Operand(scratch)); -+ } -+ -+ // Compare the object in a register to a value and jump if they are not equal. -+ void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ LoadRoot(scratch, index); -+ Branch(if_not_equal, ne, with, Operand(scratch)); -+ } -+ -+ // Checks if value is in range [lower_limit, higher_limit] using a single -+ // comparison. -+ void JumpIfIsInRange(Register value, unsigned lower_limit, -+ unsigned higher_limit, Label* on_in_range); -+ -+ // --------------------------------------------------------------------------- -+ // GC Support -+ -+ // Notify the garbage collector that we wrote a pointer into an object. -+ // |object| is the object being stored into, |value| is the object being -+ // stored. value and scratch registers are clobbered by the operation. -+ // The offset is the offset from the start of the object, not the offset from -+ // the tagged HeapObject pointer. For use with FieldOperand(reg, off). -+ void RecordWriteField( -+ Register object, int offset, Register value, Register scratch, -+ RAStatus ra_status, SaveFPRegsMode save_fp, -+ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, -+ SmiCheck smi_check = INLINE_SMI_CHECK); -+ -+ // For a given |object| notify the garbage collector that the slot |address| -+ // has been written. |value| is the object being stored. The value and -+ // address registers are clobbered by the operation. -+ void RecordWrite( -+ Register object, Register address, Register value, RAStatus ra_status, -+ SaveFPRegsMode save_fp, -+ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, -+ SmiCheck smi_check = INLINE_SMI_CHECK); -+ -+ // void Pref(int32_t hint, const MemOperand& rs); -+ -+ // --------------------------------------------------------------------------- -+ // Pseudo-instructions. -+ -+ void LoadWordPair(Register rd, const MemOperand& rs, Register scratch = t3); -+ void StoreWordPair(Register rd, const MemOperand& rs, Register scratch = t3); -+ -+ void Madd_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft); -+ void Madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft); -+ void Msub_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft); -+ void Msub_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft); -+ -+ // Enter exit frame. -+ // argc - argument count to be dropped by LeaveExitFrame. -+ // save_doubles - saves FPU registers on stack, currently disabled. -+ // stack_space - extra stack space. -+ void EnterExitFrame(bool save_doubles, int stack_space = 0, -+ StackFrame::Type frame_type = StackFrame::EXIT); -+ -+ // Leave the current exit frame. -+ void LeaveExitFrame(bool save_doubles, Register arg_count, -+ bool do_return = NO_EMIT_RETURN, -+ bool argument_count_is_length = false); -+ -+ void LoadMap(Register destination, Register object); -+ -+ // Make sure the stack is aligned. Only emits code in debug mode. -+ void AssertStackIsAligned(); -+ -+ // Load the global proxy from the current context. -+ void LoadGlobalProxy(Register dst) { -+ LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst); -+ } -+ -+ void LoadNativeContextSlot(int index, Register dst); -+ -+ // Load the initial map from the global function. The registers -+ // function and map can be the same, function is then overwritten. -+ void LoadGlobalFunctionInitialMap(Register function, Register map, -+ Register scratch); -+ -+ // ------------------------------------------------------------------------- -+ // JavaScript invokes. -+ -+ // Invoke the JavaScript function code by either calling or jumping. -+ void InvokeFunctionCode(Register function, Register new_target, -+ Register expected_parameter_count, -+ Register actual_parameter_count, InvokeFlag flag); -+ -+ // On function call, call into the debugger if necessary. -+ void CheckDebugHook(Register fun, Register new_target, -+ Register expected_parameter_count, -+ Register actual_parameter_count); -+ -+ // Invoke the JavaScript function in the given register. Changes the -+ // current context to the context in the function before invoking. -+ void InvokeFunctionWithNewTarget(Register function, Register new_target, -+ Register actual_parameter_count, -+ InvokeFlag flag); -+ void InvokeFunction(Register function, Register expected_parameter_count, -+ Register actual_parameter_count, InvokeFlag flag); -+ -+ // Frame restart support. -+ void MaybeDropFrames(); -+ -+ // Exception handling. -+ -+ // Push a new stack handler and link into stack handler chain. -+ void PushStackHandler(); -+ -+ // Unlink the stack handler on top of the stack from the stack handler chain. -+ // Must preserve the result register. -+ void PopStackHandler(); -+ -+ // ------------------------------------------------------------------------- -+ // Support functions. -+ -+ void GetObjectType(Register function, Register map, Register type_reg); -+ -+ // ------------------------------------------------------------------------- -+ // Runtime calls. -+ -+ // Call a runtime routine. -+ void CallRuntime(const Runtime::Function* f, int num_arguments, -+ SaveFPRegsMode save_doubles = kDontSaveFPRegs); -+ -+ // Convenience function: Same as above, but takes the fid instead. -+ void CallRuntime(Runtime::FunctionId fid, -+ SaveFPRegsMode save_doubles = kDontSaveFPRegs) { -+ const Runtime::Function* function = Runtime::FunctionForId(fid); -+ CallRuntime(function, function->nargs, save_doubles); -+ } -+ -+ // Convenience function: Same as above, but takes the fid instead. -+ void CallRuntime(Runtime::FunctionId fid, int num_arguments, -+ SaveFPRegsMode save_doubles = kDontSaveFPRegs) { -+ CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles); -+ } -+ -+ // Convenience function: tail call a runtime routine (jump). -+ void TailCallRuntime(Runtime::FunctionId fid); -+ -+ // Jump to the builtin routine. -+ void JumpToExternalReference(const ExternalReference& builtin, -+ bool builtin_exit_frame = false); -+ -+ // Generates a trampoline to jump to the off-heap instruction stream. -+ void JumpToInstructionStream(Address entry); -+ -+ // --------------------------------------------------------------------------- -+ // In-place weak references. -+ void LoadWeakValue(Register out, Register in, Label* target_if_cleared); -+ -+ // ------------------------------------------------------------------------- -+ // StatsCounter support. -+ -+ void IncrementCounter(StatsCounter* counter, int value, Register scratch1, -+ Register scratch2); -+ void DecrementCounter(StatsCounter* counter, int value, Register scratch1, -+ Register scratch2); -+ -+ // ------------------------------------------------------------------------- -+ // Smi utilities. -+ -+ void SmiTag(Register dst, Register src) { -+ STATIC_ASSERT(kSmiTag == 0); -+ if (SmiValuesAre32Bits()) { -+ // FIXME(RISCV): do not understand the logic here -+ slli(dst, src, 32); -+ } else { -+ DCHECK(SmiValuesAre31Bits()); -+ Add32(dst, src, src); -+ } -+ } -+ -+ void SmiTag(Register reg) { SmiTag(reg, reg); } -+ -+ // Left-shifted from int32 equivalent of Smi. -+ void SmiScale(Register dst, Register src, int scale) { -+ if (SmiValuesAre32Bits()) { -+ // The int portion is upper 32-bits of 64-bit word. -+ srai(dst, src, (kSmiShift - scale) & 0x3F); -+ } else { -+ DCHECK(SmiValuesAre31Bits()); -+ DCHECK_GE(scale, kSmiTagSize); -+ slliw(dst, src, scale - kSmiTagSize); -+ } -+ } -+ -+ // Test if the register contains a smi. -+ inline void SmiTst(Register value, Register scratch) { -+ And(scratch, value, Operand(kSmiTagMask)); -+ } -+ -+ // Jump if the register contains a non-smi. -+ void JumpIfNotSmi(Register value, Label* not_smi_label, -+ Register scratch = t3); -+ -+ // Abort execution if argument is a smi, enabled via --debug-code. -+ void AssertNotSmi(Register object); -+ void AssertSmi(Register object); -+ -+ // Abort execution if argument is not a Constructor, enabled via --debug-code. -+ void AssertConstructor(Register object); -+ -+ // Abort execution if argument is not a JSFunction, enabled via --debug-code. -+ void AssertFunction(Register object); -+ -+ // Abort execution if argument is not a JSBoundFunction, -+ // enabled via --debug-code. -+ void AssertBoundFunction(Register object); -+ -+ // Abort execution if argument is not a JSGeneratorObject (or subclass), -+ // enabled via --debug-code. -+ void AssertGeneratorObject(Register object); -+ -+ // Abort execution if argument is not undefined or an AllocationSite, enabled -+ // via --debug-code. -+ void AssertUndefinedOrAllocationSite(Register object, Register scratch); -+ -+ template -+ void DecodeField(Register dst, Register src) { -+ ExtractBits(dst, src, Field::kShift, Field::kSize); -+ } -+ -+ template -+ void DecodeField(Register reg) { -+ DecodeField(reg, reg); -+ } -+ -+ private: -+ // Helper functions for generating invokes. -+ void InvokePrologue(Register expected_parameter_count, -+ Register actual_parameter_count, Label* done, -+ InvokeFlag flag); -+ -+ // Compute memory operands for safepoint stack slots. -+ static int SafepointRegisterStackIndex(int reg_code); -+ -+ // Needs access to SafepointRegisterStackIndex for compiled frame -+ // traversal. -+ friend class StandardFrame; -+ -+ DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler); -+}; -+ -+template -+void TurboAssembler::GenerateSwitchTable(Register index, size_t case_count, -+ Func GetLabelFunction) { -+ // Ensure that dd-ed labels following this instruction use 8 bytes aligned -+ // addresses. -+ BlockTrampolinePoolFor(static_cast(case_count) * 2 + -+ kSwitchTablePrologueSize); -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ -+ Align(8); -+ // Load the address from the jump table at index and jump to it -+ auipc(scratch, 0); // Load the current PC into scratch -+ slli(t5, index, kPointerSizeLog2); // t5 = offset of indexth entry -+ add(t5, t5, scratch); // t5 = (saved PC) + (offset of indexth entry) -+ ld(t5, t5, 6 * kInstrSize); // Add the size of these 6 instructions to the -+ // offset, then load -+ jr(t5); // Jump to the address loaded from the table -+ nop(); // For 16-byte alignment -+ for (size_t index = 0; index < case_count; ++index) { -+ dd(GetLabelFunction(index)); -+ } -+} -+ -+#define ACCESS_MASM(masm) masm-> -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_CODEGEN_RISCV_MACRO_ASSEMBLER_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/register-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/codegen/riscv64/register-riscv64.h -@@ -0,0 +1,345 @@ -+// Copyright 2018 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. -+ -+#ifndef V8_CODEGEN_RISCV_REGISTER_RISCV_H_ -+#define V8_CODEGEN_RISCV_REGISTER_RISCV_H_ -+ -+#include "src/codegen/register.h" -+#include "src/codegen/reglist.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+ -+namespace v8 { -+namespace internal { -+ -+// clang-format off -+#define GENERAL_REGISTERS(V) \ -+ V(zero_reg) V(ra) V(sp) V(gp) V(tp) V(t0) V(t1) V(t2) \ -+ V(fp) V(s1) V(a0) V(a1) V(a2) V(a3) V(a4) V(a5) \ -+ V(a6) V(a7) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(s8) V(s9) \ -+ V(s10) V(s11) V(t3) V(t4) V(t5) V(t6) -+ -+#define ALLOCATABLE_GENERAL_REGISTERS(V) \ -+ V(a0) V(a1) V(a2) V(a3) \ -+ V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(s7) V(t4) -+ -+#define DOUBLE_REGISTERS(V) \ -+ V(ft0) V(ft1) V(ft2) V(ft3) V(ft4) V(ft5) V(ft6) V(ft7) \ -+ V(fs0) V(fs1) V(fa0) V(fa1) V(fa2) V(fa3) V(fa4) V(fa5) \ -+ V(fa6) V(fa7) V(fs2) V(fs3) V(fs4) V(fs5) V(fs6) V(fs7) \ -+ V(fs8) V(fs9) V(fs10) V(fs11) V(ft8) V(ft9) V(ft10) V(ft11) -+ -+#define FLOAT_REGISTERS DOUBLE_REGISTERS -+#define SIMD128_REGISTERS(V) \ -+ V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \ -+ V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \ -+ V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \ -+ V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31) -+ -+#define ALLOCATABLE_DOUBLE_REGISTERS(V) \ -+ V(ft0) V(ft1) V(ft2) V(ft3) \ -+ V(ft4) V(ft5) V(ft6) V(ft7) V(fa0) V(fa1) V(fa2) V(fa3) V(fa4) V(fa5) \ -+ V(fa6) V(fa7) -+ -+// clang-format on -+ -+// Note that the bit values must match those used in actual instruction -+// encoding. -+const int kNumRegs = 32; -+ -+const RegList kJSCallerSaved = 1 << 5 | // t0 -+ 1 << 6 | // t1 -+ 1 << 7 | // t2 -+ 1 << 10 | // a0 -+ 1 << 11 | // a1 -+ 1 << 12 | // a2 -+ 1 << 13 | // a3 -+ 1 << 14 | // a4 -+ 1 << 15 | // a5 -+ 1 << 16 | // a6 -+ 1 << 17 | // a7 -+ 1 << 29; // t4 -+ -+const int kNumJSCallerSaved = 12; -+ -+// Callee-saved registers preserved when switching from C to JavaScript. -+const RegList kCalleeSaved = 1 << 8 | // fp/s0 -+ 1 << 9 | // s1 -+ 1 << 18 | // s2 -+ 1 << 19 | // s3 -+ 1 << 20 | // s4 -+ 1 << 21 | // s5 -+ 1 << 22 | // s6 (roots in Javascript code) -+ 1 << 23 | // s7 (cp in Javascript code) -+ 1 << 24 | // s8 -+ 1 << 25 | // s9 -+ 1 << 26 | // s10 -+ 1 << 27; // s11 -+ -+const int kNumCalleeSaved = 12; -+ -+const RegList kCalleeSavedFPU = 1 << 8 | // fs0 -+ 1 << 9 | // fs1 -+ 1 << 18 | // fs2 -+ 1 << 19 | // fs3 -+ 1 << 20 | // fs4 -+ 1 << 21 | // fs5 -+ 1 << 22 | // fs6 -+ 1 << 23 | // fs7 -+ 1 << 24 | // fs8 -+ 1 << 25 | // fs9 -+ 1 << 26 | // fs10 -+ 1 << 27; // fs11 -+ -+const int kNumCalleeSavedFPU = 12; -+ -+const RegList kCallerSavedFPU = 1 << 0 | // ft0 -+ 1 << 1 | // ft1 -+ 1 << 2 | // ft2 -+ 1 << 3 | // ft3 -+ 1 << 4 | // ft4 -+ 1 << 5 | // ft5 -+ 1 << 6 | // ft6 -+ 1 << 7 | // ft7 -+ 1 << 10 | // fa0 -+ 1 << 11 | // fa1 -+ 1 << 12 | // fa2 -+ 1 << 13 | // fa3 -+ 1 << 14 | // fa4 -+ 1 << 15 | // fa5 -+ 1 << 16 | // fa6 -+ 1 << 17 | // fa7 -+ 1 << 28 | // ft8 -+ 1 << 29 | // ft9 -+ 1 << 30 | // ft10 -+ 1 << 31; // ft11 -+ -+// Number of registers for which space is reserved in safepoints. Must be a -+// multiple of 8. -+const int kNumSafepointRegisters = 32; -+ -+// Define the list of registers actually saved at safepoints. -+// Note that the number of saved registers may be smaller than the reserved -+// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters. -+const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved; -+const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved; -+ -+const int kUndefIndex = -1; -+// Map with indexes on stack that corresponds to codes of saved registers. -+const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg -+ kUndefIndex, // ra -+ kUndefIndex, // sp -+ kUndefIndex, // gp -+ kUndefIndex, // tp -+ 0, // t0 -+ 1, // t1 -+ 2, // t2 -+ 3, // s0/fp -+ 4, // s1 -+ 5, // a0 -+ 6, // a1 -+ 7, // a2 -+ 8, // a3 -+ 9, // a4 -+ 10, // a5 -+ 11, // a6 -+ 12, // a7 -+ 13, // s2 -+ 14, // s3 -+ 15, // s4 -+ 16, // s5 -+ 17, // s6 -+ 18, // s7 -+ 19, // s8 -+ 10, // s9 -+ 21, // s10 -+ 22, // s11 -+ kUndefIndex, // t3 -+ 23, // t4 -+ kUndefIndex, // t5 -+ kUndefIndex}; // t6 -+// CPU Registers. -+// -+// 1) We would prefer to use an enum, but enum values are assignment- -+// compatible with int, which has caused code-generation bugs. -+// -+// 2) We would prefer to use a class instead of a struct but we don't like -+// the register initialization to depend on the particular initialization -+// order (which appears to be different on OS X, Linux, and Windows for the -+// installed versions of C++ we tried). Using a struct permits C-style -+// "initialization". Also, the Register objects cannot be const as this -+// forces initialization stubs in MSVC, making us dependent on initialization -+// order. -+// -+// 3) By not using an enum, we are possibly preventing the compiler from -+// doing certain constant folds, which may significantly reduce the -+// code generated for some assembly instructions (because they boil down -+// to a few constants). If this is a problem, we could change the code -+// such that we use an enum in optimized mode, and the struct in debug -+// mode. This way we get the compile-time error checking in debug mode -+// and best performance in optimized code. -+ -+// ----------------------------------------------------------------------------- -+// Implementation of Register and FPURegister. -+ -+enum RegisterCode { -+#define REGISTER_CODE(R) kRegCode_##R, -+ GENERAL_REGISTERS(REGISTER_CODE) -+#undef REGISTER_CODE -+ kRegAfterLast -+}; -+ -+class Register : public RegisterBase { -+ public: -+#if defined(V8_TARGET_LITTLE_ENDIAN) -+ static constexpr int kMantissaOffset = 0; -+ static constexpr int kExponentOffset = 4; -+#elif defined(V8_TARGET_BIG_ENDIAN) -+ static constexpr int kMantissaOffset = 4; -+ static constexpr int kExponentOffset = 0; -+#else -+#error Unknown endianness -+#endif -+ -+ private: -+ friend class RegisterBase; -+ explicit constexpr Register(int code) : RegisterBase(code) {} -+}; -+ -+// s7: context register -+// s3: scratch register -+// s4: scratch register 2 -+#define DECLARE_REGISTER(R) \ -+ constexpr Register R = Register::from_code(kRegCode_##R); -+GENERAL_REGISTERS(DECLARE_REGISTER) -+#undef DECLARE_REGISTER -+ -+constexpr Register no_reg = Register::no_reg(); -+ -+int ToNumber(Register reg); -+ -+Register ToRegister(int num); -+ -+constexpr bool kPadArguments = false; -+constexpr bool kSimpleFPAliasing = true; -+constexpr bool kSimdMaskRegisters = false; -+ -+enum DoubleRegisterCode { -+#define REGISTER_CODE(R) kDoubleCode_##R, -+ DOUBLE_REGISTERS(REGISTER_CODE) -+#undef REGISTER_CODE -+ kDoubleAfterLast -+}; -+ -+// Coprocessor register. -+class FPURegister : public RegisterBase { -+ public: -+ // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers -+ // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to -+ // number of Double regs (64-bit regs, or FPU-reg-pairs). -+ -+ FPURegister low() const { -+ // TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1. -+ // Find low reg of a Double-reg pair, which is the reg itself. -+ return FPURegister::from_code(code()); -+ } -+ FPURegister high() const { -+ // TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1. -+ // Find high reg of a Doubel-reg pair, which is reg + 1. -+ return FPURegister::from_code(code() + 1); -+ } -+ -+ private: -+ friend class RegisterBase; -+ explicit constexpr FPURegister(int code) : RegisterBase(code) {} -+}; -+ -+enum MSARegisterCode { -+#define REGISTER_CODE(R) kMsaCode_##R, -+ SIMD128_REGISTERS(REGISTER_CODE) -+#undef REGISTER_CODE -+ kMsaAfterLast -+}; -+ -+// MIPS SIMD (MSA) register -+// FIXME (RISCV) -+class MSARegister : public RegisterBase { -+ friend class RegisterBase; -+ explicit constexpr MSARegister(int code) : RegisterBase(code) {} -+}; -+ -+// A few double registers are reserved: one as a scratch register and one to -+// hold 0.0. -+// fs9: 0.0 -+// fs11: scratch register. -+ -+// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers. -+using FloatRegister = FPURegister; -+ -+using DoubleRegister = FPURegister; -+ -+#define DECLARE_DOUBLE_REGISTER(R) \ -+ constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R); -+DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER) -+#undef DECLARE_DOUBLE_REGISTER -+ -+constexpr DoubleRegister no_dreg = DoubleRegister::no_reg(); -+ -+// SIMD registers. -+using Simd128Register = MSARegister; -+ -+#define DECLARE_SIMD128_REGISTER(R) \ -+ constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R); -+SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER) -+#undef DECLARE_SIMD128_REGISTER -+ -+const Simd128Register no_msareg = Simd128Register::no_reg(); -+ -+// Register aliases. -+// cp is assumed to be a callee saved register. -+constexpr Register kRootRegister = s6; -+constexpr Register cp = s7; -+constexpr Register kScratchReg = s3; -+constexpr Register kScratchReg2 = s4; -+ -+constexpr DoubleRegister kScratchDoubleReg = fs11; -+ -+constexpr DoubleRegister kDoubleRegZero = fs9; -+ -+// Define {RegisterName} methods for the register types. -+DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) -+DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS) -+DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS) -+ -+// Give alias names to registers for calling conventions. -+constexpr Register kReturnRegister0 = a0; -+constexpr Register kReturnRegister1 = a1; -+constexpr Register kReturnRegister2 = a2; -+constexpr Register kJSFunctionRegister = a1; -+constexpr Register kContextRegister = s7; -+constexpr Register kAllocateSizeRegister = a1; -+constexpr Register kSpeculationPoisonRegister = a7; -+constexpr Register kInterpreterAccumulatorRegister = a0; -+constexpr Register kInterpreterBytecodeOffsetRegister = t0; -+constexpr Register kInterpreterBytecodeArrayRegister = t1; -+constexpr Register kInterpreterDispatchTableRegister = t2; -+ -+constexpr Register kJavaScriptCallArgCountRegister = a0; -+constexpr Register kJavaScriptCallCodeStartRegister = a2; -+constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; -+constexpr Register kJavaScriptCallNewTargetRegister = a3; -+constexpr Register kJavaScriptCallExtraArg1Register = a2; -+ -+constexpr Register kOffHeapTrampolineRegister = t3; -+constexpr Register kRuntimeCallFunctionRegister = a1; -+constexpr Register kRuntimeCallArgCountRegister = a0; -+constexpr Register kRuntimeCallArgvRegister = a2; -+constexpr Register kWasmInstanceRegister = a0; -+constexpr Register kWasmCompileLazyFuncIndexRegister = t0; -+ -+constexpr DoubleRegister kFPReturnRegister0 = fa0; -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_CODEGEN_RISCV_REGISTER_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/common/globals.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/common/globals.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/common/globals.h -@@ -58,6 +58,12 @@ constexpr int GB = MB * 1024; - #if (V8_TARGET_ARCH_S390 && !V8_HOST_ARCH_S390) - #define USE_SIMULATOR 1 - #endif -+#if (V8_TARGET_ARCH_RISCV64 && !V8_HOST_ARCH_RISCV64) -+#define USE_SIMULATOR 1 -+#endif -+#if (V8_TARGET_ARCH_RISCV && !V8_HOST_ARCH_RISCV && !V8_HOST_ARCH_RISCV64) -+#define USE_SIMULATOR 1 -+#endif - #endif - - // Determine whether the architecture uses an embedded constant pool -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/instruction-codes.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/compiler/backend/instruction-codes.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/instruction-codes.h -@@ -23,6 +23,10 @@ - #include "src/compiler/backend/ppc/instruction-codes-ppc.h" - #elif V8_TARGET_ARCH_S390 - #include "src/compiler/backend/s390/instruction-codes-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/compiler/backend/riscv64/instruction-codes-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/compiler/backend/riscv/instruction-codes-riscv.h" - #else - #define TARGET_ARCH_OPCODE_LIST(V) - #define TARGET_ADDRESSING_MODE_LIST(V) -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/instruction-selector.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/compiler/backend/instruction-selector.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/instruction-selector.cc -@@ -2624,7 +2624,8 @@ void InstructionSelector::VisitWord32Ato - #endif // !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS - - #if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS64 && \ -- !V8_TARGET_ARCH_S390 && !V8_TARGET_ARCH_PPC64 -+ !V8_TARGET_ARCH_S390 && !V8_TARGET_ARCH_PPC64 && \ -+ !V8_TARGET_ARCH_RISCV64 && !V8_TARGET_ARCH_RISCV - void InstructionSelector::VisitWord64AtomicLoad(Node* node) { UNIMPLEMENTED(); } - - void InstructionSelector::VisitWord64AtomicStore(Node* node) { -@@ -2649,7 +2650,8 @@ void InstructionSelector::VisitWord64Ato - UNIMPLEMENTED(); - } - #endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_PPC64 -- // !V8_TARGET_ARCH_MIPS64 && !V8_TARGET_ARCH_S390 -+ // !V8_TARGET_ARCH_MIPS64 && !V8_TARGET_ARCH_S390 && -+ // !V8_TARGET_ARCH_RISCV64 && !V8_TARGET_ARCH_RISCV - - #if !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM - // This is only needed on 32-bit to split the 64-bit value into two operands. -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/code-generator-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/code-generator-riscv64.cc -@@ -0,0 +1,2759 @@ -+// 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. -+ -+#include "src/codegen/assembler-inl.h" -+#include "src/codegen/callable.h" -+#include "src/codegen/macro-assembler.h" -+#include "src/codegen/optimized-compilation-info.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/compiler/backend/code-generator-impl.h" -+#include "src/compiler/backend/code-generator.h" -+#include "src/compiler/backend/gap-resolver.h" -+#include "src/compiler/node-matchers.h" -+#include "src/compiler/osr.h" -+#include "src/heap/memory-chunk.h" -+#include "src/wasm/wasm-code-manager.h" -+ -+namespace v8 { -+namespace internal { -+namespace compiler { -+ -+#define __ tasm()-> -+ -+// TODO(plind): consider renaming these macros. -+#define TRACE_MSG(msg) \ -+ PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \ -+ __LINE__) -+ -+#define TRACE_UNIMPL() \ -+ PrintF("UNIMPLEMENTED code_generator_riscv64: %s at line %d\n", \ -+ __FUNCTION__, __LINE__) -+ -+// Adds RISC-V-specific methods to convert InstructionOperands. -+class RiscvOperandConverter final : public InstructionOperandConverter { -+ public: -+ RiscvOperandConverter(CodeGenerator* gen, Instruction* instr) -+ : InstructionOperandConverter(gen, instr) {} -+ -+ FloatRegister OutputSingleRegister(size_t index = 0) { -+ return ToSingleRegister(instr_->OutputAt(index)); -+ } -+ -+ FloatRegister InputSingleRegister(size_t index) { -+ return ToSingleRegister(instr_->InputAt(index)); -+ } -+ -+ FloatRegister ToSingleRegister(InstructionOperand* op) { -+ // Single (Float) and Double register namespace is same on RISC-V, -+ // both are typedefs of FPURegister. -+ return ToDoubleRegister(op); -+ } -+ -+ Register InputOrZeroRegister(size_t index) { -+ if (instr_->InputAt(index)->IsImmediate()) { -+ DCHECK_EQ(0, InputInt32(index)); -+ return zero_reg; -+ } -+ return InputRegister(index); -+ } -+ -+ DoubleRegister InputOrZeroDoubleRegister(size_t index) { -+ if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero; -+ -+ return InputDoubleRegister(index); -+ } -+ -+ DoubleRegister InputOrZeroSingleRegister(size_t index) { -+ if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero; -+ -+ return InputSingleRegister(index); -+ } -+ -+ Operand InputImmediate(size_t index) { -+ Constant constant = ToConstant(instr_->InputAt(index)); -+ switch (constant.type()) { -+ case Constant::kInt32: -+ return Operand(constant.ToInt32()); -+ case Constant::kInt64: -+ return Operand(constant.ToInt64()); -+ case Constant::kFloat32: -+ return Operand::EmbeddedNumber(constant.ToFloat32()); -+ case Constant::kFloat64: -+ return Operand::EmbeddedNumber(constant.ToFloat64().value()); -+ case Constant::kExternalReference: -+ case Constant::kCompressedHeapObject: -+ case Constant::kHeapObject: -+ // TODO(plind): Maybe we should handle ExtRef & HeapObj here? -+ // maybe not done on arm due to const pool ?? -+ break; -+ case Constant::kDelayedStringConstant: -+ return Operand::EmbeddedStringConstant( -+ constant.ToDelayedStringConstant()); -+ case Constant::kRpoNumber: -+ UNREACHABLE(); // TODO(titzer): RPO immediates -+ break; -+ } -+ UNREACHABLE(); -+ } -+ -+ Operand InputOperand(size_t index) { -+ InstructionOperand* op = instr_->InputAt(index); -+ if (op->IsRegister()) { -+ return Operand(ToRegister(op)); -+ } -+ return InputImmediate(index); -+ } -+ -+ MemOperand MemoryOperand(size_t* first_index) { -+ const size_t index = *first_index; -+ switch (AddressingModeField::decode(instr_->opcode())) { -+ case kMode_None: -+ break; -+ case kMode_MRI: -+ *first_index += 2; -+ return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); -+ case kMode_MRR: -+ // TODO(plind): r6 address mode, to be implemented ... -+ UNREACHABLE(); -+ } -+ UNREACHABLE(); -+ } -+ -+ MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); } -+ -+ MemOperand ToMemOperand(InstructionOperand* op) const { -+ DCHECK_NOT_NULL(op); -+ DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); -+ return SlotToMemOperand(AllocatedOperand::cast(op)->index()); -+ } -+ -+ MemOperand SlotToMemOperand(int slot) const { -+ FrameOffset offset = frame_access_state()->GetFrameOffset(slot); -+ return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); -+ } -+}; -+ -+static inline bool HasRegisterInput(Instruction* instr, size_t index) { -+ return instr->InputAt(index)->IsRegister(); -+} -+ -+namespace { -+ -+class OutOfLineRecordWrite final : public OutOfLineCode { -+ public: -+ OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index, -+ Register value, Register scratch0, Register scratch1, -+ RecordWriteMode mode, StubCallMode stub_mode) -+ : OutOfLineCode(gen), -+ object_(object), -+ index_(index), -+ value_(value), -+ scratch0_(scratch0), -+ scratch1_(scratch1), -+ mode_(mode), -+ stub_mode_(stub_mode), -+ must_save_lr_(!gen->frame_access_state()->has_frame()), -+ zone_(gen->zone()) {} -+ -+ void Generate() final { -+ if (mode_ > RecordWriteMode::kValueIsPointer) { -+ __ JumpIfSmi(value_, exit()); -+ } -+ __ CheckPageFlag(value_, scratch0_, -+ MemoryChunk::kPointersToHereAreInterestingMask, eq, -+ exit()); -+ __ Add64(scratch1_, object_, index_); -+ RememberedSetAction const remembered_set_action = -+ mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET -+ : OMIT_REMEMBERED_SET; -+ SaveFPRegsMode const save_fp_mode = -+ frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; -+ if (must_save_lr_) { -+ // We need to save and restore ra if the frame was elided. -+ __ Push(ra); -+ } -+ if (mode_ == RecordWriteMode::kValueIsEphemeronKey) { -+ __ CallEphemeronKeyBarrier(object_, scratch1_, save_fp_mode); -+ } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) { -+ // A direct call to a wasm runtime stub defined in this module. -+ // Just encode the stub index. This will be patched when the code -+ // is added to the native module and copied into wasm code space. -+ __ CallRecordWriteStub(object_, scratch1_, remembered_set_action, -+ save_fp_mode, wasm::WasmCode::kRecordWrite); -+ } else { -+ __ CallRecordWriteStub(object_, scratch1_, remembered_set_action, -+ save_fp_mode); -+ } -+ if (must_save_lr_) { -+ __ Pop(ra); -+ } -+ } -+ -+ private: -+ Register const object_; -+ Register const index_; -+ Register const value_; -+ Register const scratch0_; -+ Register const scratch1_; -+ RecordWriteMode const mode_; -+ StubCallMode const stub_mode_; -+ bool must_save_lr_; -+ Zone* zone_; -+}; -+ -+Condition FlagsConditionToConditionCmp(FlagsCondition condition) { -+ switch (condition) { -+ case kEqual: -+ return eq; -+ case kNotEqual: -+ return ne; -+ case kSignedLessThan: -+ return lt; -+ case kSignedGreaterThanOrEqual: -+ return ge; -+ case kSignedLessThanOrEqual: -+ return le; -+ case kSignedGreaterThan: -+ return gt; -+ case kUnsignedLessThan: -+ return Uless; -+ case kUnsignedGreaterThanOrEqual: -+ return Ugreater_equal; -+ case kUnsignedLessThanOrEqual: -+ return Uless_equal; -+ case kUnsignedGreaterThan: -+ return Ugreater; -+ case kUnorderedEqual: -+ case kUnorderedNotEqual: -+ break; -+ default: -+ break; -+ } -+ UNREACHABLE(); -+} -+ -+Condition FlagsConditionToConditionTst(FlagsCondition condition) { -+ switch (condition) { -+ case kNotEqual: -+ return ne; -+ case kEqual: -+ return eq; -+ default: -+ break; -+ } -+ UNREACHABLE(); -+} -+ -+Condition FlagsConditionToConditionOvf(FlagsCondition condition) { -+ switch (condition) { -+ case kOverflow: -+ return ne; -+ case kNotOverflow: -+ return eq; -+ default: -+ break; -+ } -+ UNREACHABLE(); -+} -+ -+FPUCondition FlagsConditionToConditionCmpFPU(bool* predicate, -+ FlagsCondition condition) { -+ switch (condition) { -+ case kEqual: -+ *predicate = true; -+ return EQ; -+ case kNotEqual: -+ *predicate = false; -+ return EQ; -+ case kUnsignedLessThan: -+ *predicate = true; -+ return LT; -+ case kUnsignedGreaterThanOrEqual: -+ *predicate = false; -+ return LT; -+ case kUnsignedLessThanOrEqual: -+ *predicate = true; -+ return LE; -+ case kUnsignedGreaterThan: -+ *predicate = false; -+ return LE; -+ case kUnorderedEqual: -+ case kUnorderedNotEqual: -+ *predicate = true; -+ break; -+ default: -+ *predicate = true; -+ break; -+ } -+ UNREACHABLE(); -+} -+ -+void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, -+ InstructionCode opcode, Instruction* instr, -+ RiscvOperandConverter const& i) { -+ const MemoryAccessMode access_mode = -+ static_cast(MiscField::decode(opcode)); -+ if (access_mode == kMemoryAccessPoisoned) { -+ Register value = i.OutputRegister(); -+ codegen->tasm()->And(value, value, kSpeculationPoisonRegister); -+ } -+} -+ -+} // namespace -+ -+#define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr) \ -+ do { \ -+ __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr) \ -+ do { \ -+ __ sync(); \ -+ __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_BINOP(load_linked, store_conditional, bin_instr) \ -+ do { \ -+ Label binop; \ -+ __ Add64(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ -+ __ sync(); \ -+ __ bind(&binop); \ -+ __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0)); \ -+ __ bin_instr(i.TempRegister(1), i.OutputRegister(0), \ -+ Operand(i.InputRegister(2))); \ -+ __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&binop, ne, i.TempRegister(1), Operand(zero_reg)); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_BINOP_EXT(load_linked, store_conditional, sign_extend, \ -+ size, bin_instr, representation) \ -+ do { \ -+ Label binop; \ -+ __ Add64(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ -+ if (representation == 32) { \ -+ __ And(i.TempRegister(3), i.TempRegister(0), 0x3); \ -+ } else { \ -+ DCHECK_EQ(representation, 64); \ -+ __ And(i.TempRegister(3), i.TempRegister(0), 0x7); \ -+ } \ -+ __ Sub64(i.TempRegister(0), i.TempRegister(0), \ -+ Operand(i.TempRegister(3))); \ -+ __ Sll32(i.TempRegister(3), i.TempRegister(3), 3); \ -+ __ sync(); \ -+ __ bind(&binop); \ -+ __ load_linked(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \ -+ __ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3), \ -+ size, sign_extend); \ -+ __ bin_instr(i.TempRegister(2), i.OutputRegister(0), \ -+ Operand(i.InputRegister(2))); \ -+ __ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3), \ -+ size); \ -+ __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&binop, ne, i.TempRegister(1), Operand(zero_reg)); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_linked, store_conditional) \ -+ do { \ -+ Label exchange; \ -+ __ sync(); \ -+ __ bind(&exchange); \ -+ __ Add64(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ -+ __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0)); \ -+ __ Move(i.TempRegister(1), i.InputRegister(2)); \ -+ __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&exchange, ne, i.TempRegister(1), Operand(zero_reg)); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT( \ -+ load_linked, store_conditional, sign_extend, size, representation) \ -+ do { \ -+ Label exchange; \ -+ __ Add64(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ -+ if (representation == 32) { \ -+ __ And(i.TempRegister(1), i.TempRegister(0), 0x3); \ -+ } else { \ -+ DCHECK_EQ(representation, 64); \ -+ __ And(i.TempRegister(1), i.TempRegister(0), 0x7); \ -+ } \ -+ __ Sub64(i.TempRegister(0), i.TempRegister(0), \ -+ Operand(i.TempRegister(1))); \ -+ __ Sll32(i.TempRegister(1), i.TempRegister(1), 3); \ -+ __ sync(); \ -+ __ bind(&exchange); \ -+ __ load_linked(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \ -+ __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1), \ -+ size, sign_extend); \ -+ __ InsertBits(i.TempRegister(2), i.InputRegister(2), i.TempRegister(1), \ -+ size); \ -+ __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&exchange, ne, i.TempRegister(2), Operand(zero_reg)); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_linked, \ -+ store_conditional) \ -+ do { \ -+ Label compareExchange; \ -+ Label exit; \ -+ __ Add64(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ -+ __ sync(); \ -+ __ bind(&compareExchange); \ -+ __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&exit, ne, i.InputRegister(2), \ -+ Operand(i.OutputRegister(0))); \ -+ __ Move(i.TempRegister(2), i.InputRegister(3)); \ -+ __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&compareExchange, ne, i.TempRegister(2), \ -+ Operand(zero_reg)); \ -+ __ bind(&exit); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT( \ -+ load_linked, store_conditional, sign_extend, size, representation) \ -+ do { \ -+ Label compareExchange; \ -+ Label exit; \ -+ __ Add64(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \ -+ if (representation == 32) { \ -+ __ And(i.TempRegister(1), i.TempRegister(0), 0x3); \ -+ } else { \ -+ DCHECK_EQ(representation, 64); \ -+ __ And(i.TempRegister(1), i.TempRegister(0), 0x7); \ -+ } \ -+ __ Sub64(i.TempRegister(0), i.TempRegister(0), \ -+ Operand(i.TempRegister(1))); \ -+ __ Sll32(i.TempRegister(1), i.TempRegister(1), 3); \ -+ __ sync(); \ -+ __ bind(&compareExchange); \ -+ __ load_linked(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \ -+ __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1), \ -+ size, sign_extend); \ -+ __ ExtractBits(i.InputRegister(2), i.InputRegister(2), i.TempRegister(1), \ -+ size, sign_extend); \ -+ __ BranchShort(&exit, ne, i.InputRegister(2), \ -+ Operand(i.OutputRegister(0))); \ -+ __ InsertBits(i.TempRegister(2), i.InputRegister(3), i.TempRegister(1), \ -+ size); \ -+ __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \ -+ __ BranchShort(&compareExchange, ne, i.TempRegister(2), \ -+ Operand(zero_reg)); \ -+ __ bind(&exit); \ -+ __ sync(); \ -+ } while (0) -+ -+#define ASSEMBLE_IEEE754_BINOP(name) \ -+ do { \ -+ FrameScope scope(tasm(), StackFrame::MANUAL); \ -+ __ PrepareCallCFunction(0, 2, kScratchReg); \ -+ __ MovToFloatParameters(i.InputDoubleRegister(0), \ -+ i.InputDoubleRegister(1)); \ -+ __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \ -+ /* Move the result in the double result register. */ \ -+ __ MovFromFloatResult(i.OutputDoubleRegister()); \ -+ } while (0) -+ -+#define ASSEMBLE_IEEE754_UNOP(name) \ -+ do { \ -+ FrameScope scope(tasm(), StackFrame::MANUAL); \ -+ __ PrepareCallCFunction(0, 1, kScratchReg); \ -+ __ MovToFloatParameter(i.InputDoubleRegister(0)); \ -+ __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \ -+ /* Move the result in the double result register. */ \ -+ __ MovFromFloatResult(i.OutputDoubleRegister()); \ -+ } while (0) -+ -+#define ASSEMBLE_F64X2_ARITHMETIC_BINOP(op) \ -+ do { \ -+ __ op(i.OutputSimd128Register(), i.InputSimd128Register(0), \ -+ i.InputSimd128Register(1)); \ -+ } while (0) -+ -+void CodeGenerator::AssembleDeconstructFrame() { -+ __ Move(sp, fp); -+ __ Pop(ra, fp); -+} -+ -+void CodeGenerator::AssemblePrepareTailCall() { -+ if (frame_access_state()->has_frame()) { -+ __ Ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); -+ __ Ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); -+ } -+ frame_access_state()->SetFrameAccessToSP(); -+} -+ -+void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, -+ Register scratch1, -+ Register scratch2, -+ Register scratch3) { -+ DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); -+ Label done; -+ -+ // Check if current frame is an arguments adaptor frame. -+ __ Ld(scratch3, MemOperand(fp, StandardFrameConstants::kContextOffset)); -+ __ Branch(&done, ne, scratch3, -+ Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); -+ -+ // Load arguments count from current arguments adaptor frame (note, it -+ // does not include receiver). -+ Register caller_args_count_reg = scratch1; -+ __ Ld(caller_args_count_reg, -+ MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); -+ __ SmiUntag(caller_args_count_reg); -+ -+ __ PrepareForTailCall(args_reg, caller_args_count_reg, scratch2, scratch3); -+ __ bind(&done); -+} -+ -+namespace { -+ -+void AdjustStackPointerForTailCall(TurboAssembler* tasm, -+ FrameAccessState* state, -+ int new_slot_above_sp, -+ bool allow_shrinkage = true) { -+ int current_sp_offset = state->GetSPToFPSlotCount() + -+ StandardFrameConstants::kFixedSlotCountAboveFp; -+ int stack_slot_delta = new_slot_above_sp - current_sp_offset; -+ if (stack_slot_delta > 0) { -+ tasm->Sub64(sp, sp, stack_slot_delta * kSystemPointerSize); -+ state->IncreaseSPDelta(stack_slot_delta); -+ } else if (allow_shrinkage && stack_slot_delta < 0) { -+ tasm->Add64(sp, sp, -stack_slot_delta * kSystemPointerSize); -+ state->IncreaseSPDelta(stack_slot_delta); -+ } -+} -+ -+} // namespace -+ -+void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, -+ int first_unused_stack_slot) { -+ AdjustStackPointerForTailCall(tasm(), frame_access_state(), -+ first_unused_stack_slot, false); -+} -+ -+void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr, -+ int first_unused_stack_slot) { -+ AdjustStackPointerForTailCall(tasm(), frame_access_state(), -+ first_unused_stack_slot); -+} -+ -+// Check that {kJavaScriptCallCodeStartRegister} is correct. -+void CodeGenerator::AssembleCodeStartRegisterCheck() { -+ __ ComputeCodeStartAddress(kScratchReg); -+ __ Assert(eq, AbortReason::kWrongFunctionCodeStart, -+ kJavaScriptCallCodeStartRegister, Operand(kScratchReg)); -+} -+ -+// Check if the code object is marked for deoptimization. If it is, then it -+// jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need -+// to: -+// 1. read from memory the word that contains that bit, which can be found in -+// the flags in the referenced {CodeDataContainer} object; -+// 2. test kMarkedForDeoptimizationBit in those flags; and -+// 3. if it is not zero then it jumps to the builtin. -+void CodeGenerator::BailoutIfDeoptimized() { -+ int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize; -+ __ Ld(kScratchReg, MemOperand(kJavaScriptCallCodeStartRegister, offset)); -+ __ Lw(kScratchReg, -+ FieldMemOperand(kScratchReg, -+ CodeDataContainer::kKindSpecificFlagsOffset)); -+ __ And(kScratchReg, kScratchReg, -+ Operand(1 << Code::kMarkedForDeoptimizationBit)); -+ __ Jump(BUILTIN_CODE(isolate(), CompileLazyDeoptimizedCode), -+ RelocInfo::CODE_TARGET, ne, kScratchReg, Operand(zero_reg)); -+} -+ -+void CodeGenerator::GenerateSpeculationPoisonFromCodeStartRegister() { -+ // Calculate a mask which has all bits set in the normal case, but has all -+ // bits cleared if we are speculatively executing the wrong PC. -+ // difference = (current - expected) | (expected - current) -+ // poison = ~(difference >> (kBitsPerSystemPointer - 1)) -+ __ ComputeCodeStartAddress(kScratchReg); -+ __ Move(kSpeculationPoisonRegister, kScratchReg); -+ __ Sub32(kSpeculationPoisonRegister, kSpeculationPoisonRegister, -+ kJavaScriptCallCodeStartRegister); -+ __ Sub32(kJavaScriptCallCodeStartRegister, kJavaScriptCallCodeStartRegister, -+ kScratchReg); -+ __ or_(kSpeculationPoisonRegister, kSpeculationPoisonRegister, -+ kJavaScriptCallCodeStartRegister); -+ __ Sra64(kSpeculationPoisonRegister, kSpeculationPoisonRegister, -+ kBitsPerSystemPointer - 1); -+ __ Nor(kSpeculationPoisonRegister, kSpeculationPoisonRegister, -+ kSpeculationPoisonRegister); -+} -+ -+void CodeGenerator::AssembleRegisterArgumentPoisoning() { -+ __ And(kJSFunctionRegister, kJSFunctionRegister, kSpeculationPoisonRegister); -+ __ And(kContextRegister, kContextRegister, kSpeculationPoisonRegister); -+ __ And(sp, sp, kSpeculationPoisonRegister); -+} -+ -+// Assembles an instruction after register allocation, producing machine code. -+CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( -+ Instruction* instr) { -+ RiscvOperandConverter i(this, instr); -+ InstructionCode opcode = instr->opcode(); -+ ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); -+ switch (arch_opcode) { -+ case kArchCallCodeObject: { -+ if (instr->InputAt(0)->IsImmediate()) { -+ __ Call(i.InputCode(0), RelocInfo::CODE_TARGET); -+ } else { -+ Register reg = i.InputRegister(0); -+ DCHECK_IMPLIES( -+ HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister), -+ reg == kJavaScriptCallCodeStartRegister); -+ __ Add64(reg, reg, Code::kHeaderSize - kHeapObjectTag); -+ __ Call(reg); -+ } -+ RecordCallPosition(instr); -+ frame_access_state()->ClearSPDelta(); -+ break; -+ } -+ case kArchCallBuiltinPointer: { -+ DCHECK(!instr->InputAt(0)->IsImmediate()); -+ Register builtin_index = i.InputRegister(0); -+ __ CallBuiltinByIndex(builtin_index); -+ RecordCallPosition(instr); -+ frame_access_state()->ClearSPDelta(); -+ break; -+ } -+ case kArchCallWasmFunction: { -+ // FIXME (RISCV): isnt this test deadcode? -+ if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { -+ AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, -+ i.TempRegister(0), i.TempRegister(1), -+ i.TempRegister(2)); -+ } -+ if (instr->InputAt(0)->IsImmediate()) { -+ Constant constant = i.ToConstant(instr->InputAt(0)); -+ Address wasm_code = static_cast

(constant.ToInt64()); -+ __ Call(wasm_code, constant.rmode()); -+ } else { -+ __ Add64(kScratchReg, i.InputRegister(0), 0); -+ __ Call(kScratchReg); -+ } -+ RecordCallPosition(instr); -+ frame_access_state()->ClearSPDelta(); -+ break; -+ } -+ case kArchTailCallCodeObjectFromJSFunction: -+ case kArchTailCallCodeObject: { -+ if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { -+ AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, -+ i.TempRegister(0), i.TempRegister(1), -+ i.TempRegister(2)); -+ } -+ if (instr->InputAt(0)->IsImmediate()) { -+ __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET); -+ } else { -+ Register reg = i.InputRegister(0); -+ DCHECK_IMPLIES( -+ HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister), -+ reg == kJavaScriptCallCodeStartRegister); -+ __ Add64(reg, reg, Code::kHeaderSize - kHeapObjectTag); -+ __ Jump(reg); -+ } -+ frame_access_state()->ClearSPDelta(); -+ frame_access_state()->SetFrameAccessToDefault(); -+ break; -+ } -+ case kArchTailCallWasm: { -+ if (instr->InputAt(0)->IsImmediate()) { -+ Constant constant = i.ToConstant(instr->InputAt(0)); -+ Address wasm_code = static_cast
(constant.ToInt64()); -+ __ Jump(wasm_code, constant.rmode()); -+ } else { -+ __ Add64(kScratchReg, i.InputRegister(0), 0); -+ __ Jump(kScratchReg); -+ } -+ frame_access_state()->ClearSPDelta(); -+ frame_access_state()->SetFrameAccessToDefault(); -+ break; -+ } -+ case kArchTailCallAddress: { -+ CHECK(!instr->InputAt(0)->IsImmediate()); -+ Register reg = i.InputRegister(0); -+ DCHECK_IMPLIES( -+ HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister), -+ reg == kJavaScriptCallCodeStartRegister); -+ __ Jump(reg); -+ frame_access_state()->ClearSPDelta(); -+ frame_access_state()->SetFrameAccessToDefault(); -+ break; -+ } -+ case kArchCallJSFunction: { -+ Register func = i.InputRegister(0); -+ if (FLAG_debug_code) { -+ // Check the function's context matches the context argument. -+ __ Ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); -+ __ Assert(eq, AbortReason::kWrongFunctionContext, cp, -+ Operand(kScratchReg)); -+ } -+ static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch"); -+ __ Ld(a2, FieldMemOperand(func, JSFunction::kCodeOffset)); -+ __ Add64(a2, a2, Operand(Code::kHeaderSize - kHeapObjectTag)); -+ __ Call(a2); -+ RecordCallPosition(instr); -+ frame_access_state()->ClearSPDelta(); -+ break; -+ } -+ case kArchPrepareCallCFunction: { -+ int const num_parameters = MiscField::decode(instr->opcode()); -+ __ PrepareCallCFunction(num_parameters, kScratchReg); -+ // Frame alignment requires using FP-relative frame addressing. -+ frame_access_state()->SetFrameAccessToFP(); -+ break; -+ } -+ case kArchSaveCallerRegisters: { -+ fp_mode_ = -+ static_cast(MiscField::decode(instr->opcode())); -+ DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs); -+ // kReturnRegister0 should have been saved before entering the stub. -+ int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0); -+ DCHECK(IsAligned(bytes, kSystemPointerSize)); -+ DCHECK_EQ(0, frame_access_state()->sp_delta()); -+ frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize); -+ DCHECK(!caller_registers_saved_); -+ caller_registers_saved_ = true; -+ break; -+ } -+ case kArchRestoreCallerRegisters: { -+ DCHECK(fp_mode_ == -+ static_cast(MiscField::decode(instr->opcode()))); -+ DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs); -+ // Don't overwrite the returned value. -+ int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0); -+ frame_access_state()->IncreaseSPDelta(-(bytes / kSystemPointerSize)); -+ DCHECK_EQ(0, frame_access_state()->sp_delta()); -+ DCHECK(caller_registers_saved_); -+ caller_registers_saved_ = false; -+ break; -+ } -+ case kArchPrepareTailCall: -+ AssemblePrepareTailCall(); -+ break; -+ case kArchCallCFunction: { -+ int const num_parameters = MiscField::decode(instr->opcode()); -+ Label start_call; -+ bool isWasmCapiFunction = -+ linkage()->GetIncomingDescriptor()->IsWasmCapiFunction(); -+ // from start_call to return address. -+ // FIXME (RISC_V): is the same number of instructions generated from -+ // &start_call to after __CallCFunction()? This code seems quite brittle. -+ // Better to use label and PC-relative addressing to generate the return -+ // address -+ int offset = __ root_array_available() ? 64 : 72; -+#if V8_HOST_ARCH_RISCV64 -+ if (__ emit_debug_code()) { -+ offset += 16; -+ } -+#endif -+ if (isWasmCapiFunction) { -+ // Put the return address in a stack slot. -+ __ bind(&start_call); -+ __ auipc(kScratchReg, 0); -+ __ Add64(kScratchReg, kScratchReg, offset); -+ __ Sd(kScratchReg, -+ MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset)); -+ } -+ if (instr->InputAt(0)->IsImmediate()) { -+ ExternalReference ref = i.InputExternalReference(0); -+ __ CallCFunction(ref, num_parameters); -+ } else { -+ Register func = i.InputRegister(0); -+ __ CallCFunction(func, num_parameters); -+ } -+ if (isWasmCapiFunction) { -+ CHECK_EQ(offset, __ SizeOfCodeGeneratedSince(&start_call)); -+ RecordSafepoint(instr->reference_map(), Safepoint::kNoLazyDeopt); -+ } -+ -+ frame_access_state()->SetFrameAccessToDefault(); -+ // Ideally, we should decrement SP delta to match the change of stack -+ // pointer in CallCFunction. However, for certain architectures (e.g. -+ // ARM), there may be more strict alignment requirement, causing old SP -+ // to be saved on the stack. In those cases, we can not calculate the SP -+ // delta statically. -+ frame_access_state()->ClearSPDelta(); -+ if (caller_registers_saved_) { -+ // Need to re-sync SP delta introduced in kArchSaveCallerRegisters. -+ // Here, we assume the sequence to be: -+ // kArchSaveCallerRegisters; -+ // kArchCallCFunction; -+ // kArchRestoreCallerRegisters; -+ int bytes = -+ __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0); -+ frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize); -+ } -+ break; -+ } -+ case kArchJmp: -+ AssembleArchJump(i.InputRpo(0)); -+ break; -+ case kArchBinarySearchSwitch: -+ AssembleArchBinarySearchSwitch(instr); -+ break; -+ case kArchTableSwitch: -+ AssembleArchTableSwitch(instr); -+ break; -+ case kArchAbortCSAAssert: -+ DCHECK(i.InputRegister(0) == a0); -+ { -+ // We don't actually want to generate a pile of code for this, so just -+ // claim there is a stack frame, without generating one. -+ FrameScope scope(tasm(), StackFrame::NONE); -+ __ Call( -+ isolate()->builtins()->builtin_handle(Builtins::kAbortCSAAssert), -+ RelocInfo::CODE_TARGET); -+ } -+ __ stop(); -+ break; -+ case kArchDebugBreak: -+ __ DebugBreak(); -+ break; -+ case kArchComment: -+ __ RecordComment(reinterpret_cast(i.InputInt64(0))); -+ break; -+ case kArchNop: -+ case kArchThrowTerminator: -+ // don't emit code for nops. -+ break; -+ case kArchDeoptimize: { -+ DeoptimizationExit* exit = -+ BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); -+ CodeGenResult result = AssembleDeoptimizerCall(exit); -+ if (result != kSuccess) return result; -+ break; -+ } -+ case kArchRet: -+ AssembleReturn(instr->InputAt(0)); -+ break; -+ case kArchStackPointerGreaterThan: -+ // Pseudo-instruction used for cmp/branch. No opcode emitted here. -+ break; -+ case kArchStackCheckOffset: -+ __ Move(i.OutputRegister(), Smi::FromInt(GetStackCheckOffset())); -+ break; -+ case kArchFramePointer: -+ __ Move(i.OutputRegister(), fp); -+ break; -+ case kArchParentFramePointer: -+ if (frame_access_state()->has_frame()) { -+ __ Ld(i.OutputRegister(), MemOperand(fp, 0)); -+ } else { -+ __ Move(i.OutputRegister(), fp); -+ } -+ break; -+ case kArchTruncateDoubleToI: -+ __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(), -+ i.InputDoubleRegister(0), DetermineStubCallMode()); -+ break; -+ case kArchStoreWithWriteBarrier: { -+ RecordWriteMode mode = -+ static_cast(MiscField::decode(instr->opcode())); -+ Register object = i.InputRegister(0); -+ Register index = i.InputRegister(1); -+ Register value = i.InputRegister(2); -+ Register scratch0 = i.TempRegister(0); -+ Register scratch1 = i.TempRegister(1); -+ auto ool = zone()->New(this, object, index, value, -+ scratch0, scratch1, mode, -+ DetermineStubCallMode()); -+ __ Add64(kScratchReg, object, index); -+ __ Sd(value, MemOperand(kScratchReg)); -+ __ CheckPageFlag(object, scratch0, -+ MemoryChunk::kPointersFromHereAreInterestingMask, ne, -+ ool->entry()); -+ __ bind(ool->exit()); -+ break; -+ } -+ case kArchStackSlot: { -+ FrameOffset offset = -+ frame_access_state()->GetFrameOffset(i.InputInt32(0)); -+ Register base_reg = offset.from_stack_pointer() ? sp : fp; -+ __ Add64(i.OutputRegister(), base_reg, Operand(offset.offset())); -+ int alignment = i.InputInt32(1); -+ DCHECK(alignment == 0 || alignment == 4 || alignment == 8 || -+ alignment == 16); -+ if (FLAG_debug_code && alignment > 0) { -+ // Verify that the output_register is properly aligned -+ __ And(kScratchReg, i.OutputRegister(), -+ Operand(kSystemPointerSize - 1)); -+ __ Assert(eq, AbortReason::kAllocationIsNotDoubleAligned, kScratchReg, -+ Operand(zero_reg)); -+ } -+ if (alignment == 2 * kSystemPointerSize) { -+ Label done; -+ __ Add64(kScratchReg, base_reg, Operand(offset.offset())); -+ __ And(kScratchReg, kScratchReg, Operand(alignment - 1)); -+ __ BranchShort(&done, eq, kScratchReg, Operand(zero_reg)); -+ __ Add64(i.OutputRegister(), i.OutputRegister(), kSystemPointerSize); -+ __ bind(&done); -+ } else if (alignment > 2 * kSystemPointerSize) { -+ Label done; -+ __ Add64(kScratchReg, base_reg, Operand(offset.offset())); -+ __ And(kScratchReg, kScratchReg, Operand(alignment - 1)); -+ __ BranchShort(&done, eq, kScratchReg, Operand(zero_reg)); -+ __ li(kScratchReg2, alignment); -+ __ Sub64(kScratchReg2, kScratchReg2, Operand(kScratchReg)); -+ __ Add64(i.OutputRegister(), i.OutputRegister(), kScratchReg2); -+ __ bind(&done); -+ } -+ -+ break; -+ } -+ case kArchWordPoisonOnSpeculation: -+ __ And(i.OutputRegister(), i.InputRegister(0), -+ kSpeculationPoisonRegister); -+ break; -+ case kIeee754Float64Acos: -+ ASSEMBLE_IEEE754_UNOP(acos); -+ break; -+ case kIeee754Float64Acosh: -+ ASSEMBLE_IEEE754_UNOP(acosh); -+ break; -+ case kIeee754Float64Asin: -+ ASSEMBLE_IEEE754_UNOP(asin); -+ break; -+ case kIeee754Float64Asinh: -+ ASSEMBLE_IEEE754_UNOP(asinh); -+ break; -+ case kIeee754Float64Atan: -+ ASSEMBLE_IEEE754_UNOP(atan); -+ break; -+ case kIeee754Float64Atanh: -+ ASSEMBLE_IEEE754_UNOP(atanh); -+ break; -+ case kIeee754Float64Atan2: -+ ASSEMBLE_IEEE754_BINOP(atan2); -+ break; -+ case kIeee754Float64Cos: -+ ASSEMBLE_IEEE754_UNOP(cos); -+ break; -+ case kIeee754Float64Cosh: -+ ASSEMBLE_IEEE754_UNOP(cosh); -+ break; -+ case kIeee754Float64Cbrt: -+ ASSEMBLE_IEEE754_UNOP(cbrt); -+ break; -+ case kIeee754Float64Exp: -+ ASSEMBLE_IEEE754_UNOP(exp); -+ break; -+ case kIeee754Float64Expm1: -+ ASSEMBLE_IEEE754_UNOP(expm1); -+ break; -+ case kIeee754Float64Log: -+ ASSEMBLE_IEEE754_UNOP(log); -+ break; -+ case kIeee754Float64Log1p: -+ ASSEMBLE_IEEE754_UNOP(log1p); -+ break; -+ case kIeee754Float64Log2: -+ ASSEMBLE_IEEE754_UNOP(log2); -+ break; -+ case kIeee754Float64Log10: -+ ASSEMBLE_IEEE754_UNOP(log10); -+ break; -+ case kIeee754Float64Pow: -+ ASSEMBLE_IEEE754_BINOP(pow); -+ break; -+ case kIeee754Float64Sin: -+ ASSEMBLE_IEEE754_UNOP(sin); -+ break; -+ case kIeee754Float64Sinh: -+ ASSEMBLE_IEEE754_UNOP(sinh); -+ break; -+ case kIeee754Float64Tan: -+ ASSEMBLE_IEEE754_UNOP(tan); -+ break; -+ case kIeee754Float64Tanh: -+ ASSEMBLE_IEEE754_UNOP(tanh); -+ break; -+ case kRiscvAdd32: -+ __ Add32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvAdd64: -+ __ Add64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvAddOvf64: -+ __ AddOverflow64(i.OutputRegister(), i.InputRegister(0), -+ i.InputOperand(1), kScratchReg); -+ break; -+ case kRiscvSub32: -+ __ Sub32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvSub64: -+ __ Sub64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvSubOvf64: -+ __ SubOverflow64(i.OutputRegister(), i.InputRegister(0), -+ i.InputOperand(1), kScratchReg); -+ break; -+ case kRiscvMul32: -+ __ Mul32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvMulOvf32: -+ __ MulOverflow32(i.OutputRegister(), i.InputRegister(0), -+ i.InputOperand(1), kScratchReg); -+ break; -+ case kRiscvMulHigh32: -+ __ Mulh32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvMulHighU32: -+ __ Mulhu32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1), -+ kScratchReg, kScratchReg2); -+ break; -+ case kRiscvMulHigh64: -+ __ Mulh64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvDiv32: { -+ __ Div32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ // Set ouput to zero if divisor == 0 -+ __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1)); -+ break; -+ } -+ case kRiscvDivU32: { -+ __ Divu32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ // Set ouput to zero if divisor == 0 -+ __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1)); -+ break; -+ } -+ case kRiscvMod32: -+ __ Mod32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvModU32: -+ __ Modu32(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvMul64: -+ __ Mul64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvDiv64: { -+ __ Div64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ // Set ouput to zero if divisor == 0 -+ __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1)); -+ break; -+ } -+ case kRiscvDivU64: { -+ __ Divu64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ // Set ouput to zero if divisor == 0 -+ __ LoadZeroIfConditionZero(i.OutputRegister(), i.InputRegister(1)); -+ break; -+ } -+ case kRiscvMod64: -+ __ Mod64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvModU64: -+ __ Modu64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvAnd: -+ __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvAnd32: -+ __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0); -+ break; -+ case kRiscvOr: -+ __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvOr32: -+ __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0); -+ break; -+ case kRiscvNor: -+ if (instr->InputAt(1)->IsRegister()) { -+ __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ } else { -+ DCHECK_EQ(0, i.InputOperand(1).immediate()); -+ __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg); -+ } -+ break; -+ case kRiscvNor32: -+ if (instr->InputAt(1)->IsRegister()) { -+ __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0); -+ } else { -+ DCHECK_EQ(0, i.InputOperand(1).immediate()); -+ __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg); -+ __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0); -+ } -+ break; -+ case kRiscvXor: -+ __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvXor32: -+ __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ __ Sll32(i.OutputRegister(), i.OutputRegister(), 0x0); -+ break; -+ case kRiscvClz32: -+ __ Clz32(i.OutputRegister(), i.InputRegister(0)); -+ break; -+ case kRiscvClz64: -+ __ Clz64(i.OutputRegister(), i.InputRegister(0)); -+ break; -+ case kRiscvCtz32: { -+ Register src = i.InputRegister(0); -+ Register dst = i.OutputRegister(); -+ __ Ctz32(dst, src); -+ } break; -+ case kRiscvCtz64: { -+ Register src = i.InputRegister(0); -+ Register dst = i.OutputRegister(); -+ __ Ctz64(dst, src); -+ } break; -+ case kRiscvPopcnt32: { -+ Register src = i.InputRegister(0); -+ Register dst = i.OutputRegister(); -+ __ Popcnt32(dst, src); -+ } break; -+ case kRiscvPopcnt64: { -+ Register src = i.InputRegister(0); -+ Register dst = i.OutputRegister(); -+ __ Popcnt64(dst, src); -+ } break; -+ case kRiscvShl32: -+ if (instr->InputAt(1)->IsRegister()) { -+ __ Sll32(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); -+ } else { -+ int64_t imm = i.InputOperand(1).immediate(); -+ __ Sll32(i.OutputRegister(), i.InputRegister(0), -+ static_cast(imm)); -+ } -+ break; -+ case kRiscvShr32: -+ if (instr->InputAt(1)->IsRegister()) { -+ __ Srl32(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); -+ } else { -+ int64_t imm = i.InputOperand(1).immediate(); -+ __ Srl32(i.OutputRegister(), i.InputRegister(0), -+ static_cast(imm)); -+ } -+ break; -+ case kRiscvSar32: -+ if (instr->InputAt(1)->IsRegister()) { -+ __ Sra32(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); -+ } else { -+ int64_t imm = i.InputOperand(1).immediate(); -+ __ Sra32(i.OutputRegister(), i.InputRegister(0), -+ static_cast(imm)); -+ } -+ break; -+ case kRiscvZeroExtendWord: { -+ __ ZeroExtendWord(i.OutputRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvSignExtendWord: { -+ __ SignExtendWord(i.OutputRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvShl64: -+ __ Sll64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvShr64: -+ __ Srl64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvSar64: -+ __ Sra64(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvRor32: -+ __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvRor64: -+ __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); -+ break; -+ case kRiscvTst: -+ __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1)); -+ // Pseudo-instruction used for cmp/branch. No opcode emitted here. -+ break; -+ case kRiscvCmp: -+ // Pseudo-instruction used for cmp/branch. No opcode emitted here. -+ break; -+ case kRiscvMov: -+ // TODO(plind): Should we combine mov/li like this, or use separate instr? -+ // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType -+ if (HasRegisterInput(instr, 0)) { -+ __ Move(i.OutputRegister(), i.InputRegister(0)); -+ } else { -+ __ li(i.OutputRegister(), i.InputOperand(0)); -+ } -+ break; -+ -+ case kRiscvCmpS: { -+ FPURegister left = i.InputOrZeroSingleRegister(0); -+ FPURegister right = i.InputOrZeroSingleRegister(1); -+ bool predicate; -+ FPUCondition cc = -+ FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition()); -+ -+ if ((left == kDoubleRegZero || right == kDoubleRegZero) && -+ !__ IsSingleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0f); -+ } -+ // compare result set to kScratchReg -+ __ CompareF32(kScratchReg, cc, left, right); -+ } break; -+ case kRiscvAddS: -+ // TODO(plind): add special case: combine mult & add. -+ __ fadd_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvSubS: -+ __ fsub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvMulS: -+ // TODO(plind): add special case: right op is -1.0, see arm port. -+ __ fmul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvDivS: -+ __ fdiv_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvModS: { -+ // TODO(bmeurer): We should really get rid of this special instruction, -+ // and generate a CallAddress instruction instead. -+ FrameScope scope(tasm(), StackFrame::MANUAL); -+ __ PrepareCallCFunction(0, 2, kScratchReg); -+ __ MovToFloatParameters(i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ // TODO(balazs.kilvady): implement mod_two_floats_operation(isolate()) -+ __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2); -+ // Move the result in the double result register. -+ __ MovFromFloatResult(i.OutputSingleRegister()); -+ break; -+ } -+ case kRiscvAbsS: -+ __ fabs_s(i.OutputSingleRegister(), i.InputSingleRegister(0)); -+ break; -+ case kRiscvNegS: -+ __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0)); -+ break; -+ case kRiscvSqrtS: { -+ __ fsqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); -+ break; -+ } -+ case kRiscvMaxS: -+ __ fmax_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvMinS: -+ __ fmin_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvCmpD: { -+ FPURegister left = i.InputOrZeroDoubleRegister(0); -+ FPURegister right = i.InputOrZeroDoubleRegister(1); -+ bool predicate; -+ FPUCondition cc = -+ FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition()); -+ if ((left == kDoubleRegZero || right == kDoubleRegZero) && -+ !__ IsDoubleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0); -+ } -+ // compare result set to kScratchReg -+ __ CompareF64(kScratchReg, cc, left, right); -+ } break; -+ case kRiscvAddD: -+ // TODO(plind): add special case: combine mult & add. -+ __ fadd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvSubD: -+ __ fsub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvMulD: -+ // TODO(plind): add special case: right op is -1.0, see arm port. -+ __ fmul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvDivD: -+ __ fdiv_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvModD: { -+ // TODO(bmeurer): We should really get rid of this special instruction, -+ // and generate a CallAddress instruction instead. -+ FrameScope scope(tasm(), StackFrame::MANUAL); -+ __ PrepareCallCFunction(0, 2, kScratchReg); -+ __ MovToFloatParameters(i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2); -+ // Move the result in the double result register. -+ __ MovFromFloatResult(i.OutputDoubleRegister()); -+ break; -+ } -+ case kRiscvAbsD: -+ __ fabs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvNegD: -+ __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvSqrtD: { -+ __ fsqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); -+ break; -+ } -+ case kRiscvMaxD: -+ __ fmax_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvMinD: -+ __ fmin_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ i.InputDoubleRegister(1)); -+ break; -+ case kRiscvFloat64RoundDown: { -+ __ Floor_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat32RoundDown: { -+ __ Floor_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat64RoundTruncate: { -+ __ Trunc_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat32RoundTruncate: { -+ __ Trunc_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat64RoundUp: { -+ __ Ceil_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat32RoundUp: { -+ __ Ceil_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat64RoundTiesEven: { -+ __ Round_d_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat32RoundTiesEven: { -+ __ Round_s_s(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ kScratchDoubleReg); -+ break; -+ } -+ case kRiscvFloat32Max: { -+ __ Float32Max(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ i.InputSingleRegister(1)); -+ break; -+ } -+ case kRiscvFloat64Max: { -+ __ Float64Max(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ i.InputSingleRegister(1)); -+ break; -+ } -+ case kRiscvFloat32Min: { -+ __ Float32Min(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ i.InputSingleRegister(1)); -+ break; -+ } -+ case kRiscvFloat64Min: { -+ __ Float64Min(i.OutputSingleRegister(), i.InputSingleRegister(0), -+ i.InputSingleRegister(1)); -+ break; -+ } -+ case kRiscvFloat64SilenceNaN: -+ __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvCvtSD: -+ __ fcvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvCvtDS: -+ __ fcvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0)); -+ break; -+ case kRiscvCvtDW: { -+ __ fcvt_d_w(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtSW: { -+ __ fcvt_s_w(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtSUw: { -+ __ Cvt_s_uw(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtSL: { -+ __ fcvt_s_l(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtDL: { -+ __ fcvt_d_l(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtDUw: { -+ __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtDUl: { -+ __ Cvt_d_ul(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvCvtSUl: { -+ __ Cvt_s_ul(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ } -+ case kRiscvFloorWD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Floor_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvCeilWD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Ceil_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvRoundWD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Round_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvTruncWD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_w_d(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvFloorWS: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Floor_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvCeilWS: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Ceil_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvRoundWS: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Round_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvTruncWS: { -+ Label done; -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_w_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ -+ // On RISCV, if the input value exceeds INT32_MAX, the result of fcvt -+ // is INT32_MAX. Note that, since INT32_MAX means the lower 31-bits are -+ // all 1s, INT32_MAX cannot be represented precisely as a float, so an -+ // fcvt result of INT32_MAX always indicate overflow. -+ // -+ // In wasm_compiler, to detect overflow in converting a FP value, fval, to -+ // integer, V8 checks whether I2F(F2I(fval)) equals fval. However, if fval -+ // == INT32_MAX+1, the value of I2F(F2I(fval)) happens to be fval. So, -+ // INT32_MAX is not a good value to indicate overflow. Instead, we will -+ // use INT32_MIN as the converted result of an out-of-range FP value, -+ // exploiting the fact that INT32_MAX+1 is INT32_MIN. -+ // -+ // If the result of conversion overflow, the result will be set to -+ // INT32_MIN. Here we detect overflow by testing whether output + 1 < -+ // output (i.e., kScratchReg < output) -+ __ Add32(kScratchReg, i.OutputRegister(), 1); -+ __ Branch(&done, lt, i.OutputRegister(), Operand(kScratchReg)); -+ __ Move(i.OutputRegister(), kScratchReg); -+ __ bind(&done); -+ break; -+ } -+ case kRiscvTruncLS: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_l_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvTruncLD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_l_d(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvTruncUwD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvTruncUwS: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ -+ // On RISCV, if the input value exceeds UINT32_MAX, the result of fcvt -+ // is UINT32_MAX. Note that, since UINT32_MAX means all 32-bits are 1s, -+ // UINT32_MAX cannot be represented precisely as float, so an fcvt result -+ // of UINT32_MAX always indicates overflow. -+ // -+ // In wasm_compiler.cc, to detect overflow in converting a FP value, fval, -+ // to integer, V8 checks whether I2F(F2I(fval)) equals fval. However, if -+ // fval == UINT32_MAX+1, the value of I2F(F2I(fval)) happens to be fval. -+ // So, UINT32_MAX is not a good value to indicate overflow. Instead, we -+ // will use 0 as the converted result of an out-of-range FP value, -+ // exploiting the fact that UINT32_MAX+1 is 0. -+ __ Add32(kScratchReg, i.OutputRegister(), 1); -+ // Set ouput to zero if result overflows (i.e., UINT32_MAX) -+ __ LoadZeroIfConditionZero(i.OutputRegister(), kScratchReg); -+ break; -+ } -+ case kRiscvTruncUlS: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_ul_s(i.OutputRegister(), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvTruncUlD: { -+ Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg; -+ __ Trunc_ul_d(i.OutputRegister(0), i.InputDoubleRegister(0), result); -+ break; -+ } -+ case kRiscvBitcastDL: -+ __ fmv_x_d(i.OutputRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvBitcastLD: -+ __ fmv_d_x(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ case kRiscvBitcastInt32ToFloat32: -+ __ fmv_w_x(i.OutputDoubleRegister(), i.InputRegister(0)); -+ break; -+ case kRiscvBitcastFloat32ToInt32: -+ __ fmv_x_w(i.OutputRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvFloat64ExtractLowWord32: -+ __ ExtractLowWordFromF64(i.OutputRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvFloat64ExtractHighWord32: -+ __ ExtractHighWordFromF64(i.OutputRegister(), i.InputDoubleRegister(0)); -+ break; -+ case kRiscvFloat64InsertLowWord32: -+ __ InsertLowWordF64(i.OutputDoubleRegister(), i.InputRegister(1)); -+ break; -+ case kRiscvFloat64InsertHighWord32: -+ __ InsertHighWordF64(i.OutputDoubleRegister(), i.InputRegister(1)); -+ break; -+ // ... more basic instructions ... -+ -+ case kRiscvSignExtendByte: -+ __ SignExtendByte(i.OutputRegister(), i.InputRegister(0)); -+ break; -+ case kRiscvSignExtendShort: -+ __ SignExtendShort(i.OutputRegister(), i.InputRegister(0)); -+ break; -+ case kRiscvLbu: -+ __ Lbu(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvLb: -+ __ Lb(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvSb: -+ __ Sb(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvLhu: -+ __ Lhu(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvUlhu: -+ __ Ulhu(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvLh: -+ __ Lh(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvUlh: -+ __ Ulh(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvSh: -+ __ Sh(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvUsh: -+ __ Ush(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvLw: -+ __ Lw(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvUlw: -+ __ Ulw(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvLwu: -+ __ Lwu(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvUlwu: -+ __ Ulwu(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvLd: -+ __ Ld(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvUld: -+ __ Uld(i.OutputRegister(), i.MemoryOperand()); -+ EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i); -+ break; -+ case kRiscvSw: -+ __ Sw(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvUsw: -+ __ Usw(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvSd: -+ __ Sd(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvUsd: -+ __ Usd(i.InputOrZeroRegister(2), i.MemoryOperand()); -+ break; -+ case kRiscvLoadFloat: { -+ __ LoadFloat(i.OutputSingleRegister(), i.MemoryOperand()); -+ break; -+ } -+ case kRiscvULoadFloat: { -+ __ ULoadFloat(i.OutputSingleRegister(), i.MemoryOperand(), kScratchReg); -+ break; -+ } -+ case kRiscvStoreFloat: { -+ size_t index = 0; -+ MemOperand operand = i.MemoryOperand(&index); -+ FPURegister ft = i.InputOrZeroSingleRegister(index); -+ if (ft == kDoubleRegZero && !__ IsSingleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0f); -+ } -+ __ StoreFloat(ft, operand); -+ break; -+ } -+ case kRiscvUStoreFloat: { -+ size_t index = 0; -+ MemOperand operand = i.MemoryOperand(&index); -+ FPURegister ft = i.InputOrZeroSingleRegister(index); -+ if (ft == kDoubleRegZero && !__ IsSingleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0f); -+ } -+ __ UStoreFloat(ft, operand, kScratchReg); -+ break; -+ } -+ case kRiscvLoadDouble: -+ __ LoadDouble(i.OutputDoubleRegister(), i.MemoryOperand()); -+ break; -+ case kRiscvULoadDouble: -+ __ ULoadDouble(i.OutputDoubleRegister(), i.MemoryOperand(), kScratchReg); -+ break; -+ case kRiscvStoreDouble: { -+ FPURegister ft = i.InputOrZeroDoubleRegister(2); -+ if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0); -+ } -+ __ StoreDouble(ft, i.MemoryOperand()); -+ break; -+ } -+ case kRiscvUStoreDouble: { -+ FPURegister ft = i.InputOrZeroDoubleRegister(2); -+ if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0); -+ } -+ __ UStoreDouble(ft, i.MemoryOperand(), kScratchReg); -+ break; -+ } -+ case kRiscvSync: { -+ __ sync(); -+ break; -+ } -+ case kRiscvPush: -+ if (instr->InputAt(0)->IsFPRegister()) { -+ __ StoreDouble(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize)); -+ __ Sub32(sp, sp, Operand(kDoubleSize)); -+ frame_access_state()->IncreaseSPDelta(kDoubleSize / kSystemPointerSize); -+ } else { -+ __ Push(i.InputRegister(0)); -+ frame_access_state()->IncreaseSPDelta(1); -+ } -+ break; -+ case kRiscvPeek: { -+ // The incoming value is 0-based, but we need a 1-based value. -+ int reverse_slot = i.InputInt32(0) + 1; -+ int offset = -+ FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot); -+ if (instr->OutputAt(0)->IsFPRegister()) { -+ LocationOperand* op = LocationOperand::cast(instr->OutputAt(0)); -+ if (op->representation() == MachineRepresentation::kFloat64) { -+ __ LoadDouble(i.OutputDoubleRegister(), MemOperand(fp, offset)); -+ } else { -+ DCHECK_EQ(op->representation(), MachineRepresentation::kFloat32); -+ __ LoadFloat( -+ i.OutputSingleRegister(0), -+ MemOperand(fp, offset + kLessSignificantWordInDoublewordOffset)); -+ } -+ } else { -+ __ Ld(i.OutputRegister(0), MemOperand(fp, offset)); -+ } -+ break; -+ } -+ case kRiscvStackClaim: { -+ __ Sub64(sp, sp, Operand(i.InputInt32(0))); -+ frame_access_state()->IncreaseSPDelta(i.InputInt32(0) / -+ kSystemPointerSize); -+ break; -+ } -+ case kRiscvStoreToStackSlot: { -+ if (instr->InputAt(0)->IsFPRegister()) { -+ if (instr->InputAt(0)->IsSimd128Register()) { -+ UNREACHABLE(); -+ } else { -+ __ StoreDouble(i.InputDoubleRegister(0), -+ MemOperand(sp, i.InputInt32(1))); -+ } -+ } else { -+ __ Sd(i.InputRegister(0), MemOperand(sp, i.InputInt32(1))); -+ } -+ break; -+ } -+ case kRiscvByteSwap64: { -+ __ ByteSwap(i.OutputRegister(0), i.InputRegister(0), 8); -+ break; -+ } -+ case kRiscvByteSwap32: { -+ __ ByteSwap(i.OutputRegister(0), i.InputRegister(0), 4); -+ break; -+ } -+ case kWord32AtomicLoadInt8: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lb); -+ break; -+ case kWord32AtomicLoadUint8: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lbu); -+ break; -+ case kWord32AtomicLoadInt16: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lh); -+ break; -+ case kWord32AtomicLoadUint16: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lhu); -+ break; -+ case kWord32AtomicLoadWord32: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lw); -+ break; -+ case kRiscvWord64AtomicLoadUint8: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lbu); -+ break; -+ case kRiscvWord64AtomicLoadUint16: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lhu); -+ break; -+ case kRiscvWord64AtomicLoadUint32: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Lwu); -+ break; -+ case kRiscvWord64AtomicLoadUint64: -+ ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld); -+ break; -+ case kWord32AtomicStoreWord8: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sb); -+ break; -+ case kWord32AtomicStoreWord16: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sh); -+ break; -+ case kWord32AtomicStoreWord32: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sw); -+ break; -+ case kRiscvWord64AtomicStoreWord8: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sb); -+ break; -+ case kRiscvWord64AtomicStoreWord16: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sh); -+ break; -+ case kRiscvWord64AtomicStoreWord32: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sw); -+ break; -+ case kRiscvWord64AtomicStoreWord64: -+ ASSEMBLE_ATOMIC_STORE_INTEGER(Sd); -+ break; -+ case kWord32AtomicExchangeInt8: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, true, 8, 32); -+ break; -+ case kWord32AtomicExchangeUint8: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 8, 32); -+ break; -+ case kWord32AtomicExchangeInt16: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, true, 16, 32); -+ break; -+ case kWord32AtomicExchangeUint16: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 16, 32); -+ break; -+ case kWord32AtomicExchangeWord32: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(Ll, Sc); -+ break; -+ case kRiscvWord64AtomicExchangeUint8: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 8, 64); -+ break; -+ case kRiscvWord64AtomicExchangeUint16: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 16, 64); -+ break; -+ case kRiscvWord64AtomicExchangeUint32: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 32, 64); -+ break; -+ case kRiscvWord64AtomicExchangeUint64: -+ ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(Lld, Scd); -+ break; -+ case kWord32AtomicCompareExchangeInt8: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll, Sc, true, 8, 32); -+ break; -+ case kWord32AtomicCompareExchangeUint8: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 8, 32); -+ break; -+ case kWord32AtomicCompareExchangeInt16: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll, Sc, true, 16, 32); -+ break; -+ case kWord32AtomicCompareExchangeUint16: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll, Sc, false, 16, 32); -+ break; -+ case kWord32AtomicCompareExchangeWord32: -+ __ Sll32(i.InputRegister(2), i.InputRegister(2), 0); -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(Ll, Sc); -+ break; -+ case kRiscvWord64AtomicCompareExchangeUint8: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 8, 64); -+ break; -+ case kRiscvWord64AtomicCompareExchangeUint16: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 16, 64); -+ break; -+ case kRiscvWord64AtomicCompareExchangeUint32: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Lld, Scd, false, 32, 64); -+ break; -+ case kRiscvWord64AtomicCompareExchangeUint64: -+ ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(Lld, Scd); -+ break; -+#define ATOMIC_BINOP_CASE(op, inst) \ -+ case kWord32Atomic##op##Int8: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, true, 8, inst, 32); \ -+ break; \ -+ case kWord32Atomic##op##Uint8: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, false, 8, inst, 32); \ -+ break; \ -+ case kWord32Atomic##op##Int16: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, true, 16, inst, 32); \ -+ break; \ -+ case kWord32Atomic##op##Uint16: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Ll, Sc, false, 16, inst, 32); \ -+ break; \ -+ case kWord32Atomic##op##Word32: \ -+ ASSEMBLE_ATOMIC_BINOP(Ll, Sc, inst); \ -+ break; -+ ATOMIC_BINOP_CASE(Add, Add32) -+ ATOMIC_BINOP_CASE(Sub, Sub32) -+ ATOMIC_BINOP_CASE(And, And) -+ ATOMIC_BINOP_CASE(Or, Or) -+ ATOMIC_BINOP_CASE(Xor, Xor) -+#undef ATOMIC_BINOP_CASE -+#define ATOMIC_BINOP_CASE(op, inst) \ -+ case kRiscvWord64Atomic##op##Uint8: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Lld, Scd, false, 8, inst, 64); \ -+ break; \ -+ case kRiscvWord64Atomic##op##Uint16: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Lld, Scd, false, 16, inst, 64); \ -+ break; \ -+ case kRiscvWord64Atomic##op##Uint32: \ -+ ASSEMBLE_ATOMIC_BINOP_EXT(Lld, Scd, false, 32, inst, 64); \ -+ break; \ -+ case kRiscvWord64Atomic##op##Uint64: \ -+ ASSEMBLE_ATOMIC_BINOP(Lld, Scd, inst); \ -+ break; -+ ATOMIC_BINOP_CASE(Add, Add64) -+ ATOMIC_BINOP_CASE(Sub, Sub64) -+ ATOMIC_BINOP_CASE(And, And) -+ ATOMIC_BINOP_CASE(Or, Or) -+ ATOMIC_BINOP_CASE(Xor, Xor) -+#undef ATOMIC_BINOP_CASE -+ case kRiscvAssertEqual: -+ __ Assert(eq, static_cast(i.InputOperand(2).immediate()), -+ i.InputRegister(0), Operand(i.InputRegister(1))); -+ break; -+ -+ default: -+ UNIMPLEMENTED(); -+ } -+ return kSuccess; -+} // NOLINT(readability/fn_size) -+ -+#define UNSUPPORTED_COND(opcode, condition) \ -+ StdoutStream{} << "Unsupported " << #opcode << " condition: \"" << condition \ -+ << "\""; \ -+ UNIMPLEMENTED(); -+ -+void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm, -+ Instruction* instr, FlagsCondition condition, -+ Label* tlabel, Label* flabel, bool fallthru) { -+#undef __ -+#define __ tasm-> -+ RiscvOperandConverter i(gen, instr); -+ -+ Condition cc = kNoCondition; -+ // RISC-V does not have condition code flags, so compare and branch are -+ // implemented differently than on the other arch's. The compare operations -+ // emit riscv64 pseudo-instructions, which are handled here by branch -+ // instructions that do the actual comparison. Essential that the input -+ // registers to compare pseudo-op are not modified before this branch op, as -+ // they are tested here. -+ -+ if (instr->arch_opcode() == kRiscvTst) { -+ cc = FlagsConditionToConditionTst(condition); -+ __ Branch(tlabel, cc, kScratchReg, Operand(zero_reg)); -+ } else if (instr->arch_opcode() == kRiscvAdd64 || -+ instr->arch_opcode() == kRiscvSub64) { -+ cc = FlagsConditionToConditionOvf(condition); -+ __ Sra64(kScratchReg, i.OutputRegister(), 32); -+ __ Sra64(kScratchReg2, i.OutputRegister(), 31); -+ __ Branch(tlabel, cc, kScratchReg2, Operand(kScratchReg)); -+ } else if (instr->arch_opcode() == kRiscvAddOvf64 || -+ instr->arch_opcode() == kRiscvSubOvf64) { -+ switch (condition) { -+ // Overflow occurs if overflow register is negative -+ case kOverflow: -+ __ Branch(tlabel, lt, kScratchReg, Operand(zero_reg)); -+ break; -+ case kNotOverflow: -+ __ Branch(tlabel, ge, kScratchReg, Operand(zero_reg)); -+ break; -+ default: -+ UNSUPPORTED_COND(instr->arch_opcode(), condition); -+ break; -+ } -+ } else if (instr->arch_opcode() == kRiscvMulOvf32) { -+ // Overflow occurs if overflow register is not zero -+ switch (condition) { -+ case kOverflow: -+ __ Branch(tlabel, ne, kScratchReg, Operand(zero_reg)); -+ break; -+ case kNotOverflow: -+ __ Branch(tlabel, eq, kScratchReg, Operand(zero_reg)); -+ break; -+ default: -+ UNSUPPORTED_COND(kRiscvMulOvf32, condition); -+ break; -+ } -+ } else if (instr->arch_opcode() == kRiscvCmp) { -+ cc = FlagsConditionToConditionCmp(condition); -+ __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); -+ } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) { -+ cc = FlagsConditionToConditionCmp(condition); -+ Register lhs_register = sp; -+ uint32_t offset; -+ if (gen->ShouldApplyOffsetToStackCheck(instr, &offset)) { -+ lhs_register = i.TempRegister(0); -+ __ Sub64(lhs_register, sp, offset); -+ } -+ __ Branch(tlabel, cc, lhs_register, Operand(i.InputRegister(0))); -+ } else if (instr->arch_opcode() == kRiscvCmpS || -+ instr->arch_opcode() == kRiscvCmpD) { -+ bool predicate; -+ FlagsConditionToConditionCmpFPU(&predicate, condition); -+ // floating-point compare result is set in kScratchReg -+ if (predicate) { -+ __ BranchTrueF(kScratchReg, tlabel); -+ } else { -+ __ BranchFalseF(kScratchReg, tlabel); -+ } -+ } else { -+ PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n", -+ instr->arch_opcode()); -+ UNIMPLEMENTED(); -+ } -+ if (!fallthru) __ Branch(flabel); // no fallthru to flabel. -+#undef __ -+#define __ tasm()-> -+} -+ -+// Assembles branches after an instruction. -+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { -+ Label* tlabel = branch->true_label; -+ Label* flabel = branch->false_label; -+ -+ AssembleBranchToLabels(this, tasm(), instr, branch->condition, tlabel, flabel, -+ branch->fallthru); -+} -+ -+void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition, -+ Instruction* instr) { -+ // TODO(jarin) Handle float comparisons (kUnordered[Not]Equal). -+ if (condition == kUnorderedEqual || condition == kUnorderedNotEqual) { -+ return; -+ } -+ -+ RiscvOperandConverter i(this, instr); -+ condition = NegateFlagsCondition(condition); -+ -+ switch (instr->arch_opcode()) { -+ case kRiscvCmp: { -+ __ CompareI(kScratchReg, i.InputRegister(0), i.InputOperand(1), -+ FlagsConditionToConditionCmp(condition)); -+ __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, kScratchReg); -+ } -+ return; -+ case kRiscvTst: { -+ switch (condition) { -+ case kEqual: -+ __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg); -+ break; -+ case kNotEqual: -+ __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, -+ kScratchReg); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+ return; -+ case kRiscvAdd64: -+ case kRiscvSub64: { -+ // Check for overflow creates 1 or 0 for result. -+ __ Srl64(kScratchReg, i.OutputRegister(), 63); -+ __ Srl32(kScratchReg2, i.OutputRegister(), 31); -+ __ Xor(kScratchReg2, kScratchReg, kScratchReg2); -+ switch (condition) { -+ case kOverflow: -+ __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, -+ kScratchReg2); -+ break; -+ case kNotOverflow: -+ __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2); -+ break; -+ default: -+ UNSUPPORTED_COND(instr->arch_opcode(), condition); -+ } -+ } -+ return; -+ case kRiscvAddOvf64: -+ case kRiscvSubOvf64: { -+ // Overflow occurs if overflow register is negative -+ __ Slt(kScratchReg2, kScratchReg, zero_reg); -+ switch (condition) { -+ case kOverflow: -+ __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, -+ kScratchReg2); -+ break; -+ case kNotOverflow: -+ __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2); -+ break; -+ default: -+ UNSUPPORTED_COND(instr->arch_opcode(), condition); -+ } -+ } -+ return; -+ case kRiscvMulOvf32: { -+ // Overflow occurs if overflow register is not zero -+ switch (condition) { -+ case kOverflow: -+ __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, -+ kScratchReg); -+ break; -+ case kNotOverflow: -+ __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg); -+ break; -+ default: -+ UNSUPPORTED_COND(instr->arch_opcode(), condition); -+ } -+ } -+ return; -+ case kRiscvCmpS: -+ case kRiscvCmpD: { -+ bool predicate; -+ FlagsConditionToConditionCmpFPU(&predicate, condition); -+ if (predicate) { -+ __ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, kScratchReg); -+ } else { -+ __ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg); -+ } -+ } -+ return; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+#undef UNSUPPORTED_COND -+ -+void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr, -+ BranchInfo* branch) { -+ AssembleArchBranch(instr, branch); -+} -+ -+void CodeGenerator::AssembleArchJump(RpoNumber target) { -+ if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target)); -+} -+ -+void CodeGenerator::AssembleArchTrap(Instruction* instr, -+ FlagsCondition condition) { -+ class OutOfLineTrap final : public OutOfLineCode { -+ public: -+ OutOfLineTrap(CodeGenerator* gen, Instruction* instr) -+ : OutOfLineCode(gen), instr_(instr), gen_(gen) {} -+ void Generate() final { -+ RiscvOperandConverter i(gen_, instr_); -+ TrapId trap_id = -+ static_cast(i.InputInt32(instr_->InputCount() - 1)); -+ GenerateCallToTrap(trap_id); -+ } -+ -+ private: -+ void GenerateCallToTrap(TrapId trap_id) { -+ if (trap_id == TrapId::kInvalid) { -+ // We cannot test calls to the runtime in cctest/test-run-wasm. -+ // Therefore we emit a call to C here instead of a call to the runtime. -+ // We use the context register as the scratch register, because we do -+ // not have a context here. -+ __ PrepareCallCFunction(0, 0, cp); -+ __ CallCFunction( -+ ExternalReference::wasm_call_trap_callback_for_testing(), 0); -+ __ LeaveFrame(StackFrame::WASM); -+ auto call_descriptor = gen_->linkage()->GetIncomingDescriptor(); -+ int pop_count = -+ static_cast(call_descriptor->StackParameterCount()); -+ pop_count += (pop_count & 1); // align -+ __ Drop(pop_count); -+ __ Ret(); -+ } else { -+ gen_->AssembleSourcePosition(instr_); -+ // A direct call to a wasm runtime stub defined in this module. -+ // Just encode the stub index. This will be patched when the code -+ // is added to the native module and copied into wasm code space. -+ __ Call(static_cast
(trap_id), RelocInfo::WASM_STUB_CALL); -+ ReferenceMap* reference_map = -+ gen_->zone()->New(gen_->zone()); -+ gen_->RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt); -+ if (FLAG_debug_code) { -+ __ stop(); -+ } -+ } -+ } -+ Instruction* instr_; -+ CodeGenerator* gen_; -+ }; -+ auto ool = zone()->New(this, instr); -+ Label* tlabel = ool->entry(); -+ AssembleBranchToLabels(this, tasm(), instr, condition, tlabel, nullptr, true); -+} -+ -+// Assembles boolean materializations after an instruction. -+void CodeGenerator::AssembleArchBoolean(Instruction* instr, -+ FlagsCondition condition) { -+ RiscvOperandConverter i(this, instr); -+ -+ // Materialize a full 32-bit 1 or 0 value. The result register is always the -+ // last output of the instruction. -+ DCHECK_NE(0u, instr->OutputCount()); -+ Register result = i.OutputRegister(instr->OutputCount() - 1); -+ Condition cc = kNoCondition; -+ // RISC-V does not have condition code flags, so compare and branch are -+ // implemented differently than on the other arch's. The compare operations -+ // emit riscv64 pseudo-instructions, which are checked and handled here. -+ -+ if (instr->arch_opcode() == kRiscvTst) { -+ cc = FlagsConditionToConditionTst(condition); -+ if (cc == eq) { -+ __ Sltu(result, kScratchReg, 1); -+ } else { -+ __ Sltu(result, zero_reg, kScratchReg); -+ } -+ return; -+ } else if (instr->arch_opcode() == kRiscvAdd64 || -+ instr->arch_opcode() == kRiscvSub64) { -+ cc = FlagsConditionToConditionOvf(condition); -+ // Check for overflow creates 1 or 0 for result. -+ __ Srl64(kScratchReg, i.OutputRegister(), 63); -+ __ Srl32(kScratchReg2, i.OutputRegister(), 31); -+ __ Xor(result, kScratchReg, kScratchReg2); -+ if (cc == eq) // Toggle result for not overflow. -+ __ Xor(result, result, 1); -+ return; -+ } else if (instr->arch_opcode() == kRiscvAddOvf64 || -+ instr->arch_opcode() == kRiscvSubOvf64) { -+ // Overflow occurs if overflow register is negative -+ __ Slt(result, kScratchReg, zero_reg); -+ } else if (instr->arch_opcode() == kRiscvMulOvf32) { -+ // Overflow occurs if overflow register is not zero -+ __ Sgtu(result, kScratchReg, zero_reg); -+ } else if (instr->arch_opcode() == kRiscvCmp) { -+ cc = FlagsConditionToConditionCmp(condition); -+ switch (cc) { -+ case eq: -+ case ne: { -+ Register left = i.InputRegister(0); -+ Operand right = i.InputOperand(1); -+ if (instr->InputAt(1)->IsImmediate()) { -+ if (is_int12(-right.immediate())) { -+ if (right.immediate() == 0) { -+ if (cc == eq) { -+ __ Sltu(result, left, 1); -+ } else { -+ __ Sltu(result, zero_reg, left); -+ } -+ } else { -+ __ Add64(result, left, Operand(-right.immediate())); -+ if (cc == eq) { -+ __ Sltu(result, result, 1); -+ } else { -+ __ Sltu(result, zero_reg, result); -+ } -+ } -+ } else { -+ if (is_uint12(right.immediate())) { -+ __ Xor(result, left, right); -+ } else { -+ __ li(kScratchReg, right); -+ __ Xor(result, left, kScratchReg); -+ } -+ if (cc == eq) { -+ __ Sltu(result, result, 1); -+ } else { -+ __ Sltu(result, zero_reg, result); -+ } -+ } -+ } else { -+ __ Xor(result, left, right); -+ if (cc == eq) { -+ __ Sltu(result, result, 1); -+ } else { -+ __ Sltu(result, zero_reg, result); -+ } -+ } -+ } break; -+ case lt: -+ case ge: { -+ Register left = i.InputRegister(0); -+ Operand right = i.InputOperand(1); -+ __ Slt(result, left, right); -+ if (cc == ge) { -+ __ Xor(result, result, 1); -+ } -+ } break; -+ case gt: -+ case le: { -+ Register left = i.InputRegister(1); -+ Operand right = i.InputOperand(0); -+ __ Slt(result, left, right); -+ if (cc == le) { -+ __ Xor(result, result, 1); -+ } -+ } break; -+ case Uless: -+ case Ugreater_equal: { -+ Register left = i.InputRegister(0); -+ Operand right = i.InputOperand(1); -+ __ Sltu(result, left, right); -+ if (cc == Ugreater_equal) { -+ __ Xor(result, result, 1); -+ } -+ } break; -+ case Ugreater: -+ case Uless_equal: { -+ Register left = i.InputRegister(1); -+ Operand right = i.InputOperand(0); -+ __ Sltu(result, left, right); -+ if (cc == Uless_equal) { -+ __ Xor(result, result, 1); -+ } -+ } break; -+ default: -+ UNREACHABLE(); -+ } -+ return; -+ } else if (instr->arch_opcode() == kRiscvCmpD || -+ instr->arch_opcode() == kRiscvCmpS) { -+ FPURegister left = i.InputOrZeroDoubleRegister(0); -+ FPURegister right = i.InputOrZeroDoubleRegister(1); -+ if ((instr->arch_opcode() == kRiscvCmpD) && -+ (left == kDoubleRegZero || right == kDoubleRegZero) && -+ !__ IsDoubleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0); -+ } else if ((instr->arch_opcode() == kRiscvCmpS) && -+ (left == kDoubleRegZero || right == kDoubleRegZero) && -+ !__ IsSingleZeroRegSet()) { -+ __ LoadFPRImmediate(kDoubleRegZero, 0.0f); -+ } -+ bool predicate; -+ FlagsConditionToConditionCmpFPU(&predicate, condition); -+ // RISCV compare returns 0 or 1, do nothing when predicate; otherwise -+ // toggle kScratchReg (i.e., 0 -> 1, 1 -> 0) -+ if (predicate) { -+ __ Move(result, kScratchReg); -+ } else { -+ __ Xor(result, kScratchReg, 1); -+ } -+ return; -+ } else { -+ PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", -+ instr->arch_opcode()); -+ TRACE_UNIMPL(); -+ UNIMPLEMENTED(); -+ } -+} -+ -+void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) { -+ RiscvOperandConverter i(this, instr); -+ Register input = i.InputRegister(0); -+ std::vector> cases; -+ for (size_t index = 2; index < instr->InputCount(); index += 2) { -+ cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))}); -+ } -+ AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(), -+ cases.data() + cases.size()); -+} -+ -+void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { -+ RiscvOperandConverter i(this, instr); -+ Register input = i.InputRegister(0); -+ size_t const case_count = instr->InputCount() - 2; -+ -+ __ Branch(GetLabel(i.InputRpo(1)), Ugreater_equal, input, -+ Operand(case_count)); -+ __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) { -+ return GetLabel(i.InputRpo(index + 2)); -+ }); -+} -+ -+void CodeGenerator::FinishFrame(Frame* frame) { -+ auto call_descriptor = linkage()->GetIncomingDescriptor(); -+ -+ const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters(); -+ if (saves_fpu != 0) { -+ int count = base::bits::CountPopulation(saves_fpu); -+ DCHECK_EQ(kNumCalleeSavedFPU, count); -+ frame->AllocateSavedCalleeRegisterSlots(count * -+ (kDoubleSize / kSystemPointerSize)); -+ } -+ -+ const RegList saves = call_descriptor->CalleeSavedRegisters(); -+ if (saves != 0) { -+ int count = base::bits::CountPopulation(saves); -+ DCHECK_EQ(kNumCalleeSaved, count + 1); -+ frame->AllocateSavedCalleeRegisterSlots(count); -+ } -+} -+ -+void CodeGenerator::AssembleConstructFrame() { -+ auto call_descriptor = linkage()->GetIncomingDescriptor(); -+ -+ if (frame_access_state()->has_frame()) { -+ if (call_descriptor->IsCFunctionCall()) { -+ if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { -+ __ StubPrologue(StackFrame::C_WASM_ENTRY); -+ // Reserve stack space for saving the c_entry_fp later. -+ __ Sub64(sp, sp, Operand(kSystemPointerSize)); -+ } else { -+ __ Push(ra, fp); -+ __ Move(fp, sp); -+ } -+ } else if (call_descriptor->IsJSFunctionCall()) { -+ __ Prologue(); -+ } else { -+ __ StubPrologue(info()->GetOutputStackFrameType()); -+ if (call_descriptor->IsWasmFunctionCall()) { -+ __ Push(kWasmInstanceRegister); -+ } else if (call_descriptor->IsWasmImportWrapper() || -+ call_descriptor->IsWasmCapiFunction()) { -+ // Wasm import wrappers are passed a tuple in the place of the instance. -+ // Unpack the tuple into the instance and the target callable. -+ // This must be done here in the codegen because it cannot be expressed -+ // properly in the graph. -+ __ Ld(kJSFunctionRegister, -+ FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue2Offset)); -+ __ Ld(kWasmInstanceRegister, -+ FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue1Offset)); -+ __ Push(kWasmInstanceRegister); -+ if (call_descriptor->IsWasmCapiFunction()) { -+ // Reserve space for saving the PC later. -+ __ Sub64(sp, sp, Operand(kSystemPointerSize)); -+ } -+ } -+ } -+ } -+ -+ int required_slots = -+ frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount(); -+ -+ if (info()->is_osr()) { -+ // TurboFan OSR-compiled functions cannot be entered directly. -+ __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction); -+ -+ // Unoptimized code jumps directly to this entrypoint while the unoptimized -+ // frame is still on the stack. Optimized code uses OSR values directly from -+ // the unoptimized frame. Thus, all that needs to be done is to allocate the -+ // remaining stack slots. -+ if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); -+ osr_pc_offset_ = __ pc_offset(); -+ required_slots -= osr_helper()->UnoptimizedFrameSlots(); -+ ResetSpeculationPoison(); -+ } -+ -+ const RegList saves = call_descriptor->CalleeSavedRegisters(); -+ const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters(); -+ -+ if (required_slots > 0) { -+ DCHECK(frame_access_state()->has_frame()); -+ if (info()->IsWasm() && required_slots > 128) { -+ // For WebAssembly functions with big frames we have to do the stack -+ // overflow check before we construct the frame. Otherwise we may not -+ // have enough space on the stack to call the runtime for the stack -+ // overflow. -+ Label done; -+ -+ // If the frame is bigger than the stack, we throw the stack overflow -+ // exception unconditionally. Thereby we can avoid the integer overflow -+ // check in the condition code. -+ if ((required_slots * kSystemPointerSize) < (FLAG_stack_size * 1024)) { -+ __ Ld( -+ kScratchReg, -+ FieldMemOperand(kWasmInstanceRegister, -+ WasmInstanceObject::kRealStackLimitAddressOffset)); -+ __ Ld(kScratchReg, MemOperand(kScratchReg)); -+ __ Add64(kScratchReg, kScratchReg, -+ Operand(required_slots * kSystemPointerSize)); -+ __ Branch(&done, uge, sp, Operand(kScratchReg)); -+ } -+ -+ __ Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL); -+ // We come from WebAssembly, there are no references for the GC. -+ ReferenceMap* reference_map = zone()->New(zone()); -+ RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt); -+ if (FLAG_debug_code) { -+ __ stop(); -+ } -+ -+ __ bind(&done); -+ } -+ } -+ -+ const int returns = frame()->GetReturnSlotCount(); -+ -+ // Skip callee-saved and return slots, which are pushed below. -+ required_slots -= base::bits::CountPopulation(saves); -+ required_slots -= base::bits::CountPopulation(saves_fpu); -+ required_slots -= returns; -+ if (required_slots > 0) { -+ __ Sub64(sp, sp, Operand(required_slots * kSystemPointerSize)); -+ } -+ -+ if (saves_fpu != 0) { -+ // Save callee-saved FPU registers. -+ __ MultiPushFPU(saves_fpu); -+ DCHECK_EQ(kNumCalleeSavedFPU, base::bits::CountPopulation(saves_fpu)); -+ } -+ -+ if (saves != 0) { -+ // Save callee-saved registers. -+ __ MultiPush(saves); -+ DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation(saves) + 1); -+ } -+ -+ if (returns != 0) { -+ // Create space for returns. -+ __ Sub64(sp, sp, Operand(returns * kSystemPointerSize)); -+ } -+} -+ -+void CodeGenerator::AssembleReturn(InstructionOperand* pop) { -+ auto call_descriptor = linkage()->GetIncomingDescriptor(); -+ -+ const int returns = frame()->GetReturnSlotCount(); -+ if (returns != 0) { -+ __ Add64(sp, sp, Operand(returns * kSystemPointerSize)); -+ } -+ -+ // Restore GP registers. -+ const RegList saves = call_descriptor->CalleeSavedRegisters(); -+ if (saves != 0) { -+ __ MultiPop(saves); -+ } -+ -+ // Restore FPU registers. -+ const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters(); -+ if (saves_fpu != 0) { -+ __ MultiPopFPU(saves_fpu); -+ } -+ -+ RiscvOperandConverter g(this, nullptr); -+ if (call_descriptor->IsCFunctionCall()) { -+ AssembleDeconstructFrame(); -+ } else if (frame_access_state()->has_frame()) { -+ // Canonicalize JSFunction return sites for now unless they have an variable -+ // number of stack slot pops. -+ if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) { -+ if (return_label_.is_bound()) { -+ __ Branch(&return_label_); -+ return; -+ } else { -+ __ bind(&return_label_); -+ AssembleDeconstructFrame(); -+ } -+ } else { -+ AssembleDeconstructFrame(); -+ } -+ } -+ int pop_count = static_cast(call_descriptor->StackParameterCount()); -+ if (pop->IsImmediate()) { -+ pop_count += g.ToConstant(pop).ToInt32(); -+ } else { -+ Register pop_reg = g.ToRegister(pop); -+ __ Sll64(pop_reg, pop_reg, kSystemPointerSizeLog2); -+ __ Add64(sp, sp, pop_reg); -+ } -+ if (pop_count != 0) { -+ __ DropAndRet(pop_count); -+ } else { -+ __ Ret(); -+ } -+} -+ -+void CodeGenerator::FinishCode() {} -+ -+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {} -+ -+void CodeGenerator::AssembleMove(InstructionOperand* source, -+ InstructionOperand* destination) { -+ RiscvOperandConverter g(this, nullptr); -+ // Dispatch on the source and destination operand kinds. Not all -+ // combinations are possible. -+ if (source->IsRegister()) { -+ DCHECK(destination->IsRegister() || destination->IsStackSlot()); -+ Register src = g.ToRegister(source); -+ if (destination->IsRegister()) { -+ __ Move(g.ToRegister(destination), src); -+ } else { -+ __ Sd(src, g.ToMemOperand(destination)); -+ } -+ } else if (source->IsStackSlot()) { -+ DCHECK(destination->IsRegister() || destination->IsStackSlot()); -+ MemOperand src = g.ToMemOperand(source); -+ if (destination->IsRegister()) { -+ __ Ld(g.ToRegister(destination), src); -+ } else { -+ Register temp = kScratchReg; -+ __ Ld(temp, src); -+ __ Sd(temp, g.ToMemOperand(destination)); -+ } -+ } else if (source->IsConstant()) { -+ Constant src = g.ToConstant(source); -+ if (destination->IsRegister() || destination->IsStackSlot()) { -+ Register dst = -+ destination->IsRegister() ? g.ToRegister(destination) : kScratchReg; -+ switch (src.type()) { -+ case Constant::kInt32: -+ __ li(dst, Operand(src.ToInt32())); -+ break; -+ case Constant::kFloat32: -+ __ li(dst, Operand::EmbeddedNumber(src.ToFloat32())); -+ break; -+ case Constant::kInt64: -+ if (RelocInfo::IsWasmReference(src.rmode())) { -+ __ li(dst, Operand(src.ToInt64(), src.rmode())); -+ } else { -+ __ li(dst, Operand(src.ToInt64())); -+ } -+ break; -+ case Constant::kFloat64: -+ __ li(dst, Operand::EmbeddedNumber(src.ToFloat64().value())); -+ break; -+ case Constant::kExternalReference: -+ __ li(dst, src.ToExternalReference()); -+ break; -+ case Constant::kDelayedStringConstant: -+ __ li(dst, src.ToDelayedStringConstant()); -+ break; -+ case Constant::kHeapObject: { -+ Handle src_object = src.ToHeapObject(); -+ RootIndex index; -+ if (IsMaterializableFromRoot(src_object, &index)) { -+ __ LoadRoot(dst, index); -+ } else { -+ __ li(dst, src_object); -+ } -+ break; -+ } -+ case Constant::kCompressedHeapObject: -+ UNREACHABLE(); -+ case Constant::kRpoNumber: -+ UNREACHABLE(); // TODO(titzer): loading RPO numbers -+ break; -+ } -+ if (destination->IsStackSlot()) __ Sd(dst, g.ToMemOperand(destination)); -+ } else if (src.type() == Constant::kFloat32) { -+ if (destination->IsFPStackSlot()) { -+ MemOperand dst = g.ToMemOperand(destination); -+ if (bit_cast(src.ToFloat32()) == 0) { -+ __ Sw(zero_reg, dst); -+ } else { -+ __ li(kScratchReg, Operand(bit_cast(src.ToFloat32()))); -+ __ Sw(kScratchReg, dst); -+ } -+ } else { -+ DCHECK(destination->IsFPRegister()); -+ FloatRegister dst = g.ToSingleRegister(destination); -+ __ LoadFPRImmediate(dst, src.ToFloat32()); -+ } -+ } else { -+ DCHECK_EQ(Constant::kFloat64, src.type()); -+ DoubleRegister dst = destination->IsFPRegister() -+ ? g.ToDoubleRegister(destination) -+ : kScratchDoubleReg; -+ __ LoadFPRImmediate(dst, src.ToFloat64().value()); -+ if (destination->IsFPStackSlot()) { -+ __ StoreDouble(dst, g.ToMemOperand(destination)); -+ } -+ } -+ } else if (source->IsFPRegister()) { -+ MachineRepresentation rep = LocationOperand::cast(source)->representation(); -+ if (rep == MachineRepresentation::kSimd128) { -+ UNIMPLEMENTED(); -+ } else { -+ FPURegister src = g.ToDoubleRegister(source); -+ if (destination->IsFPRegister()) { -+ FPURegister dst = g.ToDoubleRegister(destination); -+ __ Move(dst, src); -+ } else { -+ DCHECK(destination->IsFPStackSlot()); -+ if (rep == MachineRepresentation::kFloat32) { -+ __ StoreFloat(src, g.ToMemOperand(destination)); -+ } else { -+ DCHECK_EQ(rep, MachineRepresentation::kFloat64); -+ __ StoreDouble(src, g.ToMemOperand(destination)); -+ } -+ } -+ } -+ } else if (source->IsFPStackSlot()) { -+ DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot()); -+ MemOperand src = g.ToMemOperand(source); -+ MachineRepresentation rep = LocationOperand::cast(source)->representation(); -+ if (rep == MachineRepresentation::kSimd128) { -+ UNIMPLEMENTED(); -+ } else { -+ if (destination->IsFPRegister()) { -+ if (rep == MachineRepresentation::kFloat32) { -+ __ LoadFloat(g.ToDoubleRegister(destination), src); -+ } else { -+ DCHECK_EQ(rep, MachineRepresentation::kFloat64); -+ __ LoadDouble(g.ToDoubleRegister(destination), src); -+ } -+ } else { -+ DCHECK(destination->IsFPStackSlot()); -+ FPURegister temp = kScratchDoubleReg; -+ if (rep == MachineRepresentation::kFloat32) { -+ __ LoadFloat(temp, src); -+ __ StoreFloat(temp, g.ToMemOperand(destination)); -+ } else { -+ DCHECK_EQ(rep, MachineRepresentation::kFloat64); -+ __ LoadDouble(temp, src); -+ __ StoreDouble(temp, g.ToMemOperand(destination)); -+ } -+ } -+ } -+ } else { -+ UNREACHABLE(); -+ } -+} -+ -+void CodeGenerator::AssembleSwap(InstructionOperand* source, -+ InstructionOperand* destination) { -+ RiscvOperandConverter g(this, nullptr); -+ // Dispatch on the source and destination operand kinds. Not all -+ // combinations are possible. -+ if (source->IsRegister()) { -+ // Register-register. -+ Register temp = kScratchReg; -+ Register src = g.ToRegister(source); -+ if (destination->IsRegister()) { -+ Register dst = g.ToRegister(destination); -+ __ Move(temp, src); -+ __ Move(src, dst); -+ __ Move(dst, temp); -+ } else { -+ DCHECK(destination->IsStackSlot()); -+ MemOperand dst = g.ToMemOperand(destination); -+ __ Move(temp, src); -+ __ Ld(src, dst); -+ __ Sd(temp, dst); -+ } -+ } else if (source->IsStackSlot()) { -+ DCHECK(destination->IsStackSlot()); -+ Register temp_0 = kScratchReg; -+ Register temp_1 = kScratchReg2; -+ MemOperand src = g.ToMemOperand(source); -+ MemOperand dst = g.ToMemOperand(destination); -+ __ Ld(temp_0, src); -+ __ Ld(temp_1, dst); -+ __ Sd(temp_0, dst); -+ __ Sd(temp_1, src); -+ } else if (source->IsFPRegister()) { -+ MachineRepresentation rep = LocationOperand::cast(source)->representation(); -+ if (rep == MachineRepresentation::kSimd128) { -+ UNIMPLEMENTED(); -+ } else { -+ FPURegister temp = kScratchDoubleReg; -+ FPURegister src = g.ToDoubleRegister(source); -+ if (destination->IsFPRegister()) { -+ FPURegister dst = g.ToDoubleRegister(destination); -+ __ Move(temp, src); -+ __ Move(src, dst); -+ __ Move(dst, temp); -+ } else { -+ DCHECK(destination->IsFPStackSlot()); -+ MemOperand dst = g.ToMemOperand(destination); -+ __ Move(temp, src); -+ __ LoadDouble(src, dst); -+ __ StoreDouble(temp, dst); -+ } -+ } -+ } else if (source->IsFPStackSlot()) { -+ DCHECK(destination->IsFPStackSlot()); -+ Register temp_0 = kScratchReg; -+ MemOperand src0 = g.ToMemOperand(source); -+ MemOperand src1(src0.rm(), src0.offset() + kIntSize); -+ MemOperand dst0 = g.ToMemOperand(destination); -+ MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize); -+ MachineRepresentation rep = LocationOperand::cast(source)->representation(); -+ if (rep == MachineRepresentation::kSimd128) { -+ UNIMPLEMENTED(); -+ } else { -+ FPURegister temp_1 = kScratchDoubleReg; -+ __ LoadDouble(temp_1, dst0); // Save destination in temp_1. -+ __ Lw(temp_0, src0); // Then use temp_0 to copy source to destination. -+ __ Sw(temp_0, dst0); -+ __ Lw(temp_0, src1); -+ __ Sw(temp_0, dst1); -+ __ StoreDouble(temp_1, src0); -+ } -+ } else { -+ // No other combinations are possible. -+ UNREACHABLE(); -+ } -+} -+ -+void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { -+ // On 64-bit RISC-V we emit the jump tables inline. -+ UNREACHABLE(); -+} -+ -+#undef ASSEMBLE_ATOMIC_LOAD_INTEGER -+#undef ASSEMBLE_ATOMIC_STORE_INTEGER -+#undef ASSEMBLE_ATOMIC_BINOP -+#undef ASSEMBLE_ATOMIC_BINOP_EXT -+#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER -+#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT -+#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER -+#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT -+#undef ASSEMBLE_IEEE754_BINOP -+#undef ASSEMBLE_IEEE754_UNOP -+ -+#undef TRACE_MSG -+#undef TRACE_UNIMPL -+#undef __ -+ -+} // namespace compiler -+} // namespace internal -+} // namespace v8 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/instruction-codes-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/instruction-codes-riscv64.h -@@ -0,0 +1,432 @@ -+// 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. -+ -+#ifndef V8_COMPILER_BACKEND_RISCV_INSTRUCTION_CODES_RISCV_H_ -+#define V8_COMPILER_BACKEND_RISCV_INSTRUCTION_CODES_RISCV_H_ -+ -+namespace v8 { -+namespace internal { -+namespace compiler { -+ -+// RISC-V-specific opcodes that specify which assembly sequence to emit. -+// Most opcodes specify a single instruction. -+#define TARGET_ARCH_OPCODE_LIST(V) \ -+ V(RiscvAdd32) \ -+ V(RiscvAdd64) \ -+ V(RiscvAddOvf64) \ -+ V(RiscvSub32) \ -+ V(RiscvSub64) \ -+ V(RiscvSubOvf64) \ -+ V(RiscvMul32) \ -+ V(RiscvMulOvf32) \ -+ V(RiscvMulHigh32) \ -+ V(RiscvMulHigh64) \ -+ V(RiscvMulHighU32) \ -+ V(RiscvMul64) \ -+ V(RiscvDiv32) \ -+ V(RiscvDiv64) \ -+ V(RiscvDivU32) \ -+ V(RiscvDivU64) \ -+ V(RiscvMod32) \ -+ V(RiscvMod64) \ -+ V(RiscvModU32) \ -+ V(RiscvModU64) \ -+ V(RiscvAnd) \ -+ V(RiscvAnd32) \ -+ V(RiscvOr) \ -+ V(RiscvOr32) \ -+ V(RiscvNor) \ -+ V(RiscvNor32) \ -+ V(RiscvXor) \ -+ V(RiscvXor32) \ -+ V(RiscvClz32) \ -+ V(RiscvShl32) \ -+ V(RiscvShr32) \ -+ V(RiscvSar32) \ -+ V(RiscvZeroExtendWord) \ -+ V(RiscvSignExtendWord) \ -+ V(RiscvClz64) \ -+ V(RiscvCtz32) \ -+ V(RiscvCtz64) \ -+ V(RiscvPopcnt32) \ -+ V(RiscvPopcnt64) \ -+ V(RiscvShl64) \ -+ V(RiscvShr64) \ -+ V(RiscvSar64) \ -+ V(RiscvRor32) \ -+ V(RiscvRor64) \ -+ V(RiscvMov) \ -+ V(RiscvTst) \ -+ V(RiscvCmp) \ -+ V(RiscvCmpS) \ -+ V(RiscvAddS) \ -+ V(RiscvSubS) \ -+ V(RiscvMulS) \ -+ V(RiscvDivS) \ -+ V(RiscvModS) \ -+ V(RiscvAbsS) \ -+ V(RiscvNegS) \ -+ V(RiscvSqrtS) \ -+ V(RiscvMaxS) \ -+ V(RiscvMinS) \ -+ V(RiscvCmpD) \ -+ V(RiscvAddD) \ -+ V(RiscvSubD) \ -+ V(RiscvMulD) \ -+ V(RiscvDivD) \ -+ V(RiscvModD) \ -+ V(RiscvAbsD) \ -+ V(RiscvNegD) \ -+ V(RiscvSqrtD) \ -+ V(RiscvMaxD) \ -+ V(RiscvMinD) \ -+ V(RiscvFloat64RoundDown) \ -+ V(RiscvFloat64RoundTruncate) \ -+ V(RiscvFloat64RoundUp) \ -+ V(RiscvFloat64RoundTiesEven) \ -+ V(RiscvFloat32RoundDown) \ -+ V(RiscvFloat32RoundTruncate) \ -+ V(RiscvFloat32RoundUp) \ -+ V(RiscvFloat32RoundTiesEven) \ -+ V(RiscvCvtSD) \ -+ V(RiscvCvtDS) \ -+ V(RiscvTruncWD) \ -+ V(RiscvRoundWD) \ -+ V(RiscvFloorWD) \ -+ V(RiscvCeilWD) \ -+ V(RiscvTruncWS) \ -+ V(RiscvRoundWS) \ -+ V(RiscvFloorWS) \ -+ V(RiscvCeilWS) \ -+ V(RiscvTruncLS) \ -+ V(RiscvTruncLD) \ -+ V(RiscvTruncUwD) \ -+ V(RiscvTruncUwS) \ -+ V(RiscvTruncUlS) \ -+ V(RiscvTruncUlD) \ -+ V(RiscvCvtDW) \ -+ V(RiscvCvtSL) \ -+ V(RiscvCvtSW) \ -+ V(RiscvCvtSUw) \ -+ V(RiscvCvtSUl) \ -+ V(RiscvCvtDL) \ -+ V(RiscvCvtDUw) \ -+ V(RiscvCvtDUl) \ -+ V(RiscvLb) \ -+ V(RiscvLbu) \ -+ V(RiscvSb) \ -+ V(RiscvLh) \ -+ V(RiscvUlh) \ -+ V(RiscvLhu) \ -+ V(RiscvUlhu) \ -+ V(RiscvSh) \ -+ V(RiscvUsh) \ -+ V(RiscvLd) \ -+ V(RiscvUld) \ -+ V(RiscvLw) \ -+ V(RiscvUlw) \ -+ V(RiscvLwu) \ -+ V(RiscvUlwu) \ -+ V(RiscvSw) \ -+ V(RiscvUsw) \ -+ V(RiscvSd) \ -+ V(RiscvUsd) \ -+ V(RiscvLoadFloat) \ -+ V(RiscvULoadFloat) \ -+ V(RiscvStoreFloat) \ -+ V(RiscvUStoreFloat) \ -+ V(RiscvLoadDouble) \ -+ V(RiscvULoadDouble) \ -+ V(RiscvStoreDouble) \ -+ V(RiscvUStoreDouble) \ -+ V(RiscvBitcastDL) \ -+ V(RiscvBitcastLD) \ -+ V(RiscvBitcastInt32ToFloat32) \ -+ V(RiscvBitcastFloat32ToInt32) \ -+ V(RiscvFloat64ExtractLowWord32) \ -+ V(RiscvFloat64ExtractHighWord32) \ -+ V(RiscvFloat64InsertLowWord32) \ -+ V(RiscvFloat64InsertHighWord32) \ -+ V(RiscvFloat32Max) \ -+ V(RiscvFloat64Max) \ -+ V(RiscvFloat32Min) \ -+ V(RiscvFloat64Min) \ -+ V(RiscvFloat64SilenceNaN) \ -+ V(RiscvPush) \ -+ V(RiscvPeek) \ -+ V(RiscvByteSwap64) \ -+ V(RiscvByteSwap32) \ -+ V(RiscvStoreToStackSlot) \ -+ V(RiscvStackClaim) \ -+ V(RiscvSignExtendByte) \ -+ V(RiscvSignExtendShort) \ -+ V(RiscvSync) \ -+ V(RiscvAssertEqual) \ -+ V(RiscvS128Const) \ -+ V(RiscvS128Zero) \ -+ V(RiscvS128AllOnes) \ -+ V(RiscvI32x4Splat) \ -+ V(RiscvI32x4ExtractLane) \ -+ V(RiscvI32x4ReplaceLane) \ -+ V(RiscvI32x4Add) \ -+ V(RiscvI32x4AddHoriz) \ -+ V(RiscvI32x4Sub) \ -+ V(RiscvF64x2Abs) \ -+ V(RiscvF64x2Neg) \ -+ V(RiscvF32x4Splat) \ -+ V(RiscvF32x4ExtractLane) \ -+ V(RiscvF32x4ReplaceLane) \ -+ V(RiscvF32x4SConvertI32x4) \ -+ V(RiscvF32x4UConvertI32x4) \ -+ V(RiscvI32x4Mul) \ -+ V(RiscvI32x4MaxS) \ -+ V(RiscvI32x4MinS) \ -+ V(RiscvI32x4Eq) \ -+ V(RiscvI32x4Ne) \ -+ V(RiscvI32x4Shl) \ -+ V(RiscvI32x4ShrS) \ -+ V(RiscvI32x4ShrU) \ -+ V(RiscvI32x4MaxU) \ -+ V(RiscvI32x4MinU) \ -+ V(RiscvF64x2Sqrt) \ -+ V(RiscvF64x2Add) \ -+ V(RiscvF64x2Sub) \ -+ V(RiscvF64x2Mul) \ -+ V(RiscvF64x2Div) \ -+ V(RiscvF64x2Min) \ -+ V(RiscvF64x2Max) \ -+ V(RiscvF64x2Eq) \ -+ V(RiscvF64x2Ne) \ -+ V(RiscvF64x2Lt) \ -+ V(RiscvF64x2Le) \ -+ V(RiscvF64x2Splat) \ -+ V(RiscvF64x2ExtractLane) \ -+ V(RiscvF64x2ReplaceLane) \ -+ V(RiscvF64x2Pmin) \ -+ V(RiscvF64x2Pmax) \ -+ V(RiscvF64x2Ceil) \ -+ V(RiscvF64x2Floor) \ -+ V(RiscvF64x2Trunc) \ -+ V(RiscvF64x2NearestInt) \ -+ V(RiscvI64x2Splat) \ -+ V(RiscvI64x2ExtractLane) \ -+ V(RiscvI64x2ReplaceLane) \ -+ V(RiscvI64x2Add) \ -+ V(RiscvI64x2Sub) \ -+ V(RiscvI64x2Mul) \ -+ V(RiscvI64x2Neg) \ -+ V(RiscvI64x2Shl) \ -+ V(RiscvI64x2ShrS) \ -+ V(RiscvI64x2ShrU) \ -+ V(RiscvF32x4Abs) \ -+ V(RiscvF32x4Neg) \ -+ V(RiscvF32x4Sqrt) \ -+ V(RiscvF32x4RecipApprox) \ -+ V(RiscvF32x4RecipSqrtApprox) \ -+ V(RiscvF32x4Add) \ -+ V(RiscvF32x4AddHoriz) \ -+ V(RiscvF32x4Sub) \ -+ V(RiscvF32x4Mul) \ -+ V(RiscvF32x4Div) \ -+ V(RiscvF32x4Max) \ -+ V(RiscvF32x4Min) \ -+ V(RiscvF32x4Eq) \ -+ V(RiscvF32x4Ne) \ -+ V(RiscvF32x4Lt) \ -+ V(RiscvF32x4Le) \ -+ V(RiscvF32x4Pmin) \ -+ V(RiscvF32x4Pmax) \ -+ V(RiscvF32x4Ceil) \ -+ V(RiscvF32x4Floor) \ -+ V(RiscvF32x4Trunc) \ -+ V(RiscvF32x4NearestInt) \ -+ V(RiscvI32x4SConvertF32x4) \ -+ V(RiscvI32x4UConvertF32x4) \ -+ V(RiscvI32x4Neg) \ -+ V(RiscvI32x4GtS) \ -+ V(RiscvI32x4GeS) \ -+ V(RiscvI32x4GtU) \ -+ V(RiscvI32x4GeU) \ -+ V(RiscvI32x4Abs) \ -+ V(RiscvI32x4BitMask) \ -+ V(RiscvI16x8Splat) \ -+ V(RiscvI16x8ExtractLaneU) \ -+ V(RiscvI16x8ExtractLaneS) \ -+ V(RiscvI16x8ReplaceLane) \ -+ V(RiscvI16x8Neg) \ -+ V(RiscvI16x8Shl) \ -+ V(RiscvI16x8ShrS) \ -+ V(RiscvI16x8ShrU) \ -+ V(RiscvI16x8Add) \ -+ V(RiscvI16x8AddSaturateS) \ -+ V(RiscvI16x8AddHoriz) \ -+ V(RiscvI16x8Sub) \ -+ V(RiscvI16x8SubSaturateS) \ -+ V(RiscvI16x8Mul) \ -+ V(RiscvI16x8MaxS) \ -+ V(RiscvI16x8MinS) \ -+ V(RiscvI16x8Eq) \ -+ V(RiscvI16x8Ne) \ -+ V(RiscvI16x8GtS) \ -+ V(RiscvI16x8GeS) \ -+ V(RiscvI16x8AddSaturateU) \ -+ V(RiscvI16x8SubSaturateU) \ -+ V(RiscvI16x8MaxU) \ -+ V(RiscvI16x8MinU) \ -+ V(RiscvI16x8GtU) \ -+ V(RiscvI16x8GeU) \ -+ V(RiscvI16x8RoundingAverageU) \ -+ V(RiscvI16x8Abs) \ -+ V(RiscvI16x8BitMask) \ -+ V(RiscvI8x16Splat) \ -+ V(RiscvI8x16ExtractLaneU) \ -+ V(RiscvI8x16ExtractLaneS) \ -+ V(RiscvI8x16ReplaceLane) \ -+ V(RiscvI8x16Neg) \ -+ V(RiscvI8x16Shl) \ -+ V(RiscvI8x16ShrS) \ -+ V(RiscvI8x16Add) \ -+ V(RiscvI8x16AddSaturateS) \ -+ V(RiscvI8x16Sub) \ -+ V(RiscvI8x16SubSaturateS) \ -+ V(RiscvI8x16Mul) \ -+ V(RiscvI8x16MaxS) \ -+ V(RiscvI8x16MinS) \ -+ V(RiscvI8x16Eq) \ -+ V(RiscvI8x16Ne) \ -+ V(RiscvI8x16GtS) \ -+ V(RiscvI8x16GeS) \ -+ V(RiscvI8x16ShrU) \ -+ V(RiscvI8x16AddSaturateU) \ -+ V(RiscvI8x16SubSaturateU) \ -+ V(RiscvI8x16MaxU) \ -+ V(RiscvI8x16MinU) \ -+ V(RiscvI8x16GtU) \ -+ V(RiscvI8x16GeU) \ -+ V(RiscvI8x16RoundingAverageU) \ -+ V(RiscvI8x16Abs) \ -+ V(RiscvI8x16BitMask) \ -+ V(RiscvS128And) \ -+ V(RiscvS128Or) \ -+ V(RiscvS128Xor) \ -+ V(RiscvS128Not) \ -+ V(RiscvS128Select) \ -+ V(RiscvS128AndNot) \ -+ V(RiscvV32x4AnyTrue) \ -+ V(RiscvV32x4AllTrue) \ -+ V(RiscvV16x8AnyTrue) \ -+ V(RiscvV16x8AllTrue) \ -+ V(RiscvV8x16AnyTrue) \ -+ V(RiscvV8x16AllTrue) \ -+ V(RiscvS32x4InterleaveRight) \ -+ V(RiscvS32x4InterleaveLeft) \ -+ V(RiscvS32x4PackEven) \ -+ V(RiscvS32x4PackOdd) \ -+ V(RiscvS32x4InterleaveEven) \ -+ V(RiscvS32x4InterleaveOdd) \ -+ V(RiscvS32x4Shuffle) \ -+ V(RiscvS16x8InterleaveRight) \ -+ V(RiscvS16x8InterleaveLeft) \ -+ V(RiscvS16x8PackEven) \ -+ V(RiscvS16x8PackOdd) \ -+ V(RiscvS16x8InterleaveEven) \ -+ V(RiscvS16x8InterleaveOdd) \ -+ V(RiscvS16x4Reverse) \ -+ V(RiscvS16x2Reverse) \ -+ V(RiscvS8x16InterleaveRight) \ -+ V(RiscvS8x16InterleaveLeft) \ -+ V(RiscvS8x16PackEven) \ -+ V(RiscvS8x16PackOdd) \ -+ V(RiscvS8x16InterleaveEven) \ -+ V(RiscvS8x16InterleaveOdd) \ -+ V(RiscvI8x16Shuffle) \ -+ V(RiscvI8x16Swizzle) \ -+ V(RiscvS8x16Concat) \ -+ V(RiscvS8x8Reverse) \ -+ V(RiscvS8x4Reverse) \ -+ V(RiscvS8x2Reverse) \ -+ V(RiscvS8x16LoadSplat) \ -+ V(RiscvS16x8LoadSplat) \ -+ V(RiscvS32x4LoadSplat) \ -+ V(RiscvS64x2LoadSplat) \ -+ V(RiscvI16x8Load8x8S) \ -+ V(RiscvI16x8Load8x8U) \ -+ V(RiscvI32x4Load16x4S) \ -+ V(RiscvI32x4Load16x4U) \ -+ V(RiscvI64x2Load32x2S) \ -+ V(RiscvI64x2Load32x2U) \ -+ V(RiscvMsaLd) \ -+ V(RiscvMsaSt) \ -+ V(RiscvI32x4SConvertI16x8Low) \ -+ V(RiscvI32x4SConvertI16x8High) \ -+ V(RiscvI32x4UConvertI16x8Low) \ -+ V(RiscvI32x4UConvertI16x8High) \ -+ V(RiscvI16x8SConvertI8x16Low) \ -+ V(RiscvI16x8SConvertI8x16High) \ -+ V(RiscvI16x8SConvertI32x4) \ -+ V(RiscvI16x8UConvertI32x4) \ -+ V(RiscvI16x8UConvertI8x16Low) \ -+ V(RiscvI16x8UConvertI8x16High) \ -+ V(RiscvI8x16SConvertI16x8) \ -+ V(RiscvI8x16UConvertI16x8) \ -+ V(RiscvWord64AtomicLoadUint8) \ -+ V(RiscvWord64AtomicLoadUint16) \ -+ V(RiscvWord64AtomicLoadUint32) \ -+ V(RiscvWord64AtomicLoadUint64) \ -+ V(RiscvWord64AtomicStoreWord8) \ -+ V(RiscvWord64AtomicStoreWord16) \ -+ V(RiscvWord64AtomicStoreWord32) \ -+ V(RiscvWord64AtomicStoreWord64) \ -+ V(RiscvWord64AtomicAddUint8) \ -+ V(RiscvWord64AtomicAddUint16) \ -+ V(RiscvWord64AtomicAddUint32) \ -+ V(RiscvWord64AtomicAddUint64) \ -+ V(RiscvWord64AtomicSubUint8) \ -+ V(RiscvWord64AtomicSubUint16) \ -+ V(RiscvWord64AtomicSubUint32) \ -+ V(RiscvWord64AtomicSubUint64) \ -+ V(RiscvWord64AtomicAndUint8) \ -+ V(RiscvWord64AtomicAndUint16) \ -+ V(RiscvWord64AtomicAndUint32) \ -+ V(RiscvWord64AtomicAndUint64) \ -+ V(RiscvWord64AtomicOrUint8) \ -+ V(RiscvWord64AtomicOrUint16) \ -+ V(RiscvWord64AtomicOrUint32) \ -+ V(RiscvWord64AtomicOrUint64) \ -+ V(RiscvWord64AtomicXorUint8) \ -+ V(RiscvWord64AtomicXorUint16) \ -+ V(RiscvWord64AtomicXorUint32) \ -+ V(RiscvWord64AtomicXorUint64) \ -+ V(RiscvWord64AtomicExchangeUint8) \ -+ V(RiscvWord64AtomicExchangeUint16) \ -+ V(RiscvWord64AtomicExchangeUint32) \ -+ V(RiscvWord64AtomicExchangeUint64) \ -+ V(RiscvWord64AtomicCompareExchangeUint8) \ -+ V(RiscvWord64AtomicCompareExchangeUint16) \ -+ V(RiscvWord64AtomicCompareExchangeUint32) \ -+ V(RiscvWord64AtomicCompareExchangeUint64) -+ -+// Addressing modes represent the "shape" of inputs to an instruction. -+// Many instructions support multiple addressing modes. Addressing modes -+// are encoded into the InstructionCode of the instruction and tell the -+// code generator after register allocation which assembler method to call. -+// -+// We use the following local notation for addressing modes: -+// -+// R = register -+// O = register or stack slot -+// D = double register -+// I = immediate (handle, external, int32) -+// MRI = [register + immediate] -+// MRR = [register + register] -+// TODO(plind): Add the new r6 address modes. -+#define TARGET_ADDRESSING_MODE_LIST(V) \ -+ V(MRI) /* [%r0 + K] */ \ -+ V(MRR) /* [%r0 + %r1] */ -+ -+} // namespace compiler -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_COMPILER_BACKEND_RISCV_INSTRUCTION_CODES_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/instruction-scheduler-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/instruction-scheduler-riscv64.cc -@@ -0,0 +1,1571 @@ -+// Copyright 2015 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. -+ -+#include "src/codegen/macro-assembler.h" -+#include "src/compiler/backend/instruction-scheduler.h" -+ -+namespace v8 { -+namespace internal { -+namespace compiler { -+ -+bool InstructionScheduler::SchedulerSupported() { return true; } -+ -+int InstructionScheduler::GetTargetInstructionFlags( -+ const Instruction* instr) const { -+ switch (instr->arch_opcode()) { -+ case kRiscvAbsD: -+ case kRiscvAbsS: -+ case kRiscvAdd32: -+ case kRiscvAddD: -+ case kRiscvAddS: -+ case kRiscvAnd: -+ case kRiscvAnd32: -+ case kRiscvAssertEqual: -+ case kRiscvBitcastDL: -+ case kRiscvBitcastLD: -+ case kRiscvBitcastInt32ToFloat32: -+ case kRiscvBitcastFloat32ToInt32: -+ case kRiscvByteSwap32: -+ case kRiscvByteSwap64: -+ case kRiscvCeilWD: -+ case kRiscvCeilWS: -+ case kRiscvClz32: -+ case kRiscvCmp: -+ case kRiscvCmpD: -+ case kRiscvCmpS: -+ case kRiscvCtz32: -+ case kRiscvCvtDL: -+ case kRiscvCvtDS: -+ case kRiscvCvtDUl: -+ case kRiscvCvtDUw: -+ case kRiscvCvtDW: -+ case kRiscvCvtSD: -+ case kRiscvCvtSL: -+ case kRiscvCvtSUl: -+ case kRiscvCvtSUw: -+ case kRiscvCvtSW: -+ case kRiscvMulHigh64: -+ case kRiscvMulHighU32: -+ case kRiscvAdd64: -+ case kRiscvAddOvf64: -+ case kRiscvClz64: -+ case kRiscvCtz64: -+ case kRiscvDiv64: -+ case kRiscvDivU64: -+ case kRiscvZeroExtendWord: -+ case kRiscvSignExtendWord: -+ case kRiscvDiv32: -+ case kRiscvDivD: -+ case kRiscvDivS: -+ case kRiscvDivU32: -+ case kRiscvMod64: -+ case kRiscvModU64: -+ case kRiscvMul64: -+ case kRiscvPopcnt64: -+ case kRiscvRor64: -+ case kRiscvSar64: -+ case kRiscvShl64: -+ case kRiscvShr64: -+ case kRiscvSub64: -+ case kRiscvSubOvf64: -+ case kRiscvF64x2Abs: -+ case kRiscvF64x2Neg: -+ case kRiscvF64x2Sqrt: -+ case kRiscvF64x2Add: -+ case kRiscvF64x2Sub: -+ case kRiscvF64x2Mul: -+ case kRiscvF64x2Div: -+ case kRiscvF64x2Min: -+ case kRiscvF64x2Max: -+ case kRiscvF64x2Eq: -+ case kRiscvF64x2Ne: -+ case kRiscvF64x2Lt: -+ case kRiscvF64x2Le: -+ case kRiscvF64x2Pmin: -+ case kRiscvF64x2Pmax: -+ case kRiscvF64x2Ceil: -+ case kRiscvF64x2Floor: -+ case kRiscvF64x2Trunc: -+ case kRiscvF64x2NearestInt: -+ case kRiscvI64x2Splat: -+ case kRiscvI64x2ExtractLane: -+ case kRiscvI64x2ReplaceLane: -+ case kRiscvI64x2Add: -+ case kRiscvI64x2Sub: -+ case kRiscvI64x2Mul: -+ case kRiscvI64x2Neg: -+ case kRiscvI64x2Shl: -+ case kRiscvI64x2ShrS: -+ case kRiscvI64x2ShrU: -+ case kRiscvF32x4Abs: -+ case kRiscvF32x4Add: -+ case kRiscvF32x4AddHoriz: -+ case kRiscvF32x4Eq: -+ case kRiscvF32x4ExtractLane: -+ case kRiscvF32x4Lt: -+ case kRiscvF32x4Le: -+ case kRiscvF32x4Max: -+ case kRiscvF32x4Min: -+ case kRiscvF32x4Mul: -+ case kRiscvF32x4Div: -+ case kRiscvF32x4Ne: -+ case kRiscvF32x4Neg: -+ case kRiscvF32x4Sqrt: -+ case kRiscvF32x4RecipApprox: -+ case kRiscvF32x4RecipSqrtApprox: -+ case kRiscvF32x4ReplaceLane: -+ case kRiscvF32x4SConvertI32x4: -+ case kRiscvF32x4Splat: -+ case kRiscvF32x4Sub: -+ case kRiscvF32x4UConvertI32x4: -+ case kRiscvF32x4Pmin: -+ case kRiscvF32x4Pmax: -+ case kRiscvF32x4Ceil: -+ case kRiscvF32x4Floor: -+ case kRiscvF32x4Trunc: -+ case kRiscvF32x4NearestInt: -+ case kRiscvF64x2Splat: -+ case kRiscvF64x2ExtractLane: -+ case kRiscvF64x2ReplaceLane: -+ case kRiscvFloat32Max: -+ case kRiscvFloat32Min: -+ case kRiscvFloat32RoundDown: -+ case kRiscvFloat32RoundTiesEven: -+ case kRiscvFloat32RoundTruncate: -+ case kRiscvFloat32RoundUp: -+ case kRiscvFloat64ExtractLowWord32: -+ case kRiscvFloat64ExtractHighWord32: -+ case kRiscvFloat64InsertLowWord32: -+ case kRiscvFloat64InsertHighWord32: -+ case kRiscvFloat64Max: -+ case kRiscvFloat64Min: -+ case kRiscvFloat64RoundDown: -+ case kRiscvFloat64RoundTiesEven: -+ case kRiscvFloat64RoundTruncate: -+ case kRiscvFloat64RoundUp: -+ case kRiscvFloat64SilenceNaN: -+ case kRiscvFloorWD: -+ case kRiscvFloorWS: -+ case kRiscvI16x8Add: -+ case kRiscvI16x8AddHoriz: -+ case kRiscvI16x8AddSaturateS: -+ case kRiscvI16x8AddSaturateU: -+ case kRiscvI16x8Eq: -+ case kRiscvI16x8ExtractLaneU: -+ case kRiscvI16x8ExtractLaneS: -+ case kRiscvI16x8GeS: -+ case kRiscvI16x8GeU: -+ case kRiscvI16x8GtS: -+ case kRiscvI16x8GtU: -+ case kRiscvI16x8MaxS: -+ case kRiscvI16x8MaxU: -+ case kRiscvI16x8MinS: -+ case kRiscvI16x8MinU: -+ case kRiscvI16x8Mul: -+ case kRiscvI16x8Ne: -+ case kRiscvI16x8Neg: -+ case kRiscvI16x8ReplaceLane: -+ case kRiscvI8x16SConvertI16x8: -+ case kRiscvI16x8SConvertI32x4: -+ case kRiscvI16x8SConvertI8x16High: -+ case kRiscvI16x8SConvertI8x16Low: -+ case kRiscvI16x8Shl: -+ case kRiscvI16x8ShrS: -+ case kRiscvI16x8ShrU: -+ case kRiscvI16x8Splat: -+ case kRiscvI16x8Sub: -+ case kRiscvI16x8SubSaturateS: -+ case kRiscvI16x8SubSaturateU: -+ case kRiscvI8x16UConvertI16x8: -+ case kRiscvI16x8UConvertI32x4: -+ case kRiscvI16x8UConvertI8x16High: -+ case kRiscvI16x8UConvertI8x16Low: -+ case kRiscvI16x8RoundingAverageU: -+ case kRiscvI16x8Abs: -+ case kRiscvI16x8BitMask: -+ case kRiscvI32x4Add: -+ case kRiscvI32x4AddHoriz: -+ case kRiscvI32x4Eq: -+ case kRiscvI32x4ExtractLane: -+ case kRiscvI32x4GeS: -+ case kRiscvI32x4GeU: -+ case kRiscvI32x4GtS: -+ case kRiscvI32x4GtU: -+ case kRiscvI32x4MaxS: -+ case kRiscvI32x4MaxU: -+ case kRiscvI32x4MinS: -+ case kRiscvI32x4MinU: -+ case kRiscvI32x4Mul: -+ case kRiscvI32x4Ne: -+ case kRiscvI32x4Neg: -+ case kRiscvI32x4ReplaceLane: -+ case kRiscvI32x4SConvertF32x4: -+ case kRiscvI32x4SConvertI16x8High: -+ case kRiscvI32x4SConvertI16x8Low: -+ case kRiscvI32x4Shl: -+ case kRiscvI32x4ShrS: -+ case kRiscvI32x4ShrU: -+ case kRiscvI32x4Splat: -+ case kRiscvI32x4Sub: -+ case kRiscvI32x4UConvertF32x4: -+ case kRiscvI32x4UConvertI16x8High: -+ case kRiscvI32x4UConvertI16x8Low: -+ case kRiscvI32x4Abs: -+ case kRiscvI32x4BitMask: -+ case kRiscvI8x16Add: -+ case kRiscvI8x16AddSaturateS: -+ case kRiscvI8x16AddSaturateU: -+ case kRiscvI8x16Eq: -+ case kRiscvI8x16ExtractLaneU: -+ case kRiscvI8x16ExtractLaneS: -+ case kRiscvI8x16GeS: -+ case kRiscvI8x16GeU: -+ case kRiscvI8x16GtS: -+ case kRiscvI8x16GtU: -+ case kRiscvI8x16MaxS: -+ case kRiscvI8x16MaxU: -+ case kRiscvI8x16MinS: -+ case kRiscvI8x16MinU: -+ case kRiscvI8x16Mul: -+ case kRiscvI8x16Ne: -+ case kRiscvI8x16Neg: -+ case kRiscvI8x16ReplaceLane: -+ case kRiscvI8x16Shl: -+ case kRiscvI8x16ShrS: -+ case kRiscvI8x16ShrU: -+ case kRiscvI8x16Splat: -+ case kRiscvI8x16Sub: -+ case kRiscvI8x16SubSaturateS: -+ case kRiscvI8x16SubSaturateU: -+ case kRiscvI8x16RoundingAverageU: -+ case kRiscvI8x16Abs: -+ case kRiscvI8x16BitMask: -+ case kRiscvMaxD: -+ case kRiscvMaxS: -+ case kRiscvMinD: -+ case kRiscvMinS: -+ case kRiscvMod32: -+ case kRiscvModU32: -+ case kRiscvMov: -+ case kRiscvMul32: -+ case kRiscvMulD: -+ case kRiscvMulHigh32: -+ case kRiscvMulOvf32: -+ case kRiscvMulS: -+ case kRiscvNegD: -+ case kRiscvNegS: -+ case kRiscvNor: -+ case kRiscvNor32: -+ case kRiscvOr: -+ case kRiscvOr32: -+ case kRiscvPopcnt32: -+ case kRiscvRor32: -+ case kRiscvRoundWD: -+ case kRiscvRoundWS: -+ case kRiscvS128And: -+ case kRiscvS128Or: -+ case kRiscvS128Not: -+ case kRiscvS128Select: -+ case kRiscvS128AndNot: -+ case kRiscvS128Xor: -+ case kRiscvS128Const: -+ case kRiscvS128Zero: -+ case kRiscvS128AllOnes: -+ case kRiscvS16x8InterleaveEven: -+ case kRiscvS16x8InterleaveOdd: -+ case kRiscvS16x8InterleaveLeft: -+ case kRiscvS16x8InterleaveRight: -+ case kRiscvS16x8PackEven: -+ case kRiscvS16x8PackOdd: -+ case kRiscvS16x2Reverse: -+ case kRiscvS16x4Reverse: -+ case kRiscvV8x16AllTrue: -+ case kRiscvV8x16AnyTrue: -+ case kRiscvV32x4AllTrue: -+ case kRiscvV32x4AnyTrue: -+ case kRiscvV16x8AllTrue: -+ case kRiscvV16x8AnyTrue: -+ case kRiscvS32x4InterleaveEven: -+ case kRiscvS32x4InterleaveOdd: -+ case kRiscvS32x4InterleaveLeft: -+ case kRiscvS32x4InterleaveRight: -+ case kRiscvS32x4PackEven: -+ case kRiscvS32x4PackOdd: -+ case kRiscvS32x4Shuffle: -+ case kRiscvS8x16Concat: -+ case kRiscvS8x16InterleaveEven: -+ case kRiscvS8x16InterleaveOdd: -+ case kRiscvS8x16InterleaveLeft: -+ case kRiscvS8x16InterleaveRight: -+ case kRiscvS8x16PackEven: -+ case kRiscvS8x16PackOdd: -+ case kRiscvS8x2Reverse: -+ case kRiscvS8x4Reverse: -+ case kRiscvS8x8Reverse: -+ case kRiscvI8x16Shuffle: -+ case kRiscvI8x16Swizzle: -+ case kRiscvSar32: -+ case kRiscvSignExtendByte: -+ case kRiscvSignExtendShort: -+ case kRiscvShl32: -+ case kRiscvShr32: -+ case kRiscvSqrtD: -+ case kRiscvSqrtS: -+ case kRiscvSub32: -+ case kRiscvSubD: -+ case kRiscvSubS: -+ case kRiscvTruncLD: -+ case kRiscvTruncLS: -+ case kRiscvTruncUlD: -+ case kRiscvTruncUlS: -+ case kRiscvTruncUwD: -+ case kRiscvTruncUwS: -+ case kRiscvTruncWD: -+ case kRiscvTruncWS: -+ case kRiscvTst: -+ case kRiscvXor: -+ case kRiscvXor32: -+ return kNoOpcodeFlags; -+ -+ case kRiscvLb: -+ case kRiscvLbu: -+ case kRiscvLd: -+ case kRiscvLoadDouble: -+ case kRiscvLh: -+ case kRiscvLhu: -+ case kRiscvLw: -+ case kRiscvLoadFloat: -+ case kRiscvLwu: -+ case kRiscvMsaLd: -+ case kRiscvPeek: -+ case kRiscvUld: -+ case kRiscvULoadDouble: -+ case kRiscvUlh: -+ case kRiscvUlhu: -+ case kRiscvUlw: -+ case kRiscvUlwu: -+ case kRiscvULoadFloat: -+ case kRiscvS8x16LoadSplat: -+ case kRiscvS16x8LoadSplat: -+ case kRiscvS32x4LoadSplat: -+ case kRiscvS64x2LoadSplat: -+ case kRiscvI16x8Load8x8S: -+ case kRiscvI16x8Load8x8U: -+ case kRiscvI32x4Load16x4S: -+ case kRiscvI32x4Load16x4U: -+ case kRiscvI64x2Load32x2S: -+ case kRiscvI64x2Load32x2U: -+ case kRiscvWord64AtomicLoadUint8: -+ case kRiscvWord64AtomicLoadUint16: -+ case kRiscvWord64AtomicLoadUint32: -+ case kRiscvWord64AtomicLoadUint64: -+ -+ return kIsLoadOperation; -+ -+ case kRiscvModD: -+ case kRiscvModS: -+ case kRiscvMsaSt: -+ case kRiscvPush: -+ case kRiscvSb: -+ case kRiscvSd: -+ case kRiscvStoreDouble: -+ case kRiscvSh: -+ case kRiscvStackClaim: -+ case kRiscvStoreToStackSlot: -+ case kRiscvSw: -+ case kRiscvStoreFloat: -+ case kRiscvUsd: -+ case kRiscvUStoreDouble: -+ case kRiscvUsh: -+ case kRiscvUsw: -+ case kRiscvUStoreFloat: -+ case kRiscvSync: -+ case kRiscvWord64AtomicStoreWord8: -+ case kRiscvWord64AtomicStoreWord16: -+ case kRiscvWord64AtomicStoreWord32: -+ case kRiscvWord64AtomicStoreWord64: -+ case kRiscvWord64AtomicAddUint8: -+ case kRiscvWord64AtomicAddUint16: -+ case kRiscvWord64AtomicAddUint32: -+ case kRiscvWord64AtomicAddUint64: -+ case kRiscvWord64AtomicSubUint8: -+ case kRiscvWord64AtomicSubUint16: -+ case kRiscvWord64AtomicSubUint32: -+ case kRiscvWord64AtomicSubUint64: -+ case kRiscvWord64AtomicAndUint8: -+ case kRiscvWord64AtomicAndUint16: -+ case kRiscvWord64AtomicAndUint32: -+ case kRiscvWord64AtomicAndUint64: -+ case kRiscvWord64AtomicOrUint8: -+ case kRiscvWord64AtomicOrUint16: -+ case kRiscvWord64AtomicOrUint32: -+ case kRiscvWord64AtomicOrUint64: -+ case kRiscvWord64AtomicXorUint8: -+ case kRiscvWord64AtomicXorUint16: -+ case kRiscvWord64AtomicXorUint32: -+ case kRiscvWord64AtomicXorUint64: -+ case kRiscvWord64AtomicExchangeUint8: -+ case kRiscvWord64AtomicExchangeUint16: -+ case kRiscvWord64AtomicExchangeUint32: -+ case kRiscvWord64AtomicExchangeUint64: -+ case kRiscvWord64AtomicCompareExchangeUint8: -+ case kRiscvWord64AtomicCompareExchangeUint16: -+ case kRiscvWord64AtomicCompareExchangeUint32: -+ case kRiscvWord64AtomicCompareExchangeUint64: -+ return kHasSideEffect; -+ -+#define CASE(Name) case k##Name: -+ COMMON_ARCH_OPCODE_LIST(CASE) -+#undef CASE -+ // Already covered in architecture independent code. -+ UNREACHABLE(); -+ } -+ -+ UNREACHABLE(); -+} -+ -+enum Latency { -+ BRANCH = 4, // Estimated max. -+ RINT_S = 4, // Estimated. -+ RINT_D = 4, // Estimated. -+ -+ // FIXME (RISCV): remove MULT instructions (MIPS legacy) -+ MULT = 4, -+ MULTU = 4, -+ DMULT = 4, -+ -+ MUL32 = 7, -+ -+ DIV32 = 50, // Min:11 Max:50 -+ DIV64 = 50, -+ DIVU32 = 50, -+ DIVU64 = 50, -+ -+ ABS_S = 4, -+ ABS_D = 4, -+ NEG_S = 4, -+ NEG_D = 4, -+ ADD_S = 4, -+ ADD_D = 4, -+ SUB_S = 4, -+ SUB_D = 4, -+ MAX_S = 4, // Estimated. -+ MIN_S = 4, -+ MAX_D = 4, // Estimated. -+ MIN_D = 4, -+ C_cond_S = 4, -+ C_cond_D = 4, -+ MUL_S = 4, -+ -+ MADD_S = 4, -+ MSUB_S = 4, -+ NMADD_S = 4, -+ NMSUB_S = 4, -+ -+ CABS_cond_S = 4, -+ CABS_cond_D = 4, -+ -+ CVT_D_S = 4, -+ CVT_PS_PW = 4, -+ -+ CVT_S_W = 4, -+ CVT_S_L = 4, -+ CVT_D_W = 4, -+ CVT_D_L = 4, -+ -+ CVT_S_D = 4, -+ -+ CVT_W_S = 4, -+ CVT_W_D = 4, -+ CVT_L_S = 4, -+ CVT_L_D = 4, -+ -+ CEIL_W_S = 4, -+ CEIL_W_D = 4, -+ CEIL_L_S = 4, -+ CEIL_L_D = 4, -+ -+ FLOOR_W_S = 4, -+ FLOOR_W_D = 4, -+ FLOOR_L_S = 4, -+ FLOOR_L_D = 4, -+ -+ ROUND_W_S = 4, -+ ROUND_W_D = 4, -+ ROUND_L_S = 4, -+ ROUND_L_D = 4, -+ -+ TRUNC_W_S = 4, -+ TRUNC_W_D = 4, -+ TRUNC_L_S = 4, -+ TRUNC_L_D = 4, -+ -+ MOV_S = 4, -+ MOV_D = 4, -+ -+ MOVF_S = 4, -+ MOVF_D = 4, -+ -+ MOVN_S = 4, -+ MOVN_D = 4, -+ -+ MOVT_S = 4, -+ MOVT_D = 4, -+ -+ MOVZ_S = 4, -+ MOVZ_D = 4, -+ -+ MUL_D = 5, -+ MADD_D = 5, -+ MSUB_D = 5, -+ NMADD_D = 5, -+ NMSUB_D = 5, -+ -+ RECIP_S = 13, -+ RECIP_D = 26, -+ -+ RSQRT_S = 17, -+ RSQRT_D = 36, -+ -+ DIV_S = 17, -+ SQRT_S = 17, -+ -+ DIV_D = 32, -+ SQRT_D = 32, -+ -+ MOVT_FREG = 4, -+ MOVT_HIGH_FREG = 4, -+ MOVT_DREG = 4, -+ LOAD_FLOAT = 4, -+ LOAD_DOUBLE = 4, -+ -+ MOVF_FREG = 1, -+ MOVF_HIGH_FREG = 1, -+ MOVF_HIGH_DREG = 1, -+ MOVF_HIGH = 1, -+ MOVF_LOW = 1, -+ STORE_FLOAT = 1, -+ STORE_DOUBLE = 1, -+}; -+ -+int Add64Latency(bool is_operand_register = true) { -+ if (is_operand_register) { -+ return 1; -+ } else { -+ return 2; // Estimated max. -+ } -+} -+ -+int Sub64Latency(bool is_operand_register = true) { -+ return Add64Latency(is_operand_register); -+} -+ -+int AndLatency(bool is_operand_register = true) { -+ return Add64Latency(is_operand_register); -+} -+ -+int OrLatency(bool is_operand_register = true) { -+ return Add64Latency(is_operand_register); -+} -+ -+int NorLatency(bool is_operand_register = true) { -+ if (is_operand_register) { -+ return 1; -+ } else { -+ return 2; // Estimated max. -+ } -+} -+ -+int XorLatency(bool is_operand_register = true) { -+ return Add64Latency(is_operand_register); -+} -+ -+int Mul32Latency(bool is_operand_register = true) { -+ if (is_operand_register) { -+ return Latency::MUL32; -+ } else { -+ return Latency::MUL32 + 1; -+ } -+} -+ -+int Mul64Latency(bool is_operand_register = true) { -+ int latency = Latency::DMULT + Latency::MOVF_LOW; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Mulh32Latency(bool is_operand_register = true) { -+ int latency = Latency::MULT + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Mulhu32Latency(bool is_operand_register = true) { -+ int latency = Latency::MULTU + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Mulh64Latency(bool is_operand_register = true) { -+ int latency = Latency::DMULT + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Div32Latency(bool is_operand_register = true) { -+ if (is_operand_register) { -+ return Latency::DIV32; -+ } else { -+ return Latency::DIV32 + 1; -+ } -+} -+ -+int Divu32Latency(bool is_operand_register = true) { -+ if (is_operand_register) { -+ return Latency::DIVU32; -+ } else { -+ return Latency::DIVU32 + 1; -+ } -+} -+ -+int Div64Latency(bool is_operand_register = true) { -+ int latency = Latency::DIV64 + Latency::MOVF_LOW; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Divu64Latency(bool is_operand_register = true) { -+ int latency = Latency::DIVU64 + Latency::MOVF_LOW; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Mod32Latency(bool is_operand_register = true) { -+ int latency = Latency::DIV32 + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Modu32Latency(bool is_operand_register = true) { -+ int latency = Latency::DIVU32 + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Mod64Latency(bool is_operand_register = true) { -+ int latency = Latency::DIV64 + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int Modu64Latency(bool is_operand_register = true) { -+ int latency = Latency::DIV64 + Latency::MOVF_HIGH; -+ if (!is_operand_register) { -+ latency += 1; -+ } -+ return latency; -+} -+ -+int MovzLatency() { return 1; } -+ -+int MovnLatency() { return 1; } -+ -+int CallLatency() { -+ // Estimated. -+ return Add64Latency(false) + Latency::BRANCH + 5; -+} -+ -+int JumpLatency() { -+ // Estimated max. -+ return 1 + Add64Latency() + Latency::BRANCH + 2; -+} -+ -+int SmiUntagLatency() { return 1; } -+ -+int PrepareForTailCallLatency() { -+ // Estimated max. -+ return 2 * (Add64Latency() + 1 + Add64Latency(false)) + 2 + Latency::BRANCH + -+ Latency::BRANCH + 2 * Sub64Latency(false) + 2 + Latency::BRANCH + 1; -+} -+ -+int AssemblePopArgumentsAdoptFrameLatency() { -+ return 1 + Latency::BRANCH + 1 + SmiUntagLatency() + -+ PrepareForTailCallLatency(); -+} -+ -+int AssertLatency() { return 1; } -+ -+int PrepareCallCFunctionLatency() { -+ int frame_alignment = TurboAssembler::ActivationFrameAlignment(); -+ if (frame_alignment > kSystemPointerSize) { -+ return 1 + Sub64Latency(false) + AndLatency(false) + 1; -+ } else { -+ return Sub64Latency(false); -+ } -+} -+ -+int AdjustBaseAndOffsetLatency() { -+ return 3; // Estimated max. -+} -+ -+int AlignedMemoryLatency() { return AdjustBaseAndOffsetLatency() + 1; } -+ -+int UlhuLatency() { -+ return AdjustBaseAndOffsetLatency() + 2 * AlignedMemoryLatency() + 2; -+} -+ -+int UlwLatency() { -+ // Estimated max. -+ return AdjustBaseAndOffsetLatency() + 3; -+} -+ -+int UlwuLatency() { return UlwLatency() + 1; } -+ -+int UldLatency() { -+ // Estimated max. -+ return AdjustBaseAndOffsetLatency() + 3; -+} -+ -+int ULoadFloatLatency() { return UlwLatency() + Latency::MOVT_FREG; } -+ -+int ULoadDoubleLatency() { return UldLatency() + Latency::MOVT_DREG; } -+ -+int UshLatency() { -+ // Estimated max. -+ return AdjustBaseAndOffsetLatency() + 2 + 2 * AlignedMemoryLatency(); -+} -+ -+int UswLatency() { return AdjustBaseAndOffsetLatency() + 2; } -+ -+int UsdLatency() { return AdjustBaseAndOffsetLatency() + 2; } -+ -+int UStoreFloatLatency() { return Latency::MOVF_FREG + UswLatency(); } -+ -+int UStoreDoubleLatency() { return Latency::MOVF_HIGH_DREG + UsdLatency(); } -+ -+int LoadFloatLatency() { -+ return AdjustBaseAndOffsetLatency() + Latency::LOAD_FLOAT; -+} -+ -+int StoreFloatLatency() { -+ return AdjustBaseAndOffsetLatency() + Latency::STORE_FLOAT; -+} -+ -+int StoreDoubleLatency() { -+ return AdjustBaseAndOffsetLatency() + Latency::STORE_DOUBLE; -+} -+ -+int LoadDoubleLatency() { -+ return AdjustBaseAndOffsetLatency() + Latency::LOAD_DOUBLE; -+} -+ -+int MultiPushLatency() { -+ int latency = Sub64Latency(false); -+ for (int16_t i = kNumRegisters - 1; i >= 0; i--) { -+ latency++; -+ } -+ return latency; -+} -+ -+int MultiPushFPULatency() { -+ int latency = Sub64Latency(false); -+ for (int16_t i = kNumRegisters - 1; i >= 0; i--) { -+ latency += StoreDoubleLatency(); -+ } -+ return latency; -+} -+ -+int PushCallerSavedLatency(SaveFPRegsMode fp_mode) { -+ int latency = MultiPushLatency(); -+ if (fp_mode == kSaveFPRegs) { -+ latency += MultiPushFPULatency(); -+ } -+ return latency; -+} -+ -+int MultiPopLatency() { -+ int latency = Add64Latency(false); -+ for (int16_t i = 0; i < kNumRegisters; i++) { -+ latency++; -+ } -+ return latency; -+} -+ -+int MultiPopFPULatency() { -+ int latency = Add64Latency(false); -+ for (int16_t i = 0; i < kNumRegisters; i++) { -+ latency += LoadDoubleLatency(); -+ } -+ return latency; -+} -+ -+int PopCallerSavedLatency(SaveFPRegsMode fp_mode) { -+ int latency = MultiPopLatency(); -+ if (fp_mode == kSaveFPRegs) { -+ latency += MultiPopFPULatency(); -+ } -+ return latency; -+} -+ -+int CallCFunctionHelperLatency() { -+ // Estimated. -+ int latency = AndLatency(false) + Latency::BRANCH + 2 + CallLatency(); -+ if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) { -+ latency++; -+ } else { -+ latency += Add64Latency(false); -+ } -+ return latency; -+} -+ -+int CallCFunctionLatency() { return 1 + CallCFunctionHelperLatency(); } -+ -+int AssembleArchJumpLatency() { -+ // Estimated max. -+ return Latency::BRANCH; -+} -+ -+int GenerateSwitchTableLatency() { -+ int latency = 6; -+ latency += 2; -+ return latency; -+} -+ -+int AssembleArchTableSwitchLatency() { -+ return Latency::BRANCH + GenerateSwitchTableLatency(); -+} -+ -+int DropAndRetLatency() { -+ // Estimated max. -+ return Add64Latency(false) + JumpLatency(); -+} -+ -+int AssemblerReturnLatency() { -+ // Estimated max. -+ return Add64Latency(false) + MultiPopLatency() + MultiPopFPULatency() + -+ Latency::BRANCH + Add64Latency() + 1 + DropAndRetLatency(); -+} -+ -+int TryInlineTruncateDoubleToILatency() { -+ return 2 + Latency::TRUNC_W_D + Latency::MOVF_FREG + 2 + AndLatency(false) + -+ Latency::BRANCH; -+} -+ -+int CallStubDelayedLatency() { return 1 + CallLatency(); } -+ -+int TruncateDoubleToIDelayedLatency() { -+ // TODO(riscv): This no longer reflects how TruncateDoubleToI is called. -+ return TryInlineTruncateDoubleToILatency() + 1 + Sub64Latency(false) + -+ StoreDoubleLatency() + CallStubDelayedLatency() + Add64Latency(false) + -+ 1; -+} -+ -+int CheckPageFlagLatency() { -+ return AndLatency(false) + AlignedMemoryLatency() + AndLatency(false) + -+ Latency::BRANCH; -+} -+ -+int SltuLatency(bool is_operand_register = true) { -+ if (is_operand_register) { -+ return 1; -+ } else { -+ return 2; // Estimated max. -+ } -+} -+ -+int BranchShortHelperLatency() { -+ return SltuLatency() + 2; // Estimated max. -+} -+ -+int BranchShortLatency() { return BranchShortHelperLatency(); } -+ -+int MoveLatency() { return 1; } -+ -+int MovToFloatParametersLatency() { return 2 * MoveLatency(); } -+ -+int MovFromFloatResultLatency() { return MoveLatency(); } -+ -+int AddOverflow64Latency() { -+ // Estimated max. -+ return 6; -+} -+ -+int SubOverflow64Latency() { -+ // Estimated max. -+ return 6; -+} -+ -+int MulOverflow32Latency() { -+ // Estimated max. -+ return Mul32Latency() + Mulh32Latency() + 2; -+} -+ -+// FIXME (RISCV): need update -+int Clz64Latency() { return 1; } -+ -+int Ctz32Latency() { -+ return Add64Latency(false) + XorLatency() + AndLatency() + Clz64Latency() + -+ 1 + Sub64Latency(); -+} -+ -+int Ctz64Latency() { -+ return Add64Latency(false) + XorLatency() + AndLatency() + 1 + Sub64Latency(); -+} -+ -+int Popcnt32Latency() { -+ return 2 + AndLatency() + Sub64Latency() + 1 + AndLatency() + 1 + -+ AndLatency() + Add64Latency() + 1 + Add64Latency() + 1 + AndLatency() + -+ 1 + Mul32Latency() + 1; -+} -+ -+int Popcnt64Latency() { -+ return 2 + AndLatency() + Sub64Latency() + 1 + AndLatency() + 1 + -+ AndLatency() + Add64Latency() + 1 + Add64Latency() + 1 + AndLatency() + -+ 1 + Mul64Latency() + 1; -+} -+ -+int CompareFLatency() { return Latency::C_cond_S; } -+ -+int CompareF32Latency() { return CompareFLatency(); } -+ -+int CompareF64Latency() { return CompareFLatency(); } -+ -+int CompareIsNanFLatency() { return CompareFLatency(); } -+ -+int CompareIsNanF32Latency() { return CompareIsNanFLatency(); } -+ -+int CompareIsNanF64Latency() { return CompareIsNanFLatency(); } -+ -+int NegsLatency() { -+ // Estimated. -+ return CompareIsNanF32Latency() + 2 * Latency::BRANCH + Latency::NEG_S + -+ Latency::MOVF_FREG + 1 + XorLatency() + Latency::MOVT_FREG; -+} -+ -+int NegdLatency() { -+ // Estimated. -+ return CompareIsNanF64Latency() + 2 * Latency::BRANCH + Latency::NEG_D + -+ Latency::MOVF_HIGH_DREG + 1 + XorLatency() + Latency::MOVT_DREG; -+} -+ -+int Float64RoundLatency() { -+ // For ceil_l_d, floor_l_d, round_l_d, trunc_l_d latency is 4. -+ return Latency::MOVF_HIGH_DREG + 1 + Latency::BRANCH + Latency::MOV_D + 4 + -+ Latency::MOVF_HIGH_DREG + Latency::BRANCH + Latency::CVT_D_L + 2 + -+ Latency::MOVT_HIGH_FREG; -+} -+ -+int Float32RoundLatency() { -+ // For ceil_w_s, floor_w_s, round_w_s, trunc_w_s latency is 4. -+ return Latency::MOVF_FREG + 1 + Latency::BRANCH + Latency::MOV_S + 4 + -+ Latency::MOVF_FREG + Latency::BRANCH + Latency::CVT_S_W + 2 + -+ Latency::MOVT_FREG; -+} -+ -+int Float32MaxLatency() { -+ // Estimated max. -+ int latency = CompareIsNanF32Latency() + Latency::BRANCH; -+ return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + -+ Latency::MOVF_FREG + 1 + Latency::MOV_S; -+} -+ -+int Float64MaxLatency() { -+ // Estimated max. -+ int latency = CompareIsNanF64Latency() + Latency::BRANCH; -+ return latency + 5 * Latency::BRANCH + 2 * CompareF64Latency() + -+ Latency::MOVF_HIGH_DREG + Latency::MOV_D; -+} -+ -+int Float32MinLatency() { -+ // Estimated max. -+ int latency = CompareIsNanF32Latency() + Latency::BRANCH; -+ return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + -+ Latency::MOVF_FREG + 1 + Latency::MOV_S; -+} -+ -+int Float64MinLatency() { -+ // Estimated max. -+ int latency = CompareIsNanF64Latency() + Latency::BRANCH; -+ return latency + 5 * Latency::BRANCH + 2 * CompareF32Latency() + -+ Latency::MOVF_HIGH_DREG + Latency::MOV_D; -+} -+ -+int TruncLSLatency(bool load_status) { -+ int latency = Latency::TRUNC_L_S + Latency::MOVF_HIGH_DREG; -+ if (load_status) { -+ latency += SltuLatency() + 7; -+ } -+ return latency; -+} -+ -+int TruncLDLatency(bool load_status) { -+ int latency = Latency::TRUNC_L_D + Latency::MOVF_HIGH_DREG; -+ if (load_status) { -+ latency += SltuLatency() + 7; -+ } -+ return latency; -+} -+ -+int TruncUlSLatency() { -+ // Estimated max. -+ return 2 * CompareF32Latency() + CompareIsNanF32Latency() + -+ 4 * Latency::BRANCH + Latency::SUB_S + 2 * Latency::TRUNC_L_S + -+ 3 * Latency::MOVF_HIGH_DREG + OrLatency() + Latency::MOVT_FREG + -+ Latency::MOV_S + SltuLatency() + 4; -+} -+ -+int TruncUlDLatency() { -+ // Estimated max. -+ return 2 * CompareF64Latency() + CompareIsNanF64Latency() + -+ 4 * Latency::BRANCH + Latency::SUB_D + 2 * Latency::TRUNC_L_D + -+ 3 * Latency::MOVF_HIGH_DREG + OrLatency() + Latency::MOVT_DREG + -+ Latency::MOV_D + SltuLatency() + 4; -+} -+ -+int PushLatency() { return Add64Latency() + AlignedMemoryLatency(); } -+ -+int ByteSwapSignedLatency() { return 2; } -+ -+int LlLatency(int offset) { -+ bool is_one_instruction = is_int12(offset); -+ if (is_one_instruction) { -+ return 1; -+ } else { -+ return 3; -+ } -+} -+ -+int ExtractBitsLatency(bool sign_extend, int size) { -+ int latency = 2; -+ if (sign_extend) { -+ switch (size) { -+ case 8: -+ case 16: -+ case 32: -+ latency += 1; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+ return latency; -+} -+ -+int InsertBitsLatency() { return 2 + Sub64Latency(false) + 2; } -+ -+int ScLatency(int offset) { return 3; } -+ -+int Word32AtomicExchangeLatency(bool sign_extend, int size) { -+ return Add64Latency(false) + 1 + Sub64Latency() + 2 + LlLatency(0) + -+ ExtractBitsLatency(sign_extend, size) + InsertBitsLatency() + -+ ScLatency(0) + BranchShortLatency() + 1; -+} -+ -+int Word32AtomicCompareExchangeLatency(bool sign_extend, int size) { -+ return 2 + Sub64Latency() + 2 + LlLatency(0) + -+ ExtractBitsLatency(sign_extend, size) + InsertBitsLatency() + -+ ScLatency(0) + BranchShortLatency() + 1; -+} -+ -+int InstructionScheduler::GetInstructionLatency(const Instruction* instr) { -+ // FIXME(RISCV): Verify these latencies for RISC-V (currently using MIPS -+ // numbers) -+ switch (instr->arch_opcode()) { -+ case kArchCallCodeObject: -+ case kArchCallWasmFunction: -+ return CallLatency(); -+ case kArchTailCallCodeObjectFromJSFunction: -+ case kArchTailCallCodeObject: { -+ int latency = 0; -+ if (instr->arch_opcode() == kArchTailCallCodeObjectFromJSFunction) { -+ latency = AssemblePopArgumentsAdoptFrameLatency(); -+ } -+ return latency + JumpLatency(); -+ } -+ case kArchTailCallWasm: -+ case kArchTailCallAddress: -+ return JumpLatency(); -+ case kArchCallJSFunction: { -+ int latency = 0; -+ if (FLAG_debug_code) { -+ latency = 1 + AssertLatency(); -+ } -+ return latency + 1 + Add64Latency(false) + CallLatency(); -+ } -+ case kArchPrepareCallCFunction: -+ return PrepareCallCFunctionLatency(); -+ case kArchSaveCallerRegisters: { -+ auto fp_mode = -+ static_cast(MiscField::decode(instr->opcode())); -+ return PushCallerSavedLatency(fp_mode); -+ } -+ case kArchRestoreCallerRegisters: { -+ auto fp_mode = -+ static_cast(MiscField::decode(instr->opcode())); -+ return PopCallerSavedLatency(fp_mode); -+ } -+ case kArchPrepareTailCall: -+ return 2; -+ case kArchCallCFunction: -+ return CallCFunctionLatency(); -+ case kArchJmp: -+ return AssembleArchJumpLatency(); -+ case kArchTableSwitch: -+ return AssembleArchTableSwitchLatency(); -+ case kArchAbortCSAAssert: -+ return CallLatency() + 1; -+ case kArchDebugBreak: -+ return 1; -+ case kArchComment: -+ case kArchNop: -+ case kArchThrowTerminator: -+ case kArchDeoptimize: -+ return 0; -+ case kArchRet: -+ return AssemblerReturnLatency(); -+ case kArchFramePointer: -+ return 1; -+ case kArchParentFramePointer: -+ // Estimated max. -+ return AlignedMemoryLatency(); -+ case kArchTruncateDoubleToI: -+ return TruncateDoubleToIDelayedLatency(); -+ case kArchStoreWithWriteBarrier: -+ return Add64Latency() + 1 + CheckPageFlagLatency(); -+ case kArchStackSlot: -+ // Estimated max. -+ return Add64Latency(false) + AndLatency(false) + AssertLatency() + -+ Add64Latency(false) + AndLatency(false) + BranchShortLatency() + -+ 1 + Sub64Latency() + Add64Latency(); -+ case kArchWordPoisonOnSpeculation: -+ return AndLatency(); -+ case kIeee754Float64Acos: -+ case kIeee754Float64Acosh: -+ case kIeee754Float64Asin: -+ case kIeee754Float64Asinh: -+ case kIeee754Float64Atan: -+ case kIeee754Float64Atanh: -+ case kIeee754Float64Atan2: -+ case kIeee754Float64Cos: -+ case kIeee754Float64Cosh: -+ case kIeee754Float64Cbrt: -+ case kIeee754Float64Exp: -+ case kIeee754Float64Expm1: -+ case kIeee754Float64Log: -+ case kIeee754Float64Log1p: -+ case kIeee754Float64Log10: -+ case kIeee754Float64Log2: -+ case kIeee754Float64Pow: -+ case kIeee754Float64Sin: -+ case kIeee754Float64Sinh: -+ case kIeee754Float64Tan: -+ case kIeee754Float64Tanh: -+ return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + -+ CallCFunctionLatency() + MovFromFloatResultLatency(); -+ case kRiscvAdd32: -+ case kRiscvAdd64: -+ return Add64Latency(instr->InputAt(1)->IsRegister()); -+ case kRiscvAddOvf64: -+ return AddOverflow64Latency(); -+ case kRiscvSub32: -+ case kRiscvSub64: -+ return Sub64Latency(instr->InputAt(1)->IsRegister()); -+ case kRiscvSubOvf64: -+ return SubOverflow64Latency(); -+ case kRiscvMul32: -+ return Mul32Latency(); -+ case kRiscvMulOvf32: -+ return MulOverflow32Latency(); -+ case kRiscvMulHigh32: -+ return Mulh32Latency(); -+ case kRiscvMulHighU32: -+ return Mulhu32Latency(); -+ case kRiscvMulHigh64: -+ return Mulh64Latency(); -+ case kRiscvDiv32: { -+ int latency = Div32Latency(instr->InputAt(1)->IsRegister()); -+ return latency + MovzLatency(); -+ } -+ case kRiscvDivU32: { -+ int latency = Divu32Latency(instr->InputAt(1)->IsRegister()); -+ return latency + MovzLatency(); -+ } -+ case kRiscvMod32: -+ return Mod32Latency(); -+ case kRiscvModU32: -+ return Modu32Latency(); -+ case kRiscvMul64: -+ return Mul64Latency(); -+ case kRiscvDiv64: { -+ int latency = Div64Latency(); -+ return latency + MovzLatency(); -+ } -+ case kRiscvDivU64: { -+ int latency = Divu64Latency(); -+ return latency + MovzLatency(); -+ } -+ case kRiscvMod64: -+ return Mod64Latency(); -+ case kRiscvModU64: -+ return Modu64Latency(); -+ case kRiscvAnd: -+ return AndLatency(instr->InputAt(1)->IsRegister()); -+ case kRiscvAnd32: { -+ bool is_operand_register = instr->InputAt(1)->IsRegister(); -+ int latency = AndLatency(is_operand_register); -+ if (is_operand_register) { -+ return latency + 2; -+ } else { -+ return latency + 1; -+ } -+ } -+ case kRiscvOr: -+ return OrLatency(instr->InputAt(1)->IsRegister()); -+ case kRiscvOr32: { -+ bool is_operand_register = instr->InputAt(1)->IsRegister(); -+ int latency = OrLatency(is_operand_register); -+ if (is_operand_register) { -+ return latency + 2; -+ } else { -+ return latency + 1; -+ } -+ } -+ case kRiscvNor: -+ return NorLatency(instr->InputAt(1)->IsRegister()); -+ case kRiscvNor32: { -+ bool is_operand_register = instr->InputAt(1)->IsRegister(); -+ int latency = NorLatency(is_operand_register); -+ if (is_operand_register) { -+ return latency + 2; -+ } else { -+ return latency + 1; -+ } -+ } -+ case kRiscvXor: -+ return XorLatency(instr->InputAt(1)->IsRegister()); -+ case kRiscvXor32: { -+ bool is_operand_register = instr->InputAt(1)->IsRegister(); -+ int latency = XorLatency(is_operand_register); -+ if (is_operand_register) { -+ return latency + 2; -+ } else { -+ return latency + 1; -+ } -+ } -+ case kRiscvClz32: -+ case kRiscvClz64: -+ return Clz64Latency(); -+ case kRiscvCtz32: -+ return Ctz32Latency(); -+ case kRiscvCtz64: -+ return Ctz64Latency(); -+ case kRiscvPopcnt32: -+ return Popcnt32Latency(); -+ case kRiscvPopcnt64: -+ return Popcnt64Latency(); -+ case kRiscvShl32: -+ return 1; -+ case kRiscvShr32: -+ case kRiscvSar32: -+ case kRiscvZeroExtendWord: -+ return 2; -+ case kRiscvSignExtendWord: -+ case kRiscvShl64: -+ case kRiscvShr64: -+ case kRiscvSar64: -+ case kRiscvRor32: -+ case kRiscvRor64: -+ return 1; -+ case kRiscvTst: -+ return AndLatency(instr->InputAt(1)->IsRegister()); -+ case kRiscvMov: -+ return 1; -+ case kRiscvCmpS: -+ return MoveLatency() + CompareF32Latency(); -+ case kRiscvAddS: -+ return Latency::ADD_S; -+ case kRiscvSubS: -+ return Latency::SUB_S; -+ case kRiscvMulS: -+ return Latency::MUL_S; -+ case kRiscvDivS: -+ return Latency::DIV_S; -+ case kRiscvModS: -+ return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + -+ CallCFunctionLatency() + MovFromFloatResultLatency(); -+ case kRiscvAbsS: -+ return Latency::ABS_S; -+ case kRiscvNegS: -+ return NegdLatency(); -+ case kRiscvSqrtS: -+ return Latency::SQRT_S; -+ case kRiscvMaxS: -+ return Latency::MAX_S; -+ case kRiscvMinS: -+ return Latency::MIN_S; -+ case kRiscvCmpD: -+ return MoveLatency() + CompareF64Latency(); -+ case kRiscvAddD: -+ return Latency::ADD_D; -+ case kRiscvSubD: -+ return Latency::SUB_D; -+ case kRiscvMulD: -+ return Latency::MUL_D; -+ case kRiscvDivD: -+ return Latency::DIV_D; -+ case kRiscvModD: -+ return PrepareCallCFunctionLatency() + MovToFloatParametersLatency() + -+ CallCFunctionLatency() + MovFromFloatResultLatency(); -+ case kRiscvAbsD: -+ return Latency::ABS_D; -+ case kRiscvNegD: -+ return NegdLatency(); -+ case kRiscvSqrtD: -+ return Latency::SQRT_D; -+ case kRiscvMaxD: -+ return Latency::MAX_D; -+ case kRiscvMinD: -+ return Latency::MIN_D; -+ case kRiscvFloat64RoundDown: -+ case kRiscvFloat64RoundTruncate: -+ case kRiscvFloat64RoundUp: -+ case kRiscvFloat64RoundTiesEven: -+ return Float64RoundLatency(); -+ case kRiscvFloat32RoundDown: -+ case kRiscvFloat32RoundTruncate: -+ case kRiscvFloat32RoundUp: -+ case kRiscvFloat32RoundTiesEven: -+ return Float32RoundLatency(); -+ case kRiscvFloat32Max: -+ return Float32MaxLatency(); -+ case kRiscvFloat64Max: -+ return Float64MaxLatency(); -+ case kRiscvFloat32Min: -+ return Float32MinLatency(); -+ case kRiscvFloat64Min: -+ return Float64MinLatency(); -+ case kRiscvFloat64SilenceNaN: -+ return Latency::SUB_D; -+ case kRiscvCvtSD: -+ return Latency::CVT_S_D; -+ case kRiscvCvtDS: -+ return Latency::CVT_D_S; -+ case kRiscvCvtDW: -+ return Latency::MOVT_FREG + Latency::CVT_D_W; -+ case kRiscvCvtSW: -+ return Latency::MOVT_FREG + Latency::CVT_S_W; -+ case kRiscvCvtSUw: -+ return 1 + Latency::MOVT_DREG + Latency::CVT_S_L; -+ case kRiscvCvtSL: -+ return Latency::MOVT_DREG + Latency::CVT_S_L; -+ case kRiscvCvtDL: -+ return Latency::MOVT_DREG + Latency::CVT_D_L; -+ case kRiscvCvtDUw: -+ return 1 + Latency::MOVT_DREG + Latency::CVT_D_L; -+ case kRiscvCvtDUl: -+ return 2 * Latency::BRANCH + 3 + 2 * Latency::MOVT_DREG + -+ 2 * Latency::CVT_D_L + Latency::ADD_D; -+ case kRiscvCvtSUl: -+ return 2 * Latency::BRANCH + 3 + 2 * Latency::MOVT_DREG + -+ 2 * Latency::CVT_S_L + Latency::ADD_S; -+ case kRiscvFloorWD: -+ return Latency::FLOOR_W_D + Latency::MOVF_FREG; -+ case kRiscvCeilWD: -+ return Latency::CEIL_W_D + Latency::MOVF_FREG; -+ case kRiscvRoundWD: -+ return Latency::ROUND_W_D + Latency::MOVF_FREG; -+ case kRiscvTruncWD: -+ return Latency::TRUNC_W_D + Latency::MOVF_FREG; -+ case kRiscvFloorWS: -+ return Latency::FLOOR_W_S + Latency::MOVF_FREG; -+ case kRiscvCeilWS: -+ return Latency::CEIL_W_S + Latency::MOVF_FREG; -+ case kRiscvRoundWS: -+ return Latency::ROUND_W_S + Latency::MOVF_FREG; -+ case kRiscvTruncWS: -+ return Latency::TRUNC_W_S + Latency::MOVF_FREG + 2 + MovnLatency(); -+ case kRiscvTruncLS: -+ return TruncLSLatency(instr->OutputCount() > 1); -+ case kRiscvTruncLD: -+ return TruncLDLatency(instr->OutputCount() > 1); -+ case kRiscvTruncUwD: -+ // Estimated max. -+ return CompareF64Latency() + 2 * Latency::BRANCH + -+ 2 * Latency::TRUNC_W_D + Latency::SUB_D + OrLatency() + -+ Latency::MOVT_FREG + Latency::MOVF_FREG + Latency::MOVT_HIGH_FREG + -+ 1; -+ case kRiscvTruncUwS: -+ // Estimated max. -+ return CompareF32Latency() + 2 * Latency::BRANCH + -+ 2 * Latency::TRUNC_W_S + Latency::SUB_S + OrLatency() + -+ Latency::MOVT_FREG + 2 * Latency::MOVF_FREG + 2 + MovzLatency(); -+ case kRiscvTruncUlS: -+ return TruncUlSLatency(); -+ case kRiscvTruncUlD: -+ return TruncUlDLatency(); -+ case kRiscvBitcastDL: -+ return Latency::MOVF_HIGH_DREG; -+ case kRiscvBitcastLD: -+ return Latency::MOVT_DREG; -+ case kRiscvFloat64ExtractLowWord32: -+ return Latency::MOVF_FREG; -+ case kRiscvFloat64InsertLowWord32: -+ return Latency::MOVF_HIGH_FREG + Latency::MOVT_FREG + -+ Latency::MOVT_HIGH_FREG; -+ case kRiscvFloat64ExtractHighWord32: -+ return Latency::MOVF_HIGH_FREG; -+ case kRiscvFloat64InsertHighWord32: -+ return Latency::MOVT_HIGH_FREG; -+ case kRiscvSignExtendByte: -+ case kRiscvSignExtendShort: -+ return 1; -+ case kRiscvLbu: -+ case kRiscvLb: -+ case kRiscvLhu: -+ case kRiscvLh: -+ case kRiscvLwu: -+ case kRiscvLw: -+ case kRiscvLd: -+ case kRiscvSb: -+ case kRiscvSh: -+ case kRiscvSw: -+ case kRiscvSd: -+ return AlignedMemoryLatency(); -+ case kRiscvLoadFloat: -+ return ULoadFloatLatency(); -+ case kRiscvLoadDouble: -+ return LoadDoubleLatency(); -+ case kRiscvStoreFloat: -+ return StoreFloatLatency(); -+ case kRiscvStoreDouble: -+ return StoreDoubleLatency(); -+ case kRiscvUlhu: -+ case kRiscvUlh: -+ return UlhuLatency(); -+ case kRiscvUlwu: -+ return UlwuLatency(); -+ case kRiscvUlw: -+ return UlwLatency(); -+ case kRiscvUld: -+ return UldLatency(); -+ case kRiscvULoadFloat: -+ return ULoadFloatLatency(); -+ case kRiscvULoadDouble: -+ return ULoadDoubleLatency(); -+ case kRiscvUsh: -+ return UshLatency(); -+ case kRiscvUsw: -+ return UswLatency(); -+ case kRiscvUsd: -+ return UsdLatency(); -+ case kRiscvUStoreFloat: -+ return UStoreFloatLatency(); -+ case kRiscvUStoreDouble: -+ return UStoreDoubleLatency(); -+ case kRiscvPush: { -+ int latency = 0; -+ if (instr->InputAt(0)->IsFPRegister()) { -+ latency = StoreDoubleLatency() + Sub64Latency(false); -+ } else { -+ latency = PushLatency(); -+ } -+ return latency; -+ } -+ case kRiscvPeek: { -+ int latency = 0; -+ if (instr->OutputAt(0)->IsFPRegister()) { -+ auto op = LocationOperand::cast(instr->OutputAt(0)); -+ switch (op->representation()) { -+ case MachineRepresentation::kFloat64: -+ latency = LoadDoubleLatency(); -+ break; -+ case MachineRepresentation::kFloat32: -+ latency = Latency::LOAD_FLOAT; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } else { -+ latency = AlignedMemoryLatency(); -+ } -+ return latency; -+ } -+ case kRiscvStackClaim: -+ return Sub64Latency(false); -+ case kRiscvStoreToStackSlot: { -+ int latency = 0; -+ if (instr->InputAt(0)->IsFPRegister()) { -+ if (instr->InputAt(0)->IsSimd128Register()) { -+ latency = 1; // Estimated value. -+ } else { -+ latency = StoreDoubleLatency(); -+ } -+ } else { -+ latency = AlignedMemoryLatency(); -+ } -+ return latency; -+ } -+ case kRiscvByteSwap64: -+ return ByteSwapSignedLatency(); -+ case kRiscvByteSwap32: -+ return ByteSwapSignedLatency(); -+ case kWord32AtomicLoadInt8: -+ case kWord32AtomicLoadUint8: -+ case kWord32AtomicLoadInt16: -+ case kWord32AtomicLoadUint16: -+ case kWord32AtomicLoadWord32: -+ return 2; -+ case kWord32AtomicStoreWord8: -+ case kWord32AtomicStoreWord16: -+ case kWord32AtomicStoreWord32: -+ return 3; -+ case kWord32AtomicExchangeInt8: -+ return Word32AtomicExchangeLatency(true, 8); -+ case kWord32AtomicExchangeUint8: -+ return Word32AtomicExchangeLatency(false, 8); -+ case kWord32AtomicExchangeInt16: -+ return Word32AtomicExchangeLatency(true, 16); -+ case kWord32AtomicExchangeUint16: -+ return Word32AtomicExchangeLatency(false, 16); -+ case kWord32AtomicExchangeWord32: -+ return 2 + LlLatency(0) + 1 + ScLatency(0) + BranchShortLatency() + 1; -+ case kWord32AtomicCompareExchangeInt8: -+ return Word32AtomicCompareExchangeLatency(true, 8); -+ case kWord32AtomicCompareExchangeUint8: -+ return Word32AtomicCompareExchangeLatency(false, 8); -+ case kWord32AtomicCompareExchangeInt16: -+ return Word32AtomicCompareExchangeLatency(true, 16); -+ case kWord32AtomicCompareExchangeUint16: -+ return Word32AtomicCompareExchangeLatency(false, 16); -+ case kWord32AtomicCompareExchangeWord32: -+ return 3 + LlLatency(0) + BranchShortLatency() + 1 + ScLatency(0) + -+ BranchShortLatency() + 1; -+ case kRiscvAssertEqual: -+ return AssertLatency(); -+ default: -+ return 1; -+ } -+} -+ -+} // namespace compiler -+} // namespace internal -+} // namespace v8 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/instruction-selector-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/backend/riscv64/instruction-selector-riscv64.cc -@@ -0,0 +1,2985 @@ -+// 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. -+ -+#include "src/base/bits.h" -+#include "src/compiler/backend/instruction-selector-impl.h" -+#include "src/compiler/node-matchers.h" -+#include "src/compiler/node-properties.h" -+ -+namespace v8 { -+namespace internal { -+namespace compiler { -+ -+#define TRACE_UNIMPL() \ -+ PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__) -+ -+#define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__) -+ -+// Adds RISC-V-specific methods for generating InstructionOperands. -+class RiscvOperandGenerator final : public OperandGenerator { -+ public: -+ explicit RiscvOperandGenerator(InstructionSelector* selector) -+ : OperandGenerator(selector) {} -+ -+ InstructionOperand UseOperand(Node* node, InstructionCode opcode) { -+ if (CanBeImmediate(node, opcode)) { -+ return UseImmediate(node); -+ } -+ return UseRegister(node); -+ } -+ -+ // Use the zero register if the node has the immediate value zero, otherwise -+ // assign a register. -+ InstructionOperand UseRegisterOrImmediateZero(Node* node) { -+ if ((IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) || -+ (IsFloatConstant(node) && -+ (bit_cast(GetFloatConstantValue(node)) == 0))) { -+ return UseImmediate(node); -+ } -+ return UseRegister(node); -+ } -+ -+ bool IsIntegerConstant(Node* node) { -+ return (node->opcode() == IrOpcode::kInt32Constant) || -+ (node->opcode() == IrOpcode::kInt64Constant); -+ } -+ -+ int64_t GetIntegerConstantValue(Node* node) { -+ if (node->opcode() == IrOpcode::kInt32Constant) { -+ return OpParameter(node->op()); -+ } -+ DCHECK_EQ(IrOpcode::kInt64Constant, node->opcode()); -+ return OpParameter(node->op()); -+ } -+ -+ bool IsFloatConstant(Node* node) { -+ return (node->opcode() == IrOpcode::kFloat32Constant) || -+ (node->opcode() == IrOpcode::kFloat64Constant); -+ } -+ -+ double GetFloatConstantValue(Node* node) { -+ if (node->opcode() == IrOpcode::kFloat32Constant) { -+ return OpParameter(node->op()); -+ } -+ DCHECK_EQ(IrOpcode::kFloat64Constant, node->opcode()); -+ return OpParameter(node->op()); -+ } -+ -+ bool CanBeImmediate(Node* node, InstructionCode mode) { -+ return IsIntegerConstant(node) && -+ CanBeImmediate(GetIntegerConstantValue(node), mode); -+ } -+ -+ bool CanBeImmediate(int64_t value, InstructionCode opcode) { -+ switch (ArchOpcodeField::decode(opcode)) { -+ case kRiscvShl32: -+ case kRiscvSar32: -+ case kRiscvShr32: -+ return is_uint5(value); -+ case kRiscvShl64: -+ case kRiscvSar64: -+ case kRiscvShr64: -+ return is_uint6(value); -+ case kRiscvAdd32: -+ case kRiscvAnd32: -+ case kRiscvAnd: -+ case kRiscvAdd64: -+ case kRiscvOr32: -+ case kRiscvOr: -+ case kRiscvTst: -+ case kRiscvXor: -+ return is_int12(value); -+ case kRiscvLb: -+ case kRiscvLbu: -+ case kRiscvSb: -+ case kRiscvLh: -+ case kRiscvLhu: -+ case kRiscvSh: -+ case kRiscvLw: -+ case kRiscvSw: -+ case kRiscvLd: -+ case kRiscvSd: -+ case kRiscvLoadFloat: -+ case kRiscvStoreFloat: -+ case kRiscvLoadDouble: -+ case kRiscvStoreDouble: -+ return is_int32(value); -+ default: -+ return is_int12(value); -+ } -+ } -+ -+ private: -+ bool ImmediateFitsAddrMode1Instruction(int32_t imm) const { -+ TRACE_UNIMPL(); -+ return false; -+ } -+}; -+ -+static void VisitRR(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+static void VisitRRI(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ int32_t imm = OpParameter(node->op()); -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), g.UseImmediate(imm)); -+} -+ -+static void VisitSimdShift(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ if (g.IsIntegerConstant(node->InputAt(1))) { -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), -+ g.UseImmediate(node->InputAt(1))); -+ } else { -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), -+ g.UseRegister(node->InputAt(1))); -+ } -+} -+ -+static void VisitRRIR(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ int32_t imm = OpParameter(node->op()); -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), g.UseImmediate(imm), -+ g.UseRegister(node->InputAt(1))); -+} -+ -+static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), -+ g.UseRegister(node->InputAt(1))); -+} -+ -+static void VisitUniqueRRR(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseUniqueRegister(node->InputAt(0)), -+ g.UseUniqueRegister(node->InputAt(1))); -+} -+ -+void VisitRRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { -+ RiscvOperandGenerator g(selector); -+ selector->Emit( -+ opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)), -+ g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(2))); -+} -+ -+static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, -+ Node* node) { -+ RiscvOperandGenerator g(selector); -+ selector->Emit(opcode, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), -+ g.UseOperand(node->InputAt(1), opcode)); -+} -+ -+struct ExtendingLoadMatcher { -+ ExtendingLoadMatcher(Node* node, InstructionSelector* selector) -+ : matches_(false), selector_(selector), base_(nullptr), immediate_(0) { -+ Initialize(node); -+ } -+ -+ bool Matches() const { return matches_; } -+ -+ Node* base() const { -+ DCHECK(Matches()); -+ return base_; -+ } -+ int64_t immediate() const { -+ DCHECK(Matches()); -+ return immediate_; -+ } -+ ArchOpcode opcode() const { -+ DCHECK(Matches()); -+ return opcode_; -+ } -+ -+ private: -+ bool matches_; -+ InstructionSelector* selector_; -+ Node* base_; -+ int64_t immediate_; -+ ArchOpcode opcode_; -+ -+ void Initialize(Node* node) { -+ Int64BinopMatcher m(node); -+ // When loading a 64-bit value and shifting by 32, we should -+ // just load and sign-extend the interesting 4 bytes instead. -+ // This happens, for example, when we're loading and untagging SMIs. -+ DCHECK(m.IsWord64Sar()); -+ if (m.left().IsLoad() && m.right().Is(32) && -+ selector_->CanCover(m.node(), m.left().node())) { -+ DCHECK_EQ(selector_->GetEffectLevel(node), -+ selector_->GetEffectLevel(m.left().node())); -+ MachineRepresentation rep = -+ LoadRepresentationOf(m.left().node()->op()).representation(); -+ DCHECK_EQ(3, ElementSizeLog2Of(rep)); -+ if (rep != MachineRepresentation::kTaggedSigned && -+ rep != MachineRepresentation::kTaggedPointer && -+ rep != MachineRepresentation::kTagged && -+ rep != MachineRepresentation::kWord64) { -+ return; -+ } -+ -+ RiscvOperandGenerator g(selector_); -+ Node* load = m.left().node(); -+ Node* offset = load->InputAt(1); -+ base_ = load->InputAt(0); -+ opcode_ = kRiscvLw; -+ if (g.CanBeImmediate(offset, opcode_)) { -+#if defined(V8_TARGET_LITTLE_ENDIAN) -+ immediate_ = g.GetIntegerConstantValue(offset) + 4; -+#elif defined(V8_TARGET_BIG_ENDIAN) -+ immediate_ = g.GetIntegerConstantValue(offset); -+#endif -+ matches_ = g.CanBeImmediate(immediate_, kRiscvLw); -+ } -+ } -+ } -+}; -+ -+bool TryEmitExtendingLoad(InstructionSelector* selector, Node* node, -+ Node* output_node) { -+ ExtendingLoadMatcher m(node, selector); -+ RiscvOperandGenerator g(selector); -+ if (m.Matches()) { -+ InstructionOperand inputs[2]; -+ inputs[0] = g.UseRegister(m.base()); -+ InstructionCode opcode = -+ m.opcode() | AddressingModeField::encode(kMode_MRI); -+ DCHECK(is_int32(m.immediate())); -+ inputs[1] = g.TempImmediate(static_cast(m.immediate())); -+ InstructionOperand outputs[] = {g.DefineAsRegister(output_node)}; -+ selector->Emit(opcode, arraysize(outputs), outputs, arraysize(inputs), -+ inputs); -+ return true; -+ } -+ return false; -+} -+ -+bool TryMatchImmediate(InstructionSelector* selector, -+ InstructionCode* opcode_return, Node* node, -+ size_t* input_count_return, InstructionOperand* inputs) { -+ RiscvOperandGenerator g(selector); -+ if (g.CanBeImmediate(node, *opcode_return)) { -+ *opcode_return |= AddressingModeField::encode(kMode_MRI); -+ inputs[0] = g.UseImmediate(node); -+ *input_count_return = 1; -+ return true; -+ } -+ return false; -+} -+ -+static void VisitBinop(InstructionSelector* selector, Node* node, -+ InstructionCode opcode, bool has_reverse_opcode, -+ InstructionCode reverse_opcode, -+ FlagsContinuation* cont) { -+ RiscvOperandGenerator g(selector); -+ Int32BinopMatcher m(node); -+ InstructionOperand inputs[2]; -+ size_t input_count = 0; -+ InstructionOperand outputs[1]; -+ size_t output_count = 0; -+ -+ if (TryMatchImmediate(selector, &opcode, m.right().node(), &input_count, -+ &inputs[1])) { -+ inputs[0] = g.UseRegister(m.left().node()); -+ input_count++; -+ } else if (has_reverse_opcode && -+ TryMatchImmediate(selector, &reverse_opcode, m.left().node(), -+ &input_count, &inputs[1])) { -+ inputs[0] = g.UseRegister(m.right().node()); -+ opcode = reverse_opcode; -+ input_count++; -+ } else { -+ inputs[input_count++] = g.UseRegister(m.left().node()); -+ inputs[input_count++] = g.UseOperand(m.right().node(), opcode); -+ } -+ -+ if (cont->IsDeoptimize()) { -+ // If we can deoptimize as a result of the binop, we need to make sure that -+ // the deopt inputs are not overwritten by the binop result. One way -+ // to achieve that is to declare the output register as same-as-first. -+ outputs[output_count++] = g.DefineSameAsFirst(node); -+ } else { -+ outputs[output_count++] = g.DefineAsRegister(node); -+ } -+ -+ DCHECK_NE(0u, input_count); -+ DCHECK_EQ(1u, output_count); -+ DCHECK_GE(arraysize(inputs), input_count); -+ DCHECK_GE(arraysize(outputs), output_count); -+ -+ selector->EmitWithContinuation(opcode, output_count, outputs, input_count, -+ inputs, cont); -+} -+ -+static void VisitBinop(InstructionSelector* selector, Node* node, -+ InstructionCode opcode, bool has_reverse_opcode, -+ InstructionCode reverse_opcode) { -+ FlagsContinuation cont; -+ VisitBinop(selector, node, opcode, has_reverse_opcode, reverse_opcode, &cont); -+} -+ -+static void VisitBinop(InstructionSelector* selector, Node* node, -+ InstructionCode opcode, FlagsContinuation* cont) { -+ VisitBinop(selector, node, opcode, false, kArchNop, cont); -+} -+ -+static void VisitBinop(InstructionSelector* selector, Node* node, -+ InstructionCode opcode) { -+ VisitBinop(selector, node, opcode, false, kArchNop); -+} -+ -+void InstructionSelector::VisitStackSlot(Node* node) { -+ StackSlotRepresentation rep = StackSlotRepresentationOf(node->op()); -+ int alignment = rep.alignment(); -+ int slot = frame_->AllocateSpillSlot(rep.size(), alignment); -+ OperandGenerator g(this); -+ -+ Emit(kArchStackSlot, g.DefineAsRegister(node), -+ sequence()->AddImmediate(Constant(slot)), -+ sequence()->AddImmediate(Constant(alignment)), 0, nullptr); -+} -+ -+void InstructionSelector::VisitAbortCSAAssert(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kArchAbortCSAAssert, g.NoOutput(), g.UseFixed(node->InputAt(0), a0)); -+} -+ -+void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode, -+ Node* output = nullptr) { -+ RiscvOperandGenerator g(selector); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ -+ if (g.CanBeImmediate(index, opcode)) { -+ selector->Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.DefineAsRegister(output == nullptr ? node : output), -+ g.UseRegister(base), g.UseImmediate(index)); -+ } else { -+ InstructionOperand addr_reg = g.TempRegister(); -+ selector->Emit(kRiscvAdd64 | AddressingModeField::encode(kMode_None), -+ addr_reg, g.UseRegister(index), g.UseRegister(base)); -+ // Emit desired load opcode, using temp addr_reg. -+ selector->Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.DefineAsRegister(output == nullptr ? node : output), -+ addr_reg, g.TempImmediate(0)); -+ } -+} -+ -+void InstructionSelector::VisitLoadTransform(Node* node) { -+ LoadTransformParameters params = LoadTransformParametersOf(node->op()); -+ -+ InstructionCode opcode = kArchNop; -+ switch (params.transformation) { -+ case LoadTransformation::kS8x16LoadSplat: -+ opcode = kRiscvS8x16LoadSplat; -+ break; -+ case LoadTransformation::kS16x8LoadSplat: -+ opcode = kRiscvS16x8LoadSplat; -+ break; -+ case LoadTransformation::kS32x4LoadSplat: -+ opcode = kRiscvS32x4LoadSplat; -+ break; -+ case LoadTransformation::kS64x2LoadSplat: -+ opcode = kRiscvS64x2LoadSplat; -+ break; -+ case LoadTransformation::kI16x8Load8x8S: -+ opcode = kRiscvI16x8Load8x8S; -+ break; -+ case LoadTransformation::kI16x8Load8x8U: -+ opcode = kRiscvI16x8Load8x8U; -+ break; -+ case LoadTransformation::kI32x4Load16x4S: -+ opcode = kRiscvI32x4Load16x4S; -+ break; -+ case LoadTransformation::kI32x4Load16x4U: -+ opcode = kRiscvI32x4Load16x4U; -+ break; -+ case LoadTransformation::kI64x2Load32x2S: -+ opcode = kRiscvI64x2Load32x2S; -+ break; -+ case LoadTransformation::kI64x2Load32x2U: -+ opcode = kRiscvI64x2Load32x2U; -+ break; -+ default: -+ UNIMPLEMENTED(); -+ } -+ -+ EmitLoad(this, node, opcode); -+} -+ -+void InstructionSelector::VisitLoad(Node* node) { -+ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); -+ -+ InstructionCode opcode = kArchNop; -+ switch (load_rep.representation()) { -+ case MachineRepresentation::kFloat32: -+ opcode = kRiscvLoadFloat; -+ break; -+ case MachineRepresentation::kFloat64: -+ opcode = kRiscvLoadDouble; -+ break; -+ case MachineRepresentation::kBit: // Fall through. -+ case MachineRepresentation::kWord8: -+ opcode = load_rep.IsUnsigned() ? kRiscvLbu : kRiscvLb; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = load_rep.IsUnsigned() ? kRiscvLhu : kRiscvLh; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = load_rep.IsUnsigned() ? kRiscvLwu : kRiscvLw; -+ break; -+ case MachineRepresentation::kTaggedSigned: // Fall through. -+ case MachineRepresentation::kTaggedPointer: // Fall through. -+ case MachineRepresentation::kTagged: // Fall through. -+ case MachineRepresentation::kWord64: -+ opcode = kRiscvLd; -+ break; -+ case MachineRepresentation::kSimd128: -+ opcode = kRiscvMsaLd; -+ break; -+ case MachineRepresentation::kCompressedPointer: // Fall through. -+ case MachineRepresentation::kCompressed: // Fall through. -+ case MachineRepresentation::kNone: -+ UNREACHABLE(); -+ } -+ if (node->opcode() == IrOpcode::kPoisonedLoad) { -+ CHECK_NE(poisoning_level_, PoisoningMitigationLevel::kDontPoison); -+ opcode |= MiscField::encode(kMemoryAccessPoisoned); -+ } -+ -+ EmitLoad(this, node, opcode); -+} -+ -+void InstructionSelector::VisitPoisonedLoad(Node* node) { VisitLoad(node); } -+ -+void InstructionSelector::VisitProtectedLoad(Node* node) { -+ // TODO(eholk) -+ UNIMPLEMENTED(); -+} -+ -+void InstructionSelector::VisitStore(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ Node* value = node->InputAt(2); -+ -+ StoreRepresentation store_rep = StoreRepresentationOf(node->op()); -+ WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind(); -+ MachineRepresentation rep = store_rep.representation(); -+ -+ // TODO(riscv): I guess this could be done in a better way. -+ if (write_barrier_kind != kNoWriteBarrier && -+ V8_LIKELY(!FLAG_disable_write_barriers)) { -+ DCHECK(CanBeTaggedPointer(rep)); -+ InstructionOperand inputs[3]; -+ size_t input_count = 0; -+ inputs[input_count++] = g.UseUniqueRegister(base); -+ inputs[input_count++] = g.UseUniqueRegister(index); -+ inputs[input_count++] = g.UseUniqueRegister(value); -+ RecordWriteMode record_write_mode = -+ WriteBarrierKindToRecordWriteMode(write_barrier_kind); -+ InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; -+ size_t const temp_count = arraysize(temps); -+ InstructionCode code = kArchStoreWithWriteBarrier; -+ code |= MiscField::encode(static_cast(record_write_mode)); -+ Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); -+ } else { -+ ArchOpcode opcode = kArchNop; -+ switch (rep) { -+ case MachineRepresentation::kFloat32: -+ opcode = kRiscvStoreFloat; -+ break; -+ case MachineRepresentation::kFloat64: -+ opcode = kRiscvStoreDouble; -+ break; -+ case MachineRepresentation::kBit: // Fall through. -+ case MachineRepresentation::kWord8: -+ opcode = kRiscvSb; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = kRiscvSh; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kRiscvSw; -+ break; -+ case MachineRepresentation::kTaggedSigned: // Fall through. -+ case MachineRepresentation::kTaggedPointer: // Fall through. -+ case MachineRepresentation::kTagged: // Fall through. -+ case MachineRepresentation::kWord64: -+ opcode = kRiscvSd; -+ break; -+ case MachineRepresentation::kSimd128: -+ opcode = kRiscvMsaSt; -+ break; -+ case MachineRepresentation::kCompressedPointer: // Fall through. -+ case MachineRepresentation::kCompressed: // Fall through. -+ case MachineRepresentation::kNone: -+ UNREACHABLE(); -+ return; -+ } -+ -+ if (g.CanBeImmediate(index, opcode)) { -+ Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), -+ g.UseRegister(base), g.UseImmediate(index), -+ g.UseRegisterOrImmediateZero(value)); -+ } else { -+ InstructionOperand addr_reg = g.TempRegister(); -+ Emit(kRiscvAdd64 | AddressingModeField::encode(kMode_None), addr_reg, -+ g.UseRegister(index), g.UseRegister(base)); -+ // Emit desired store opcode, using temp addr_reg. -+ Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), -+ addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value)); -+ } -+ } -+} -+ -+void InstructionSelector::VisitProtectedStore(Node* node) { -+ // TODO(eholk) -+ UNIMPLEMENTED(); -+} -+ -+void InstructionSelector::VisitWord32And(Node* node) { -+ VisitBinop(this, node, kRiscvAnd32, true, kRiscvAnd32); -+} -+ -+void InstructionSelector::VisitWord64And(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) && -+ m.right().HasValue()) { -+ uint64_t mask = m.right().Value(); -+ uint32_t mask_width = base::bits::CountPopulation(mask); -+ uint32_t mask_msb = base::bits::CountLeadingZeros64(mask); -+ if ((mask_width != 0) && (mask_msb + mask_width == 64)) { -+ // The mask must be contiguous, and occupy the least-significant bits. -+ DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask)); -+ -+ // Select Dext for And(Shr(x, imm), mask) where the mask is in the least -+ // significant bits. -+ Int64BinopMatcher mleft(m.left().node()); -+ if (mleft.right().HasValue()) { -+ // Any shift value can match; int64 shifts use `value % 64`. -+ uint32_t lsb = static_cast(mleft.right().Value() & 0x3F); -+ -+ // Dext cannot extract bits past the register size, however since -+ // shifting the original value would have introduced some zeros we can -+ // still use Dext with a smaller mask and the remaining bits will be -+ // zeros. -+ if (lsb + mask_width > 64) mask_width = 64 - lsb; -+ -+ if (lsb == 0 && mask_width == 64) { -+ Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(mleft.left().node())); -+ return; -+ } -+ } -+ // Other cases fall through to the normal And operation. -+ } -+ } -+ VisitBinop(this, node, kRiscvAnd, true, kRiscvAnd); -+} -+ -+void InstructionSelector::VisitWord32Or(Node* node) { -+ VisitBinop(this, node, kRiscvOr32, true, kRiscvOr32); -+} -+ -+void InstructionSelector::VisitWord64Or(Node* node) { -+ VisitBinop(this, node, kRiscvOr, true, kRiscvOr); -+} -+ -+void InstructionSelector::VisitWord32Xor(Node* node) { -+ Int32BinopMatcher m(node); -+ if (m.left().IsWord32Or() && CanCover(node, m.left().node()) && -+ m.right().Is(-1)) { -+ Int32BinopMatcher mleft(m.left().node()); -+ if (!mleft.right().HasValue()) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvNor32, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node()), -+ g.UseRegister(mleft.right().node())); -+ return; -+ } -+ } -+ if (m.right().Is(-1)) { -+ // Use Nor for bit negation and eliminate constant loading for xori. -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvNor32, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.TempImmediate(0)); -+ return; -+ } -+ VisitBinop(this, node, kRiscvXor32, true, kRiscvXor32); -+} -+ -+void InstructionSelector::VisitWord64Xor(Node* node) { -+ Int64BinopMatcher m(node); -+ if (m.left().IsWord64Or() && CanCover(node, m.left().node()) && -+ m.right().Is(-1)) { -+ Int64BinopMatcher mleft(m.left().node()); -+ if (!mleft.right().HasValue()) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvNor, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node()), -+ g.UseRegister(mleft.right().node())); -+ return; -+ } -+ } -+ if (m.right().Is(-1)) { -+ // Use Nor for bit negation and eliminate constant loading for xori. -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvNor, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.TempImmediate(0)); -+ return; -+ } -+ VisitBinop(this, node, kRiscvXor, true, kRiscvXor); -+} -+ -+void InstructionSelector::VisitWord32Shl(Node* node) { -+ Int32BinopMatcher m(node); -+ if (m.left().IsWord32And() && CanCover(node, m.left().node()) && -+ m.right().IsInRange(1, 31)) { -+ RiscvOperandGenerator g(this); -+ Int32BinopMatcher mleft(m.left().node()); -+ // Match Word32Shl(Word32And(x, mask), imm) to Shl where the mask is -+ // contiguous, and the shift immediate non-zero. -+ if (mleft.right().HasValue()) { -+ uint32_t mask = mleft.right().Value(); -+ uint32_t mask_width = base::bits::CountPopulation(mask); -+ uint32_t mask_msb = base::bits::CountLeadingZeros32(mask); -+ if ((mask_width != 0) && (mask_msb + mask_width == 32)) { -+ uint32_t shift = m.right().Value(); -+ DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask)); -+ DCHECK_NE(0u, shift); -+ if ((shift + mask_width) >= 32) { -+ // If the mask is contiguous and reaches or extends beyond the top -+ // bit, only the shift is needed. -+ Emit(kRiscvShl32, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node()), -+ g.UseImmediate(m.right().node())); -+ return; -+ } -+ } -+ } -+ } -+ VisitRRO(this, kRiscvShl32, node); -+} -+ -+void InstructionSelector::VisitWord32Shr(Node* node) { -+ VisitRRO(this, kRiscvShr32, node); -+} -+ -+void InstructionSelector::VisitWord32Sar(Node* node) { -+ Int32BinopMatcher m(node); -+ if (m.left().IsWord32Shl() && CanCover(node, m.left().node())) { -+ Int32BinopMatcher mleft(m.left().node()); -+ if (m.right().HasValue() && mleft.right().HasValue()) { -+ RiscvOperandGenerator g(this); -+ uint32_t sar = m.right().Value(); -+ uint32_t shl = mleft.right().Value(); -+ if ((sar == shl) && (sar == 16)) { -+ Emit(kRiscvSignExtendShort, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node())); -+ return; -+ } else if ((sar == shl) && (sar == 24)) { -+ Emit(kRiscvSignExtendByte, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node())); -+ return; -+ } else if ((sar == shl) && (sar == 32)) { -+ Emit(kRiscvShl32, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node()), g.TempImmediate(0)); -+ return; -+ } -+ } -+ } -+ VisitRRO(this, kRiscvSar32, node); -+} -+ -+void InstructionSelector::VisitWord64Shl(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) && -+ m.right().IsInRange(32, 63) && CanCover(node, m.left().node())) { -+ // There's no need to sign/zero-extend to 64-bit if we shift out the upper -+ // 32 bits anyway. -+ Emit(kRiscvShl64, g.DefineSameAsFirst(node), -+ g.UseRegister(m.left().node()->InputAt(0)), -+ g.UseImmediate(m.right().node())); -+ return; -+ } -+ if (m.left().IsWord64And() && CanCover(node, m.left().node()) && -+ m.right().IsInRange(1, 63)) { -+ // Match Word64Shl(Word64And(x, mask), imm) to Dshl where the mask is -+ // contiguous, and the shift immediate non-zero. -+ Int64BinopMatcher mleft(m.left().node()); -+ if (mleft.right().HasValue()) { -+ uint64_t mask = mleft.right().Value(); -+ uint32_t mask_width = base::bits::CountPopulation(mask); -+ uint32_t mask_msb = base::bits::CountLeadingZeros64(mask); -+ if ((mask_width != 0) && (mask_msb + mask_width == 64)) { -+ uint64_t shift = m.right().Value(); -+ DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask)); -+ DCHECK_NE(0u, shift); -+ -+ if ((shift + mask_width) >= 64) { -+ // If the mask is contiguous and reaches or extends beyond the top -+ // bit, only the shift is needed. -+ Emit(kRiscvShl64, g.DefineAsRegister(node), -+ g.UseRegister(mleft.left().node()), -+ g.UseImmediate(m.right().node())); -+ return; -+ } -+ } -+ } -+ } -+ VisitRRO(this, kRiscvShl64, node); -+} -+ -+void InstructionSelector::VisitWord64Shr(Node* node) { -+ VisitRRO(this, kRiscvShr64, node); -+} -+ -+void InstructionSelector::VisitWord64Sar(Node* node) { -+ if (TryEmitExtendingLoad(this, node, node)) return; -+ VisitRRO(this, kRiscvSar64, node); -+} -+ -+void InstructionSelector::VisitWord32Rol(Node* node) { UNREACHABLE(); } -+ -+void InstructionSelector::VisitWord64Rol(Node* node) { UNREACHABLE(); } -+ -+void InstructionSelector::VisitWord32Ror(Node* node) { -+ VisitRRO(this, kRiscvRor32, node); -+} -+ -+void InstructionSelector::VisitWord32Clz(Node* node) { -+ VisitRR(this, kRiscvClz32, node); -+} -+ -+void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); } -+ -+void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); } -+ -+void InstructionSelector::VisitWord64ReverseBytes(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvByteSwap64, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitWord32ReverseBytes(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvByteSwap32, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitSimd128ReverseBytes(Node* node) { -+ UNREACHABLE(); -+} -+ -+void InstructionSelector::VisitWord32Ctz(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvCtz32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitWord64Ctz(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvCtz64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitWord32Popcnt(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvPopcnt32, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitWord64Popcnt(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvPopcnt64, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitWord64Ror(Node* node) { -+ VisitRRO(this, kRiscvRor64, node); -+} -+ -+void InstructionSelector::VisitWord64Clz(Node* node) { -+ VisitRR(this, kRiscvClz64, node); -+} -+ -+void InstructionSelector::VisitInt32Add(Node* node) { -+ VisitBinop(this, node, kRiscvAdd32, true, kRiscvAdd32); -+} -+ -+void InstructionSelector::VisitInt64Add(Node* node) { -+ VisitBinop(this, node, kRiscvAdd64, true, kRiscvAdd64); -+} -+ -+void InstructionSelector::VisitInt32Sub(Node* node) { -+ VisitBinop(this, node, kRiscvSub32); -+} -+ -+void InstructionSelector::VisitInt64Sub(Node* node) { -+ VisitBinop(this, node, kRiscvSub64); -+} -+ -+void InstructionSelector::VisitInt32Mul(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int32BinopMatcher m(node); -+ if (m.right().HasValue() && m.right().Value() > 0) { -+ uint32_t value = static_cast(m.right().Value()); -+ if (base::bits::IsPowerOfTwo(value)) { -+ Emit(kRiscvShl32 | AddressingModeField::encode(kMode_None), -+ g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.TempImmediate(base::bits::WhichPowerOfTwo(value))); -+ return; -+ } -+ if (base::bits::IsPowerOfTwo(value + 1)) { -+ InstructionOperand temp = g.TempRegister(); -+ Emit(kRiscvShl32 | AddressingModeField::encode(kMode_None), temp, -+ g.UseRegister(m.left().node()), -+ g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1))); -+ Emit(kRiscvSub32 | AddressingModeField::encode(kMode_None), -+ g.DefineAsRegister(node), temp, g.UseRegister(m.left().node())); -+ return; -+ } -+ } -+ Node* left = node->InputAt(0); -+ Node* right = node->InputAt(1); -+ if (CanCover(node, left) && CanCover(node, right)) { -+ if (left->opcode() == IrOpcode::kWord64Sar && -+ right->opcode() == IrOpcode::kWord64Sar) { -+ Int64BinopMatcher leftInput(left), rightInput(right); -+ if (leftInput.right().Is(32) && rightInput.right().Is(32)) { -+ // Combine untagging shifts with Dmul high. -+ Emit(kRiscvMulHigh64, g.DefineSameAsFirst(node), -+ g.UseRegister(leftInput.left().node()), -+ g.UseRegister(rightInput.left().node())); -+ return; -+ } -+ } -+ } -+ VisitRRR(this, kRiscvMul32, node); -+} -+ -+void InstructionSelector::VisitInt32MulHigh(Node* node) { -+ VisitRRR(this, kRiscvMulHigh32, node); -+} -+ -+void InstructionSelector::VisitUint32MulHigh(Node* node) { -+ VisitRRR(this, kRiscvMulHighU32, node); -+} -+ -+void InstructionSelector::VisitInt64Mul(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ // TODO(dusmil): Add optimization for shifts larger than 32. -+ if (m.right().HasValue() && m.right().Value() > 0) { -+ uint32_t value = static_cast(m.right().Value()); -+ if (base::bits::IsPowerOfTwo(value)) { -+ Emit(kRiscvShl64 | AddressingModeField::encode(kMode_None), -+ g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.TempImmediate(base::bits::WhichPowerOfTwo(value))); -+ return; -+ } -+ if (base::bits::IsPowerOfTwo(value + 1)) { -+ InstructionOperand temp = g.TempRegister(); -+ Emit(kRiscvShl64 | AddressingModeField::encode(kMode_None), temp, -+ g.UseRegister(m.left().node()), -+ g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1))); -+ Emit(kRiscvSub64 | AddressingModeField::encode(kMode_None), -+ g.DefineAsRegister(node), temp, g.UseRegister(m.left().node())); -+ return; -+ } -+ } -+ Emit(kRiscvMul64, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitInt32Div(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int32BinopMatcher m(node); -+ Node* left = node->InputAt(0); -+ Node* right = node->InputAt(1); -+ if (CanCover(node, left) && CanCover(node, right)) { -+ if (left->opcode() == IrOpcode::kWord64Sar && -+ right->opcode() == IrOpcode::kWord64Sar) { -+ Int64BinopMatcher rightInput(right), leftInput(left); -+ if (rightInput.right().Is(32) && leftInput.right().Is(32)) { -+ // Combine both shifted operands with Ddiv. -+ Emit(kRiscvDiv64, g.DefineSameAsFirst(node), -+ g.UseRegister(leftInput.left().node()), -+ g.UseRegister(rightInput.left().node())); -+ return; -+ } -+ } -+ } -+ Emit(kRiscvDiv32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitUint32Div(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int32BinopMatcher m(node); -+ Emit(kRiscvDivU32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitInt32Mod(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int32BinopMatcher m(node); -+ Node* left = node->InputAt(0); -+ Node* right = node->InputAt(1); -+ if (CanCover(node, left) && CanCover(node, right)) { -+ if (left->opcode() == IrOpcode::kWord64Sar && -+ right->opcode() == IrOpcode::kWord64Sar) { -+ Int64BinopMatcher rightInput(right), leftInput(left); -+ if (rightInput.right().Is(32) && leftInput.right().Is(32)) { -+ // Combine both shifted operands with Dmod. -+ Emit(kRiscvMod64, g.DefineSameAsFirst(node), -+ g.UseRegister(leftInput.left().node()), -+ g.UseRegister(rightInput.left().node())); -+ return; -+ } -+ } -+ } -+ Emit(kRiscvMod32, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitUint32Mod(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int32BinopMatcher m(node); -+ Emit(kRiscvModU32, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitInt64Div(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ Emit(kRiscvDiv64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitUint64Div(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ Emit(kRiscvDivU64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitInt64Mod(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ Emit(kRiscvMod64, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitUint64Mod(Node* node) { -+ RiscvOperandGenerator g(this); -+ Int64BinopMatcher m(node); -+ Emit(kRiscvModU64, g.DefineAsRegister(node), g.UseRegister(m.left().node()), -+ g.UseRegister(m.right().node())); -+} -+ -+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { -+ VisitRR(this, kRiscvCvtDS, node); -+} -+ -+void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) { -+ VisitRR(this, kRiscvCvtSW, node); -+} -+ -+void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) { -+ VisitRR(this, kRiscvCvtSUw, node); -+} -+ -+void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { -+ VisitRR(this, kRiscvCvtDW, node); -+} -+ -+void InstructionSelector::VisitChangeInt64ToFloat64(Node* node) { -+ VisitRR(this, kRiscvCvtDL, node); -+} -+ -+void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { -+ VisitRR(this, kRiscvCvtDUw, node); -+} -+ -+void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) { -+ VisitRR(this, kRiscvTruncWS, node); -+} -+ -+void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) { -+ VisitRR(this, kRiscvTruncUwS, node); -+} -+ -+void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* value = node->InputAt(0); -+ // Match ChangeFloat64ToInt32(Float64Round##OP) to corresponding instruction -+ // which does rounding and conversion to integer format. -+ if (CanCover(node, value)) { -+ switch (value->opcode()) { -+ case IrOpcode::kFloat64RoundDown: -+ Emit(kRiscvFloorWD, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ case IrOpcode::kFloat64RoundUp: -+ Emit(kRiscvCeilWD, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ case IrOpcode::kFloat64RoundTiesEven: -+ Emit(kRiscvRoundWD, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ case IrOpcode::kFloat64RoundTruncate: -+ Emit(kRiscvTruncWD, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ default: -+ break; -+ } -+ if (value->opcode() == IrOpcode::kChangeFloat32ToFloat64) { -+ Node* next = value->InputAt(0); -+ if (CanCover(value, next)) { -+ // Match ChangeFloat64ToInt32(ChangeFloat32ToFloat64(Float64Round##OP)) -+ switch (next->opcode()) { -+ case IrOpcode::kFloat32RoundDown: -+ Emit(kRiscvFloorWS, g.DefineAsRegister(node), -+ g.UseRegister(next->InputAt(0))); -+ return; -+ case IrOpcode::kFloat32RoundUp: -+ Emit(kRiscvCeilWS, g.DefineAsRegister(node), -+ g.UseRegister(next->InputAt(0))); -+ return; -+ case IrOpcode::kFloat32RoundTiesEven: -+ Emit(kRiscvRoundWS, g.DefineAsRegister(node), -+ g.UseRegister(next->InputAt(0))); -+ return; -+ case IrOpcode::kFloat32RoundTruncate: -+ Emit(kRiscvTruncWS, g.DefineAsRegister(node), -+ g.UseRegister(next->InputAt(0))); -+ return; -+ default: -+ Emit(kRiscvTruncWS, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ } -+ } else { -+ // Match float32 -> float64 -> int32 representation change path. -+ Emit(kRiscvTruncWS, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ } -+ } -+ } -+ VisitRR(this, kRiscvTruncWD, node); -+} -+ -+void InstructionSelector::VisitChangeFloat64ToInt64(Node* node) { -+ VisitRR(this, kRiscvTruncLD, node); -+} -+ -+void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { -+ VisitRR(this, kRiscvTruncUwD, node); -+} -+ -+void InstructionSelector::VisitChangeFloat64ToUint64(Node* node) { -+ VisitRR(this, kRiscvTruncUlD, node); -+} -+ -+void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) { -+ VisitRR(this, kRiscvTruncUwD, node); -+} -+ -+void InstructionSelector::VisitTruncateFloat64ToInt64(Node* node) { -+ VisitRR(this, kRiscvTruncLD, node); -+} -+ -+void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) { -+ RiscvOperandGenerator g(this); -+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))}; -+ InstructionOperand outputs[2]; -+ size_t output_count = 0; -+ outputs[output_count++] = g.DefineAsRegister(node); -+ -+ Node* success_output = NodeProperties::FindProjection(node, 1); -+ if (success_output) { -+ outputs[output_count++] = g.DefineAsRegister(success_output); -+ } -+ -+ this->Emit(kRiscvTruncLS, output_count, outputs, 1, inputs); -+} -+ -+void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) { -+ RiscvOperandGenerator g(this); -+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))}; -+ InstructionOperand outputs[2]; -+ size_t output_count = 0; -+ outputs[output_count++] = g.DefineAsRegister(node); -+ -+ Node* success_output = NodeProperties::FindProjection(node, 1); -+ if (success_output) { -+ outputs[output_count++] = g.DefineAsRegister(success_output); -+ } -+ -+ Emit(kRiscvTruncLD, output_count, outputs, 1, inputs); -+} -+ -+void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) { -+ RiscvOperandGenerator g(this); -+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))}; -+ InstructionOperand outputs[2]; -+ size_t output_count = 0; -+ outputs[output_count++] = g.DefineAsRegister(node); -+ -+ Node* success_output = NodeProperties::FindProjection(node, 1); -+ if (success_output) { -+ outputs[output_count++] = g.DefineAsRegister(success_output); -+ } -+ -+ Emit(kRiscvTruncUlS, output_count, outputs, 1, inputs); -+} -+ -+void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) { -+ RiscvOperandGenerator g(this); -+ -+ InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))}; -+ InstructionOperand outputs[2]; -+ size_t output_count = 0; -+ outputs[output_count++] = g.DefineAsRegister(node); -+ -+ Node* success_output = NodeProperties::FindProjection(node, 1); -+ if (success_output) { -+ outputs[output_count++] = g.DefineAsRegister(success_output); -+ } -+ -+ Emit(kRiscvTruncUlD, output_count, outputs, 1, inputs); -+} -+ -+void InstructionSelector::VisitBitcastWord32ToWord64(Node* node) { -+ UNIMPLEMENTED(); -+} -+ -+void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { -+ Node* value = node->InputAt(0); -+ if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) { -+ // Generate sign-extending load. -+ LoadRepresentation load_rep = LoadRepresentationOf(value->op()); -+ InstructionCode opcode = kArchNop; -+ switch (load_rep.representation()) { -+ case MachineRepresentation::kBit: // Fall through. -+ case MachineRepresentation::kWord8: -+ opcode = load_rep.IsUnsigned() ? kRiscvLbu : kRiscvLb; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = load_rep.IsUnsigned() ? kRiscvLhu : kRiscvLh; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kRiscvLw; -+ break; -+ default: -+ UNREACHABLE(); -+ return; -+ } -+ EmitLoad(this, value, opcode, node); -+ } else { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvShl32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), -+ g.TempImmediate(0)); -+ } -+} -+ -+void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* value = node->InputAt(0); -+ switch (value->opcode()) { -+ case IrOpcode::kLoad: { -+ LoadRepresentation load_rep = LoadRepresentationOf(value->op()); -+ if (load_rep.IsUnsigned()) { -+ switch (load_rep.representation()) { -+ case MachineRepresentation::kWord8: -+ case MachineRepresentation::kWord16: -+ case MachineRepresentation::kWord32: -+ Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value)); -+ return; -+ default: -+ break; -+ } -+ } -+ break; -+ } -+ default: -+ break; -+ } -+ Emit(kRiscvZeroExtendWord, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* value = node->InputAt(0); -+ if (CanCover(node, value)) { -+ switch (value->opcode()) { -+ case IrOpcode::kWord64Sar: { -+ if (CanCover(value, value->InputAt(0)) && -+ TryEmitExtendingLoad(this, value, node)) { -+ return; -+ } else { -+ Int64BinopMatcher m(value); -+ if (m.right().IsInRange(32, 63)) { -+ // After smi untagging no need for truncate. Combine sequence. -+ Emit(kRiscvSar64, g.DefineSameAsFirst(node), -+ g.UseRegister(m.left().node()), -+ g.UseImmediate(m.right().node())); -+ return; -+ } -+ } -+ break; -+ } -+ default: -+ break; -+ } -+ } -+ -+ // Semantics of this machine IR is not clear. For example, x86 zero-extend the -+ // truncated value; arm treats it as nop thus the upper 32-bit as undefined; -+ // mips emits ext instruction which zero-extend the 32-bit value; for riscv, -+ // we do sign-extension of the truncated value -+ Emit(kRiscvSignExtendWord, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* value = node->InputAt(0); -+ // Match TruncateFloat64ToFloat32(ChangeInt32ToFloat64) to corresponding -+ // instruction. -+ if (CanCover(node, value) && -+ value->opcode() == IrOpcode::kChangeInt32ToFloat64) { -+ Emit(kRiscvCvtSW, g.DefineAsRegister(node), -+ g.UseRegister(value->InputAt(0))); -+ return; -+ } -+ VisitRR(this, kRiscvCvtSD, node); -+} -+ -+void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) { -+ VisitRR(this, kArchTruncateDoubleToI, node); -+} -+ -+void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) { -+ VisitRR(this, kRiscvTruncWD, node); -+} -+ -+void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) { -+ VisitRR(this, kRiscvCvtSL, node); -+} -+ -+void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) { -+ VisitRR(this, kRiscvCvtDL, node); -+} -+ -+void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) { -+ VisitRR(this, kRiscvCvtSUl, node); -+} -+ -+void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) { -+ VisitRR(this, kRiscvCvtDUl, node); -+} -+ -+void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) { -+ VisitRR(this, kRiscvBitcastFloat32ToInt32, node); -+} -+ -+void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) { -+ VisitRR(this, kRiscvBitcastDL, node); -+} -+ -+void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) { -+ VisitRR(this, kRiscvBitcastInt32ToFloat32, node); -+} -+ -+void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) { -+ VisitRR(this, kRiscvBitcastLD, node); -+} -+ -+void InstructionSelector::VisitFloat32Add(Node* node) { -+ VisitRRR(this, kRiscvAddS, node); -+} -+ -+void InstructionSelector::VisitFloat64Add(Node* node) { -+ VisitRRR(this, kRiscvAddD, node); -+} -+ -+void InstructionSelector::VisitFloat32Sub(Node* node) { -+ VisitRRR(this, kRiscvSubS, node); -+} -+ -+void InstructionSelector::VisitFloat64Sub(Node* node) { -+ VisitRRR(this, kRiscvSubD, node); -+} -+ -+void InstructionSelector::VisitFloat32Mul(Node* node) { -+ VisitRRR(this, kRiscvMulS, node); -+} -+ -+void InstructionSelector::VisitFloat64Mul(Node* node) { -+ VisitRRR(this, kRiscvMulD, node); -+} -+ -+void InstructionSelector::VisitFloat32Div(Node* node) { -+ VisitRRR(this, kRiscvDivS, node); -+} -+ -+void InstructionSelector::VisitFloat64Div(Node* node) { -+ VisitRRR(this, kRiscvDivD, node); -+} -+ -+void InstructionSelector::VisitFloat64Mod(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvModD, g.DefineAsFixed(node, fa0), -+ g.UseFixed(node->InputAt(0), fa0), g.UseFixed(node->InputAt(1), fa1)) -+ ->MarkAsCall(); -+} -+ -+void InstructionSelector::VisitFloat32Max(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvFloat32Max, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); -+} -+ -+void InstructionSelector::VisitFloat64Max(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvFloat64Max, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); -+} -+ -+void InstructionSelector::VisitFloat32Min(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvFloat32Min, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); -+} -+ -+void InstructionSelector::VisitFloat64Min(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvFloat64Min, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); -+} -+ -+void InstructionSelector::VisitFloat32Abs(Node* node) { -+ VisitRR(this, kRiscvAbsS, node); -+} -+ -+void InstructionSelector::VisitFloat64Abs(Node* node) { -+ VisitRR(this, kRiscvAbsD, node); -+} -+ -+void InstructionSelector::VisitFloat32Sqrt(Node* node) { -+ VisitRR(this, kRiscvSqrtS, node); -+} -+ -+void InstructionSelector::VisitFloat64Sqrt(Node* node) { -+ VisitRR(this, kRiscvSqrtD, node); -+} -+ -+void InstructionSelector::VisitFloat32RoundDown(Node* node) { -+ VisitRR(this, kRiscvFloat32RoundDown, node); -+} -+ -+void InstructionSelector::VisitFloat64RoundDown(Node* node) { -+ VisitRR(this, kRiscvFloat64RoundDown, node); -+} -+ -+void InstructionSelector::VisitFloat32RoundUp(Node* node) { -+ VisitRR(this, kRiscvFloat32RoundUp, node); -+} -+ -+void InstructionSelector::VisitFloat64RoundUp(Node* node) { -+ VisitRR(this, kRiscvFloat64RoundUp, node); -+} -+ -+void InstructionSelector::VisitFloat32RoundTruncate(Node* node) { -+ VisitRR(this, kRiscvFloat32RoundTruncate, node); -+} -+ -+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { -+ VisitRR(this, kRiscvFloat64RoundTruncate, node); -+} -+ -+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { -+ UNREACHABLE(); -+} -+ -+void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) { -+ VisitRR(this, kRiscvFloat32RoundTiesEven, node); -+} -+ -+void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { -+ VisitRR(this, kRiscvFloat64RoundTiesEven, node); -+} -+ -+void InstructionSelector::VisitFloat32Neg(Node* node) { -+ VisitRR(this, kRiscvNegS, node); -+} -+ -+void InstructionSelector::VisitFloat64Neg(Node* node) { -+ VisitRR(this, kRiscvNegD, node); -+} -+ -+void InstructionSelector::VisitFloat64Ieee754Binop(Node* node, -+ InstructionCode opcode) { -+ RiscvOperandGenerator g(this); -+ Emit(opcode, g.DefineAsFixed(node, fa0), g.UseFixed(node->InputAt(0), fa0), -+ g.UseFixed(node->InputAt(1), fa1)) -+ ->MarkAsCall(); -+} -+ -+void InstructionSelector::VisitFloat64Ieee754Unop(Node* node, -+ InstructionCode opcode) { -+ RiscvOperandGenerator g(this); -+ Emit(opcode, g.DefineAsFixed(node, fa0), g.UseFixed(node->InputAt(0), fa1)) -+ ->MarkAsCall(); -+} -+ -+void InstructionSelector::EmitPrepareArguments( -+ ZoneVector* arguments, const CallDescriptor* call_descriptor, -+ Node* node) { -+ RiscvOperandGenerator g(this); -+ -+ // Prepare for C function call. -+ if (call_descriptor->IsCFunctionCall()) { -+ Emit(kArchPrepareCallCFunction | MiscField::encode(static_cast( -+ call_descriptor->ParameterCount())), -+ 0, nullptr, 0, nullptr); -+ -+ // Poke any stack arguments. -+ int slot = kCArgSlotCount; -+ for (PushParameter input : (*arguments)) { -+ Emit(kRiscvStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node), -+ g.TempImmediate(slot << kSystemPointerSizeLog2)); -+ ++slot; -+ } -+ } else { -+ int push_count = static_cast(call_descriptor->StackParameterCount()); -+ if (push_count > 0) { -+ // Calculate needed space -+ int stack_size = 0; -+ for (PushParameter input : (*arguments)) { -+ if (input.node) { -+ stack_size += input.location.GetSizeInPointers(); -+ } -+ } -+ Emit(kRiscvStackClaim, g.NoOutput(), -+ g.TempImmediate(stack_size << kSystemPointerSizeLog2)); -+ } -+ for (size_t n = 0; n < arguments->size(); ++n) { -+ PushParameter input = (*arguments)[n]; -+ if (input.node) { -+ Emit(kRiscvStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node), -+ g.TempImmediate(static_cast(n << kSystemPointerSizeLog2))); -+ } -+ } -+ } -+} -+ -+void InstructionSelector::EmitPrepareResults( -+ ZoneVector* results, const CallDescriptor* call_descriptor, -+ Node* node) { -+ RiscvOperandGenerator g(this); -+ -+ int reverse_slot = 0; -+ for (PushParameter output : *results) { -+ if (!output.location.IsCallerFrameSlot()) continue; -+ // Skip any alignment holes in nodes. -+ if (output.node != nullptr) { -+ DCHECK(!call_descriptor->IsCFunctionCall()); -+ if (output.location.GetType() == MachineType::Float32()) { -+ MarkAsFloat32(output.node); -+ } else if (output.location.GetType() == MachineType::Float64()) { -+ MarkAsFloat64(output.node); -+ } -+ Emit(kRiscvPeek, g.DefineAsRegister(output.node), -+ g.UseImmediate(reverse_slot)); -+ } -+ reverse_slot += output.location.GetSizeInPointers(); -+ } -+} -+ -+bool InstructionSelector::IsTailCallAddressImmediate() { return false; } -+ -+int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; } -+ -+void InstructionSelector::VisitUnalignedLoad(Node* node) { -+ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); -+ RiscvOperandGenerator g(this); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ -+ ArchOpcode opcode = kArchNop; -+ switch (load_rep.representation()) { -+ case MachineRepresentation::kFloat32: -+ opcode = kRiscvULoadFloat; -+ break; -+ case MachineRepresentation::kFloat64: -+ opcode = kRiscvULoadDouble; -+ break; -+ case MachineRepresentation::kBit: // Fall through. -+ case MachineRepresentation::kWord8: -+ UNREACHABLE(); -+ case MachineRepresentation::kWord16: -+ opcode = load_rep.IsUnsigned() ? kRiscvUlhu : kRiscvUlh; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = load_rep.IsUnsigned() ? kRiscvUlwu : kRiscvUlw; -+ break; -+ case MachineRepresentation::kTaggedSigned: // Fall through. -+ case MachineRepresentation::kTaggedPointer: // Fall through. -+ case MachineRepresentation::kTagged: // Fall through. -+ case MachineRepresentation::kWord64: -+ opcode = kRiscvUld; -+ break; -+ case MachineRepresentation::kSimd128: -+ opcode = kRiscvMsaLd; -+ break; -+ case MachineRepresentation::kCompressedPointer: // Fall through. -+ case MachineRepresentation::kCompressed: // Fall through. -+ case MachineRepresentation::kNone: -+ UNREACHABLE(); -+ } -+ -+ if (g.CanBeImmediate(index, opcode)) { -+ Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); -+ } else { -+ InstructionOperand addr_reg = g.TempRegister(); -+ Emit(kRiscvAdd64 | AddressingModeField::encode(kMode_None), addr_reg, -+ g.UseRegister(index), g.UseRegister(base)); -+ // Emit desired load opcode, using temp addr_reg. -+ Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.DefineAsRegister(node), addr_reg, g.TempImmediate(0)); -+ } -+} -+ -+void InstructionSelector::VisitUnalignedStore(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ Node* value = node->InputAt(2); -+ -+ UnalignedStoreRepresentation rep = UnalignedStoreRepresentationOf(node->op()); -+ ArchOpcode opcode = kArchNop; -+ switch (rep) { -+ case MachineRepresentation::kFloat32: -+ opcode = kRiscvUStoreFloat; -+ break; -+ case MachineRepresentation::kFloat64: -+ opcode = kRiscvUStoreDouble; -+ break; -+ case MachineRepresentation::kBit: // Fall through. -+ case MachineRepresentation::kWord8: -+ UNREACHABLE(); -+ case MachineRepresentation::kWord16: -+ opcode = kRiscvUsh; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kRiscvUsw; -+ break; -+ case MachineRepresentation::kTaggedSigned: // Fall through. -+ case MachineRepresentation::kTaggedPointer: // Fall through. -+ case MachineRepresentation::kTagged: // Fall through. -+ case MachineRepresentation::kWord64: -+ opcode = kRiscvUsd; -+ break; -+ case MachineRepresentation::kSimd128: -+ opcode = kRiscvMsaSt; -+ break; -+ case MachineRepresentation::kCompressedPointer: // Fall through. -+ case MachineRepresentation::kCompressed: // Fall through. -+ case MachineRepresentation::kNone: -+ UNREACHABLE(); -+ } -+ -+ if (g.CanBeImmediate(index, opcode)) { -+ Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), -+ g.UseRegister(base), g.UseImmediate(index), -+ g.UseRegisterOrImmediateZero(value)); -+ } else { -+ InstructionOperand addr_reg = g.TempRegister(); -+ Emit(kRiscvAdd64 | AddressingModeField::encode(kMode_None), addr_reg, -+ g.UseRegister(index), g.UseRegister(base)); -+ // Emit desired store opcode, using temp addr_reg. -+ Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), -+ addr_reg, g.TempImmediate(0), g.UseRegisterOrImmediateZero(value)); -+ } -+} -+ -+namespace { -+ -+// Shared routine for multiple compare operations. -+static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, -+ InstructionOperand left, InstructionOperand right, -+ FlagsContinuation* cont) { -+ selector->EmitWithContinuation(opcode, left, right, cont); -+} -+ -+// Shared routine for multiple float32 compare operations. -+void VisitFloat32Compare(InstructionSelector* selector, Node* node, -+ FlagsContinuation* cont) { -+ RiscvOperandGenerator g(selector); -+ Float32BinopMatcher m(node); -+ InstructionOperand lhs, rhs; -+ -+ lhs = m.left().IsZero() ? g.UseImmediate(m.left().node()) -+ : g.UseRegister(m.left().node()); -+ rhs = m.right().IsZero() ? g.UseImmediate(m.right().node()) -+ : g.UseRegister(m.right().node()); -+ VisitCompare(selector, kRiscvCmpS, lhs, rhs, cont); -+} -+ -+// Shared routine for multiple float64 compare operations. -+void VisitFloat64Compare(InstructionSelector* selector, Node* node, -+ FlagsContinuation* cont) { -+ RiscvOperandGenerator g(selector); -+ Float64BinopMatcher m(node); -+ InstructionOperand lhs, rhs; -+ -+ lhs = m.left().IsZero() ? g.UseImmediate(m.left().node()) -+ : g.UseRegister(m.left().node()); -+ rhs = m.right().IsZero() ? g.UseImmediate(m.right().node()) -+ : g.UseRegister(m.right().node()); -+ VisitCompare(selector, kRiscvCmpD, lhs, rhs, cont); -+} -+ -+// Shared routine for multiple word compare operations. -+void VisitWordCompare(InstructionSelector* selector, Node* node, -+ InstructionCode opcode, FlagsContinuation* cont, -+ bool commutative) { -+ RiscvOperandGenerator g(selector); -+ Node* left = node->InputAt(0); -+ Node* right = node->InputAt(1); -+ -+ // Match immediates on left or right side of comparison. -+ if (g.CanBeImmediate(right, opcode)) { -+ if (opcode == kRiscvTst) { -+ VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), -+ cont); -+ } else { -+ switch (cont->condition()) { -+ case kEqual: -+ case kNotEqual: -+ if (cont->IsSet()) { -+ VisitCompare(selector, opcode, g.UseRegister(left), -+ g.UseImmediate(right), cont); -+ } else { -+ VisitCompare(selector, opcode, g.UseRegister(left), -+ g.UseRegister(right), cont); -+ } -+ break; -+ case kSignedLessThan: -+ case kSignedGreaterThanOrEqual: -+ case kUnsignedLessThan: -+ case kUnsignedGreaterThanOrEqual: -+ VisitCompare(selector, opcode, g.UseRegister(left), -+ g.UseImmediate(right), cont); -+ break; -+ default: -+ VisitCompare(selector, opcode, g.UseRegister(left), -+ g.UseRegister(right), cont); -+ } -+ } -+ } else if (g.CanBeImmediate(left, opcode)) { -+ if (!commutative) cont->Commute(); -+ if (opcode == kRiscvTst) { -+ VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), -+ cont); -+ } else { -+ switch (cont->condition()) { -+ case kEqual: -+ case kNotEqual: -+ if (cont->IsSet()) { -+ VisitCompare(selector, opcode, g.UseRegister(right), -+ g.UseImmediate(left), cont); -+ } else { -+ VisitCompare(selector, opcode, g.UseRegister(right), -+ g.UseRegister(left), cont); -+ } -+ break; -+ case kSignedLessThan: -+ case kSignedGreaterThanOrEqual: -+ case kUnsignedLessThan: -+ case kUnsignedGreaterThanOrEqual: -+ VisitCompare(selector, opcode, g.UseRegister(right), -+ g.UseImmediate(left), cont); -+ break; -+ default: -+ VisitCompare(selector, opcode, g.UseRegister(right), -+ g.UseRegister(left), cont); -+ } -+ } -+ } else { -+ VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), -+ cont); -+ } -+} -+ -+bool IsNodeUnsigned(Node* n) { -+ NodeMatcher m(n); -+ -+ if (m.IsLoad() || m.IsUnalignedLoad() || m.IsPoisonedLoad() || -+ m.IsProtectedLoad() || m.IsWord32AtomicLoad() || m.IsWord64AtomicLoad()) { -+ LoadRepresentation load_rep = LoadRepresentationOf(n->op()); -+ return load_rep.IsUnsigned(); -+ } else { -+ return m.IsUint32Div() || m.IsUint32LessThan() || -+ m.IsUint32LessThanOrEqual() || m.IsUint32Mod() || -+ m.IsUint32MulHigh() || m.IsChangeFloat64ToUint32() || -+ m.IsTruncateFloat64ToUint32() || m.IsTruncateFloat32ToUint32(); -+ } -+} -+ -+// Shared routine for multiple word compare operations. -+void VisitFullWord32Compare(InstructionSelector* selector, Node* node, -+ InstructionCode opcode, FlagsContinuation* cont) { -+ RiscvOperandGenerator g(selector); -+ InstructionOperand leftOp = g.TempRegister(); -+ InstructionOperand rightOp = g.TempRegister(); -+ -+ selector->Emit(kRiscvShl64, leftOp, g.UseRegister(node->InputAt(0)), -+ g.TempImmediate(32)); -+ selector->Emit(kRiscvShl64, rightOp, g.UseRegister(node->InputAt(1)), -+ g.TempImmediate(32)); -+ -+ VisitCompare(selector, opcode, leftOp, rightOp, cont); -+} -+ -+void VisitOptimizedWord32Compare(InstructionSelector* selector, Node* node, -+ InstructionCode opcode, -+ FlagsContinuation* cont) { -+ if (FLAG_debug_code) { -+ RiscvOperandGenerator g(selector); -+ InstructionOperand leftOp = g.TempRegister(); -+ InstructionOperand rightOp = g.TempRegister(); -+ InstructionOperand optimizedResult = g.TempRegister(); -+ InstructionOperand fullResult = g.TempRegister(); -+ FlagsCondition condition = cont->condition(); -+ InstructionCode testOpcode = opcode | -+ FlagsConditionField::encode(condition) | -+ FlagsModeField::encode(kFlags_set); -+ -+ selector->Emit(testOpcode, optimizedResult, g.UseRegister(node->InputAt(0)), -+ g.UseRegister(node->InputAt(1))); -+ -+ selector->Emit(kRiscvShl64, leftOp, g.UseRegister(node->InputAt(0)), -+ g.TempImmediate(32)); -+ selector->Emit(kRiscvShl64, rightOp, g.UseRegister(node->InputAt(1)), -+ g.TempImmediate(32)); -+ selector->Emit(testOpcode, fullResult, leftOp, rightOp); -+ -+ selector->Emit(kRiscvAssertEqual, g.NoOutput(), optimizedResult, fullResult, -+ g.TempImmediate(static_cast( -+ AbortReason::kUnsupportedNonPrimitiveCompare))); -+ } -+ -+ VisitWordCompare(selector, node, opcode, cont, false); -+} -+ -+void VisitWord32Compare(InstructionSelector* selector, Node* node, -+ FlagsContinuation* cont) { -+ // RISC-V doesn't support Word32 compare instructions. Instead it relies -+ // that the values in registers are correctly sign-extended and uses -+ // Word64 comparison instead. This behavior is correct in most cases, -+ // but doesn't work when comparing signed with unsigned operands. -+ // We could simulate full Word32 compare in all cases but this would -+ // create an unnecessary overhead since unsigned integers are rarely -+ // used in JavaScript. -+ // The solution proposed here tries to match a comparison of signed -+ // with unsigned operand, and perform full Word32Compare only -+ // in those cases. Unfortunately, the solution is not complete because -+ // it might skip cases where Word32 full compare is needed, so -+ // basically it is a hack. -+ // When call to a host function in simulator, if the function return a -+ // int32 value, the simulator do not sign-extended to int64 because in -+ // simulator we do not know the function whether return a int32 or int64. -+ // so we need do a full word32 compare in this case. -+#ifndef USE_SIMULATOR -+ if (IsNodeUnsigned(node->InputAt(0)) != IsNodeUnsigned(node->InputAt(1))) { -+#else -+ if (IsNodeUnsigned(node->InputAt(0)) != IsNodeUnsigned(node->InputAt(1)) || -+ node->InputAt(0)->opcode() == IrOpcode::kCall || -+ node->InputAt(1)->opcode() == IrOpcode::kCall) { -+#endif -+ VisitFullWord32Compare(selector, node, kRiscvCmp, cont); -+ } else { -+ VisitOptimizedWord32Compare(selector, node, kRiscvCmp, cont); -+ } -+} -+ -+void VisitWord64Compare(InstructionSelector* selector, Node* node, -+ FlagsContinuation* cont) { -+ VisitWordCompare(selector, node, kRiscvCmp, cont, false); -+} -+ -+void EmitWordCompareZero(InstructionSelector* selector, Node* value, -+ FlagsContinuation* cont) { -+ RiscvOperandGenerator g(selector); -+ selector->EmitWithContinuation(kRiscvCmp, g.UseRegister(value), -+ g.TempImmediate(0), cont); -+} -+ -+void VisitAtomicLoad(InstructionSelector* selector, Node* node, -+ ArchOpcode opcode) { -+ RiscvOperandGenerator g(selector); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ if (g.CanBeImmediate(index, opcode)) { -+ selector->Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.DefineAsRegister(node), g.UseRegister(base), -+ g.UseImmediate(index)); -+ } else { -+ InstructionOperand addr_reg = g.TempRegister(); -+ selector->Emit(kRiscvAdd64 | AddressingModeField::encode(kMode_None), -+ addr_reg, g.UseRegister(index), g.UseRegister(base)); -+ // Emit desired load opcode, using temp addr_reg. -+ selector->Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.DefineAsRegister(node), addr_reg, g.TempImmediate(0)); -+ } -+} -+ -+void VisitAtomicStore(InstructionSelector* selector, Node* node, -+ ArchOpcode opcode) { -+ RiscvOperandGenerator g(selector); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ Node* value = node->InputAt(2); -+ -+ if (g.CanBeImmediate(index, opcode)) { -+ selector->Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.NoOutput(), g.UseRegister(base), g.UseImmediate(index), -+ g.UseRegisterOrImmediateZero(value)); -+ } else { -+ InstructionOperand addr_reg = g.TempRegister(); -+ selector->Emit(kRiscvAdd64 | AddressingModeField::encode(kMode_None), -+ addr_reg, g.UseRegister(index), g.UseRegister(base)); -+ // Emit desired store opcode, using temp addr_reg. -+ selector->Emit(opcode | AddressingModeField::encode(kMode_MRI), -+ g.NoOutput(), addr_reg, g.TempImmediate(0), -+ g.UseRegisterOrImmediateZero(value)); -+ } -+} -+ -+void VisitAtomicExchange(InstructionSelector* selector, Node* node, -+ ArchOpcode opcode) { -+ RiscvOperandGenerator g(selector); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ Node* value = node->InputAt(2); -+ -+ AddressingMode addressing_mode = kMode_MRI; -+ InstructionOperand inputs[3]; -+ size_t input_count = 0; -+ inputs[input_count++] = g.UseUniqueRegister(base); -+ inputs[input_count++] = g.UseUniqueRegister(index); -+ inputs[input_count++] = g.UseUniqueRegister(value); -+ InstructionOperand outputs[1]; -+ outputs[0] = g.UseUniqueRegister(node); -+ InstructionOperand temp[3]; -+ temp[0] = g.TempRegister(); -+ temp[1] = g.TempRegister(); -+ temp[2] = g.TempRegister(); -+ InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); -+ selector->Emit(code, 1, outputs, input_count, inputs, 3, temp); -+} -+ -+void VisitAtomicCompareExchange(InstructionSelector* selector, Node* node, -+ ArchOpcode opcode) { -+ RiscvOperandGenerator g(selector); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ Node* old_value = node->InputAt(2); -+ Node* new_value = node->InputAt(3); -+ -+ AddressingMode addressing_mode = kMode_MRI; -+ InstructionOperand inputs[4]; -+ size_t input_count = 0; -+ inputs[input_count++] = g.UseUniqueRegister(base); -+ inputs[input_count++] = g.UseUniqueRegister(index); -+ inputs[input_count++] = g.UseUniqueRegister(old_value); -+ inputs[input_count++] = g.UseUniqueRegister(new_value); -+ InstructionOperand outputs[1]; -+ outputs[0] = g.UseUniqueRegister(node); -+ InstructionOperand temp[3]; -+ temp[0] = g.TempRegister(); -+ temp[1] = g.TempRegister(); -+ temp[2] = g.TempRegister(); -+ InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); -+ selector->Emit(code, 1, outputs, input_count, inputs, 3, temp); -+} -+ -+void VisitAtomicBinop(InstructionSelector* selector, Node* node, -+ ArchOpcode opcode) { -+ RiscvOperandGenerator g(selector); -+ Node* base = node->InputAt(0); -+ Node* index = node->InputAt(1); -+ Node* value = node->InputAt(2); -+ -+ AddressingMode addressing_mode = kMode_MRI; -+ InstructionOperand inputs[3]; -+ size_t input_count = 0; -+ inputs[input_count++] = g.UseUniqueRegister(base); -+ inputs[input_count++] = g.UseUniqueRegister(index); -+ inputs[input_count++] = g.UseUniqueRegister(value); -+ InstructionOperand outputs[1]; -+ outputs[0] = g.UseUniqueRegister(node); -+ InstructionOperand temps[4]; -+ temps[0] = g.TempRegister(); -+ temps[1] = g.TempRegister(); -+ temps[2] = g.TempRegister(); -+ temps[3] = g.TempRegister(); -+ InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); -+ selector->Emit(code, 1, outputs, input_count, inputs, 4, temps); -+} -+ -+} // namespace -+ -+void InstructionSelector::VisitStackPointerGreaterThan( -+ Node* node, FlagsContinuation* cont) { -+ StackCheckKind kind = StackCheckKindOf(node->op()); -+ InstructionCode opcode = -+ kArchStackPointerGreaterThan | MiscField::encode(static_cast(kind)); -+ -+ RiscvOperandGenerator g(this); -+ -+ // No outputs. -+ InstructionOperand* const outputs = nullptr; -+ const int output_count = 0; -+ -+ // Applying an offset to this stack check requires a temp register. Offsets -+ // are only applied to the first stack check. If applying an offset, we must -+ // ensure the input and temp registers do not alias, thus kUniqueRegister. -+ InstructionOperand temps[] = {g.TempRegister()}; -+ const int temp_count = (kind == StackCheckKind::kJSFunctionEntry ? 1 : 0); -+ const auto register_mode = (kind == StackCheckKind::kJSFunctionEntry) -+ ? OperandGenerator::kUniqueRegister -+ : OperandGenerator::kRegister; -+ -+ Node* const value = node->InputAt(0); -+ InstructionOperand inputs[] = {g.UseRegisterWithMode(value, register_mode)}; -+ static constexpr int input_count = arraysize(inputs); -+ -+ EmitWithContinuation(opcode, output_count, outputs, input_count, inputs, -+ temp_count, temps, cont); -+} -+ -+// Shared routine for word comparisons against zero. -+void InstructionSelector::VisitWordCompareZero(Node* user, Node* value, -+ FlagsContinuation* cont) { -+ // Try to combine with comparisons against 0 by simply inverting the branch. -+ while (CanCover(user, value)) { -+ if (value->opcode() == IrOpcode::kWord32Equal) { -+ Int32BinopMatcher m(value); -+ if (!m.right().Is(0)) break; -+ user = value; -+ value = m.left().node(); -+ } else if (value->opcode() == IrOpcode::kWord64Equal) { -+ Int64BinopMatcher m(value); -+ if (!m.right().Is(0)) break; -+ user = value; -+ value = m.left().node(); -+ } else { -+ break; -+ } -+ -+ cont->Negate(); -+ } -+ -+ if (CanCover(user, value)) { -+ switch (value->opcode()) { -+ case IrOpcode::kWord32Equal: -+ cont->OverwriteAndNegateIfEqual(kEqual); -+ return VisitWord32Compare(this, value, cont); -+ case IrOpcode::kInt32LessThan: -+ cont->OverwriteAndNegateIfEqual(kSignedLessThan); -+ return VisitWord32Compare(this, value, cont); -+ case IrOpcode::kInt32LessThanOrEqual: -+ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); -+ return VisitWord32Compare(this, value, cont); -+ case IrOpcode::kUint32LessThan: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); -+ return VisitWord32Compare(this, value, cont); -+ case IrOpcode::kUint32LessThanOrEqual: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); -+ return VisitWord32Compare(this, value, cont); -+ case IrOpcode::kWord64Equal: -+ cont->OverwriteAndNegateIfEqual(kEqual); -+ return VisitWord64Compare(this, value, cont); -+ case IrOpcode::kInt64LessThan: -+ cont->OverwriteAndNegateIfEqual(kSignedLessThan); -+ return VisitWord64Compare(this, value, cont); -+ case IrOpcode::kInt64LessThanOrEqual: -+ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); -+ return VisitWord64Compare(this, value, cont); -+ case IrOpcode::kUint64LessThan: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); -+ return VisitWord64Compare(this, value, cont); -+ case IrOpcode::kUint64LessThanOrEqual: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); -+ return VisitWord64Compare(this, value, cont); -+ case IrOpcode::kFloat32Equal: -+ cont->OverwriteAndNegateIfEqual(kEqual); -+ return VisitFloat32Compare(this, value, cont); -+ case IrOpcode::kFloat32LessThan: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); -+ return VisitFloat32Compare(this, value, cont); -+ case IrOpcode::kFloat32LessThanOrEqual: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); -+ return VisitFloat32Compare(this, value, cont); -+ case IrOpcode::kFloat64Equal: -+ cont->OverwriteAndNegateIfEqual(kEqual); -+ return VisitFloat64Compare(this, value, cont); -+ case IrOpcode::kFloat64LessThan: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); -+ return VisitFloat64Compare(this, value, cont); -+ case IrOpcode::kFloat64LessThanOrEqual: -+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); -+ return VisitFloat64Compare(this, value, cont); -+ case IrOpcode::kProjection: -+ // Check if this is the overflow output projection of an -+ // WithOverflow node. -+ if (ProjectionIndexOf(value->op()) == 1u) { -+ // We cannot combine the WithOverflow with this branch -+ // unless the 0th projection (the use of the actual value of the -+ // is either nullptr, which means there's no use of the -+ // actual value, or was already defined, which means it is scheduled -+ // *AFTER* this branch). -+ Node* const node = value->InputAt(0); -+ Node* const result = NodeProperties::FindProjection(node, 0); -+ if (result == nullptr || IsDefined(result)) { -+ switch (node->opcode()) { -+ case IrOpcode::kInt32AddWithOverflow: -+ cont->OverwriteAndNegateIfEqual(kOverflow); -+ return VisitBinop(this, node, kRiscvAdd64, cont); -+ case IrOpcode::kInt32SubWithOverflow: -+ cont->OverwriteAndNegateIfEqual(kOverflow); -+ return VisitBinop(this, node, kRiscvSub64, cont); -+ case IrOpcode::kInt32MulWithOverflow: -+ cont->OverwriteAndNegateIfEqual(kOverflow); -+ return VisitBinop(this, node, kRiscvMulOvf32, cont); -+ case IrOpcode::kInt64AddWithOverflow: -+ cont->OverwriteAndNegateIfEqual(kOverflow); -+ return VisitBinop(this, node, kRiscvAddOvf64, cont); -+ case IrOpcode::kInt64SubWithOverflow: -+ cont->OverwriteAndNegateIfEqual(kOverflow); -+ return VisitBinop(this, node, kRiscvSubOvf64, cont); -+ default: -+ break; -+ } -+ } -+ } -+ break; -+ case IrOpcode::kWord32And: -+ case IrOpcode::kWord64And: -+ return VisitWordCompare(this, value, kRiscvTst, cont, true); -+ case IrOpcode::kStackPointerGreaterThan: -+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition); -+ return VisitStackPointerGreaterThan(value, cont); -+ default: -+ break; -+ } -+ } -+ -+ // Continuation could not be combined with a compare, emit compare against 0. -+ EmitWordCompareZero(this, value, cont); -+} -+ -+void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { -+ RiscvOperandGenerator g(this); -+ InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); -+ -+ // Emit either ArchTableSwitch or ArchBinarySearchSwitch. -+ if (enable_switch_jump_table_ == kEnableSwitchJumpTable) { -+ static const size_t kMaxTableSwitchValueRange = 2 << 16; -+ size_t table_space_cost = 10 + 2 * sw.value_range(); -+ size_t table_time_cost = 3; -+ size_t lookup_space_cost = 2 + 2 * sw.case_count(); -+ size_t lookup_time_cost = sw.case_count(); -+ if (sw.case_count() > 0 && -+ table_space_cost + 3 * table_time_cost <= -+ lookup_space_cost + 3 * lookup_time_cost && -+ sw.min_value() > std::numeric_limits::min() && -+ sw.value_range() <= kMaxTableSwitchValueRange) { -+ InstructionOperand index_operand = value_operand; -+ if (sw.min_value()) { -+ index_operand = g.TempRegister(); -+ Emit(kRiscvSub32, index_operand, value_operand, -+ g.TempImmediate(sw.min_value())); -+ } -+ // Generate a table lookup. -+ return EmitTableSwitch(sw, index_operand); -+ } -+ } -+ -+ // Generate a tree of conditional jumps. -+ return EmitBinarySearchSwitch(sw, value_operand); -+} -+ -+void InstructionSelector::VisitWord32Equal(Node* const node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); -+ Int32BinopMatcher m(node); -+ if (m.right().Is(0)) { -+ return VisitWordCompareZero(m.node(), m.left().node(), &cont); -+ } -+ -+ VisitWord32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitInt32LessThan(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); -+ VisitWord32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { -+ FlagsContinuation cont = -+ FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); -+ VisitWord32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitUint32LessThan(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); -+ VisitWord32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { -+ FlagsContinuation cont = -+ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); -+ VisitWord32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { -+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); -+ return VisitBinop(this, node, kRiscvAdd64, &cont); -+ } -+ FlagsContinuation cont; -+ VisitBinop(this, node, kRiscvAdd64, &cont); -+} -+ -+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { -+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); -+ return VisitBinop(this, node, kRiscvSub64, &cont); -+ } -+ FlagsContinuation cont; -+ VisitBinop(this, node, kRiscvSub64, &cont); -+} -+ -+void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { -+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); -+ return VisitBinop(this, node, kRiscvMulOvf32, &cont); -+ } -+ FlagsContinuation cont; -+ VisitBinop(this, node, kRiscvMulOvf32, &cont); -+} -+ -+void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { -+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); -+ return VisitBinop(this, node, kRiscvAddOvf64, &cont); -+ } -+ FlagsContinuation cont; -+ VisitBinop(this, node, kRiscvAddOvf64, &cont); -+} -+ -+void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { -+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); -+ return VisitBinop(this, node, kRiscvSubOvf64, &cont); -+ } -+ FlagsContinuation cont; -+ VisitBinop(this, node, kRiscvSubOvf64, &cont); -+} -+ -+void InstructionSelector::VisitWord64Equal(Node* const node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); -+ Int64BinopMatcher m(node); -+ if (m.right().Is(0)) { -+ return VisitWordCompareZero(m.node(), m.left().node(), &cont); -+ } -+ -+ VisitWord64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitInt64LessThan(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); -+ VisitWord64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { -+ FlagsContinuation cont = -+ FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); -+ VisitWord64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitUint64LessThan(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); -+ VisitWord64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) { -+ FlagsContinuation cont = -+ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); -+ VisitWord64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat32Equal(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); -+ VisitFloat32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat32LessThan(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); -+ VisitFloat32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { -+ FlagsContinuation cont = -+ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); -+ VisitFloat32Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat64Equal(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); -+ VisitFloat64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat64LessThan(Node* node) { -+ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); -+ VisitFloat64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { -+ FlagsContinuation cont = -+ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); -+ VisitFloat64Compare(this, node, &cont); -+} -+ -+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { -+ VisitRR(this, kRiscvFloat64ExtractLowWord32, node); -+} -+ -+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { -+ VisitRR(this, kRiscvFloat64ExtractHighWord32, node); -+} -+ -+void InstructionSelector::VisitFloat64SilenceNaN(Node* node) { -+ VisitRR(this, kRiscvFloat64SilenceNaN, node); -+} -+ -+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* left = node->InputAt(0); -+ Node* right = node->InputAt(1); -+ Emit(kRiscvFloat64InsertLowWord32, g.DefineSameAsFirst(node), -+ g.UseRegister(left), g.UseRegister(right)); -+} -+ -+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Node* left = node->InputAt(0); -+ Node* right = node->InputAt(1); -+ Emit(kRiscvFloat64InsertHighWord32, g.DefineSameAsFirst(node), -+ g.UseRegister(left), g.UseRegister(right)); -+} -+ -+void InstructionSelector::VisitMemoryBarrier(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvSync, g.NoOutput()); -+} -+ -+void InstructionSelector::VisitWord32AtomicLoad(Node* node) { -+ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); -+ ArchOpcode opcode = kArchNop; -+ switch (load_rep.representation()) { -+ case MachineRepresentation::kWord8: -+ opcode = -+ load_rep.IsSigned() ? kWord32AtomicLoadInt8 : kWord32AtomicLoadUint8; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = load_rep.IsSigned() ? kWord32AtomicLoadInt16 -+ : kWord32AtomicLoadUint16; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kWord32AtomicLoadWord32; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ VisitAtomicLoad(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord32AtomicStore(Node* node) { -+ MachineRepresentation rep = AtomicStoreRepresentationOf(node->op()); -+ ArchOpcode opcode = kArchNop; -+ switch (rep) { -+ case MachineRepresentation::kWord8: -+ opcode = kWord32AtomicStoreWord8; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = kWord32AtomicStoreWord16; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kWord32AtomicStoreWord32; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+ VisitAtomicStore(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord64AtomicLoad(Node* node) { -+ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); -+ ArchOpcode opcode = kArchNop; -+ switch (load_rep.representation()) { -+ case MachineRepresentation::kWord8: -+ opcode = kRiscvWord64AtomicLoadUint8; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = kRiscvWord64AtomicLoadUint16; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kRiscvWord64AtomicLoadUint32; -+ break; -+ case MachineRepresentation::kWord64: -+ opcode = kRiscvWord64AtomicLoadUint64; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ VisitAtomicLoad(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord64AtomicStore(Node* node) { -+ MachineRepresentation rep = AtomicStoreRepresentationOf(node->op()); -+ ArchOpcode opcode = kArchNop; -+ switch (rep) { -+ case MachineRepresentation::kWord8: -+ opcode = kRiscvWord64AtomicStoreWord8; -+ break; -+ case MachineRepresentation::kWord16: -+ opcode = kRiscvWord64AtomicStoreWord16; -+ break; -+ case MachineRepresentation::kWord32: -+ opcode = kRiscvWord64AtomicStoreWord32; -+ break; -+ case MachineRepresentation::kWord64: -+ opcode = kRiscvWord64AtomicStoreWord64; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+ VisitAtomicStore(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord32AtomicExchange(Node* node) { -+ ArchOpcode opcode = kArchNop; -+ MachineType type = AtomicOpType(node->op()); -+ if (type == MachineType::Int8()) { -+ opcode = kWord32AtomicExchangeInt8; -+ } else if (type == MachineType::Uint8()) { -+ opcode = kWord32AtomicExchangeUint8; -+ } else if (type == MachineType::Int16()) { -+ opcode = kWord32AtomicExchangeInt16; -+ } else if (type == MachineType::Uint16()) { -+ opcode = kWord32AtomicExchangeUint16; -+ } else if (type == MachineType::Int32() || type == MachineType::Uint32()) { -+ opcode = kWord32AtomicExchangeWord32; -+ } else { -+ UNREACHABLE(); -+ return; -+ } -+ -+ VisitAtomicExchange(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord64AtomicExchange(Node* node) { -+ ArchOpcode opcode = kArchNop; -+ MachineType type = AtomicOpType(node->op()); -+ if (type == MachineType::Uint8()) { -+ opcode = kRiscvWord64AtomicExchangeUint8; -+ } else if (type == MachineType::Uint16()) { -+ opcode = kRiscvWord64AtomicExchangeUint16; -+ } else if (type == MachineType::Uint32()) { -+ opcode = kRiscvWord64AtomicExchangeUint32; -+ } else if (type == MachineType::Uint64()) { -+ opcode = kRiscvWord64AtomicExchangeUint64; -+ } else { -+ UNREACHABLE(); -+ return; -+ } -+ VisitAtomicExchange(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) { -+ ArchOpcode opcode = kArchNop; -+ MachineType type = AtomicOpType(node->op()); -+ if (type == MachineType::Int8()) { -+ opcode = kWord32AtomicCompareExchangeInt8; -+ } else if (type == MachineType::Uint8()) { -+ opcode = kWord32AtomicCompareExchangeUint8; -+ } else if (type == MachineType::Int16()) { -+ opcode = kWord32AtomicCompareExchangeInt16; -+ } else if (type == MachineType::Uint16()) { -+ opcode = kWord32AtomicCompareExchangeUint16; -+ } else if (type == MachineType::Int32() || type == MachineType::Uint32()) { -+ opcode = kWord32AtomicCompareExchangeWord32; -+ } else { -+ UNREACHABLE(); -+ return; -+ } -+ -+ VisitAtomicCompareExchange(this, node, opcode); -+} -+ -+void InstructionSelector::VisitWord64AtomicCompareExchange(Node* node) { -+ ArchOpcode opcode = kArchNop; -+ MachineType type = AtomicOpType(node->op()); -+ if (type == MachineType::Uint8()) { -+ opcode = kRiscvWord64AtomicCompareExchangeUint8; -+ } else if (type == MachineType::Uint16()) { -+ opcode = kRiscvWord64AtomicCompareExchangeUint16; -+ } else if (type == MachineType::Uint32()) { -+ opcode = kRiscvWord64AtomicCompareExchangeUint32; -+ } else if (type == MachineType::Uint64()) { -+ opcode = kRiscvWord64AtomicCompareExchangeUint64; -+ } else { -+ UNREACHABLE(); -+ return; -+ } -+ VisitAtomicCompareExchange(this, node, opcode); -+} -+void InstructionSelector::VisitWord32AtomicBinaryOperation( -+ Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op, -+ ArchOpcode uint16_op, ArchOpcode word32_op) { -+ ArchOpcode opcode = kArchNop; -+ MachineType type = AtomicOpType(node->op()); -+ if (type == MachineType::Int8()) { -+ opcode = int8_op; -+ } else if (type == MachineType::Uint8()) { -+ opcode = uint8_op; -+ } else if (type == MachineType::Int16()) { -+ opcode = int16_op; -+ } else if (type == MachineType::Uint16()) { -+ opcode = uint16_op; -+ } else if (type == MachineType::Int32() || type == MachineType::Uint32()) { -+ opcode = word32_op; -+ } else { -+ UNREACHABLE(); -+ return; -+ } -+ -+ VisitAtomicBinop(this, node, opcode); -+} -+ -+#define VISIT_ATOMIC_BINOP(op) \ -+ void InstructionSelector::VisitWord32Atomic##op(Node* node) { \ -+ VisitWord32AtomicBinaryOperation( \ -+ node, kWord32Atomic##op##Int8, kWord32Atomic##op##Uint8, \ -+ kWord32Atomic##op##Int16, kWord32Atomic##op##Uint16, \ -+ kWord32Atomic##op##Word32); \ -+ } -+VISIT_ATOMIC_BINOP(Add) -+VISIT_ATOMIC_BINOP(Sub) -+VISIT_ATOMIC_BINOP(And) -+VISIT_ATOMIC_BINOP(Or) -+VISIT_ATOMIC_BINOP(Xor) -+#undef VISIT_ATOMIC_BINOP -+ -+void InstructionSelector::VisitWord64AtomicBinaryOperation( -+ Node* node, ArchOpcode uint8_op, ArchOpcode uint16_op, ArchOpcode uint32_op, -+ ArchOpcode uint64_op) { -+ ArchOpcode opcode = kArchNop; -+ MachineType type = AtomicOpType(node->op()); -+ if (type == MachineType::Uint8()) { -+ opcode = uint8_op; -+ } else if (type == MachineType::Uint16()) { -+ opcode = uint16_op; -+ } else if (type == MachineType::Uint32()) { -+ opcode = uint32_op; -+ } else if (type == MachineType::Uint64()) { -+ opcode = uint64_op; -+ } else { -+ UNREACHABLE(); -+ return; -+ } -+ VisitAtomicBinop(this, node, opcode); -+} -+ -+#define VISIT_ATOMIC_BINOP(op) \ -+ void InstructionSelector::VisitWord64Atomic##op(Node* node) { \ -+ VisitWord64AtomicBinaryOperation( \ -+ node, kRiscvWord64Atomic##op##Uint8, kRiscvWord64Atomic##op##Uint16, \ -+ kRiscvWord64Atomic##op##Uint32, kRiscvWord64Atomic##op##Uint64); \ -+ } -+VISIT_ATOMIC_BINOP(Add) -+VISIT_ATOMIC_BINOP(Sub) -+VISIT_ATOMIC_BINOP(And) -+VISIT_ATOMIC_BINOP(Or) -+VISIT_ATOMIC_BINOP(Xor) -+#undef VISIT_ATOMIC_BINOP -+ -+void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) { -+ UNREACHABLE(); -+} -+ -+void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) { -+ UNREACHABLE(); -+} -+ -+#define SIMD_TYPE_LIST(V) \ -+ V(F32x4) \ -+ V(I32x4) \ -+ V(I16x8) \ -+ V(I8x16) -+ -+#define SIMD_UNOP_LIST(V) \ -+ V(F64x2Abs, kRiscvF64x2Abs) \ -+ V(F64x2Neg, kRiscvF64x2Neg) \ -+ V(F64x2Sqrt, kRiscvF64x2Sqrt) \ -+ V(F64x2Ceil, kRiscvF64x2Ceil) \ -+ V(F64x2Floor, kRiscvF64x2Floor) \ -+ V(F64x2Trunc, kRiscvF64x2Trunc) \ -+ V(F64x2NearestInt, kRiscvF64x2NearestInt) \ -+ V(I64x2Neg, kRiscvI64x2Neg) \ -+ V(F32x4SConvertI32x4, kRiscvF32x4SConvertI32x4) \ -+ V(F32x4UConvertI32x4, kRiscvF32x4UConvertI32x4) \ -+ V(F32x4Abs, kRiscvF32x4Abs) \ -+ V(F32x4Neg, kRiscvF32x4Neg) \ -+ V(F32x4Sqrt, kRiscvF32x4Sqrt) \ -+ V(F32x4RecipApprox, kRiscvF32x4RecipApprox) \ -+ V(F32x4RecipSqrtApprox, kRiscvF32x4RecipSqrtApprox) \ -+ V(F32x4Ceil, kRiscvF32x4Ceil) \ -+ V(F32x4Floor, kRiscvF32x4Floor) \ -+ V(F32x4Trunc, kRiscvF32x4Trunc) \ -+ V(F32x4NearestInt, kRiscvF32x4NearestInt) \ -+ V(I32x4SConvertF32x4, kRiscvI32x4SConvertF32x4) \ -+ V(I32x4UConvertF32x4, kRiscvI32x4UConvertF32x4) \ -+ V(I32x4Neg, kRiscvI32x4Neg) \ -+ V(I32x4SConvertI16x8Low, kRiscvI32x4SConvertI16x8Low) \ -+ V(I32x4SConvertI16x8High, kRiscvI32x4SConvertI16x8High) \ -+ V(I32x4UConvertI16x8Low, kRiscvI32x4UConvertI16x8Low) \ -+ V(I32x4UConvertI16x8High, kRiscvI32x4UConvertI16x8High) \ -+ V(I32x4Abs, kRiscvI32x4Abs) \ -+ V(I32x4BitMask, kRiscvI32x4BitMask) \ -+ V(I16x8Neg, kRiscvI16x8Neg) \ -+ V(I16x8SConvertI8x16Low, kRiscvI16x8SConvertI8x16Low) \ -+ V(I16x8SConvertI8x16High, kRiscvI16x8SConvertI8x16High) \ -+ V(I16x8UConvertI8x16Low, kRiscvI16x8UConvertI8x16Low) \ -+ V(I16x8UConvertI8x16High, kRiscvI16x8UConvertI8x16High) \ -+ V(I16x8Abs, kRiscvI16x8Abs) \ -+ V(I16x8BitMask, kRiscvI16x8BitMask) \ -+ V(I8x16Neg, kRiscvI8x16Neg) \ -+ V(I8x16Abs, kRiscvI8x16Abs) \ -+ V(I8x16BitMask, kRiscvI8x16BitMask) \ -+ V(S128Not, kRiscvS128Not) \ -+ V(V32x4AnyTrue, kRiscvV32x4AnyTrue) \ -+ V(V32x4AllTrue, kRiscvV32x4AllTrue) \ -+ V(V16x8AnyTrue, kRiscvV16x8AnyTrue) \ -+ V(V16x8AllTrue, kRiscvV16x8AllTrue) \ -+ V(V8x16AnyTrue, kRiscvV8x16AnyTrue) \ -+ V(V8x16AllTrue, kRiscvV8x16AllTrue) -+ -+#define SIMD_SHIFT_OP_LIST(V) \ -+ V(I64x2Shl) \ -+ V(I64x2ShrS) \ -+ V(I64x2ShrU) \ -+ V(I32x4Shl) \ -+ V(I32x4ShrS) \ -+ V(I32x4ShrU) \ -+ V(I16x8Shl) \ -+ V(I16x8ShrS) \ -+ V(I16x8ShrU) \ -+ V(I8x16Shl) \ -+ V(I8x16ShrS) \ -+ V(I8x16ShrU) -+ -+#define SIMD_BINOP_LIST(V) \ -+ V(F64x2Add, kRiscvF64x2Add) \ -+ V(F64x2Sub, kRiscvF64x2Sub) \ -+ V(F64x2Mul, kRiscvF64x2Mul) \ -+ V(F64x2Div, kRiscvF64x2Div) \ -+ V(F64x2Min, kRiscvF64x2Min) \ -+ V(F64x2Max, kRiscvF64x2Max) \ -+ V(F64x2Eq, kRiscvF64x2Eq) \ -+ V(F64x2Ne, kRiscvF64x2Ne) \ -+ V(F64x2Lt, kRiscvF64x2Lt) \ -+ V(F64x2Le, kRiscvF64x2Le) \ -+ V(I64x2Add, kRiscvI64x2Add) \ -+ V(I64x2Sub, kRiscvI64x2Sub) \ -+ V(I64x2Mul, kRiscvI64x2Mul) \ -+ V(F32x4Add, kRiscvF32x4Add) \ -+ V(F32x4AddHoriz, kRiscvF32x4AddHoriz) \ -+ V(F32x4Sub, kRiscvF32x4Sub) \ -+ V(F32x4Mul, kRiscvF32x4Mul) \ -+ V(F32x4Div, kRiscvF32x4Div) \ -+ V(F32x4Max, kRiscvF32x4Max) \ -+ V(F32x4Min, kRiscvF32x4Min) \ -+ V(F32x4Eq, kRiscvF32x4Eq) \ -+ V(F32x4Ne, kRiscvF32x4Ne) \ -+ V(F32x4Lt, kRiscvF32x4Lt) \ -+ V(F32x4Le, kRiscvF32x4Le) \ -+ V(I32x4Add, kRiscvI32x4Add) \ -+ V(I32x4AddHoriz, kRiscvI32x4AddHoriz) \ -+ V(I32x4Sub, kRiscvI32x4Sub) \ -+ V(I32x4Mul, kRiscvI32x4Mul) \ -+ V(I32x4MaxS, kRiscvI32x4MaxS) \ -+ V(I32x4MinS, kRiscvI32x4MinS) \ -+ V(I32x4MaxU, kRiscvI32x4MaxU) \ -+ V(I32x4MinU, kRiscvI32x4MinU) \ -+ V(I32x4Eq, kRiscvI32x4Eq) \ -+ V(I32x4Ne, kRiscvI32x4Ne) \ -+ V(I32x4GtS, kRiscvI32x4GtS) \ -+ V(I32x4GeS, kRiscvI32x4GeS) \ -+ V(I32x4GtU, kRiscvI32x4GtU) \ -+ V(I32x4GeU, kRiscvI32x4GeU) \ -+ V(I16x8Add, kRiscvI16x8Add) \ -+ V(I16x8AddSaturateS, kRiscvI16x8AddSaturateS) \ -+ V(I16x8AddSaturateU, kRiscvI16x8AddSaturateU) \ -+ V(I16x8AddHoriz, kRiscvI16x8AddHoriz) \ -+ V(I16x8Sub, kRiscvI16x8Sub) \ -+ V(I16x8SubSaturateS, kRiscvI16x8SubSaturateS) \ -+ V(I16x8SubSaturateU, kRiscvI16x8SubSaturateU) \ -+ V(I16x8Mul, kRiscvI16x8Mul) \ -+ V(I16x8MaxS, kRiscvI16x8MaxS) \ -+ V(I16x8MinS, kRiscvI16x8MinS) \ -+ V(I16x8MaxU, kRiscvI16x8MaxU) \ -+ V(I16x8MinU, kRiscvI16x8MinU) \ -+ V(I16x8Eq, kRiscvI16x8Eq) \ -+ V(I16x8Ne, kRiscvI16x8Ne) \ -+ V(I16x8GtS, kRiscvI16x8GtS) \ -+ V(I16x8GeS, kRiscvI16x8GeS) \ -+ V(I16x8GtU, kRiscvI16x8GtU) \ -+ V(I16x8GeU, kRiscvI16x8GeU) \ -+ V(I16x8RoundingAverageU, kRiscvI16x8RoundingAverageU) \ -+ V(I16x8SConvertI32x4, kRiscvI16x8SConvertI32x4) \ -+ V(I16x8UConvertI32x4, kRiscvI16x8UConvertI32x4) \ -+ V(I8x16Add, kRiscvI8x16Add) \ -+ V(I8x16AddSaturateS, kRiscvI8x16AddSaturateS) \ -+ V(I8x16AddSaturateU, kRiscvI8x16AddSaturateU) \ -+ V(I8x16Sub, kRiscvI8x16Sub) \ -+ V(I8x16SubSaturateS, kRiscvI8x16SubSaturateS) \ -+ V(I8x16SubSaturateU, kRiscvI8x16SubSaturateU) \ -+ V(I8x16Mul, kRiscvI8x16Mul) \ -+ V(I8x16MaxS, kRiscvI8x16MaxS) \ -+ V(I8x16MinS, kRiscvI8x16MinS) \ -+ V(I8x16MaxU, kRiscvI8x16MaxU) \ -+ V(I8x16MinU, kRiscvI8x16MinU) \ -+ V(I8x16Eq, kRiscvI8x16Eq) \ -+ V(I8x16Ne, kRiscvI8x16Ne) \ -+ V(I8x16GtS, kRiscvI8x16GtS) \ -+ V(I8x16GeS, kRiscvI8x16GeS) \ -+ V(I8x16GtU, kRiscvI8x16GtU) \ -+ V(I8x16GeU, kRiscvI8x16GeU) \ -+ V(I8x16RoundingAverageU, kRiscvI8x16RoundingAverageU) \ -+ V(I8x16SConvertI16x8, kRiscvI8x16SConvertI16x8) \ -+ V(I8x16UConvertI16x8, kRiscvI8x16UConvertI16x8) \ -+ V(S128And, kRiscvS128And) \ -+ V(S128Or, kRiscvS128Or) \ -+ V(S128Xor, kRiscvS128Xor) \ -+ V(S128AndNot, kRiscvS128AndNot) -+ -+void InstructionSelector::VisitS128Const(Node* node) { -+ RiscvOperandGenerator g(this); -+ static const int kUint32Immediates = kSimd128Size / sizeof(uint32_t); -+ uint32_t val[kUint32Immediates]; -+ memcpy(val, S128ImmediateParameterOf(node->op()).data(), kSimd128Size); -+ // If all bytes are zeros or ones, avoid emitting code for generic constants -+ bool all_zeros = !(val[0] || val[1] || val[2] || val[3]); -+ bool all_ones = val[0] == UINT32_MAX && val[1] == UINT32_MAX && -+ val[2] == UINT32_MAX && val[3] == UINT32_MAX; -+ InstructionOperand dst = g.DefineAsRegister(node); -+ if (all_zeros) { -+ Emit(kRiscvS128Zero, dst); -+ } else if (all_ones) { -+ Emit(kRiscvS128AllOnes, dst); -+ } else { -+ Emit(kRiscvS128Const, dst, g.UseImmediate(val[0]), g.UseImmediate(val[1]), -+ g.UseImmediate(val[2]), g.UseImmediate(val[3])); -+ } -+} -+ -+void InstructionSelector::VisitS128Zero(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvS128Zero, g.DefineAsRegister(node)); -+} -+ -+#define SIMD_VISIT_SPLAT(Type) \ -+ void InstructionSelector::Visit##Type##Splat(Node* node) { \ -+ VisitRR(this, kRiscv##Type##Splat, node); \ -+ } -+SIMD_TYPE_LIST(SIMD_VISIT_SPLAT) -+SIMD_VISIT_SPLAT(F64x2) -+#undef SIMD_VISIT_SPLAT -+ -+#define SIMD_VISIT_EXTRACT_LANE(Type, Sign) \ -+ void InstructionSelector::Visit##Type##ExtractLane##Sign(Node* node) { \ -+ VisitRRI(this, kRiscv##Type##ExtractLane##Sign, node); \ -+ } -+SIMD_VISIT_EXTRACT_LANE(F64x2, ) -+SIMD_VISIT_EXTRACT_LANE(F32x4, ) -+SIMD_VISIT_EXTRACT_LANE(I32x4, ) -+SIMD_VISIT_EXTRACT_LANE(I16x8, U) -+SIMD_VISIT_EXTRACT_LANE(I16x8, S) -+SIMD_VISIT_EXTRACT_LANE(I8x16, U) -+SIMD_VISIT_EXTRACT_LANE(I8x16, S) -+#undef SIMD_VISIT_EXTRACT_LANE -+ -+#define SIMD_VISIT_REPLACE_LANE(Type) \ -+ void InstructionSelector::Visit##Type##ReplaceLane(Node* node) { \ -+ VisitRRIR(this, kRiscv##Type##ReplaceLane, node); \ -+ } -+SIMD_TYPE_LIST(SIMD_VISIT_REPLACE_LANE) -+SIMD_VISIT_REPLACE_LANE(F64x2) -+#undef SIMD_VISIT_REPLACE_LANE -+ -+#define SIMD_VISIT_UNOP(Name, instruction) \ -+ void InstructionSelector::Visit##Name(Node* node) { \ -+ VisitRR(this, instruction, node); \ -+ } -+SIMD_UNOP_LIST(SIMD_VISIT_UNOP) -+#undef SIMD_VISIT_UNOP -+ -+#define SIMD_VISIT_SHIFT_OP(Name) \ -+ void InstructionSelector::Visit##Name(Node* node) { \ -+ VisitSimdShift(this, kRiscv##Name, node); \ -+ } -+SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP) -+#undef SIMD_VISIT_SHIFT_OP -+ -+#define SIMD_VISIT_BINOP(Name, instruction) \ -+ void InstructionSelector::Visit##Name(Node* node) { \ -+ VisitRRR(this, instruction, node); \ -+ } -+SIMD_BINOP_LIST(SIMD_VISIT_BINOP) -+#undef SIMD_VISIT_BINOP -+ -+void InstructionSelector::VisitS128Select(Node* node) { -+ VisitRRRR(this, kRiscvS128Select, node); -+} -+ -+namespace { -+ -+struct ShuffleEntry { -+ uint8_t shuffle[kSimd128Size]; -+ ArchOpcode opcode; -+}; -+ -+static const ShuffleEntry arch_shuffles[] = { -+ {{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23}, -+ kRiscvS32x4InterleaveRight}, -+ {{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31}, -+ kRiscvS32x4InterleaveLeft}, -+ {{0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27}, -+ kRiscvS32x4PackEven}, -+ {{4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31}, -+ kRiscvS32x4PackOdd}, -+ {{0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27}, -+ kRiscvS32x4InterleaveEven}, -+ {{4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31}, -+ kRiscvS32x4InterleaveOdd}, -+ -+ {{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23}, -+ kRiscvS16x8InterleaveRight}, -+ {{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31}, -+ kRiscvS16x8InterleaveLeft}, -+ {{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29}, -+ kRiscvS16x8PackEven}, -+ {{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31}, -+ kRiscvS16x8PackOdd}, -+ {{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29}, -+ kRiscvS16x8InterleaveEven}, -+ {{2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31}, -+ kRiscvS16x8InterleaveOdd}, -+ {{6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9}, -+ kRiscvS16x4Reverse}, -+ {{2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13}, -+ kRiscvS16x2Reverse}, -+ -+ {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}, -+ kRiscvS8x16InterleaveRight}, -+ {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31}, -+ kRiscvS8x16InterleaveLeft}, -+ {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}, -+ kRiscvS8x16PackEven}, -+ {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, -+ kRiscvS8x16PackOdd}, -+ {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30}, -+ kRiscvS8x16InterleaveEven}, -+ {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31}, -+ kRiscvS8x16InterleaveOdd}, -+ {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, kRiscvS8x8Reverse}, -+ {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, kRiscvS8x4Reverse}, -+ {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, -+ kRiscvS8x2Reverse}}; -+ -+bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table, -+ size_t num_entries, bool is_swizzle, -+ ArchOpcode* opcode) { -+ uint8_t mask = is_swizzle ? kSimd128Size - 1 : 2 * kSimd128Size - 1; -+ for (size_t i = 0; i < num_entries; ++i) { -+ const ShuffleEntry& entry = table[i]; -+ int j = 0; -+ for (; j < kSimd128Size; ++j) { -+ if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) { -+ break; -+ } -+ } -+ if (j == kSimd128Size) { -+ *opcode = entry.opcode; -+ return true; -+ } -+ } -+ return false; -+} -+ -+} // namespace -+ -+void InstructionSelector::VisitI8x16Shuffle(Node* node) { -+ uint8_t shuffle[kSimd128Size]; -+ bool is_swizzle; -+ CanonicalizeShuffle(node, shuffle, &is_swizzle); -+ uint8_t shuffle32x4[4]; -+ ArchOpcode opcode; -+ if (TryMatchArchShuffle(shuffle, arch_shuffles, arraysize(arch_shuffles), -+ is_swizzle, &opcode)) { -+ VisitRRR(this, opcode, node); -+ return; -+ } -+ Node* input0 = node->InputAt(0); -+ Node* input1 = node->InputAt(1); -+ uint8_t offset; -+ RiscvOperandGenerator g(this); -+ if (wasm::SimdShuffle::TryMatchConcat(shuffle, &offset)) { -+ Emit(kRiscvS8x16Concat, g.DefineSameAsFirst(node), g.UseRegister(input1), -+ g.UseRegister(input0), g.UseImmediate(offset)); -+ return; -+ } -+ if (wasm::SimdShuffle::TryMatch32x4Shuffle(shuffle, shuffle32x4)) { -+ Emit(kRiscvS32x4Shuffle, g.DefineAsRegister(node), g.UseRegister(input0), -+ g.UseRegister(input1), -+ g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle32x4))); -+ return; -+ } -+ Emit(kRiscvI8x16Shuffle, g.DefineAsRegister(node), g.UseRegister(input0), -+ g.UseRegister(input1), -+ g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle)), -+ g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle + 4)), -+ g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle + 8)), -+ g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle + 12))); -+} -+ -+void InstructionSelector::VisitI8x16Swizzle(Node* node) { -+ RiscvOperandGenerator g(this); -+ InstructionOperand temps[] = {g.TempSimd128Register()}; -+ // We don't want input 0 or input 1 to be the same as output, since we will -+ // modify output before do the calculation. -+ Emit(kRiscvI8x16Swizzle, g.DefineAsRegister(node), -+ g.UseUniqueRegister(node->InputAt(0)), -+ g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps); -+} -+ -+void InstructionSelector::VisitSignExtendWord8ToInt32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvSignExtendByte, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitSignExtendWord16ToInt32(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvSignExtendShort, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitSignExtendWord8ToInt64(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvSignExtendByte, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitSignExtendWord16ToInt64(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvSignExtendShort, g.DefineAsRegister(node), -+ g.UseRegister(node->InputAt(0))); -+} -+ -+void InstructionSelector::VisitSignExtendWord32ToInt64(Node* node) { -+ RiscvOperandGenerator g(this); -+ Emit(kRiscvShl32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), -+ g.TempImmediate(0)); -+} -+ -+void InstructionSelector::VisitF32x4Pmin(Node* node) { -+ VisitUniqueRRR(this, kRiscvF32x4Pmin, node); -+} -+ -+void InstructionSelector::VisitF32x4Pmax(Node* node) { -+ VisitUniqueRRR(this, kRiscvF32x4Pmax, node); -+} -+ -+void InstructionSelector::VisitF64x2Pmin(Node* node) { -+ VisitUniqueRRR(this, kRiscvF64x2Pmin, node); -+} -+ -+void InstructionSelector::VisitF64x2Pmax(Node* node) { -+ VisitUniqueRRR(this, kRiscvF64x2Pmax, node); -+} -+ -+// static -+MachineOperatorBuilder::Flags -+InstructionSelector::SupportedMachineOperatorFlags() { -+ MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags; -+ return flags | MachineOperatorBuilder::kWord32ShiftIsSafe | -+ MachineOperatorBuilder::kInt32DivIsSafe | -+ MachineOperatorBuilder::kUint32DivIsSafe | -+ MachineOperatorBuilder::kFloat64RoundDown | -+ MachineOperatorBuilder::kFloat32RoundDown | -+ MachineOperatorBuilder::kFloat64RoundUp | -+ MachineOperatorBuilder::kFloat32RoundUp | -+ MachineOperatorBuilder::kFloat64RoundTruncate | -+ MachineOperatorBuilder::kFloat32RoundTruncate | -+ MachineOperatorBuilder::kFloat64RoundTiesEven | -+ MachineOperatorBuilder::kFloat32RoundTiesEven; -+} -+ -+// static -+MachineOperatorBuilder::AlignmentRequirements -+InstructionSelector::AlignmentRequirements() { -+ return MachineOperatorBuilder::AlignmentRequirements:: -+ NoUnalignedAccessSupport(); -+} -+ -+#undef SIMD_BINOP_LIST -+#undef SIMD_SHIFT_OP_LIST -+#undef SIMD_UNOP_LIST -+#undef SIMD_TYPE_LIST -+#undef TRACE_UNIMPL -+#undef TRACE -+ -+} // namespace compiler -+} // namespace internal -+} // namespace v8 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc -@@ -131,6 +131,19 @@ namespace { - d8.bit() | d9.bit() | d10.bit() | d11.bit() | d12.bit() | d13.bit() | \ - d14.bit() | d15.bit() - -+#elif V8_TARGET_ARCH_RISCV64 -+// =========================================================================== -+// == riscv64 ================================================================= -+// =========================================================================== -+#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7 -+// fp is not part of CALLEE_SAVE_REGISTERS (similar to how MIPS64 or PPC defines -+// it) -+#define CALLEE_SAVE_REGISTERS \ -+ s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | \ -+ s8.bit() | s9.bit() | s10.bit() | s11.bit() -+#define CALLEE_SAVE_FP_REGISTERS \ -+ fs0.bit() | fs1.bit() | fs2.bit() | fs3.bit() | fs4.bit() | fs5.bit() | \ -+ fs6.bit() | fs7.bit() | fs8.bit() | fs9.bit() | fs10.bit() | fs11.bit() - #else - // =========================================================================== - // == unknown ================================================================ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/debug/debug-evaluate.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/debug/debug-evaluate.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/debug/debug-evaluate.cc -@@ -1060,8 +1060,10 @@ void DebugEvaluate::VerifyTransitiveBuil - } - } - CHECK(!failed); --#if defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_PPC64) || \ -- defined(V8_TARGET_ARCH_MIPS64) -+ // FIXME (RISCV): does RISCV need this? -+#if defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_PPC64) || \ -+ defined(V8_TARGET_ARCH_MIPS64) || defined(V8_TARGET_ARCH_RISCV64) || \ -+ defined(V8_TARGET_ARCH_RISCV) - // Isolate-independent builtin calls and jumps do not emit reloc infos - // on PPC. We try to avoid using PC relative code due to performance - // issue with especially older hardwares. -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/debug/riscv64/debug-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/debug/riscv64/debug-riscv64.cc -@@ -0,0 +1,55 @@ -+// Copyright 2012 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. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/codegen/macro-assembler.h" -+#include "src/debug/debug.h" -+#include "src/debug/liveedit.h" -+#include "src/execution/frames-inl.h" -+ -+namespace v8 { -+namespace internal { -+ -+#define __ ACCESS_MASM(masm) -+ -+void DebugCodegen::GenerateHandleDebuggerStatement(MacroAssembler* masm) { -+ { -+ FrameScope scope(masm, StackFrame::INTERNAL); -+ __ CallRuntime(Runtime::kHandleDebuggerStatement, 0); -+ } -+ __ MaybeDropFrames(); -+ -+ // Return to caller. -+ __ Ret(); -+} -+ -+void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) { -+ // Frame is being dropped: -+ // - Drop to the target frame specified by a1. -+ // - Look up current function on the frame. -+ // - Leave the frame. -+ // - Restart the frame by calling the function. -+ __ mv(fp, a1); -+ __ Ld(a1, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); -+ -+ // Pop return address and frame. -+ __ LeaveFrame(StackFrame::INTERNAL); -+ -+ __ Ld(a0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); -+ __ Lhu(a0, -+ FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset)); -+ __ mv(a2, a0); -+ -+ __ InvokeFunction(a1, a2, a0, JUMP_FUNCTION); -+} -+ -+const bool LiveEdit::kFrameDropperSupported = true; -+ -+#undef __ -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/deoptimizer/riscv64/deoptimizer-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/deoptimizer/riscv64/deoptimizer-riscv64.cc -@@ -0,0 +1,240 @@ -+// Copyright 2011 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. -+ -+#include "src/codegen/macro-assembler.h" -+#include "src/codegen/register-configuration.h" -+#include "src/codegen/safepoint-table.h" -+#include "src/deoptimizer/deoptimizer.h" -+ -+namespace v8 { -+namespace internal { -+ -+const bool Deoptimizer::kSupportsFixedDeoptExitSizes = false; -+const int Deoptimizer::kNonLazyDeoptExitSize = 0; -+const int Deoptimizer::kLazyDeoptExitSize = 0; -+ -+#define __ masm-> -+ -+// This code tries to be close to ia32 code so that any changes can be -+// easily ported. -+void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, -+ Isolate* isolate, -+ DeoptimizeKind deopt_kind) { -+ NoRootArrayScope no_root_array(masm); -+ -+ // Unlike on ARM we don't save all the registers, just the useful ones. -+ // For the rest, there are gaps on the stack, so the offsets remain the same. -+ const int kNumberOfRegisters = Register::kNumRegisters; -+ -+ RegList restored_regs = kJSCallerSaved | kCalleeSaved; -+ RegList saved_regs = restored_regs | sp.bit() | ra.bit(); -+ -+ const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters; -+ -+ // Save all double FPU registers before messing with them. -+ __ Sub64(sp, sp, Operand(kDoubleRegsSize)); -+ const RegisterConfiguration* config = RegisterConfiguration::Default(); -+ for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { -+ int code = config->GetAllocatableDoubleCode(i); -+ const DoubleRegister fpu_reg = DoubleRegister::from_code(code); -+ int offset = code * kDoubleSize; -+ __ StoreDouble(fpu_reg, MemOperand(sp, offset)); -+ } -+ -+ // Push saved_regs (needed to populate FrameDescription::registers_). -+ // Leave gaps for other registers. -+ __ Sub64(sp, sp, kNumberOfRegisters * kPointerSize); -+ for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) { -+ if ((saved_regs & (1 << i)) != 0) { -+ __ Sd(ToRegister(i), MemOperand(sp, kPointerSize * i)); -+ } -+ } -+ -+ __ li(a2, Operand(ExternalReference::Create( -+ IsolateAddressId::kCEntryFPAddress, isolate))); -+ __ Sd(fp, MemOperand(a2)); -+ -+ const int kSavedRegistersAreaSize = -+ (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; -+ -+ // Get the bailout is passed as kRootRegister by the caller. -+ __ mv(a2, kRootRegister); -+ -+ // Get the address of the location in the code object (a3) (return -+ // address for lazy deoptimization) and compute the fp-to-sp delta in -+ // register a4. -+ __ mv(a3, ra); -+ __ Add64(a4, sp, Operand(kSavedRegistersAreaSize)); -+ -+ __ Sub64(a4, fp, a4); -+ -+ // Allocate a new deoptimizer object. -+ __ PrepareCallCFunction(6, a5); -+ // Pass six arguments, according to n64 ABI. -+ __ mv(a0, zero_reg); -+ Label context_check; -+ __ Ld(a1, MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset)); -+ __ JumpIfSmi(a1, &context_check); -+ __ Ld(a0, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); -+ __ bind(&context_check); -+ __ li(a1, Operand(static_cast(deopt_kind))); -+ // a2: bailout id already loaded. -+ // a3: code address or 0 already loaded. -+ // a4: already has fp-to-sp delta. -+ __ li(a5, Operand(ExternalReference::isolate_address(isolate))); -+ -+ // Call Deoptimizer::New(). -+ { -+ AllowExternalCallThatCantCauseGC scope(masm); -+ __ CallCFunction(ExternalReference::new_deoptimizer_function(), 6); -+ } -+ -+ // Preserve "deoptimizer" object in register a0 and get the input -+ // frame descriptor pointer to a1 (deoptimizer->input_); -+ // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below. -+ __ Ld(a1, MemOperand(a0, Deoptimizer::input_offset())); -+ -+ // Copy core registers into FrameDescription::registers_[kNumRegisters]. -+ DCHECK_EQ(Register::kNumRegisters, kNumberOfRegisters); -+ for (int i = 0; i < kNumberOfRegisters; i++) { -+ int offset = (i * kPointerSize) + FrameDescription::registers_offset(); -+ if ((saved_regs & (1 << i)) != 0) { -+ __ Ld(a2, MemOperand(sp, i * kPointerSize)); -+ __ Sd(a2, MemOperand(a1, offset)); -+ } else if (FLAG_debug_code) { -+ __ li(a2, kDebugZapValue); -+ __ Sd(a2, MemOperand(a1, offset)); -+ } -+ } -+ -+ int double_regs_offset = FrameDescription::double_registers_offset(); -+ // Copy FPU registers to -+ // double_registers_[DoubleRegister::kNumAllocatableRegisters] -+ for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { -+ int code = config->GetAllocatableDoubleCode(i); -+ int dst_offset = code * kDoubleSize + double_regs_offset; -+ int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize; -+ __ LoadDouble(ft0, MemOperand(sp, src_offset)); -+ __ StoreDouble(ft0, MemOperand(a1, dst_offset)); -+ } -+ -+ // Remove the saved registers from the stack. -+ __ Add64(sp, sp, Operand(kSavedRegistersAreaSize)); -+ -+ // Compute a pointer to the unwinding limit in register a2; that is -+ // the first stack slot not part of the input frame. -+ __ Ld(a2, MemOperand(a1, FrameDescription::frame_size_offset())); -+ __ Add64(a2, a2, sp); -+ -+ // Unwind the stack down to - but not including - the unwinding -+ // limit and copy the contents of the activation frame to the input -+ // frame description. -+ __ Add64(a3, a1, Operand(FrameDescription::frame_content_offset())); -+ Label pop_loop; -+ Label pop_loop_header; -+ __ BranchShort(&pop_loop_header); -+ __ bind(&pop_loop); -+ __ pop(a4); -+ __ Sd(a4, MemOperand(a3, 0)); -+ __ addi(a3, a3, sizeof(uint64_t)); -+ __ bind(&pop_loop_header); -+ __ BranchShort(&pop_loop, ne, a2, Operand(sp)); -+ // Compute the output frame in the deoptimizer. -+ __ push(a0); // Preserve deoptimizer object across call. -+ // a0: deoptimizer object; a1: scratch. -+ __ PrepareCallCFunction(1, a1); -+ // Call Deoptimizer::ComputeOutputFrames(). -+ { -+ AllowExternalCallThatCantCauseGC scope(masm); -+ __ CallCFunction(ExternalReference::compute_output_frames_function(), 1); -+ } -+ __ pop(a0); // Restore deoptimizer object (class Deoptimizer). -+ -+ __ Ld(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset())); -+ -+ // Replace the current (input) frame with the output frames. -+ Label outer_push_loop, inner_push_loop, outer_loop_header, inner_loop_header; -+ // Outer loop state: a4 = current "FrameDescription** output_", -+ // a1 = one past the last FrameDescription**. -+ __ Lw(a1, MemOperand(a0, Deoptimizer::output_count_offset())); -+ __ Ld(a4, MemOperand(a0, Deoptimizer::output_offset())); // a4 is output_. -+ __ CalcScaledAddress(a1, a4, a1, kPointerSizeLog2); -+ __ BranchShort(&outer_loop_header); -+ __ bind(&outer_push_loop); -+ // Inner loop state: a2 = current FrameDescription*, a3 = loop index. -+ __ Ld(a2, MemOperand(a4, 0)); // output_[ix] -+ __ Ld(a3, MemOperand(a2, FrameDescription::frame_size_offset())); -+ __ BranchShort(&inner_loop_header); -+ __ bind(&inner_push_loop); -+ __ Sub64(a3, a3, Operand(sizeof(uint64_t))); -+ __ Add64(a6, a2, Operand(a3)); -+ __ Ld(a7, MemOperand(a6, FrameDescription::frame_content_offset())); -+ __ push(a7); -+ __ bind(&inner_loop_header); -+ __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg)); -+ -+ __ Add64(a4, a4, Operand(kPointerSize)); -+ __ bind(&outer_loop_header); -+ __ BranchShort(&outer_push_loop, lt, a4, Operand(a1)); -+ -+ __ Ld(a1, MemOperand(a0, Deoptimizer::input_offset())); -+ for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { -+ int code = config->GetAllocatableDoubleCode(i); -+ const DoubleRegister fpu_reg = DoubleRegister::from_code(code); -+ int src_offset = code * kDoubleSize + double_regs_offset; -+ __ LoadDouble(fpu_reg, MemOperand(a1, src_offset)); -+ } -+ -+ // Push pc and continuation from the last output frame. -+ __ Ld(a6, MemOperand(a2, FrameDescription::pc_offset())); -+ __ push(a6); -+ __ Ld(a6, MemOperand(a2, FrameDescription::continuation_offset())); -+ __ push(a6); -+ -+ // Technically restoring 't3' should work unless zero_reg is also restored -+ // but it's safer to check for this. -+ DCHECK(!(t3.bit() & restored_regs)); -+ // Restore the registers from the last output frame. -+ __ mv(t3, a2); -+ for (int i = kNumberOfRegisters - 1; i >= 0; i--) { -+ int offset = (i * kPointerSize) + FrameDescription::registers_offset(); -+ if ((restored_regs & (1 << i)) != 0) { -+ __ Ld(ToRegister(i), MemOperand(t3, offset)); -+ } -+ } -+ -+ __ pop(t3); // Get continuation, leave pc on stack. -+ __ pop(ra); -+ __ Jump(t3); -+ __ stop(); -+} -+ -+// Maximum size of a table entry generated below. -+// FIXME(RISCV): Is this value correct? -+const int Deoptimizer::table_entry_size_ = 2 * kInstrSize; -+ -+Float32 RegisterValues::GetFloatRegister(unsigned n) const { -+ return Float32::FromBits( -+ static_cast(double_registers_[n].get_bits())); -+} -+ -+void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { -+ SetFrameSlot(offset, value); -+} -+ -+void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { -+ SetFrameSlot(offset, value); -+} -+ -+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { -+ // No embedded constant pool support. -+ UNREACHABLE(); -+} -+ -+void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } -+ -+#undef __ -+ -+} // namespace internal -+} // namespace v8 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/diagnostics/perf-jit.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/diagnostics/perf-jit.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/diagnostics/perf-jit.h -@@ -86,6 +86,7 @@ class PerfJitLogger : public CodeEventLo - static const uint32_t kElfMachARM64 = 183; - static const uint32_t kElfMachS390x = 22; - static const uint32_t kElfMachPPC64 = 21; -+ static const uint32_t kElfMachRISCV = 243; - - uint32_t GetElfMach() { - #if V8_TARGET_ARCH_IA32 -@@ -104,6 +105,8 @@ class PerfJitLogger : public CodeEventLo - return kElfMachS390x; - #elif V8_TARGET_ARCH_PPC64 - return kElfMachPPC64; -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+ return kElfMachRISCV; - #else - UNIMPLEMENTED(); - return 0; -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/diagnostics/riscv64/disasm-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/diagnostics/riscv64/disasm-riscv64.cc -@@ -0,0 +1,1448 @@ -+// Copyright 2012 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. -+ -+// A Disassembler object is used to disassemble a block of code instruction by -+// instruction. The default implementation of the NameConverter object can be -+// overriden to modify register names or to do symbol lookup on addresses. -+// -+// The example below will disassemble a block of code and print it to stdout. -+// -+// NameConverter converter; -+// Disassembler d(converter); -+// for (byte* pc = begin; pc < end;) { -+// v8::internal::EmbeddedVector buffer; -+// byte* prev_pc = pc; -+// pc += d.InstructionDecode(buffer, pc); -+// printf("%p %08x %s\n", -+// prev_pc, *reinterpret_cast(prev_pc), buffer); -+// } -+// -+// The Disassembler class also has a convenience method to disassemble a block -+// of code into a FILE*, meaning that the above functionality could also be -+// achieved by just calling Disassembler::Disassemble(stdout, begin, end); -+ -+#include -+#include -+#include -+#include -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/base/platform/platform.h" -+#include "src/codegen/macro-assembler.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/diagnostics/disasm.h" -+ -+namespace v8 { -+namespace internal { -+ -+//------------------------------------------------------------------------------ -+ -+// Decoder decodes and disassembles instructions into an output buffer. -+// It uses the converter to convert register names and call destinations into -+// more informative description. -+class Decoder { -+ public: -+ Decoder(const disasm::NameConverter& converter, -+ v8::internal::Vector out_buffer) -+ : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) { -+ out_buffer_[out_buffer_pos_] = '\0'; -+ } -+ -+ ~Decoder() {} -+ -+ // Writes one disassembled instruction into 'buffer' (0-terminated). -+ // Returns the length of the disassembled machine instruction in bytes. -+ int InstructionDecode(byte* instruction); -+ -+ private: -+ // Bottleneck functions to print into the out_buffer. -+ void PrintChar(const char ch); -+ void Print(const char* str); -+ -+ // Printing of common values. -+ void PrintRegister(int reg); -+ void PrintFPURegister(int freg); -+ void PrintFPUStatusRegister(int freg); -+ void PrintRs1(Instruction* instr); -+ void PrintRs2(Instruction* instr); -+ void PrintRd(Instruction* instr); -+ void PrintVs1(Instruction* instr); -+ void PrintFRs1(Instruction* instr); -+ void PrintFRs2(Instruction* instr); -+ void PrintFRs3(Instruction* instr); -+ void PrintFRd(Instruction* instr); -+ void PrintImm12(Instruction* instr); -+ void PrintImm12X(Instruction* instr); -+ void PrintImm20U(Instruction* instr); -+ void PrintImm20J(Instruction* instr); -+ void PrintShamt(Instruction* instr); -+ void PrintShamt32(Instruction* instr); -+ void PrintAcquireRelease(Instruction* instr); -+ void PrintBranchOffset(Instruction* instr); -+ void PrintStoreOffset(Instruction* instr); -+ void PrintCSRReg(Instruction* instr); -+ void PrintRoundingMode(Instruction* instr); -+ void PrintMemoryOrder(Instruction* instr, bool is_pred); -+ -+ // Each of these functions decodes one particular instruction type. -+ void DecodeRType(Instruction* instr); -+ void DecodeR4Type(Instruction* instr); -+ void DecodeRAType(Instruction* instr); -+ void DecodeRFPType(Instruction* instr); -+ void DecodeIType(Instruction* instr); -+ void DecodeSType(Instruction* instr); -+ void DecodeBType(Instruction* instr); -+ void DecodeUType(Instruction* instr); -+ void DecodeJType(Instruction* instr); -+ -+ // Printing of instruction name. -+ void PrintInstructionName(Instruction* instr); -+ -+ // Handle formatting of instructions and their options. -+ int FormatRegister(Instruction* instr, const char* option); -+ int FormatFPURegisterOrRoundMode(Instruction* instr, const char* option); -+ int FormatOption(Instruction* instr, const char* option); -+ void Format(Instruction* instr, const char* format); -+ void Unknown(Instruction* instr); -+ -+ const disasm::NameConverter& converter_; -+ v8::internal::Vector out_buffer_; -+ int out_buffer_pos_; -+ -+ DISALLOW_COPY_AND_ASSIGN(Decoder); -+}; -+ -+// Support for assertions in the Decoder formatting functions. -+#define STRING_STARTS_WITH(string, compare_string) \ -+ (strncmp(string, compare_string, strlen(compare_string)) == 0) -+ -+// Append the ch to the output buffer. -+void Decoder::PrintChar(const char ch) { out_buffer_[out_buffer_pos_++] = ch; } -+ -+// Append the str to the output buffer. -+void Decoder::Print(const char* str) { -+ char cur = *str++; -+ while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) { -+ PrintChar(cur); -+ cur = *str++; -+ } -+ out_buffer_[out_buffer_pos_] = 0; -+} -+ -+// Print the register name according to the active name converter. -+void Decoder::PrintRegister(int reg) { -+ Print(converter_.NameOfCPURegister(reg)); -+} -+ -+void Decoder::PrintRs1(Instruction* instr) { -+ int reg = instr->Rs1Value(); -+ PrintRegister(reg); -+} -+ -+void Decoder::PrintRs2(Instruction* instr) { -+ int reg = instr->Rs2Value(); -+ PrintRegister(reg); -+} -+ -+void Decoder::PrintRd(Instruction* instr) { -+ int reg = instr->RdValue(); -+ PrintRegister(reg); -+} -+ -+void Decoder::PrintVs1(Instruction* instr) { -+ int val = instr->Rs1Value(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", val); -+} -+ -+// Print the FPUregister name according to the active name converter. -+void Decoder::PrintFPURegister(int freg) { -+ Print(converter_.NameOfXMMRegister(freg)); -+} -+ -+void Decoder::PrintFRs1(Instruction* instr) { -+ int reg = instr->Rs1Value(); -+ PrintFPURegister(reg); -+} -+ -+void Decoder::PrintFRs2(Instruction* instr) { -+ int reg = instr->Rs2Value(); -+ PrintFPURegister(reg); -+} -+ -+void Decoder::PrintFRs3(Instruction* instr) { -+ int reg = instr->Rs3Value(); -+ PrintFPURegister(reg); -+} -+ -+void Decoder::PrintFRd(Instruction* instr) { -+ int reg = instr->RdValue(); -+ PrintFPURegister(reg); -+} -+ -+void Decoder::PrintImm12X(Instruction* instr) { -+ int32_t imm = instr->Imm12Value(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); -+} -+ -+void Decoder::PrintImm12(Instruction* instr) { -+ int32_t imm = instr->Imm12Value(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); -+} -+ -+void Decoder::PrintBranchOffset(Instruction* instr) { -+ int32_t imm = instr->BranchOffset(); -+ const char* target = converter_.NameOfAddress(reinterpret_cast(instr) + imm); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d -> %s", imm, target); -+} -+ -+void Decoder::PrintStoreOffset(Instruction* instr) { -+ int32_t imm = instr->StoreOffset(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); -+} -+ -+void Decoder::PrintImm20U(Instruction* instr) { -+ int32_t imm = instr->Imm20UValue(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); -+} -+ -+void Decoder::PrintImm20J(Instruction* instr) { -+ int32_t imm = instr->Imm20JValue(); -+ const char* target = converter_.NameOfAddress(reinterpret_cast(instr) + imm); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d -> %s", imm, target); -+} -+ -+void Decoder::PrintShamt(Instruction* instr) { -+ int32_t imm = instr->Shamt(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); -+} -+ -+void Decoder::PrintShamt32(Instruction* instr) { -+ int32_t imm = instr->Shamt32(); -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); -+} -+ -+void Decoder::PrintAcquireRelease(Instruction* instr) { -+ bool aq = instr->AqValue(); -+ bool rl = instr->RlValue(); -+ if (aq || rl) { -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "."); -+ } -+ if (aq) { -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "aq"); -+ } -+ if (rl) { -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "rl"); -+ } -+} -+ -+void Decoder::PrintCSRReg(Instruction* instr) { -+ int32_t csr_reg = instr->CsrValue(); -+ std::string s; -+ switch (csr_reg) { -+ case csr_fflags: // Floating-Point Accrued Exceptions (RW) -+ s = "csr_fflags"; -+ break; -+ case csr_frm: // Floating-Point Dynamic Rounding Mode (RW) -+ s = "csr_frm"; -+ break; -+ case csr_fcsr: // Floating-Point Control and Status Register (RW) -+ s = "csr_fcsr"; -+ break; -+ case csr_cycle: -+ s = "csr_cycle"; -+ break; -+ case csr_time: -+ s = "csr_time"; -+ break; -+ case csr_instret: -+ s = "csr_instret"; -+ break; -+ case csr_cycleh: -+ s = "csr_cycleh"; -+ break; -+ case csr_timeh: -+ s = "csr_timeh"; -+ break; -+ case csr_instreth: -+ s = "csr_instreth"; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); -+} -+ -+void Decoder::PrintRoundingMode(Instruction* instr) { -+ int frm = instr->RoundMode(); -+ std::string s; -+ switch (frm) { -+ case RNE: -+ s = "RNE"; -+ break; -+ case RTZ: -+ s = "RTZ"; -+ break; -+ case RDN: -+ s = "RDN"; -+ break; -+ case RUP: -+ s = "RUP"; -+ break; -+ case RMM: -+ s = "RMM"; -+ break; -+ case DYN: -+ s = "DYN"; -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); -+} -+ -+void Decoder::PrintMemoryOrder(Instruction* instr, bool is_pred) { -+ int memOrder = instr->MemoryOrder(is_pred); -+ std::string s; -+ if ((memOrder & PSI) == PSI) { -+ s += "i"; -+ } -+ if ((memOrder & PSO) == PSO) { -+ s += "o"; -+ } -+ if ((memOrder & PSR) == PSR) { -+ s += "r"; -+ } -+ if ((memOrder & PSW) == PSW) { -+ s += "w"; -+ } -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); -+} -+ -+// Printing of instruction name. -+void Decoder::PrintInstructionName(Instruction* instr) {} -+ -+// Handle all register based formatting in this function to reduce the -+// complexity of FormatOption. -+int Decoder::FormatRegister(Instruction* instr, const char* format) { -+ DCHECK_EQ(format[0], 'r'); -+ if (format[1] == 's') { // 'rs[12]: Rs register. -+ if (format[2] == '1') { -+ int reg = instr->Rs1Value(); -+ PrintRegister(reg); -+ return 3; -+ } else if (format[2] == '2') { -+ int reg = instr->Rs2Value(); -+ PrintRegister(reg); -+ return 3; -+ } -+ UNREACHABLE(); -+ } else if (format[1] == 'd') { // 'rd: rd register. -+ int reg = instr->RdValue(); -+ PrintRegister(reg); -+ return 2; -+ } -+ UNREACHABLE(); -+} -+ -+// Handle all FPUregister based formatting in this function to reduce the -+// complexity of FormatOption. -+int Decoder::FormatFPURegisterOrRoundMode(Instruction* instr, -+ const char* format) { -+ DCHECK_EQ(format[0], 'f'); -+ if (format[1] == 's') { // 'fs[1-3]: Rs register. -+ if (format[2] == '1') { -+ int reg = instr->Rs1Value(); -+ PrintFPURegister(reg); -+ return 3; -+ } else if (format[2] == '2') { -+ int reg = instr->Rs2Value(); -+ PrintFPURegister(reg); -+ return 3; -+ } else if (format[2] == '3') { -+ int reg = instr->Rs3Value(); -+ PrintFPURegister(reg); -+ return 3; -+ } -+ UNREACHABLE(); -+ } else if (format[1] == 'd') { // 'fd: fd register. -+ int reg = instr->RdValue(); -+ PrintFPURegister(reg); -+ return 2; -+ } else if (format[1] == 'r') { // 'frm -+ DCHECK(STRING_STARTS_WITH(format, "frm")); -+ PrintRoundingMode(instr); -+ return 3; -+ } -+ UNREACHABLE(); -+} -+ -+// FormatOption takes a formatting string and interprets it based on -+// the current instructions. The format string points to the first -+// character of the option string (the option escape has already been -+// consumed by the caller.) FormatOption returns the number of -+// characters that were consumed from the formatting string. -+int Decoder::FormatOption(Instruction* instr, const char* format) { -+ switch (format[0]) { -+ case 'c': { // `csr: CSR registers -+ if (format[1] == 's') { -+ if (format[2] == 'r') { -+ PrintCSRReg(instr); -+ return 3; -+ } -+ } -+ UNREACHABLE(); -+ } -+ case 'i': { // 'imm12, 'imm12x, 'imm20U, or 'imm20J: Immediates. -+ if (format[3] == '1') { -+ if (format[4] == '2') { -+ DCHECK(STRING_STARTS_WITH(format, "imm12")); -+ if (format[5] == 'x') { -+ PrintImm12X(instr); -+ return 6; -+ } -+ PrintImm12(instr); -+ return 5; -+ } -+ } else if (format[3] == '2' && format[4] == '0') { -+ DCHECK(STRING_STARTS_WITH(format, "imm20")); -+ switch (format[5]) { -+ case 'U': -+ DCHECK(STRING_STARTS_WITH(format, "imm20U")); -+ PrintImm20U(instr); -+ break; -+ case 'J': -+ DCHECK(STRING_STARTS_WITH(format, "imm20J")); -+ PrintImm20J(instr); -+ break; -+ } -+ return 6; -+ } -+ UNREACHABLE(); -+ } -+ case 'o': { // 'offB or 'offS: Offsets. -+ if (format[3] == 'B') { -+ DCHECK(STRING_STARTS_WITH(format, "offB")); -+ PrintBranchOffset(instr); -+ return 4; -+ } else if (format[3] == 'S') { -+ DCHECK(STRING_STARTS_WITH(format, "offS")); -+ PrintStoreOffset(instr); -+ return 4; -+ } -+ UNREACHABLE(); -+ } -+ case 'r': { // 'r: registers. -+ return FormatRegister(instr, format); -+ } -+ case 'f': { // 'f: FPUregisters or `frm -+ return FormatFPURegisterOrRoundMode(instr, format); -+ } -+ case 'a': { // 'a: Atomic acquire and release. -+ PrintAcquireRelease(instr); -+ return 1; -+ } -+ case 'p': { // `pre -+ DCHECK(STRING_STARTS_WITH(format, "pre")); -+ PrintMemoryOrder(instr, true); -+ return 3; -+ } -+ case 's': { // 's32 or 's64: Shift amount. -+ if (format[1] == '3') { -+ DCHECK(STRING_STARTS_WITH(format, "s32")); -+ PrintShamt32(instr); -+ return 3; -+ } else if (format[1] == '6') { -+ DCHECK(STRING_STARTS_WITH(format, "s64")); -+ PrintShamt(instr); -+ return 3; -+ } else if (format[1] == 'u') { -+ DCHECK(STRING_STARTS_WITH(format, "suc")); -+ PrintMemoryOrder(instr, false); -+ return 3; -+ } -+ UNREACHABLE(); -+ } -+ case 'v': { // 'vs1: Raw values from register fields -+ DCHECK(STRING_STARTS_WITH(format, "vs1")); -+ PrintVs1(instr); -+ return 3; -+ } -+ } -+ UNREACHABLE(); -+} -+ -+// Format takes a formatting string for a whole instruction and prints it into -+// the output buffer. All escaped options are handed to FormatOption to be -+// parsed further. -+void Decoder::Format(Instruction* instr, const char* format) { -+ char cur = *format++; -+ while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) { -+ if (cur == '\'') { // Single quote is used as the formatting escape. -+ format += FormatOption(instr, format); -+ } else { -+ out_buffer_[out_buffer_pos_++] = cur; -+ } -+ cur = *format++; -+ } -+ out_buffer_[out_buffer_pos_] = '\0'; -+} -+ -+// For currently unimplemented decodings the disassembler calls Unknown(instr) -+// which will just print "unknown" of the instruction bits. -+void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); } -+ -+// RISCV Instruction Decode Routine -+void Decoder::DecodeRType(Instruction* instr) { -+ switch (instr->InstructionBits() & kRTypeMask) { -+ case RO_ADD: -+ Format(instr, "add 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SUB: -+ if (instr->Rs1Value() == zero_reg.code()) -+ Format(instr, "neg 'rd, rs2"); -+ else -+ Format(instr, "sub 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SLL: -+ Format(instr, "sll 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SLT: -+ if (instr->Rs2Value() == zero_reg.code()) -+ Format(instr, "sltz 'rd, 'rs1"); -+ else if (instr->Rs1Value() == zero_reg.code()) -+ Format(instr, "sgtz 'rd, 'rs2"); -+ else -+ Format(instr, "slt 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SLTU: -+ if (instr->Rs1Value() == zero_reg.code()) -+ Format(instr, "snez 'rd, 'rs2"); -+ else -+ Format(instr, "sltu 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_XOR: -+ Format(instr, "xor 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SRL: -+ Format(instr, "srl 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SRA: -+ Format(instr, "sra 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_OR: -+ Format(instr, "or 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_AND: -+ Format(instr, "and 'rd, 'rs1, 'rs2"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_ADDW: -+ Format(instr, "addw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SUBW: -+ if (instr->Rs1Value() == zero_reg.code()) -+ Format(instr, "negw 'rd, 'rs2"); -+ else -+ Format(instr, "subw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SLLW: -+ Format(instr, "sllw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SRLW: -+ Format(instr, "srlw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_SRAW: -+ Format(instr, "sraw 'rd, 'rs1, 'rs2"); -+ break; -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ // TODO: Add RISCV M extension macro -+ case RO_MUL: -+ Format(instr, "mul 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_MULH: -+ Format(instr, "mulh 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_MULHSU: -+ Format(instr, "mulhsu 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_MULHU: -+ Format(instr, "mulhu 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_DIV: -+ Format(instr, "div 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_DIVU: -+ Format(instr, "divu 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_REM: -+ Format(instr, "rem 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_REMU: -+ Format(instr, "remu 'rd, 'rs1, 'rs2"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_MULW: -+ Format(instr, "mulw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_DIVW: -+ Format(instr, "divw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_DIVUW: -+ Format(instr, "divuw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_REMW: -+ Format(instr, "remw 'rd, 'rs1, 'rs2"); -+ break; -+ case RO_REMUW: -+ Format(instr, "remuw 'rd, 'rs1, 'rs2"); -+ break; -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ // TODO: End Add RISCV M extension macro -+ default: { -+ switch (instr->BaseOpcode()) { -+ case AMO: -+ DecodeRAType(instr); -+ break; -+ case OP_FP: -+ DecodeRFPType(instr); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ } -+ } -+} -+ -+void Decoder::DecodeRAType(Instruction* instr) { -+ // TODO: Add macro for RISCV A extension -+ // Special handling for A extension instructions because it uses func5 -+ // For all A extension instruction, V8 simulator is pure sequential. No -+ // Memory address lock or other synchronizaiton behaviors. -+ switch (instr->InstructionBits() & kRATypeMask) { -+ case RO_LR_W: -+ Format(instr, "lr.w'a 'rd, ('rs1)"); -+ break; -+ case RO_SC_W: -+ Format(instr, "sc.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOSWAP_W: -+ Format(instr, "amoswap.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOADD_W: -+ Format(instr, "amoadd.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOXOR_W: -+ Format(instr, "amoxor.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOAND_W: -+ Format(instr, "amoand.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOOR_W: -+ Format(instr, "amoor.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMIN_W: -+ Format(instr, "amomin.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMAX_W: -+ Format(instr, "amomax.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMINU_W: -+ Format(instr, "amominu.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMAXU_W: -+ Format(instr, "amomaxu.w'a 'rd, 'rs2, ('rs1)"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_LR_D: -+ Format(instr, "lr.d'a 'rd, ('rs1)"); -+ break; -+ case RO_SC_D: -+ Format(instr, "sc.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOSWAP_D: -+ Format(instr, "amoswap.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOADD_D: -+ Format(instr, "amoadd.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOXOR_D: -+ Format(instr, "amoxor.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOAND_D: -+ Format(instr, "amoand.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOOR_D: -+ Format(instr, "amoor.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMIN_D: -+ Format(instr, "amomin.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMAX_D: -+ Format(instr, "amoswap.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMINU_D: -+ Format(instr, "amominu.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+ case RO_AMOMAXU_D: -+ Format(instr, "amomaxu.d'a 'rd, 'rs2, ('rs1)"); -+ break; -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ // TODO: End Add macro for RISCV A extension -+ default: { -+ UNSUPPORTED_RISCV(); -+ } -+ } -+} -+ -+void Decoder::DecodeRFPType(Instruction* instr) { -+ // OP_FP instructions (F/D) uses func7 first. Some further uses fun3 and rs2() -+ -+ // kRATypeMask is only for func7 -+ switch (instr->InstructionBits() & kRFPTypeMask) { -+ // TODO: Add macro for RISCV F extension -+ case RO_FADD_S: -+ Format(instr, "fadd.s 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FSUB_S: -+ Format(instr, "fsub.s 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FMUL_S: -+ Format(instr, "fmul.s 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FDIV_S: -+ Format(instr, "fdiv.s 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FSQRT_S: -+ Format(instr, "fsqrt.s 'fd, 'fs1"); -+ break; -+ case RO_FSGNJ_S: { // RO_FSGNJN_S RO_FSGNJX_S -+ switch (instr->Funct3Value()) { -+ case 0b000: // RO_FSGNJ_S -+ if (instr->Rs1Value() == instr->Rs2Value()) -+ Format(instr, "fmv.s 'fd, 'fs1"); -+ else -+ Format(instr, "fsgnj.s 'fd, 'fs1, 'fs2"); -+ break; -+ case 0b001: // RO_FSGNJN_S -+ if (instr->Rs1Value() == instr->Rs2Value()) -+ Format(instr, "fneg.s 'fd, 'fs1"); -+ else -+ Format(instr, "fsgnjn.s 'fd, 'fs1, 'fs2"); -+ break; -+ case 0b010: // RO_FSGNJX_S -+ if (instr->Rs1Value() == instr->Rs2Value()) -+ Format(instr, "fabs.s 'fd, 'fs1"); -+ else -+ Format(instr, "fsgnjx.s 'fd, 'fs1, 'fs2"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FMIN_S: { // RO_FMAX_S -+ switch (instr->Funct3Value()) { -+ case 0b000: // RO_FMIN_S -+ Format(instr, "fmin.s 'fd, 'fs1, 'fs2"); -+ break; -+ case 0b001: // RO_FMAX_S -+ Format(instr, "fmax.s 'fd, 'fs1, 'fs2"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FCVT_W_S: { // RO_FCVT_WU_S , 64F RO_FCVT_L_S RO_FCVT_LU_S -+ switch (instr->Rs2Value()) { -+ case 0b00000: // RO_FCVT_W_S -+ Format(instr, "fcvt.w.s ['frm] 'rd, 'fs1"); -+ break; -+ case 0b00001: // RO_FCVT_WU_S -+ Format(instr, "fcvt.wu.s ['frm] 'rd, 'fs1"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: // RO_FCVT_L_S -+ Format(instr, "fcvt.l.s ['frm] 'rd, 'fs1"); -+ break; -+ case 0b00011: // RO_FCVT_LU_S -+ Format(instr, "fcvt.lu.s ['frm] 'rd, 'fs1"); -+ break; -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FMV: { // RO_FCLASS_S -+ if (instr->Rs2Value() != 0b00000) { -+ UNSUPPORTED_RISCV(); -+ } -+ switch (instr->Funct3Value()) { -+ case 0b000: // RO_FMV_X_W -+ Format(instr, "fmv.x.w 'rd, 'fs1"); -+ break; -+ case 0b001: // RO_FCLASS_S -+ Format(instr, "fclass.s 'rd, 'fs1"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FLE_S: { // RO_FEQ_S RO_FLT_S RO_FLE_S -+ switch (instr->Funct3Value()) { -+ case 0b010: // RO_FEQ_S -+ Format(instr, "feq.s 'rd, 'fs1, 'fs2"); -+ break; -+ case 0b001: // RO_FLT_S -+ Format(instr, "flt.s 'rd, 'fs1, 'fs2"); -+ break; -+ case 0b000: // RO_FLE_S -+ Format(instr, "fle.s 'rd, 'fs1, 'fs2"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FCVT_S_W: { // RO_FCVT_S_WU , 64F RO_FCVT_S_L RO_FCVT_S_LU -+ switch (instr->Rs2Value()) { -+ case 0b00000: // RO_FCVT_S_W -+ Format(instr, "fcvt.s.w 'fd, 'rs1"); -+ break; -+ case 0b00001: // RO_FCVT_S_WU -+ Format(instr, "fcvt.s.wu 'fd, 'rs1"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: // RO_FCVT_S_L -+ Format(instr, "fcvt.s.l 'fd, 'rs1"); -+ break; -+ case 0b00011: // RO_FCVT_S_LU -+ Format(instr, "fcvt.s.lu 'fd, 'rs1"); -+ break; -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED_RISCV(); -+ } -+ } -+ break; -+ } -+ case RO_FMV_W_X: { -+ if (instr->Funct3Value() == 0b000) { -+ Format(instr, "fmv.w.x 'fd, 'rs1"); -+ } else { -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ // TODO: Add macro for RISCV D extension -+ case RO_FADD_D: -+ Format(instr, "fadd.d 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FSUB_D: -+ Format(instr, "fsub.d 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FMUL_D: -+ Format(instr, "fmul.d 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FDIV_D: -+ Format(instr, "fdiv.d 'fd, 'fs1, 'fs2"); -+ break; -+ case RO_FSQRT_D: { -+ if (instr->Rs2Value() == 0b00000) { -+ Format(instr, "fsqrt.d 'fd, 'fs1"); -+ } else { -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FSGNJ_D: { // RO_FSGNJN_D RO_FSGNJX_D -+ switch (instr->Funct3Value()) { -+ case 0b000: // RO_FSGNJ_D -+ if (instr->Rs1Value() == instr->Rs2Value()) -+ Format(instr, "fmv.d 'fd, 'fs1"); -+ else -+ Format(instr, "fsgnj.d 'fd, 'fs1, 'fs2"); -+ break; -+ case 0b001: // RO_FSGNJN_D -+ if (instr->Rs1Value() == instr->Rs2Value()) -+ Format(instr, "fneg.d 'fd, 'fs1"); -+ else -+ Format(instr, "fsgnjn.d 'fd, 'fs1, 'fs2"); -+ break; -+ case 0b010: // RO_FSGNJX_D -+ if (instr->Rs1Value() == instr->Rs2Value()) -+ Format(instr, "fabs.d 'fd, 'fs1"); -+ else -+ Format(instr, "fsgnjx.d 'fd, 'fs1, 'fs2"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FMIN_D: { // RO_FMAX_D -+ switch (instr->Funct3Value()) { -+ case 0b000: // RO_FMIN_D -+ Format(instr, "fmin.d 'fd, 'fs1, 'fs2"); -+ break; -+ case 0b001: // RO_FMAX_D -+ Format(instr, "fmax.d 'fd, 'fs1, 'fs2"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case (RO_FCVT_S_D & kRFPTypeMask): { -+ if (instr->Rs2Value() == 0b00001) { -+ Format(instr, "fcvt.s.d ['frm] 'fd, 'rs1"); -+ } else { -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FCVT_D_S: { -+ if (instr->Rs2Value() == 0b00000) { -+ Format(instr, "fcvt.d.s 'fd, 'fs1"); -+ } else { -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FLE_D: { // RO_FEQ_D RO_FLT_D RO_FLE_D -+ switch (instr->Funct3Value()) { -+ case 0b010: // RO_FEQ_S -+ Format(instr, "feq.d 'rd, 'fs1, 'fs2"); -+ break; -+ case 0b001: // RO_FLT_D -+ Format(instr, "flt.d 'rd, 'fs1, 'fs2"); -+ break; -+ case 0b000: // RO_FLE_D -+ Format(instr, "fle.d 'rd, 'fs1, 'fs2"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case (RO_FCLASS_D & kRFPTypeMask): { // RO_FCLASS_D , 64D RO_FMV_X_D -+ if (instr->Rs2Value() != 0b00000) { -+ UNSUPPORTED_RISCV(); -+ break; -+ } -+ switch (instr->Funct3Value()) { -+ case 0b001: // RO_FCLASS_D -+ Format(instr, "fclass.d 'rd, 'fs1"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b000: // RO_FMV_X_D -+ Format(instr, "fmv.x.d 'rd, 'fs1"); -+ break; -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FCVT_W_D: { // RO_FCVT_WU_D , 64F RO_FCVT_L_D RO_FCVT_LU_D -+ switch (instr->Rs2Value()) { -+ case 0b00000: // RO_FCVT_W_D -+ Format(instr, "fcvt.w.d ['frm] 'rd, 'fs1"); -+ break; -+ case 0b00001: // RO_FCVT_WU_D -+ Format(instr, "fcvt.wu.d ['frm] 'rd, 'fs1"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: // RO_FCVT_L_D -+ Format(instr, "fcvt.l.d ['frm] 'rd, 'fs1"); -+ break; -+ case 0b00011: // RO_FCVT_LU_D -+ Format(instr, "fcvt.lu.d ['frm] 'rd, 'fs1"); -+ break; -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ case RO_FCVT_D_W: { // RO_FCVT_D_WU , 64F RO_FCVT_D_L RO_FCVT_D_LU -+ switch (instr->Rs2Value()) { -+ case 0b00000: // RO_FCVT_D_W -+ Format(instr, "fcvt.d.w 'fd, 'rs1"); -+ break; -+ case 0b00001: // RO_FCVT_D_WU -+ Format(instr, "fcvt.d.wu 'fd, 'rs1"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: // RO_FCVT_D_L -+ Format(instr, "fcvt.d.l 'fd, 'rs1"); -+ break; -+ case 0b00011: // RO_FCVT_D_LU -+ Format(instr, "fcvt.d.lu 'fd, 'rs1"); -+ break; -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_FMV_D_X: { -+ if (instr->Funct3Value() == 0b000 && instr->Rs2Value() == 0b00000) { -+ Format(instr, "fmv.d.x 'fd, 'rs1"); -+ } else { -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED_RISCV(); -+ } -+ } -+} -+ -+void Decoder::DecodeR4Type(Instruction* instr) { -+ switch (instr->InstructionBits() & kR4TypeMask) { -+ // TODO: use F Extension macro block -+ case RO_FMADD_S: -+ Format(instr, "fmadd.s 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ case RO_FMSUB_S: -+ Format(instr, "fmsub.s 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ case RO_FNMSUB_S: -+ Format(instr, "fnmsub.s 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ case RO_FNMADD_S: -+ Format(instr, "fnmadd.s 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ // TODO: use F Extension macro block -+ case RO_FMADD_D: -+ Format(instr, "fmadd.d 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ case RO_FMSUB_D: -+ Format(instr, "fmsub.d 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ case RO_FNMSUB_D: -+ Format(instr, "fnmsub.d 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ case RO_FNMADD_D: -+ Format(instr, "fnmadd.d 'fd, 'fs1, 'fs2, 'fs3"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+} -+ -+void Decoder::DecodeIType(Instruction* instr) { -+ switch (instr->InstructionBits() & kITypeMask) { -+ case RO_JALR: -+ if (instr->RdValue() == zero_reg.code() && -+ instr->Rs1Value() == ra.code() && instr->Imm12Value() == 0) -+ Format(instr, "ret"); -+ else if (instr->RdValue() == zero_reg.code() && instr->Imm12Value() == 0) -+ Format(instr, "jr 'rs1"); -+ else if (instr->RdValue() == ra.code() && instr->Imm12Value() == 0) -+ Format(instr, "jalr 'rs1"); -+ else -+ Format(instr, "jalr 'rd, 'imm12('rs1)"); -+ break; -+ case RO_LB: -+ Format(instr, "lb 'rd, 'imm12('rs1)"); -+ break; -+ case RO_LH: -+ Format(instr, "lh 'rd, 'imm12('rs1)"); -+ break; -+ case RO_LW: -+ Format(instr, "lw 'rd, 'imm12('rs1)"); -+ break; -+ case RO_LBU: -+ Format(instr, "lbu 'rd, 'imm12('rs1)"); -+ break; -+ case RO_LHU: -+ Format(instr, "lhu 'rd, 'imm12('rs1)"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_LWU: -+ Format(instr, "lwu 'rd, 'imm12('rs1)"); -+ break; -+ case RO_LD: -+ Format(instr, "ld 'rd, 'imm12('rs1)"); -+ break; -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ case RO_ADDI: -+ if (instr->Imm12Value() == 0) { -+ if (instr->RdValue() == zero_reg.code() && -+ instr->Rs1Value() == zero_reg.code()) -+ Format(instr, "nop"); -+ else -+ Format(instr, "mv 'rd, 'rs1"); -+ } else if (instr->Rs1Value() == zero_reg.code()) { -+ Format(instr, "li 'rd, 'imm12"); -+ } else { -+ Format(instr, "addi 'rd, 'rs1, 'imm12"); -+ } -+ break; -+ case RO_SLTI: -+ Format(instr, "slti 'rd, 'rs1, 'imm12"); -+ break; -+ case RO_SLTIU: -+ if (instr->Imm12Value() == 1) -+ Format(instr, "seqz 'rd, 'rs1"); -+ else -+ Format(instr, "sltiu 'rd, 'rs1, 'imm12"); -+ break; -+ case RO_XORI: -+ if (instr->Imm12Value() == -1) -+ Format(instr, "not 'rd, 'rs1"); -+ else -+ Format(instr, "xori 'rd, 'rs1, 'imm12x"); -+ break; -+ case RO_ORI: -+ Format(instr, "ori 'rd, 'rs1, 'imm12x"); -+ break; -+ case RO_ANDI: -+ Format(instr, "andi 'rd, 'rs1, 'imm12x"); -+ break; -+ case RO_SLLI: -+ Format(instr, "slli 'rd, 'rs1, 's64"); -+ break; -+ case RO_SRLI: { // RO_SRAI -+ if (!instr->IsArithShift()) { -+ Format(instr, "srli 'rd, 'rs1, 's64"); -+ } else { -+ Format(instr, "srai 'rd, 'rs1, 's64"); -+ } -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_ADDIW: -+ if (instr->Imm12Value() == 0) -+ Format(instr, "sext.w 'rd, 'rs1"); -+ else -+ Format(instr, "addiw 'rd, 'rs1, 'imm12"); -+ break; -+ case RO_SLLIW: -+ Format(instr, "slliw 'rd, 'rs1, 's32"); -+ break; -+ case RO_SRLIW: { // RO_SRAIW -+ if (!instr->IsArithShift()) { -+ Format(instr, "srliw 'rd, 'rs1, 's32"); -+ } else { -+ Format(instr, "sraiw 'rd, 'rs1, 's32"); -+ } -+ break; -+ } -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ case RO_FENCE: -+ if (instr->MemoryOrder(true) == PSIORW && -+ instr->MemoryOrder(false) == PSIORW) -+ Format(instr, "fence"); -+ else -+ Format(instr, "fence 'pre, 'suc"); -+ break; -+ case RO_ECALL: { // RO_EBREAK -+ if (instr->Imm12Value() == 0) { // ECALL -+ Format(instr, "ecall"); -+ } else if (instr->Imm12Value() == 1) { // EBREAK -+ Format(instr, "ebreak"); -+ } else { -+ UNSUPPORTED_RISCV(); -+ } -+ break; -+ } -+ // TODO: use Zifencei Standard Extension macro block -+ case RO_FENCE_I: -+ Format(instr, "fence.i"); -+ break; -+ // TODO: use Zicsr Standard Extension macro block -+ // FIXME(RISC-V): Add special formatting for CSR registers -+ case RO_CSRRW: -+ if (instr->CsrValue() == csr_fcsr) { -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "fscsr 'rs1"); -+ else -+ Format(instr, "fscsr 'rd, 'rs1"); -+ } else if (instr->CsrValue() == csr_frm) { -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "fsrm 'rs1"); -+ else -+ Format(instr, "fsrm 'rd, 'rs1"); -+ } else if (instr->CsrValue() == csr_fflags) { -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "fsflags 'rs1"); -+ else -+ Format(instr, "fsflags 'rd, 'rs1"); -+ } else if (instr->RdValue() == zero_reg.code()) { -+ Format(instr, "csrw 'csr, 'rs1"); -+ } else { -+ Format(instr, "csrrw 'rd, 'csr, 'rs1"); -+ } -+ break; -+ case RO_CSRRS: -+ if (instr->Rs1Value() == zero_reg.code()) { -+ switch (instr->CsrValue()) { -+ case csr_instret: -+ Format(instr, "rdinstret 'rd"); -+ break; -+ case csr_instreth: -+ Format(instr, "rdinstreth 'rd"); -+ break; -+ case csr_time: -+ Format(instr, "rdtime 'rd"); -+ break; -+ case csr_timeh: -+ Format(instr, "rdtimeh 'rd"); -+ break; -+ case csr_cycle: -+ Format(instr, "rdcycle 'rd"); -+ break; -+ case csr_cycleh: -+ Format(instr, "rdcycleh 'rd"); -+ break; -+ case csr_fflags: -+ Format(instr, "frflags 'rd"); -+ break; -+ case csr_frm: -+ Format(instr, "frrm 'rd"); -+ break; -+ case csr_fcsr: -+ Format(instr, "frcsr 'rd"); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } else if (instr->Rs1Value() == zero_reg.code()) { -+ Format(instr, "csrr 'rd, 'csr"); -+ } else if (instr->RdValue() == zero_reg.code()) { -+ Format(instr, "csrs 'csr, 'rs1"); -+ } else -+ Format(instr, "csrrs 'rd, 'csr, 'rs1"); -+ break; -+ case RO_CSRRC: -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "csrc 'csr, 'rs1"); -+ else -+ Format(instr, "csrrc 'rd, 'csr, 'rs1"); -+ break; -+ case RO_CSRRWI: -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "csrwi 'csr, 'vs1"); -+ else -+ Format(instr, "csrrwi 'rd, 'csr, 'vs1"); -+ break; -+ case RO_CSRRSI: -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "csrsi 'csr, 'vs1"); -+ else -+ Format(instr, "csrrsi 'rd, 'csr, 'vs1"); -+ break; -+ case RO_CSRRCI: -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "csrci 'csr, 'vs1"); -+ else -+ Format(instr, "csrrci 'rd, 'csr, 'vs1"); -+ break; -+ // TODO: use F Extension macro block -+ case RO_FLW: -+ Format(instr, "flw 'fd, 'imm12('rs1)"); -+ break; -+ // TODO: use D Extension macro block -+ case RO_FLD: -+ Format(instr, "fld 'fd, 'imm12('rs1)"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+} -+ -+void Decoder::DecodeSType(Instruction* instr) { -+ switch (instr->InstructionBits() & kSTypeMask) { -+ case RO_SB: -+ Format(instr, "sb 'rs2, 'offS('rs1)"); -+ break; -+ case RO_SH: -+ Format(instr, "sh 'rs2, 'offS('rs1)"); -+ break; -+ case RO_SW: -+ Format(instr, "sw 'rs2, 'offS('rs1)"); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_SD: -+ Format(instr, "sd 'rs2, 'offS('rs1)"); -+ break; -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ // TODO: use F Extension macro block -+ case RO_FSW: -+ Format(instr, "fsw 'fs2, 'offS('rs1)"); -+ break; -+ // TODO: use D Extension macro block -+ case RO_FSD: -+ Format(instr, "fsd 'fs2, 'offS('rs1)"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+} -+ -+void Decoder::DecodeBType(Instruction* instr) { -+ switch (instr->InstructionBits() & kBTypeMask) { -+ case RO_BEQ: -+ Format(instr, "beq 'rs1, 'rs2, 'offB"); -+ break; -+ case RO_BNE: -+ Format(instr, "bne 'rs1, 'rs2, 'offB"); -+ break; -+ case RO_BLT: -+ Format(instr, "blt 'rs1, 'rs2, 'offB"); -+ break; -+ case RO_BGE: -+ Format(instr, "bge 'rs1, 'rs2, 'offB"); -+ break; -+ case RO_BLTU: -+ Format(instr, "bltu 'rs1, 'rs2, 'offB"); -+ break; -+ case RO_BGEU: -+ Format(instr, "bgeu 'rs1, 'rs2, 'offB"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+} -+void Decoder::DecodeUType(Instruction* instr) { -+ // U Type doesn't have additional mask -+ switch (instr->BaseOpcodeFieldRaw()) { -+ case RO_LUI: -+ Format(instr, "lui 'rd, 'imm20U"); -+ break; -+ case RO_AUIPC: -+ Format(instr, "auipc 'rd, 'imm20U"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+} -+void Decoder::DecodeJType(Instruction* instr) { -+ // J Type doesn't have additional mask -+ switch (instr->BaseOpcodeValue()) { -+ case RO_JAL: -+ if (instr->RdValue() == zero_reg.code()) -+ Format(instr, "j 'imm20J"); -+ else if (instr->RdValue() == ra.code()) -+ Format(instr, "jal 'imm20J"); -+ else -+ Format(instr, "jal 'rd, 'imm20J"); -+ break; -+ default: -+ UNSUPPORTED_RISCV(); -+ } -+} -+ -+// Disassemble the instruction at *instr_ptr into the output buffer. -+// All instructions are one word long, except for the simulator -+// pseudo-instruction stop(msg). For that one special case, we return -+// size larger than one kInstrSize. -+int Decoder::InstructionDecode(byte* instr_ptr) { -+ Instruction* instr = Instruction::At(instr_ptr); -+ // Print raw instruction bytes. -+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x ", -+ instr->InstructionBits()); -+ switch (instr->InstructionType()) { -+ case Instruction::kRType: -+ DecodeRType(instr); -+ break; -+ case Instruction::kR4Type: -+ DecodeR4Type(instr); -+ break; -+ case Instruction::kIType: -+ DecodeIType(instr); -+ break; -+ case Instruction::kSType: -+ DecodeSType(instr); -+ break; -+ case Instruction::kBType: -+ DecodeBType(instr); -+ break; -+ case Instruction::kUType: -+ DecodeUType(instr); -+ break; -+ case Instruction::kJType: -+ DecodeJType(instr); -+ break; -+ default: -+ Format(instr, "UNSUPPORTED"); -+ UNSUPPORTED_RISCV(); -+ } -+ return kInstrSize; -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+//------------------------------------------------------------------------------ -+ -+namespace disasm { -+ -+const char* NameConverter::NameOfAddress(byte* addr) const { -+ v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast(addr)); -+ return tmp_buffer_.begin(); -+} -+ -+const char* NameConverter::NameOfConstant(byte* addr) const { -+ return NameOfAddress(addr); -+} -+ -+const char* NameConverter::NameOfCPURegister(int reg) const { -+ return v8::internal::Registers::Name(reg); -+} -+ -+const char* NameConverter::NameOfXMMRegister(int reg) const { -+ return v8::internal::FPURegisters::Name(reg); -+} -+ -+const char* NameConverter::NameOfByteCPURegister(int reg) const { -+ UNREACHABLE(); // RISC-V does not have the concept of a byte register. -+ return "nobytereg"; -+} -+ -+const char* NameConverter::NameInCode(byte* addr) const { -+ // The default name converter is called for unknown code. So we will not try -+ // to access any memory. -+ return ""; -+} -+ -+//------------------------------------------------------------------------------ -+ -+int Disassembler::InstructionDecode(v8::internal::Vector buffer, -+ byte* instruction) { -+ v8::internal::Decoder d(converter_, buffer); -+ return d.InstructionDecode(instruction); -+} -+ -+// The RISC-V assembler does not currently use constant pools. -+int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } -+ -+void Disassembler::Disassemble(FILE* f, byte* begin, byte* end, -+ UnimplementedOpcodeAction unimplemented_action) { -+ NameConverter converter; -+ Disassembler d(converter, unimplemented_action); -+ for (byte* pc = begin; pc < end;) { -+ v8::internal::EmbeddedVector buffer; -+ buffer[0] = '\0'; -+ byte* prev_pc = pc; -+ pc += d.InstructionDecode(buffer, pc); -+ v8::internal::PrintF(f, "%p %08x %s\n", static_cast(prev_pc), -+ *reinterpret_cast(prev_pc), buffer.begin()); -+ } -+} -+ -+#undef STRING_STARTS_WITH -+ -+} // namespace disasm -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/frame-constants.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/execution/frame-constants.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/frame-constants.h -@@ -356,6 +356,10 @@ inline static int FrameSlotToFPOffset(in - #include "src/execution/mips64/frame-constants-mips64.h" // NOLINT - #elif V8_TARGET_ARCH_S390 - #include "src/execution/s390/frame-constants-s390.h" // NOLINT -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/execution/riscv64/frame-constants-riscv64.h" // NOLINT -+#elif V8_TARGET_ARCH_RISCV -+#include "src/execution/riscv/frame-constants-riscv.h" // NOLINT - #else - #error Unsupported target architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/frame-constants-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/frame-constants-riscv64.cc -@@ -0,0 +1,32 @@ -+// Copyright 2011 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. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/codegen/riscv64/assembler-riscv64-inl.h" -+#include "src/execution/frame-constants.h" -+#include "src/execution/frames.h" -+ -+#include "src/execution/riscv64/frame-constants-riscv64.h" -+ -+namespace v8 { -+namespace internal { -+ -+Register JavaScriptFrame::fp_register() { return v8::internal::fp; } -+Register JavaScriptFrame::context_register() { return cp; } -+Register JavaScriptFrame::constant_pool_pointer_register() { UNREACHABLE(); } -+ -+int InterpreterFrameConstants::RegisterStackSlotCount(int register_count) { -+ return register_count; -+} -+ -+int BuiltinContinuationFrameConstants::PaddingSlotCount(int register_count) { -+ USE(register_count); -+ return 0; -+} -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/frame-constants-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/frame-constants-riscv64.h -@@ -0,0 +1,87 @@ -+// Copyright 2011 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. -+ -+#ifndef V8_EXECUTION_RISCV_FRAME_CONSTANTS_RISCV_H_ -+#define V8_EXECUTION_RISCV_FRAME_CONSTANTS_RISCV_H_ -+ -+#include "src/base/bits.h" -+#include "src/base/macros.h" -+#include "src/execution/frame-constants.h" -+#include "src/wasm/baseline/liftoff-assembler-defs.h" -+#include "src/wasm/wasm-linkage.h" -+ -+namespace v8 { -+namespace internal { -+ -+class EntryFrameConstants : public AllStatic { -+ public: -+ // This is the offset to where JSEntry pushes the current value of -+ // Isolate::c_entry_fp onto the stack. -+ static constexpr int kCallerFPOffset = -+ -(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize); -+}; -+ -+class WasmCompileLazyFrameConstants : public TypedFrameConstants { -+ public: -+ static constexpr int kNumberOfSavedGpParamRegs = -+ arraysize(wasm::kGpParamRegisters); -+ static constexpr int kNumberOfSavedFpParamRegs = -+ arraysize(wasm::kFpParamRegisters); -+ -+ // FP-relative. -+ // Builtins::Generate_WasmCompileLazy pushes WasmInstance to the stack after -+ // pushing SavedGPParamRegs and SavedFpParamRegs onto the stack, therefore -+ // kWasmInstanceOffset is setup as such -+ static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET( -+ kNumberOfSavedGpParamRegs + kNumberOfSavedGpParamRegs); -+ static constexpr int kFixedFrameSizeFromFp = -+ TypedFrameConstants::kFixedFrameSizeFromFp + -+ kNumberOfSavedGpParamRegs * kPointerSize + -+ kNumberOfSavedFpParamRegs * kDoubleSize; -+}; -+ -+// Frame constructed by the {WasmDebugBreak} builtin. -+// After pushing the frame type marker, the builtin pushes all Liftoff cache -+// registers (see liftoff-assembler-defs.h). -+class WasmDebugBreakFrameConstants : public TypedFrameConstants { -+ public: -+ // constexpr RegList kLiftoffAssemblerGpCacheRegs = -+ // Register::ListOf(a0, a1, a2, a3, a4, a5, a6, a7, t0, t1, t2, s7); -+ static constexpr uint32_t kPushedGpRegs = wasm::kLiftoffAssemblerGpCacheRegs; -+ -+ // constexpr RegList kLiftoffAssemblerFpCacheRegs = DoubleRegister::ListOf( -+ // ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7, fa0, fa1, fa2, fa3, fa4, fa5, -+ // fa6, fa7, ft8, ft9, ft10, ft11); -+ static constexpr uint32_t kPushedFpRegs = wasm::kLiftoffAssemblerFpCacheRegs; -+ -+ static constexpr int kNumPushedGpRegisters = -+ base::bits::CountPopulation(kPushedGpRegs); -+ static constexpr int kNumPushedFpRegisters = -+ base::bits::CountPopulation(kPushedFpRegs); -+ -+ static constexpr int kLastPushedGpRegisterOffset = -+ -kFixedFrameSizeFromFp - kNumPushedGpRegisters * kSystemPointerSize; -+ static constexpr int kLastPushedFpRegisterOffset = -+ kLastPushedGpRegisterOffset - kNumPushedFpRegisters * kDoubleSize; -+ -+ // Offsets are fp-relative. -+ static int GetPushedGpRegisterOffset(int reg_code) { -+ DCHECK_NE(0, kPushedGpRegs & (1 << reg_code)); -+ uint32_t lower_regs = kPushedGpRegs & ((uint32_t{1} << reg_code) - 1); -+ return kLastPushedGpRegisterOffset + -+ base::bits::CountPopulation(lower_regs) * kSystemPointerSize; -+ } -+ -+ static int GetPushedFpRegisterOffset(int reg_code) { -+ DCHECK_NE(0, kPushedFpRegs & (1 << reg_code)); -+ uint32_t lower_regs = kPushedFpRegs & ((uint32_t{1} << reg_code) - 1); -+ return kLastPushedFpRegisterOffset + -+ base::bits::CountPopulation(lower_regs) * kDoubleSize; -+ } -+}; -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_EXECUTION_RISCV_FRAME_CONSTANTS_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/simulator-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/simulator-riscv64.cc -@@ -0,0 +1,3509 @@ -+// Copyright 2020 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. -+ -+// Copyright(c) 2010 - 2017, -+// The Regents of the University of California(Regents).All Rights Reserved. -+// -+// Redistribution and use in source and binary forms, -+// with or without modification, -+// are permitted provided that the following -+// conditions are met : 1. Redistributions of source code must retain the -+// above copyright notice, this list of conditions and the following -+// disclaimer.2. Redistributions in binary form must reproduce the above -+// copyright notice, this list of conditions and the following disclaimer in -+// the -+// documentation and / -+// or -+// other materials provided with the distribution.3. Neither the name of -+// the Regents nor the names of its contributors may be used to endorse -+// or -+// promote products derived from -+// this software without specific prior written permission. -+// -+// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, -+// INDIRECT, SPECIAL, -+// INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, -+// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, -+// EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+// -+// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, -+// INCLUDING, BUT NOT LIMITED TO, -+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -+// PARTICULAR PURPOSE.THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, -+// IF ANY, -+// PROVIDED HEREUNDER IS PROVIDED -+// "AS IS".REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, -+// SUPPORT, UPDATES, ENHANCEMENTS, -+// OR MODIFICATIONS. -+ -+// The original source code covered by the above license above has been -+// modified significantly by the v8 project authors. -+ -+#include "src/execution/riscv64/simulator-riscv64.h" -+ -+// Only build the simulator if not compiling for real RISCV hardware. -+#if defined(USE_SIMULATOR) -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "src/base/bits.h" -+#include "src/codegen/assembler-inl.h" -+#include "src/codegen/macro-assembler.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/diagnostics/disasm.h" -+#include "src/heap/combined-heap.h" -+#include "src/runtime/runtime-utils.h" -+#include "src/utils/ostreams.h" -+#include "src/utils/vector.h" -+ -+namespace v8 { -+namespace internal { -+ -+DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor, -+ Simulator::GlobalMonitor::Get) -+ -+// Util functions. -+inline bool HaveSameSign(int64_t a, int64_t b) { return ((a ^ b) >= 0); } -+ -+uint32_t get_fcsr_condition_bit(uint32_t cc) { -+ if (cc == 0) { -+ return 23; -+ } else { -+ return 24 + cc; -+ } -+} -+ -+// Generated by Assembler::break_()/stop(), ebreak code is passed as immediate -+// field of a subsequent LUI instruction; otherwise returns -1 -+static inline int32_t get_ebreak_code(Instruction* instr) { -+ DCHECK(instr->InstructionBits() == kBreakInstr); -+ byte* cur = reinterpret_cast(instr); -+ Instruction* next_instr = reinterpret_cast(cur + kInstrSize); -+ if (next_instr->BaseOpcodeFieldRaw() == RO_LUI) -+ return (next_instr->Imm20UValue()); -+ else -+ return -1; -+} -+ -+// This macro provides a platform independent use of sscanf. The reason for -+// SScanF not being implemented in a platform independent was through -+// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time -+// Library does not provide vsscanf. -+#define SScanF sscanf // NOLINT -+ -+// The RiscvDebugger class is used by the simulator while debugging simulated -+// code. -+class RiscvDebugger { -+ public: -+ explicit RiscvDebugger(Simulator* sim) : sim_(sim) {} -+ -+ void Debug(); -+ // Print all registers with a nice formatting. -+ void PrintRegs(char name_prefix, int start_index, int end_index); -+ void PrintAllRegs(); -+ void PrintAllRegsIncludingFPU(); -+ -+ static const Instr kNopInstr = 0x0; -+ -+ private: -+ Simulator* sim_; -+ -+ int64_t GetRegisterValue(int regnum); -+ int64_t GetFPURegisterValue(int regnum); -+ float GetFPURegisterValueFloat(int regnum); -+ double GetFPURegisterValueDouble(int regnum); -+ bool GetValue(const char* desc, int64_t* value); -+}; -+ -+inline void UNSUPPORTED() { -+ printf("Sim: Unsupported instruction.\n"); -+ base::OS::Abort(); -+} -+ -+int64_t RiscvDebugger::GetRegisterValue(int regnum) { -+ if (regnum == kNumSimuRegisters) { -+ return sim_->get_pc(); -+ } else { -+ return sim_->get_register(regnum); -+ } -+} -+ -+int64_t RiscvDebugger::GetFPURegisterValue(int regnum) { -+ if (regnum == kNumFPURegisters) { -+ return sim_->get_pc(); -+ } else { -+ return sim_->get_fpu_register(regnum); -+ } -+} -+ -+float RiscvDebugger::GetFPURegisterValueFloat(int regnum) { -+ if (regnum == kNumFPURegisters) { -+ return sim_->get_pc(); -+ } else { -+ return sim_->get_fpu_register_float(regnum); -+ } -+} -+ -+double RiscvDebugger::GetFPURegisterValueDouble(int regnum) { -+ if (regnum == kNumFPURegisters) { -+ return sim_->get_pc(); -+ } else { -+ return sim_->get_fpu_register_double(regnum); -+ } -+} -+ -+bool RiscvDebugger::GetValue(const char* desc, int64_t* value) { -+ int regnum = Registers::Number(desc); -+ int fpuregnum = FPURegisters::Number(desc); -+ -+ if (regnum != kInvalidRegister) { -+ *value = GetRegisterValue(regnum); -+ return true; -+ } else if (fpuregnum != kInvalidFPURegister) { -+ *value = GetFPURegisterValue(fpuregnum); -+ return true; -+ } else if (strncmp(desc, "0x", 2) == 0) { -+ return SScanF(desc + 2, "%" SCNx64, reinterpret_cast(value)) == -+ 1; -+ } else { -+ return SScanF(desc, "%" SCNu64, reinterpret_cast(value)) == 1; -+ } -+ return false; -+} -+ -+#define REG_INFO(name) \ -+ name, GetRegisterValue(Registers::Number(name)), \ -+ GetRegisterValue(Registers::Number(name)) -+ -+void RiscvDebugger::PrintRegs(char name_prefix, int start_index, -+ int end_index) { -+ EmbeddedVector name1, name2; -+ DCHECK(name_prefix == 'a' || name_prefix == 't' || name_prefix == 's'); -+ DCHECK(start_index >= 0 && end_index <= 99); -+ int num_registers = (end_index - start_index) + 1; -+ for (int i = 0; i < num_registers / 2; i++) { -+ SNPrintF(name1, "%c%d", name_prefix, start_index + 2 * i); -+ SNPrintF(name2, "%c%d", name_prefix, start_index + 2 * i + 1); -+ PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \t%3s: 0x%016" PRIx64 -+ " %14" PRId64 " \n", -+ REG_INFO(name1.begin()), REG_INFO(name2.begin())); -+ } -+ if (num_registers % 2 == 1) { -+ SNPrintF(name1, "%c%d", name_prefix, end_index); -+ PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 " \n", REG_INFO(name1.begin())); -+ } -+} -+ -+void RiscvDebugger::PrintAllRegs() { -+ PrintF("\n"); -+ // ra, sp, gp -+ PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 "\t%3s: 0x%016" PRIx64 " %14" PRId64 -+ "\t%3s: 0x%016" PRIx64 " %14" PRId64 "\n", -+ REG_INFO("ra"), REG_INFO("sp"), REG_INFO("gp")); -+ -+ // tp, fp, pc -+ PrintF("%3s: 0x%016" PRIx64 " %14" PRId64 "\t%3s: 0x%016" PRIx64 " %14" PRId64 -+ "\t%3s: 0x%016" PRIx64 " %14" PRId64 "\n", -+ REG_INFO("tp"), REG_INFO("fp"), REG_INFO("pc")); -+ -+ // print register a0, .., a7 -+ PrintRegs('a', 0, 7); -+ // print registers s1, ..., s11 -+ PrintRegs('s', 1, 11); -+ // print registers t0, ..., t6 -+ PrintRegs('t', 0, 6); -+} -+ -+#undef REG_INFO -+ -+void RiscvDebugger::PrintAllRegsIncludingFPU() { -+#define FPU_REG_INFO(n) \ -+ FPURegisters::Name(n), GetFPURegisterValue(n), GetFPURegisterValueDouble(n) -+ -+ PrintAllRegs(); -+ -+ PrintF("\n\n"); -+ // f0, f1, f2, ... f31. -+ DCHECK(kNumFPURegisters % 2 == 0); -+ for (int i = 0; i < kNumFPURegisters; i += 2) -+ PrintF("%3s: 0x%016" PRIx64 " %16.4e \t%3s: 0x%016" PRIx64 " %16.4e\n", -+ FPU_REG_INFO(i), FPU_REG_INFO(i + 1)); -+#undef FPU_REG_INFO -+} -+ -+void RiscvDebugger::Debug() { -+ intptr_t last_pc = -1; -+ bool done = false; -+ -+#define COMMAND_SIZE 63 -+#define ARG_SIZE 255 -+ -+#define STR(a) #a -+#define XSTR(a) STR(a) -+ -+ char cmd[COMMAND_SIZE + 1]; -+ char arg1[ARG_SIZE + 1]; -+ char arg2[ARG_SIZE + 1]; -+ char* argv[3] = {cmd, arg1, arg2}; -+ -+ // Make sure to have a proper terminating character if reaching the limit. -+ cmd[COMMAND_SIZE] = 0; -+ arg1[ARG_SIZE] = 0; -+ arg2[ARG_SIZE] = 0; -+ -+ while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) { -+ if (last_pc != sim_->get_pc()) { -+ disasm::NameConverter converter; -+ disasm::Disassembler dasm(converter); -+ // Use a reasonably large buffer. -+ v8::internal::EmbeddedVector buffer; -+ dasm.InstructionDecode(buffer, reinterpret_cast(sim_->get_pc())); -+ PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.begin()); -+ last_pc = sim_->get_pc(); -+ } -+ char* line = ReadLine("sim> "); -+ if (line == nullptr) { -+ break; -+ } else { -+ char* last_input = sim_->last_debugger_input(); -+ if (strcmp(line, "\n") == 0 && last_input != nullptr) { -+ line = last_input; -+ } else { -+ // Ownership is transferred to sim_; -+ sim_->set_last_debugger_input(line); -+ } -+ // Use sscanf to parse the individual parts of the command line. At the -+ // moment no command expects more than two parameters. -+ int argc = SScanF( -+ line, -+ "%" XSTR(COMMAND_SIZE) "s " -+ "%" XSTR(ARG_SIZE) "s " -+ "%" XSTR(ARG_SIZE) "s", -+ cmd, arg1, arg2); -+ if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { -+ Instruction* instr = reinterpret_cast(sim_->get_pc()); -+ if (!(instr->IsTrap()) || -+ instr->InstructionBits() == rtCallRedirInstr) { -+ sim_->InstructionDecode( -+ reinterpret_cast(sim_->get_pc())); -+ } else { -+ // Allow si to jump over generated breakpoints. -+ PrintF("/!\\ Jumping over generated breakpoint.\n"); -+ sim_->set_pc(sim_->get_pc() + kInstrSize); -+ } -+ } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { -+ // Execute the one instruction we broke at with breakpoints disabled. -+ sim_->InstructionDecode(reinterpret_cast(sim_->get_pc())); -+ // Leave the debugger shell. -+ done = true; -+ } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { -+ if (argc == 2) { -+ int64_t value; -+ double dvalue; -+ if (strcmp(arg1, "all") == 0) { -+ PrintAllRegs(); -+ } else if (strcmp(arg1, "allf") == 0) { -+ PrintAllRegsIncludingFPU(); -+ } else { -+ int regnum = Registers::Number(arg1); -+ int fpuregnum = FPURegisters::Number(arg1); -+ -+ if (regnum != kInvalidRegister) { -+ value = GetRegisterValue(regnum); -+ PrintF("%s: 0x%08" PRIx64 " %" PRId64 " \n", arg1, value, -+ value); -+ } else if (fpuregnum != kInvalidFPURegister) { -+ value = GetFPURegisterValue(fpuregnum); -+ dvalue = GetFPURegisterValueDouble(fpuregnum); -+ PrintF("%3s: 0x%016" PRIx64 " %16.4e\n", -+ FPURegisters::Name(fpuregnum), value, dvalue); -+ } else { -+ PrintF("%s unrecognized\n", arg1); -+ } -+ } -+ } else { -+ if (argc == 3) { -+ if (strcmp(arg2, "single") == 0) { -+ int64_t value; -+ float fvalue; -+ int fpuregnum = FPURegisters::Number(arg1); -+ -+ if (fpuregnum != kInvalidFPURegister) { -+ value = GetFPURegisterValue(fpuregnum); -+ value &= 0xFFFFFFFFUL; -+ fvalue = GetFPURegisterValueFloat(fpuregnum); -+ PrintF("%s: 0x%08" PRIx64 " %11.4e\n", arg1, value, fvalue); -+ } else { -+ PrintF("%s unrecognized\n", arg1); -+ } -+ } else { -+ PrintF("print single\n"); -+ } -+ } else { -+ PrintF("print or print single\n"); -+ } -+ } -+ } else if ((strcmp(cmd, "po") == 0) || -+ (strcmp(cmd, "printobject") == 0)) { -+ if (argc == 2) { -+ int64_t value; -+ StdoutStream os; -+ if (GetValue(arg1, &value)) { -+ Object obj(value); -+ os << arg1 << ": \n"; -+#ifdef DEBUG -+ obj.Print(os); -+ os << "\n"; -+#else -+ os << Brief(obj) << "\n"; -+#endif -+ } else { -+ os << arg1 << " unrecognized\n"; -+ } -+ } else { -+ PrintF("printobject \n"); -+ } -+ } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { -+ int64_t* cur = nullptr; -+ int64_t* end = nullptr; -+ int next_arg = 1; -+ -+ if (strcmp(cmd, "stack") == 0) { -+ cur = reinterpret_cast(sim_->get_register(Simulator::sp)); -+ } else { // Command "mem". -+ if (argc < 2) { -+ PrintF("Need to specify
to mem command\n"); -+ continue; -+ } -+ int64_t value; -+ if (!GetValue(arg1, &value)) { -+ PrintF("%s unrecognized\n", arg1); -+ continue; -+ } -+ cur = reinterpret_cast(value); -+ next_arg++; -+ } -+ -+ int64_t words; -+ if (argc == next_arg) { -+ words = 10; -+ } else { -+ if (!GetValue(argv[next_arg], &words)) { -+ words = 10; -+ } -+ } -+ end = cur + words; -+ -+ while (cur < end) { -+ PrintF(" 0x%012" PRIxPTR " : 0x%016" PRIx64 " %14" PRId64 " ", -+ reinterpret_cast(cur), *cur, *cur); -+ Object obj(*cur); -+ Heap* current_heap = sim_->isolate_->heap(); -+ if (obj.IsSmi() || -+ IsValidHeapObject(current_heap, HeapObject::cast(obj))) { -+ PrintF(" ("); -+ if (obj.IsSmi()) { -+ PrintF("smi %d", Smi::ToInt(obj)); -+ } else { -+ obj.ShortPrint(); -+ } -+ PrintF(")"); -+ } -+ PrintF("\n"); -+ cur++; -+ } -+ -+ } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) || -+ (strcmp(cmd, "di") == 0)) { -+ disasm::NameConverter converter; -+ disasm::Disassembler dasm(converter); -+ // Use a reasonably large buffer. -+ v8::internal::EmbeddedVector buffer; -+ -+ byte* cur = nullptr; -+ byte* end = nullptr; -+ -+ if (argc == 1) { -+ cur = reinterpret_cast(sim_->get_pc()); -+ end = cur + (10 * kInstrSize); -+ } else if (argc == 2) { -+ int regnum = Registers::Number(arg1); -+ if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) { -+ // The argument is an address or a register name. -+ int64_t value; -+ if (GetValue(arg1, &value)) { -+ cur = reinterpret_cast(value); -+ // Disassemble 10 instructions at . -+ end = cur + (10 * kInstrSize); -+ } -+ } else { -+ // The argument is the number of instructions. -+ int64_t value; -+ if (GetValue(arg1, &value)) { -+ cur = reinterpret_cast(sim_->get_pc()); -+ // Disassemble instructions. -+ end = cur + (value * kInstrSize); -+ } -+ } -+ } else { -+ int64_t value1; -+ int64_t value2; -+ if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { -+ cur = reinterpret_cast(value1); -+ end = cur + (value2 * kInstrSize); -+ } -+ } -+ -+ while (cur < end) { -+ dasm.InstructionDecode(buffer, cur); -+ PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast(cur), -+ buffer.begin()); -+ cur += kInstrSize; -+ } -+ } else if (strcmp(cmd, "gdb") == 0) { -+ PrintF("relinquishing control to gdb\n"); -+ v8::base::OS::DebugBreak(); -+ PrintF("regaining control from gdb\n"); -+ } else if (strcmp(cmd, "break") == 0 -+ || strcmp(cmd, "b") == 0 -+ || strcmp(cmd, "tbreak") == 0) { -+ bool is_tbreak = strcmp(cmd, "tbreak") == 0; -+ if (argc == 2) { -+ int64_t value; -+ if (GetValue(arg1, &value)) { -+ sim_->SetBreakpoint(reinterpret_cast(value), is_tbreak); -+ } else { -+ PrintF("%s unrecognized\n", arg1); -+ } -+ } else { -+ sim_->ListBreakpoints(); -+ PrintF("Use `break
` to set or disable a breakpoint\n"); -+ PrintF("Use `tbreak
` to set or disable a temporary breakpoint\n"); -+ } -+ } else if (strcmp(cmd, "flags") == 0) { -+ PrintF("No flags on RISC-V !\n"); -+ } else if (strcmp(cmd, "stop") == 0) { -+ int64_t value; -+ if (argc == 3) { -+ // Print information about all/the specified breakpoint(s). -+ if (strcmp(arg1, "info") == 0) { -+ if (strcmp(arg2, "all") == 0) { -+ PrintF("Stop information:\n"); -+ for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; -+ i++) { -+ sim_->PrintStopInfo(i); -+ } -+ } else if (GetValue(arg2, &value)) { -+ sim_->PrintStopInfo(value); -+ } else { -+ PrintF("Unrecognized argument.\n"); -+ } -+ } else if (strcmp(arg1, "enable") == 0) { -+ // Enable all/the specified breakpoint(s). -+ if (strcmp(arg2, "all") == 0) { -+ for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; -+ i++) { -+ sim_->EnableStop(i); -+ } -+ } else if (GetValue(arg2, &value)) { -+ sim_->EnableStop(value); -+ } else { -+ PrintF("Unrecognized argument.\n"); -+ } -+ } else if (strcmp(arg1, "disable") == 0) { -+ // Disable all/the specified breakpoint(s). -+ if (strcmp(arg2, "all") == 0) { -+ for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; -+ i++) { -+ sim_->DisableStop(i); -+ } -+ } else if (GetValue(arg2, &value)) { -+ sim_->DisableStop(value); -+ } else { -+ PrintF("Unrecognized argument.\n"); -+ } -+ } -+ } else { -+ PrintF("Wrong usage. Use help command for more information.\n"); -+ } -+ } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) { -+ // Print registers and disassemble. -+ PrintAllRegs(); -+ PrintF("\n"); -+ -+ disasm::NameConverter converter; -+ disasm::Disassembler dasm(converter); -+ // Use a reasonably large buffer. -+ v8::internal::EmbeddedVector buffer; -+ -+ byte* cur = nullptr; -+ byte* end = nullptr; -+ -+ if (argc == 1) { -+ cur = reinterpret_cast(sim_->get_pc()); -+ end = cur + (10 * kInstrSize); -+ } else if (argc == 2) { -+ int64_t value; -+ if (GetValue(arg1, &value)) { -+ cur = reinterpret_cast(value); -+ // no length parameter passed, assume 10 instructions -+ end = cur + (10 * kInstrSize); -+ } -+ } else { -+ int64_t value1; -+ int64_t value2; -+ if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) { -+ cur = reinterpret_cast(value1); -+ end = cur + (value2 * kInstrSize); -+ } -+ } -+ -+ while (cur < end) { -+ dasm.InstructionDecode(buffer, cur); -+ PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast(cur), -+ buffer.begin()); -+ cur += kInstrSize; -+ } -+ } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { -+ PrintF("cont (alias 'c')\n"); -+ PrintF(" Continue execution\n"); -+ PrintF("stepi (alias 'si')\n"); -+ PrintF(" Step one instruction\n"); -+ PrintF("print (alias 'p')\n"); -+ PrintF(" print \n"); -+ PrintF(" Print register content\n"); -+ PrintF(" Use register name 'all' to print all GPRs\n"); -+ PrintF(" Use register name 'allf' to print all GPRs and FPRs\n"); -+ PrintF("printobject (alias 'po')\n"); -+ PrintF(" printobject \n"); -+ PrintF(" Print an object from a register\n"); -+ PrintF("stack\n"); -+ PrintF(" stack []\n"); -+ PrintF(" Dump stack content, default dump 10 words)\n"); -+ PrintF("mem\n"); -+ PrintF(" mem
[]\n"); -+ PrintF(" Dump memory content, default dump 10 words)\n"); -+ PrintF("flags\n"); -+ PrintF(" print flags\n"); -+ PrintF("disasm (alias 'di')\n"); -+ PrintF(" disasm []\n"); -+ PrintF(" disasm [
] (e.g., disasm pc) \n"); -+ PrintF(" disasm [[
] ]\n"); -+ PrintF(" Disassemble code, default is 10 instructions\n"); -+ PrintF(" from pc\n"); -+ PrintF("gdb \n"); -+ PrintF(" Return to gdb if the simulator was started with gdb\n"); -+ PrintF("break (alias 'b')\n"); -+ PrintF(" break : list all breakpoints\n"); -+ PrintF(" break
: set / enable / disable a breakpoint.\n"); -+ PrintF("tbreak\n"); -+ PrintF(" tbreak : list all breakpoints\n"); -+ PrintF(" tbreak
: set / enable / disable a temporary breakpoint.\n"); -+ PrintF(" Set a breakpoint enabled only for one stop. \n"); -+ PrintF("stop feature:\n"); -+ PrintF(" Description:\n"); -+ PrintF(" Stops are debug instructions inserted by\n"); -+ PrintF(" the Assembler::stop() function.\n"); -+ PrintF(" When hitting a stop, the Simulator will\n"); -+ PrintF(" stop and give control to the Debugger.\n"); -+ PrintF(" All stop codes are watched:\n"); -+ PrintF(" - They can be enabled / disabled: the Simulator\n"); -+ PrintF(" will / won't stop when hitting them.\n"); -+ PrintF(" - The Simulator keeps track of how many times they \n"); -+ PrintF(" are met. (See the info command.) Going over a\n"); -+ PrintF(" disabled stop still increases its counter. \n"); -+ PrintF(" Commands:\n"); -+ PrintF(" stop info all/ : print infos about number \n"); -+ PrintF(" or all stop(s).\n"); -+ PrintF(" stop enable/disable all/ : enables / disables\n"); -+ PrintF(" all or number stop(s)\n"); -+ } else { -+ PrintF("Unknown command: %s\n", cmd); -+ } -+ } -+ } -+ -+#undef COMMAND_SIZE -+#undef ARG_SIZE -+ -+#undef STR -+#undef XSTR -+} -+ -+void Simulator::SetBreakpoint(Instruction* location, bool is_tbreak) { -+ for (unsigned i = 0; i < breakpoints_.size(); i++) { -+ if (breakpoints_.at(i).location == location) { -+ if (breakpoints_.at(i).is_tbreak != is_tbreak) { -+ PrintF("Change breakpoint at %p to %s breakpoint\n", -+ reinterpret_cast(location), -+ is_tbreak ? "temporary" : "regular"); -+ breakpoints_.at(i).is_tbreak = is_tbreak; -+ return; -+ } -+ PrintF("Existing breakpoint at %p was %s\n", -+ reinterpret_cast(location), -+ breakpoints_.at(i).enabled ? "disabled" : "enabled"); -+ breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled; -+ return; -+ } -+ } -+ Breakpoint new_breakpoint = {location, true, is_tbreak}; -+ breakpoints_.push_back(new_breakpoint); -+ PrintF("Set a %sbreakpoint at %p\n", -+ is_tbreak ? "temporary " : "", -+ reinterpret_cast(location)); -+} -+ -+void Simulator::ListBreakpoints() { -+ PrintF("Breakpoints:\n"); -+ for (unsigned i = 0; i < breakpoints_.size(); i++) { -+ PrintF("%p : %s %s\n", -+ reinterpret_cast(breakpoints_.at(i).location), -+ breakpoints_.at(i).enabled ? "enabled" : "disabled", -+ breakpoints_.at(i).is_tbreak ? ": temporary" : ""); -+ } -+} -+ -+void Simulator::CheckBreakpoints() { -+ bool hit_a_breakpoint = false; -+ bool is_tbreak = false; -+ Instruction* pc_ = reinterpret_cast(get_pc()); -+ for (unsigned i = 0; i < breakpoints_.size(); i++) { -+ if ((breakpoints_.at(i).location == pc_) && breakpoints_.at(i).enabled) { -+ hit_a_breakpoint = true; -+ if (breakpoints_.at(i).is_tbreak) { -+ // Disable a temporary breakpoint. -+ is_tbreak = true; -+ breakpoints_.at(i).enabled = false; -+ } -+ break; -+ } -+ } -+ if (hit_a_breakpoint) { -+ PrintF("Hit %sa breakpoint at %p.\n", -+ is_tbreak ? "and disabled " : "", -+ reinterpret_cast(pc_)); -+ RiscvDebugger dbg(this); -+ dbg.Debug(); -+ } -+} -+ -+bool Simulator::ICacheMatch(void* one, void* two) { -+ DCHECK_EQ(reinterpret_cast(one) & CachePage::kPageMask, 0); -+ DCHECK_EQ(reinterpret_cast(two) & CachePage::kPageMask, 0); -+ return one == two; -+} -+ -+static uint32_t ICacheHash(void* key) { -+ return static_cast(reinterpret_cast(key)) >> 2; -+} -+ -+static bool AllOnOnePage(uintptr_t start, size_t size) { -+ intptr_t start_page = (start & ~CachePage::kPageMask); -+ intptr_t end_page = ((start + size) & ~CachePage::kPageMask); -+ return start_page == end_page; -+} -+ -+void Simulator::set_last_debugger_input(char* input) { -+ DeleteArray(last_debugger_input_); -+ last_debugger_input_ = input; -+} -+ -+void Simulator::SetRedirectInstruction(Instruction* instruction) { -+ instruction->SetInstructionBits(rtCallRedirInstr); -+} -+ -+void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache, -+ void* start_addr, size_t size) { -+ int64_t start = reinterpret_cast(start_addr); -+ int64_t intra_line = (start & CachePage::kLineMask); -+ start -= intra_line; -+ size += intra_line; -+ size = ((size - 1) | CachePage::kLineMask) + 1; -+ int offset = (start & CachePage::kPageMask); -+ while (!AllOnOnePage(start, size - 1)) { -+ int bytes_to_flush = CachePage::kPageSize - offset; -+ FlushOnePage(i_cache, start, bytes_to_flush); -+ start += bytes_to_flush; -+ size -= bytes_to_flush; -+ DCHECK_EQ((int64_t)0, start & CachePage::kPageMask); -+ offset = 0; -+ } -+ if (size != 0) { -+ FlushOnePage(i_cache, start, size); -+ } -+} -+ -+CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache, -+ void* page) { -+ base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page)); -+ if (entry->value == nullptr) { -+ CachePage* new_page = new CachePage(); -+ entry->value = new_page; -+ } -+ return reinterpret_cast(entry->value); -+} -+ -+// Flush from start up to and not including start + size. -+void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache, -+ intptr_t start, size_t size) { -+ DCHECK_LE(size, CachePage::kPageSize); -+ DCHECK(AllOnOnePage(start, size - 1)); -+ DCHECK_EQ(start & CachePage::kLineMask, 0); -+ DCHECK_EQ(size & CachePage::kLineMask, 0); -+ void* page = reinterpret_cast(start & (~CachePage::kPageMask)); -+ int offset = (start & CachePage::kPageMask); -+ CachePage* cache_page = GetCachePage(i_cache, page); -+ char* valid_bytemap = cache_page->ValidityByte(offset); -+ memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); -+} -+ -+void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache, -+ Instruction* instr) { -+ int64_t address = reinterpret_cast(instr); -+ void* page = reinterpret_cast(address & (~CachePage::kPageMask)); -+ void* line = reinterpret_cast(address & (~CachePage::kLineMask)); -+ int offset = (address & CachePage::kPageMask); -+ CachePage* cache_page = GetCachePage(i_cache, page); -+ char* cache_valid_byte = cache_page->ValidityByte(offset); -+ bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); -+ char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask); -+ if (cache_hit) { -+ // Check that the data in memory matches the contents of the I-cache. -+ CHECK_EQ(0, memcmp(reinterpret_cast(instr), -+ cache_page->CachedData(offset), kInstrSize)); -+ } else { -+ // Cache miss. Load memory into the cache. -+ memcpy(cached_line, line, CachePage::kLineLength); -+ *cache_valid_byte = CachePage::LINE_VALID; -+ } -+} -+ -+Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { -+ // Set up simulator support first. Some of this information is needed to -+ // setup the architecture state. -+ stack_size_ = FLAG_sim_stack_size * KB; -+ stack_ = reinterpret_cast(malloc(stack_size_)); -+ pc_modified_ = false; -+ icount_ = 0; -+ break_count_ = 0; -+ // Reset debug helpers. -+ breakpoints_.clear(); -+ // TODO: 'next' command -+ //break_on_next_ = false; -+ -+ // Set up architecture state. -+ // All registers are initialized to zero to start with. -+ for (int i = 0; i < kNumSimuRegisters; i++) { -+ registers_[i] = 0; -+ } -+ -+ for (int i = 0; i < kNumFPURegisters; i++) { -+ FPUregisters_[i] = 0; -+ } -+ -+ FCSR_ = 0; -+ -+ // The sp is initialized to point to the bottom (high address) of the -+ // allocated stack area. To be safe in potential stack underflows we leave -+ // some buffer below. -+ registers_[sp] = reinterpret_cast(stack_) + stack_size_ - 64; -+ // The ra and pc are initialized to a known bad value that will cause an -+ // access violation if the simulator ever tries to execute it. -+ registers_[pc] = bad_ra; -+ registers_[ra] = bad_ra; -+ -+ last_debugger_input_ = nullptr; -+} -+ -+Simulator::~Simulator() { -+ GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_); -+ free(stack_); -+} -+ -+// Get the active Simulator for the current thread. -+Simulator* Simulator::current(Isolate* isolate) { -+ v8::internal::Isolate::PerIsolateThreadData* isolate_data = -+ isolate->FindOrAllocatePerThreadDataForThisThread(); -+ DCHECK_NOT_NULL(isolate_data); -+ -+ Simulator* sim = isolate_data->simulator(); -+ if (sim == nullptr) { -+ // TODO(146): delete the simulator object when a thread/isolate goes away. -+ sim = new Simulator(isolate); -+ isolate_data->set_simulator(sim); -+ } -+ return sim; -+} -+ -+// Sets the register in the architecture state. It will also deal with -+// updating Simulator internal state for special registers such as PC. -+void Simulator::set_register(int reg, int64_t value) { -+ DCHECK((reg >= 0) && (reg < kNumSimuRegisters)); -+ if (reg == pc) { -+ pc_modified_ = true; -+ } -+ -+ // Zero register always holds 0. -+ registers_[reg] = (reg == 0) ? 0 : value; -+} -+ -+void Simulator::set_dw_register(int reg, const int* dbl) { -+ DCHECK((reg >= 0) && (reg < kNumSimuRegisters)); -+ registers_[reg] = dbl[1]; -+ registers_[reg] = registers_[reg] << 32; -+ registers_[reg] += dbl[0]; -+} -+ -+void Simulator::set_fpu_register(int fpureg, int64_t value) { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ FPUregisters_[fpureg] = value; -+} -+ -+void Simulator::set_fpu_register_word(int fpureg, int32_t value) { -+ // Set ONLY lower 32-bits, leaving upper bits untouched. -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ int32_t* pword; -+ if (kArchEndian == kLittle) { -+ pword = reinterpret_cast(&FPUregisters_[fpureg]); -+ } else { -+ pword = reinterpret_cast(&FPUregisters_[fpureg]) + 1; -+ } -+ *pword = value; -+} -+ -+void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) { -+ // Set ONLY upper 32-bits, leaving lower bits untouched. -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ int32_t* phiword; -+ if (kArchEndian == kLittle) { -+ phiword = (reinterpret_cast(&FPUregisters_[fpureg])) + 1; -+ } else { -+ phiword = reinterpret_cast(&FPUregisters_[fpureg]); -+ } -+ *phiword = value; -+} -+ -+void Simulator::set_fpu_register_float(int fpureg, float value) { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ FPUregisters_[fpureg] = box_float(value); -+} -+ -+void Simulator::set_fpu_register_double(int fpureg, double value) { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ *bit_cast(&FPUregisters_[fpureg]) = value; -+} -+ -+// Get the register from the architecture state. This function does handle -+// the special case of accessing the PC register. -+int64_t Simulator::get_register(int reg) const { -+ DCHECK((reg >= 0) && (reg < kNumSimuRegisters)); -+ if (reg == 0) -+ return 0; -+ else -+ return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0); -+} -+ -+double Simulator::get_double_from_register_pair(int reg) { -+ // TODO(plind): bad ABI stuff, refactor or remove. -+ DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0)); -+ -+ double dm_val = 0.0; -+ // Read the bits from the unsigned integer register_[] array -+ // into the double precision floating point value and return it. -+ char buffer[sizeof(registers_[0])]; -+ memcpy(buffer, ®isters_[reg], sizeof(registers_[0])); -+ memcpy(&dm_val, buffer, sizeof(registers_[0])); -+ return (dm_val); -+} -+ -+int64_t Simulator::get_fpu_register(int fpureg) const { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ return FPUregisters_[fpureg]; -+} -+ -+int32_t Simulator::get_fpu_register_word(int fpureg) const { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ return static_cast(FPUregisters_[fpureg] & 0xFFFFFFFF); -+} -+ -+int32_t Simulator::get_fpu_register_signed_word(int fpureg) const { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ return static_cast(FPUregisters_[fpureg] & 0xFFFFFFFF); -+} -+ -+int32_t Simulator::get_fpu_register_hi_word(int fpureg) const { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ return static_cast((FPUregisters_[fpureg] >> 32) & 0xFFFFFFFF); -+} -+ -+float Simulator::get_fpu_register_float(int fpureg) const { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ if (!is_boxed_float(FPUregisters_[fpureg])) { -+ return std::numeric_limits::quiet_NaN(); -+ } -+ return *bit_cast(const_cast(&FPUregisters_[fpureg])); -+} -+ -+double Simulator::get_fpu_register_double(int fpureg) const { -+ DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters)); -+ return *bit_cast(&FPUregisters_[fpureg]); -+} -+ -+// Runtime FP routines take up to two double arguments and zero -+// or one integer arguments. All are constructed here, -+// from fa0, fa1, and a0. -+void Simulator::GetFpArgs(double* x, double* y, int32_t* z) { -+ *x = get_fpu_register_double(fa0); -+ *y = get_fpu_register_double(fa1); -+ *z = static_cast(get_register(a0)); -+} -+ -+// The return value is in fa0. -+void Simulator::SetFpResult(const double& result) { -+ set_fpu_register_double(fa0, result); -+} -+ -+// helper functions to read/write/set/clear CRC values/bits -+uint32_t Simulator::read_csr_value(uint32_t csr) { -+ switch (csr) { -+ case csr_fflags: // Floating-Point Accrued Exceptions (RW) -+ return (FCSR_ & kFcsrFlagsMask); -+ case csr_frm: // Floating-Point Dynamic Rounding Mode (RW) -+ return (FCSR_ & kFcsrFrmMask) >> kFcsrFrmShift; -+ case csr_fcsr: // Floating-Point Control and Status Register (RW) -+ return (FCSR_ & kFcsrMask); -+ default: -+ UNIMPLEMENTED(); -+ } -+} -+ -+uint32_t Simulator::get_dynamic_rounding_mode() { -+ return read_csr_value(csr_frm); -+} -+ -+void Simulator::write_csr_value(uint32_t csr, uint64_t val) { -+ uint32_t value = (uint32_t)val; -+ switch (csr) { -+ case csr_fflags: // Floating-Point Accrued Exceptions (RW) -+ DCHECK(value <= ((1 << kFcsrFlagsBits) - 1)); -+ FCSR_ = (FCSR_ & (~kFcsrFlagsMask)) | value; -+ break; -+ case csr_frm: // Floating-Point Dynamic Rounding Mode (RW) -+ DCHECK(value <= ((1 << kFcsrFrmBits) - 1)); -+ FCSR_ = (FCSR_ & (~kFcsrFrmMask)) | (value << kFcsrFrmShift); -+ break; -+ case csr_fcsr: // Floating-Point Control and Status Register (RW) -+ DCHECK(value <= ((1 << kFcsrBits) - 1)); -+ FCSR_ = (FCSR_ & (~kFcsrMask)) | value; -+ break; -+ default: -+ UNIMPLEMENTED(); -+ } -+} -+ -+void Simulator::set_csr_bits(uint32_t csr, uint64_t val) { -+ uint32_t value = (uint32_t)val; -+ switch (csr) { -+ case csr_fflags: // Floating-Point Accrued Exceptions (RW) -+ DCHECK(value <= ((1 << kFcsrFlagsBits) - 1)); -+ FCSR_ = FCSR_ | value; -+ break; -+ case csr_frm: // Floating-Point Dynamic Rounding Mode (RW) -+ DCHECK(value <= ((1 << kFcsrFrmBits) - 1)); -+ FCSR_ = FCSR_ | (value << kFcsrFrmShift); -+ break; -+ case csr_fcsr: // Floating-Point Control and Status Register (RW) -+ DCHECK(value <= ((1 << kFcsrBits) - 1)); -+ FCSR_ = FCSR_ | value; -+ break; -+ default: -+ UNIMPLEMENTED(); -+ } -+} -+ -+void Simulator::clear_csr_bits(uint32_t csr, uint64_t val) { -+ uint32_t value = (uint32_t)val; -+ switch (csr) { -+ case csr_fflags: // Floating-Point Accrued Exceptions (RW) -+ DCHECK(value <= ((1 << kFcsrFlagsBits) - 1)); -+ FCSR_ = FCSR_ & (~value); -+ break; -+ case csr_frm: // Floating-Point Dynamic Rounding Mode (RW) -+ DCHECK(value <= ((1 << kFcsrFrmBits) - 1)); -+ FCSR_ = FCSR_ & (~(value << kFcsrFrmShift)); -+ break; -+ case csr_fcsr: // Floating-Point Control and Status Register (RW) -+ DCHECK(value <= ((1 << kFcsrBits) - 1)); -+ FCSR_ = FCSR_ & (~value); -+ break; -+ default: -+ UNIMPLEMENTED(); -+ } -+} -+ -+bool Simulator::test_fflags_bits(uint32_t mask) { -+ return (FCSR_ & kFcsrFlagsMask & mask) != 0; -+} -+ -+template -+T Simulator::FMaxMinHelper(T a, T b, MaxMinKind kind) { -+ // set invalid bit for signaling nan -+ if ((a == std::numeric_limits::signaling_NaN()) || -+ (b == std::numeric_limits::signaling_NaN())) { -+ // FIXME: NV -> kInvalidOperation -+ set_csr_bits(csr_fflags, kInvalidOperation); -+ } -+ -+ T result = 0; -+ if (std::isnan(a) && std::isnan(b)) { -+ result = a; -+ } else if (std::isnan(a)) { -+ result = b; -+ } else if (std::isnan(b)) { -+ result = a; -+ } else if (b == a) { // Handle -0.0 == 0.0 case. -+ if (kind == MaxMinKind::kMax) { -+ result = std::signbit(b) ? a : b; -+ } else { -+ result = std::signbit(b) ? b : a; -+ } -+ } else { -+ result = (kind == MaxMinKind::kMax) ? fmax(a, b) : fmin(a, b); -+ } -+ -+ return result; -+} -+ -+// Raw access to the PC register. -+void Simulator::set_pc(int64_t value) { -+ pc_modified_ = true; -+ registers_[pc] = value; -+ DCHECK(has_bad_pc() || ((value % kInstrSize) == 0)); -+} -+ -+bool Simulator::has_bad_pc() const { -+ return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc)); -+} -+ -+// Raw access to the PC register without the special adjustment when reading. -+int64_t Simulator::get_pc() const { return registers_[pc]; } -+ -+// The RISC-V spec leaves it open to the implementation on how to handle -+// unaligned reads and writes. For now, we simply disallow unaligned reads but -+// at some point, we may want to implement some other behavior. -+ -+// TODO(plind): refactor this messy debug code when we do unaligned access. -+void Simulator::DieOrDebug() { -+ if ((1)) { // Flag for this was removed. -+ RiscvDebugger dbg(this); -+ dbg.Debug(); -+ } else { -+ base::OS::Abort(); -+ } -+} -+ -+void Simulator::TraceRegWr(int64_t value, TraceType t) { -+ if (::v8::internal::FLAG_trace_sim) { -+ union { -+ int64_t fmt_int64; -+ int32_t fmt_int32[2]; -+ float fmt_float[2]; -+ double fmt_double; -+ } v; -+ v.fmt_int64 = value; -+ -+ switch (t) { -+ case WORD: -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") int32:%" PRId32 -+ " uint32:%" PRIu32, -+ v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]); -+ break; -+ case DWORD: -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") int64:%" PRId64 -+ " uint64:%" PRIu64, -+ value, icount_, value, value); -+ break; -+ case FLOAT: -+ SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") flt:%e", -+ v.fmt_int64, icount_, v.fmt_float[0]); -+ break; -+ case DOUBLE: -+ SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e", -+ v.fmt_int64, icount_, v.fmt_double); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+} -+ -+// TODO(plind): consider making icount_ printing a flag option. -+template -+void Simulator::TraceMemRd(int64_t addr, T value, int64_t reg_value) { -+ if (::v8::internal::FLAG_trace_sim) { -+ if (std::is_integral::value) { -+ switch (sizeof(T)) { -+ case 1: -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") int8:%" PRId8 -+ " uint8:%" PRIu8 " <-- [addr: %" PRIx64 "]", -+ reg_value, icount_, static_cast(value), -+ static_cast(value), addr); -+ break; -+ case 2: -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") int16:%" PRId16 -+ " uint16:%" PRIu16 " <-- [addr: %" PRIx64 "]", -+ reg_value, icount_, static_cast(value), -+ static_cast(value), addr); -+ break; -+ case 4: -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") int32:%" PRId32 -+ " uint32:%" PRIu32 " <-- [addr: %" PRIx64 "]", -+ reg_value, icount_, static_cast(value), -+ static_cast(value), addr); -+ break; -+ case 8: -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") int64:%" PRId64 -+ " uint64:%" PRIu64 " <-- [addr: %" PRIx64 "]", -+ reg_value, icount_, static_cast(value), -+ static_cast(value), addr); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } else if (std::is_same::value) { -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") flt:%e <-- [addr: %" PRIx64 -+ "]", -+ reg_value, icount_, static_cast(value), addr); -+ } else if (std::is_same::value) { -+ SNPrintF(trace_buf_, -+ "%016" PRIx64 " (%" PRId64 ") dbl:%e <-- [addr: %" PRIx64 -+ "]", -+ reg_value, icount_, static_cast(value), addr); -+ } else { -+ UNREACHABLE(); -+ } -+ } -+} -+ -+template -+void Simulator::TraceMemWr(int64_t addr, T value) { -+ if (::v8::internal::FLAG_trace_sim) { -+ switch (sizeof(T)) { -+ case 1: -+ SNPrintF(trace_buf_, -+ " (%" PRIu64 ") int8:%" PRId8 -+ " uint8:%" PRIu8 " --> [addr: %" PRIx64 "]", -+ icount_, static_cast(value), -+ static_cast(value), addr); -+ break; -+ case 2: -+ SNPrintF(trace_buf_, -+ " (%" PRIu64 ") int16:%" PRId16 -+ " uint16:%" PRIu16 " --> [addr: %" PRIx64 "]", -+ icount_, static_cast(value), -+ static_cast(value), addr); -+ break; -+ case 4: -+ if (std::is_integral::value) { -+ SNPrintF(trace_buf_, -+ " (%" PRIu64 ") int32:%" PRId32 -+ " uint32:%" PRIu32 " --> [addr: %" PRIx64 "]", -+ icount_, static_cast(value), -+ static_cast(value), addr); -+ } else { -+ SNPrintF(trace_buf_, -+ " (%" PRIu64 -+ ") flt:%e --> [addr: %" PRIx64 "]", -+ icount_, static_cast(value), addr); -+ } -+ break; -+ case 8: -+ if (std::is_integral::value) { -+ SNPrintF(trace_buf_, -+ " (%" PRIu64 ") int64:%" PRId64 -+ " uint64:%" PRIu64 " --> [addr: %" PRIx64 "]", -+ icount_, static_cast(value), -+ static_cast(value), addr); -+ } else { -+ SNPrintF(trace_buf_, -+ " (%" PRIu64 -+ ") dbl:%e --> [addr: %" PRIx64 "]", -+ icount_, static_cast(value), addr); -+ } -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+} -+ -+// RISCV Memory Read/Write functions -+ -+// FIXME (RISCV): check whether the specific board supports unaligned load/store -+// (determined by EEI). For now, we assume the board does not support unaligned -+// load/store (e.g., trapping) -+template -+T Simulator::ReadMem(int64_t addr, Instruction* instr) { -+ if (addr >= 0 && addr < 0x400) { -+ // This has to be a nullptr-dereference, drop into debugger. -+ PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR -+ " \n", -+ addr, reinterpret_cast(instr)); -+ DieOrDebug(); -+ } -+ -+ // check for natural alignment -+ if ((addr & (sizeof(T) - 1)) != 0) { -+ PrintF("Unaligned read at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr, -+ reinterpret_cast(instr)); -+ DieOrDebug(); -+ } -+ -+ T* ptr = reinterpret_cast(addr); -+ T value = *ptr; -+ return value; -+} -+ -+template -+void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) { -+ if (addr >= 0 && addr < 0x400) { -+ // This has to be a nullptr-dereference, drop into debugger. -+ PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR -+ " \n", -+ addr, reinterpret_cast(instr)); -+ DieOrDebug(); -+ } -+ -+ // check for natural alignment -+ if ((addr & (sizeof(T) - 1)) != 0) { -+ PrintF("Unaligned write at 0x%08" PRIx64 " , pc=0x%08" V8PRIxPTR "\n", addr, -+ reinterpret_cast(instr)); -+ DieOrDebug(); -+ } -+ -+ T* ptr = reinterpret_cast(addr); -+ TraceMemWr(addr, value); -+ *ptr = value; -+} -+ -+// Returns the limit of the stack area to enable checking for stack overflows. -+uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { -+ // The simulator uses a separate JS stack. If we have exhausted the C stack, -+ // we also drop down the JS limit to reflect the exhaustion on the JS stack. -+ if (GetCurrentStackPosition() < c_limit) { -+ return reinterpret_cast(get_sp()); -+ } -+ -+ // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes -+ // to prevent overrunning the stack when pushing values. -+ return reinterpret_cast(stack_) + 1024; -+} -+ -+// Unsupported instructions use Format to print an error and stop execution. -+void Simulator::Format(Instruction* instr, const char* format) { -+ PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR " : %s\n", -+ reinterpret_cast(instr), format); -+ UNIMPLEMENTED_RISCV(); -+} -+ -+// Calls into the V8 runtime are based on this very simple interface. -+// Note: To be able to return two values from some calls the code in -+// runtime.cc uses the ObjectPair which is essentially two 32-bit values -+// stuffed into a 64-bit value. With the code below we assume that all runtime -+// calls return 64 bits of result. If they don't, the a1 result register -+// contains a bogus value, which is fine because it is caller-saved. -+ -+using SimulatorRuntimeCall = ObjectPair (*)(int64_t arg0, int64_t arg1, -+ int64_t arg2, int64_t arg3, -+ int64_t arg4, int64_t arg5, -+ int64_t arg6, int64_t arg7, -+ int64_t arg8, int64_t arg9); -+ -+// These prototypes handle the four types of FP calls. -+using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1); -+using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1); -+using SimulatorRuntimeFPCall = double (*)(double darg0); -+using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0); -+ -+// This signature supports direct call in to API function native callback -+// (refer to InvocationCallback in v8.h). -+using SimulatorRuntimeDirectApiCall = void (*)(int64_t arg0); -+using SimulatorRuntimeProfilingApiCall = void (*)(int64_t arg0, void* arg1); -+ -+// This signature supports direct call to accessor getter callback. -+using SimulatorRuntimeDirectGetterCall = void (*)(int64_t arg0, int64_t arg1); -+using SimulatorRuntimeProfilingGetterCall = void (*)(int64_t arg0, int64_t arg1, -+ void* arg2); -+ -+// Software interrupt instructions are used by the simulator to call into the -+// C-based V8 runtime. They are also used for debugging with simulator. -+void Simulator::SoftwareInterrupt() { -+ // There are two instructions that could get us here, the ebreak or ecall -+ // instructions are "SYSTEM" class opcode distinuished by Imm12Value field w/ -+ // the rest of instruction fields being zero -+ int32_t func = instr_.Imm12Value(); -+ // We first check if we met a call_rt_redirected. -+ if (instr_.InstructionBits() == rtCallRedirInstr) { // ECALL -+ Redirection* redirection = Redirection::FromInstruction(instr_.instr()); -+ -+ int64_t* stack_pointer = reinterpret_cast(get_register(sp)); -+ -+ int64_t arg0 = get_register(a0); -+ int64_t arg1 = get_register(a1); -+ int64_t arg2 = get_register(a2); -+ int64_t arg3 = get_register(a3); -+ int64_t arg4 = get_register(a4); -+ int64_t arg5 = get_register(a5); -+ int64_t arg6 = get_register(a6); -+ int64_t arg7 = get_register(a7); -+ int64_t arg8 = stack_pointer[0]; -+ int64_t arg9 = stack_pointer[1]; -+ STATIC_ASSERT(kMaxCParameters == 10); -+ -+ bool fp_call = -+ (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || -+ (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) || -+ (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || -+ (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); -+ -+ // This is dodgy but it works because the C entry stubs are never moved. -+ // See comment in codegen-arm.cc and bug 1242173. -+ int64_t saved_ra = get_register(ra); -+ -+ intptr_t external = -+ reinterpret_cast(redirection->external_function()); -+ -+ if (fp_call) { -+ double dval0, dval1; // one or two double parameters -+ int32_t ival; // zero or one integer parameters -+ int64_t iresult = 0; // integer return value -+ double dresult = 0; // double return value -+ GetFpArgs(&dval0, &dval1, &ival); -+ SimulatorRuntimeCall generic_target = -+ reinterpret_cast(external); -+ if (::v8::internal::FLAG_trace_sim) { -+ switch (redirection->type()) { -+ case ExternalReference::BUILTIN_FP_FP_CALL: -+ case ExternalReference::BUILTIN_COMPARE_CALL: -+ PrintF("Call to host function at %p with args %f, %f", -+ reinterpret_cast(FUNCTION_ADDR(generic_target)), -+ dval0, dval1); -+ break; -+ case ExternalReference::BUILTIN_FP_CALL: -+ PrintF("Call to host function at %p with arg %f", -+ reinterpret_cast(FUNCTION_ADDR(generic_target)), -+ dval0); -+ break; -+ case ExternalReference::BUILTIN_FP_INT_CALL: -+ PrintF("Call to host function at %p with args %f, %d", -+ reinterpret_cast(FUNCTION_ADDR(generic_target)), -+ dval0, ival); -+ break; -+ default: -+ UNREACHABLE(); -+ break; -+ } -+ } -+ switch (redirection->type()) { -+ case ExternalReference::BUILTIN_COMPARE_CALL: { -+ SimulatorRuntimeCompareCall target = -+ reinterpret_cast(external); -+ iresult = target(dval0, dval1); -+ set_register(a0, static_cast(iresult)); -+ // set_register(a1, static_cast(iresult >> 32)); -+ break; -+ } -+ case ExternalReference::BUILTIN_FP_FP_CALL: { -+ SimulatorRuntimeFPFPCall target = -+ reinterpret_cast(external); -+ dresult = target(dval0, dval1); -+ SetFpResult(dresult); -+ break; -+ } -+ case ExternalReference::BUILTIN_FP_CALL: { -+ SimulatorRuntimeFPCall target = -+ reinterpret_cast(external); -+ dresult = target(dval0); -+ SetFpResult(dresult); -+ break; -+ } -+ case ExternalReference::BUILTIN_FP_INT_CALL: { -+ SimulatorRuntimeFPIntCall target = -+ reinterpret_cast(external); -+ dresult = target(dval0, ival); -+ SetFpResult(dresult); -+ break; -+ } -+ default: -+ UNREACHABLE(); -+ break; -+ } -+ if (::v8::internal::FLAG_trace_sim) { -+ switch (redirection->type()) { -+ case ExternalReference::BUILTIN_COMPARE_CALL: -+ PrintF("Returned %08x\n", static_cast(iresult)); -+ break; -+ case ExternalReference::BUILTIN_FP_FP_CALL: -+ case ExternalReference::BUILTIN_FP_CALL: -+ case ExternalReference::BUILTIN_FP_INT_CALL: -+ PrintF("Returned %f\n", dresult); -+ break; -+ default: -+ UNREACHABLE(); -+ break; -+ } -+ } -+ } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF("Call to host function at %p args %08" PRIx64 " \n", -+ reinterpret_cast(external), arg0); -+ } -+ SimulatorRuntimeDirectApiCall target = -+ reinterpret_cast(external); -+ target(arg0); -+ } else if (redirection->type() == ExternalReference::PROFILING_API_CALL) { -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64 -+ " \n", -+ reinterpret_cast(external), arg0, arg1); -+ } -+ SimulatorRuntimeProfilingApiCall target = -+ reinterpret_cast(external); -+ target(arg0, Redirection::ReverseRedirection(arg1)); -+ } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64 -+ " \n", -+ reinterpret_cast(external), arg0, arg1); -+ } -+ SimulatorRuntimeDirectGetterCall target = -+ reinterpret_cast(external); -+ target(arg0, arg1); -+ } else if (redirection->type() == -+ ExternalReference::PROFILING_GETTER_CALL) { -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF("Call to host function at %p args %08" PRIx64 " %08" PRIx64 -+ " %08" PRIx64 " \n", -+ reinterpret_cast(external), arg0, arg1, arg2); -+ } -+ SimulatorRuntimeProfilingGetterCall target = -+ reinterpret_cast(external); -+ target(arg0, arg1, Redirection::ReverseRedirection(arg2)); -+ } else { -+ DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL || -+ redirection->type() == ExternalReference::BUILTIN_CALL_PAIR); -+ SimulatorRuntimeCall target = -+ reinterpret_cast(external); -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF( -+ "Call to host function at %p " -+ "args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 -+ " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 -+ " , %08" PRIx64 " , %08" PRIx64 " \n", -+ reinterpret_cast(FUNCTION_ADDR(target)), arg0, arg1, arg2, -+ arg3, arg4, arg5, arg6, arg7, arg8, arg9); -+ } -+ ObjectPair result = -+ target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); -+ set_register(a0, (int64_t)(result.x)); -+ set_register(a1, (int64_t)(result.y)); -+ } -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF("Returned %08" PRIx64 " : %08" PRIx64 " \n", get_register(a1), -+ get_register(a0)); -+ } -+ set_register(ra, saved_ra); -+ set_pc(get_register(ra)); -+ -+ } else if (func == 1) { // EBREAK -+ int32_t code = get_ebreak_code(instr_.instr()); -+ set_pc(get_pc() + kInstrSize * 2); -+ if (code != -1 && static_cast(code) <= kMaxStopCode) { -+ if (IsWatchpoint(code)) { -+ PrintWatchpoint(code); -+ } else { -+ IncreaseStopCounter(code); -+ HandleStop(code); -+ } -+ } else { -+ // All remaining break_ codes, and all traps are handled here. -+ RiscvDebugger dbg(this); -+ dbg.Debug(); -+ } -+ } else { -+ UNREACHABLE(); -+ } -+} -+ -+// Stop helper functions. -+bool Simulator::IsWatchpoint(uint64_t code) { -+ return (code <= kMaxWatchpointCode); -+} -+ -+void Simulator::PrintWatchpoint(uint64_t code) { -+ RiscvDebugger dbg(this); -+ ++break_count_; -+ PrintF("\n---- watchpoint %" PRId64 " marker: %3d (instr count: %8" PRId64 -+ " ) ----------" -+ "----------------------------------", -+ code, break_count_, icount_); -+ dbg.PrintAllRegs(); // Print registers and continue running. -+} -+ -+void Simulator::HandleStop(uint64_t code) { -+ // Stop if it is enabled, otherwise go on jumping over the stop -+ // and the message address. -+ if (IsEnabledStop(code)) { -+ RiscvDebugger dbg(this); -+ PrintF("Simulator hit stop (%" PRId64 ")\n", code); -+ dbg.Debug(); -+ } -+} -+ -+bool Simulator::IsStopInstruction(Instruction* instr) { -+ if (instr->InstructionBits() != kBreakInstr) return false; -+ int32_t code = get_ebreak_code(instr); -+ return code != -1 && static_cast(code) > kMaxWatchpointCode && -+ static_cast(code) <= kMaxStopCode; -+} -+ -+bool Simulator::IsEnabledStop(uint64_t code) { -+ DCHECK_LE(code, kMaxStopCode); -+ DCHECK_GT(code, kMaxWatchpointCode); -+ return !(watched_stops_[code].count & kStopDisabledBit); -+} -+ -+void Simulator::EnableStop(uint64_t code) { -+ if (!IsEnabledStop(code)) { -+ watched_stops_[code].count &= ~kStopDisabledBit; -+ } -+} -+ -+void Simulator::DisableStop(uint64_t code) { -+ if (IsEnabledStop(code)) { -+ watched_stops_[code].count |= kStopDisabledBit; -+ } -+} -+ -+void Simulator::IncreaseStopCounter(uint64_t code) { -+ DCHECK_LE(code, kMaxStopCode); -+ if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) { -+ PrintF("Stop counter for code %" PRId64 -+ " has overflowed.\n" -+ "Enabling this code and reseting the counter to 0.\n", -+ code); -+ watched_stops_[code].count = 0; -+ EnableStop(code); -+ } else { -+ watched_stops_[code].count++; -+ } -+} -+ -+// Print a stop status. -+void Simulator::PrintStopInfo(uint64_t code) { -+ if (code <= kMaxWatchpointCode) { -+ PrintF("That is a watchpoint, not a stop.\n"); -+ return; -+ } else if (code > kMaxStopCode) { -+ PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1); -+ return; -+ } -+ const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled"; -+ int32_t count = watched_stops_[code].count & ~kStopDisabledBit; -+ // Don't print the state of unused breakpoints. -+ if (count != 0) { -+ if (watched_stops_[code].desc) { -+ PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i, \t%s\n", -+ code, code, state, count, watched_stops_[code].desc); -+ } else { -+ PrintF("stop %" PRId64 " - 0x%" PRIx64 " : \t%s, \tcounter = %i\n", code, -+ code, state, count); -+ } -+ } -+} -+ -+void Simulator::SignalException(Exception e) { -+ FATAL("Error: Exception %i raised.", static_cast(e)); -+} -+ -+// RISCV Instruction Decode Routine -+void Simulator::DecodeRVRType() { -+ switch (instr_.InstructionBits() & kRTypeMask) { -+ case RO_ADD: { -+ set_rd(sext_xlen(rs1() + rs2())); -+ break; -+ } -+ case RO_SUB: { -+ set_rd(sext_xlen(rs1() - rs2())); -+ break; -+ } -+ case RO_SLL: { -+ set_rd(sext_xlen(rs1() << (rs2() & (xlen - 1)))); -+ break; -+ } -+ case RO_SLT: { -+ set_rd(sreg_t(rs1()) < sreg_t(rs2())); -+ break; -+ } -+ case RO_SLTU: { -+ set_rd(reg_t(rs1()) < reg_t(rs2())); -+ break; -+ } -+ case RO_XOR: { -+ set_rd(rs1() ^ rs2()); -+ break; -+ } -+ case RO_SRL: { -+ set_rd(sext_xlen(zext_xlen(rs1()) >> (rs2() & (xlen - 1)))); -+ break; -+ } -+ case RO_SRA: { -+ set_rd(sext_xlen(sext_xlen(rs1()) >> (rs2() & (xlen - 1)))); -+ break; -+ } -+ case RO_OR: { -+ set_rd(rs1() | rs2()); -+ break; -+ } -+ case RO_AND: { -+ set_rd(rs1() & rs2()); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_ADDW: { -+ set_rd(sext32(rs1() + rs2())); -+ break; -+ } -+ case RO_SUBW: { -+ set_rd(sext32(rs1() - rs2())); -+ break; -+ } -+ case RO_SLLW: { -+ set_rd(sext32(rs1() << (rs2() & 0x1F))); -+ break; -+ } -+ case RO_SRLW: { -+ set_rd(sext32(uint32_t(rs1()) >> (rs2() & 0x1F))); -+ break; -+ } -+ case RO_SRAW: { -+ set_rd(sext32(int32_t(rs1()) >> (rs2() & 0x1F))); -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ // TODO: Add RISCV M extension macro -+ case RO_MUL: { -+ set_rd(rs1() * rs2()); -+ break; -+ } -+ case RO_MULH: { -+ set_rd(mulh(rs1(), rs2())); -+ break; -+ } -+ case RO_MULHSU: { -+ set_rd(mulhsu(rs1(), rs2())); -+ break; -+ } -+ case RO_MULHU: { -+ set_rd(mulhu(rs1(), rs2())); -+ break; -+ } -+ case RO_DIV: { -+ sreg_t lhs = sext_xlen(rs1()); -+ sreg_t rhs = sext_xlen(rs2()); -+ if (rhs == 0) { -+ set_rd(-1); -+ } else if (lhs == INT64_MIN && rhs == -1) { -+ set_rd(lhs); -+ } else { -+ set_rd(sext_xlen(lhs / rhs)); -+ } -+ break; -+ } -+ case RO_DIVU: { -+ reg_t lhs = zext_xlen(rs1()); -+ reg_t rhs = zext_xlen(rs2()); -+ if (rhs == 0) { -+ set_rd(UINT64_MAX); -+ } else { -+ set_rd(zext_xlen(lhs / rhs)); -+ } -+ break; -+ } -+ case RO_REM: { -+ sreg_t lhs = sext_xlen(rs1()); -+ sreg_t rhs = sext_xlen(rs2()); -+ if (rhs == 0) { -+ set_rd(lhs); -+ } else if (lhs == INT64_MIN && rhs == -1) { -+ set_rd(0); -+ } else { -+ set_rd(sext_xlen(lhs % rhs)); -+ } -+ break; -+ } -+ case RO_REMU: { -+ reg_t lhs = zext_xlen(rs1()); -+ reg_t rhs = zext_xlen(rs2()); -+ if (rhs == 0) { -+ set_rd(lhs); -+ } else { -+ set_rd(zext_xlen(lhs % rhs)); -+ } -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_MULW: { -+ set_rd(sext32(sext32(rs1()) * sext32(rs2()))); -+ break; -+ } -+ case RO_DIVW: { -+ sreg_t lhs = sext32(rs1()); -+ sreg_t rhs = sext32(rs2()); -+ if (rhs == 0) { -+ set_rd(-1); -+ } else if (lhs == INT32_MIN && rhs == -1) { -+ set_rd(lhs); -+ } else { -+ set_rd(sext32(lhs / rhs)); -+ } -+ break; -+ } -+ case RO_DIVUW: { -+ reg_t lhs = zext32(rs1()); -+ reg_t rhs = zext32(rs2()); -+ if (rhs == 0) { -+ set_rd(UINT32_MAX); -+ } else { -+ set_rd(zext32(lhs / rhs)); -+ } -+ break; -+ } -+ case RO_REMW: { -+ sreg_t lhs = sext32(rs1()); -+ sreg_t rhs = sext32(rs2()); -+ if (rhs == 0) { -+ set_rd(lhs); -+ } else if (lhs == INT32_MIN && rhs == -1) { -+ set_rd(0); -+ } else { -+ set_rd(sext32(lhs % rhs)); -+ } -+ break; -+ } -+ case RO_REMUW: { -+ reg_t lhs = zext32(rs1()); -+ reg_t rhs = zext32(rs2()); -+ if (rhs == 0) { -+ set_rd(zext32(lhs)); -+ } else { -+ set_rd(zext32(lhs % rhs)); -+ } -+ break; -+ } -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ // TODO: End Add RISCV M extension macro -+ default: { -+ switch (instr_.BaseOpcode()) { -+ case AMO: -+ DecodeRVRAType(); -+ break; -+ case OP_FP: -+ DecodeRVRFPType(); -+ break; -+ default: -+ UNSUPPORTED(); -+ } -+ } -+ } -+} -+ -+float Simulator::RoundF2FHelper(float input_val, int rmode) { -+ if (rmode == DYN) rmode = get_dynamic_rounding_mode(); -+ -+ float rounded = 0; -+ switch (rmode) { -+ case RNE: { // Round to Nearest, tiest to Even -+ int curr_mode = fegetround(); -+ fesetround(FE_TONEAREST); -+ rounded = std::nearbyintf(input_val); -+ fesetround(curr_mode); -+ break; -+ } -+ case RTZ: // Round towards Zero -+ rounded = std::truncf(input_val); -+ break; -+ case RDN: // Round Down (towards -infinity) -+ rounded = floorf(input_val); -+ break; -+ case RUP: // Round Up (towards +infinity) -+ rounded = ceilf(input_val); -+ break; -+ case RMM: // Round to Nearest, tiest to Max Magnitude -+ rounded = std::roundf(input_val); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+ return rounded; -+} -+ -+double Simulator::RoundF2FHelper(double input_val, int rmode) { -+ if (rmode == DYN) rmode = get_dynamic_rounding_mode(); -+ -+ double rounded = 0; -+ switch (rmode) { -+ case RNE: { // Round to Nearest, tiest to Even -+ int curr_mode = fegetround(); -+ fesetround(FE_TONEAREST); -+ rounded = std::nearbyint(input_val); -+ fesetround(curr_mode); -+ break; -+ } -+ case RTZ: // Round towards Zero -+ rounded = std::trunc(input_val); -+ break; -+ case RDN: // Round Down (towards -infinity) -+ rounded = std::floor(input_val); -+ break; -+ case RUP: // Round Up (towards +infinity) -+ rounded = std::ceil(input_val); -+ break; -+ case RMM: // Round to Nearest, tiest to Max Magnitude -+ rounded = std::round(input_val); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ return rounded; -+} -+ -+// convert rounded floating-point to integer types, handle input values that -+// are out-of-range, underflow, or NaN, and set appropriate fflags -+template -+I_TYPE Simulator::RoundF2IHelper(F_TYPE original, int rmode) { -+ DCHECK(std::is_integral::value); -+ -+ DCHECK((std::is_same::value || -+ std::is_same::value)); -+ -+ I_TYPE max_i = std::numeric_limits::max(); -+ I_TYPE min_i = std::numeric_limits::min(); -+ -+ if (!std::isfinite(original)) { -+ set_fflags(kInvalidOperation); -+ if (std::isnan(original) || -+ original == std::numeric_limits::infinity()) { -+ return max_i; -+ } else { -+ DCHECK(original == -std::numeric_limits::infinity()); -+ return min_i; -+ } -+ } -+ -+ F_TYPE rounded = RoundF2FHelper(original, rmode); -+ if (original != rounded) set_fflags(kInexact); -+ -+ if (!std::isfinite(rounded)) { -+ set_fflags(kInvalidOperation); -+ if (std::isnan(rounded) || -+ rounded == std::numeric_limits::infinity()) { -+ return max_i; -+ } else { -+ DCHECK(rounded == -std::numeric_limits::infinity()); -+ return min_i; -+ } -+ } -+ -+ // FIXME (RISCV): comparison of rounded (float) and max_i (integer) may not -+ // be precise because max_i is promoted to floating point during comparison. -+ // Rounding up may happen when converting max_i to floating-point, e.g., -+ // max is 9223372036854775807 vs. (double)max is -+ // 9223372036854775808.00000000000000 -+ -+ // Since integer max values are either all 1s (for unsigned) or all 1s -+ // except for sign-bit (for signed), they cannot be represented precisely in -+ // floating point, in order to precisely tell whether the rounded floating -+ // point is within the max range, we compare against (max_i+1) which would -+ // have a single 1 w/ many trailing zeros -+ float max_i_plus_1 = -+ std::is_same::value -+ ? 0x1p64f // uint64_t::max + 1 cannot be represented in integers, -+ // so use its float representation directly -+ : static_cast(static_cast(max_i) + 1); -+ if (rounded >= max_i_plus_1) { -+ set_fflags(kOverflow | kInvalidOperation); -+ return max_i; -+ } -+ -+ // Since min_i (either 0 for unsigned, or for signed) is represented -+ // precisely in floating-point, comparing rounded directly against min_i -+ if (rounded <= min_i) { -+ if (rounded < min_i) set_fflags(kOverflow | kInvalidOperation); -+ return min_i; -+ } -+ -+ F_TYPE underflow_fval = -+ std::is_same::value ? FLT_MIN : DBL_MIN; -+ if (rounded < underflow_fval && rounded > -underflow_fval && rounded != 0) { -+ set_fflags(kUnderflow); -+ } -+ -+ return static_cast(rounded); -+} -+ -+template -+static int64_t FclassHelper(T value) { -+ switch (std::fpclassify(value)) { -+ case FP_INFINITE: -+ return (std::signbit(value) ? kNegativeInfinity : kPositiveInfinity); -+ case FP_NAN: -+ return (isSnan(value) ? kSignalingNaN : kQuietNaN); -+ case FP_NORMAL: -+ return (std::signbit(value) ? kNegativeNormalNumber -+ : kPositiveNormalNumber); -+ case FP_SUBNORMAL: -+ return (std::signbit(value) ? kNegativeSubnormalNumber -+ : kPositiveSubnormalNumber); -+ case FP_ZERO: -+ return (std::signbit(value) ? kNegativeZero : kPositiveZero); -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+template -+bool Simulator::CompareFHelper(T input1, T input2, FPUCondition cc) { -+ DCHECK(std::is_floating_point::value); -+ bool result = false; -+ switch (cc) { -+ case LT: -+ case LE: -+ // FLT, FLE are signaling compares -+ if (std::isnan(input1) || std::isnan(input2)) { -+ set_fflags(kInvalidOperation); -+ result = false; -+ } else { -+ result = (cc == LT) ? (input1 < input2) : (input1 <= input2); -+ } -+ break; -+ -+ case EQ: -+ if (std::numeric_limits::signaling_NaN() == input1 || -+ std::numeric_limits::signaling_NaN() == input2) { -+ set_fflags(kInvalidOperation); -+ } -+ if (std::isnan(input1) || std::isnan(input2)) { -+ result = false; -+ } else { -+ result = (input1 == input2); -+ } -+ break; -+ -+ default: -+ UNREACHABLE(); -+ } -+ return result; -+} -+ -+template -+static inline bool is_invalid_fmul(T src1, T src2) { -+ return (isinf(src1) && src2 == static_cast(0.0)) || -+ (src1 == static_cast(0.0) && isinf(src2)); -+} -+ -+template -+static inline bool is_invalid_fadd(T src1, T src2) { -+ return (isinf(src1) && isinf(src2) && -+ std::signbit(src1) != std::signbit(src2)); -+} -+ -+template -+static inline bool is_invalid_fsub(T src1, T src2) { -+ return (isinf(src1) && isinf(src2) && -+ std::signbit(src1) == std::signbit(src2)); -+} -+ -+template -+static inline bool is_invalid_fdiv(T src1, T src2) { -+ return ((src1 == 0 && src2 == 0) || (isinf(src1) && isinf(src2))); -+} -+ -+template -+static inline bool is_invalid_fsqrt(T src1) { -+ return (src1 < 0); -+} -+ -+void Simulator::DecodeRVRAType() { -+ // TODO: Add macro for RISCV A extension -+ // Special handling for A extension instructions because it uses func5 -+ // For all A extension instruction, V8 simulator is pure sequential. No -+ // Memory address lock or other synchronizaiton behaviors. -+ switch (instr_.InstructionBits() & kRATypeMask) { -+ case RO_LR_W: { -+ base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); -+ int64_t addr = rs1(); -+ auto val = ReadMem(addr, instr_.instr()); -+ set_rd(sext32(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word); -+ GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr, -+ &global_monitor_thread_); -+ break; -+ } -+ case RO_SC_W: { -+ int64_t addr = rs1(); -+ base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); -+ if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) && -+ GlobalMonitor::Get()->NotifyStoreConditional_Locked( -+ addr, &global_monitor_thread_)) { -+ local_monitor_.NotifyStore(); -+ GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); -+ WriteMem(rs1(), (int32_t)rs2(), instr_.instr()); -+ set_rd(0, false); -+ } else { -+ set_rd(1, false); -+ } -+ break; -+ } -+ case RO_AMOSWAP_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return (uint32_t)rs2(); }, instr_.instr(), -+ WORD))); -+ break; -+ } -+ case RO_AMOADD_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return lhs + (uint32_t)rs2(); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOXOR_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return lhs ^ (uint32_t)rs2(); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOAND_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return lhs & (uint32_t)rs2(); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOOR_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return lhs | (uint32_t)rs2(); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOMIN_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](int32_t lhs) { return std::min(lhs, (int32_t)rs2()); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOMAX_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](int32_t lhs) { return std::max(lhs, (int32_t)rs2()); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOMINU_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return std::min(lhs, (uint32_t)rs2()); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+ case RO_AMOMAXU_W: { -+ set_rd(sext32(amo( -+ rs1(), [&](uint32_t lhs) { return std::max(lhs, (uint32_t)rs2()); }, -+ instr_.instr(), WORD))); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_LR_D: { -+ base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); -+ int64_t addr = rs1(); -+ auto val = ReadMem(addr, instr_.instr()); -+ set_rd(val, false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ local_monitor_.NotifyLoadLinked(addr, TransactionSize::DoubleWord); -+ GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr, -+ &global_monitor_thread_); -+ break; -+ } -+ case RO_SC_D: { -+ int64_t addr = rs1(); -+ base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); -+ if (local_monitor_.NotifyStoreConditional(addr, -+ TransactionSize::DoubleWord) && -+ (GlobalMonitor::Get()->NotifyStoreConditional_Locked( -+ addr, &global_monitor_thread_))) { -+ GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); -+ WriteMem(rs1(), rs2(), instr_.instr()); -+ set_rd(0, false); -+ } else { -+ set_rd(1, false); -+ } -+ break; -+ } -+ case RO_AMOSWAP_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return rs2(); }, instr_.instr(), DWORD)); -+ break; -+ } -+ case RO_AMOADD_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return lhs + rs2(); }, instr_.instr(), -+ DWORD)); -+ break; -+ } -+ case RO_AMOXOR_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return lhs ^ rs2(); }, instr_.instr(), -+ DWORD)); -+ break; -+ } -+ case RO_AMOAND_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return lhs & rs2(); }, instr_.instr(), -+ DWORD)); -+ break; -+ } -+ case RO_AMOOR_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return lhs | rs2(); }, instr_.instr(), -+ DWORD)); -+ break; -+ } -+ case RO_AMOMIN_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return std::min(lhs, rs2()); }, -+ instr_.instr(), DWORD)); -+ break; -+ } -+ case RO_AMOMAX_D: { -+ set_rd(amo( -+ rs1(), [&](int64_t lhs) { return std::max(lhs, rs2()); }, -+ instr_.instr(), DWORD)); -+ break; -+ } -+ case RO_AMOMINU_D: { -+ set_rd(amo( -+ rs1(), [&](uint64_t lhs) { return std::min(lhs, (uint64_t)rs2()); }, -+ instr_.instr(), DWORD)); -+ break; -+ } -+ case RO_AMOMAXU_D: { -+ set_rd(amo( -+ rs1(), [&](uint64_t lhs) { return std::max(lhs, (uint64_t)rs2()); }, -+ instr_.instr(), DWORD)); -+ break; -+ } -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ // TODO: End Add macro for RISCV A extension -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+} -+ -+void Simulator::DecodeRVRFPType() { -+ // OP_FP instructions (F/D) uses func7 first. Some further uses fun3 and -+ // rs2() -+ -+ // kRATypeMask is only for func7 -+ switch (instr_.InstructionBits() & kRFPTypeMask) { -+ // TODO: Add macro for RISCV F extension -+ case RO_FADD_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2) { -+ if (is_invalid_fadd(frs1, frs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return frs1 + frs2; -+ } -+ }; -+ set_frd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FSUB_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2) { -+ if (is_invalid_fsub(frs1, frs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return frs1 - frs2; -+ } -+ }; -+ set_frd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FMUL_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2) { -+ if (is_invalid_fmul(frs1, frs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return frs1 * frs2; -+ } -+ }; -+ set_frd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FDIV_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2) { -+ if (is_invalid_fdiv(frs1, frs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else if (frs2 == 0.0f) { -+ this->set_fflags(kDivideByZero); -+ return (std::signbit(frs1) == std::signbit(frs2) -+ ? std::numeric_limits::infinity() -+ : -std::numeric_limits::infinity()); -+ } else { -+ return frs1 / frs2; -+ } -+ }; -+ set_frd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FSQRT_S: { -+ if (instr_.Rs2Value() == 0b00000) { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs) { -+ if (is_invalid_fsqrt(frs)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return std::sqrt(frs); -+ } -+ }; -+ set_frd(CanonicalizeFPUOp1(fn)); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ case RO_FSGNJ_S: { // RO_FSGNJN_S RO_FSQNJX_S -+ switch (instr_.Funct3Value()) { -+ case 0b000: { // RO_FSGNJ_S -+ set_frd(fsgnj32(frs1(), frs2(), false, false)); -+ break; -+ } -+ case 0b001: { // RO_FSGNJN_S -+ set_frd(fsgnj32(frs1(), frs2(), true, false)); -+ break; -+ } -+ case 0b010: { // RO_FSQNJX_S -+ set_frd(fsgnj32(frs1(), frs2(), false, true)); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FMIN_S: { // RO_FMAX_S -+ switch (instr_.Funct3Value()) { -+ case 0b000: { // RO_FMIN_S -+ set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMin)); -+ break; -+ } -+ case 0b001: { // RO_FMAX_S -+ set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMax)); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FCVT_W_S: { // RO_FCVT_WU_S , 64F RO_FCVT_L_S RO_FCVT_LU_S -+ float original_val = frs1(); -+ switch (instr_.Rs2Value()) { -+ case 0b00000: { // RO_FCVT_W_S -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+ case 0b00001: { // RO_FCVT_WU_S -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: { // RO_FCVT_L_S -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+ case 0b00011: { // RO_FCVT_LU_S -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FMV: { // RO_FCLASS_S -+ switch (instr_.Funct3Value()) { -+ case 0b000: { -+ if (instr_.Rs2Value() == 0b00000) { -+ // RO_FMV_X_W -+ set_rd(sext_xlen(get_fpu_register_word(rs1_reg()))); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ case 0b001: { // RO_FCLASS_S -+ set_rd(FclassHelper(frs1())); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ // FIXME (RISCV): implement handling of NaN (quiet and signalling) -+ case RO_FLE_S: { // RO_FEQ_S RO_FLT_S RO_FLE_S -+ switch (instr_.Funct3Value()) { -+ case 0b010: { // RO_FEQ_S -+ set_rd(CompareFHelper(frs1(), frs2(), EQ)); -+ break; -+ } -+ case 0b001: { // RO_FLT_S -+ set_rd(CompareFHelper(frs1(), frs2(), LT)); -+ break; -+ } -+ case 0b000: { // RO_FLE_S -+ set_rd(CompareFHelper(frs1(), frs2(), LE)); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FCVT_S_W: { // RO_FCVT_S_WU , 64F RO_FCVT_S_L RO_FCVT_S_LU -+ switch (instr_.Rs2Value()) { -+ case 0b00000: { // RO_FCVT_S_W -+ set_frd((float)(int32_t)rs1()); -+ break; -+ } -+ case 0b00001: { // RO_FCVT_S_WU -+ set_frd((float)(uint32_t)rs1()); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: { // RO_FCVT_S_L -+ set_frd((float)(int64_t)rs1()); -+ break; -+ } -+ case 0b00011: { // RO_FCVT_S_LU -+ set_frd((float)(uint64_t)rs1()); -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FMV_W_X: { -+ if (instr_.Funct3Value() == 0b000) { -+ // since FMV preserves source bit-pattern, no need to canonize -+ set_frd(bit_cast((uint32_t)rs1())); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ // TODO: Add macro for RISCV D extension -+ case RO_FADD_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2) { -+ if (is_invalid_fadd(drs1, drs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return drs1 + drs2; -+ } -+ }; -+ set_drd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FSUB_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2) { -+ if (is_invalid_fsub(drs1, drs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return drs1 - drs2; -+ } -+ }; -+ set_drd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FMUL_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2) { -+ if (is_invalid_fmul(drs1, drs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return drs1 * drs2; -+ } -+ }; -+ set_drd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FDIV_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2) { -+ if (is_invalid_fdiv(drs1, drs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else if (drs2 == 0.0) { -+ this->set_fflags(kDivideByZero); -+ return (std::signbit(drs1) == std::signbit(drs2) -+ ? std::numeric_limits::infinity() -+ : -std::numeric_limits::infinity()); -+ } else { -+ return drs1 / drs2; -+ } -+ }; -+ set_drd(CanonicalizeFPUOp2(fn)); -+ break; -+ } -+ case RO_FSQRT_D: { -+ if (instr_.Rs2Value() == 0b00000) { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs) { -+ if (is_invalid_fsqrt(drs)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return std::sqrt(drs); -+ } -+ }; -+ set_drd(CanonicalizeFPUOp1(fn)); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ case RO_FSGNJ_D: { // RO_FSGNJN_D RO_FSQNJX_D -+ switch (instr_.Funct3Value()) { -+ case 0b000: { // RO_FSGNJ_D -+ set_drd(fsgnj64(drs1(), drs2(), false, false)); -+ break; -+ } -+ case 0b001: { // RO_FSGNJN_D -+ set_drd(fsgnj64(drs1(), drs2(), true, false)); -+ break; -+ } -+ case 0b010: { // RO_FSQNJX_D -+ set_drd(fsgnj64(drs1(), drs2(), false, true)); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FMIN_D: { // RO_FMAX_D -+ switch (instr_.Funct3Value()) { -+ case 0b000: { // RO_FMIN_D -+ set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMin)); -+ break; -+ } -+ case 0b001: { // RO_FMAX_D -+ set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMax)); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case (RO_FCVT_S_D & kRFPTypeMask): { -+ if (instr_.Rs2Value() == 0b00001) { -+ auto fn = [](double drs) { return (float)drs; }; -+ set_frd(CanonicalizeDoubleToFloatOperation(fn)); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ case RO_FCVT_D_S: { -+ if (instr_.Rs2Value() == 0b00000) { -+ auto fn = [](float frs) { return (double)frs; }; -+ set_drd(CanonicalizeFloatToDoubleOperation(fn)); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ case RO_FLE_D: { // RO_FEQ_D RO_FLT_D RO_FLE_D -+ switch (instr_.Funct3Value()) { -+ case 0b010: { // RO_FEQ_S -+ set_rd(CompareFHelper(drs1(), drs2(), EQ)); -+ break; -+ } -+ case 0b001: { // RO_FLT_D -+ set_rd(CompareFHelper(drs1(), drs2(), LT)); -+ break; -+ } -+ case 0b000: { // RO_FLE_D -+ set_rd(CompareFHelper(drs1(), drs2(), LE)); -+ break; -+ } -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case (RO_FCLASS_D & kRFPTypeMask): { // RO_FCLASS_D , 64D RO_FMV_X_D -+ if (instr_.Rs2Value() != 0b00000) { -+ UNSUPPORTED(); -+ break; -+ } -+ switch (instr_.Funct3Value()) { -+ case 0b001: { // RO_FCLASS_D -+ set_rd(FclassHelper(drs1())); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b000: { // RO_FMV_X_D -+ set_rd(bit_cast(drs1())); -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FCVT_W_D: { // RO_FCVT_WU_D , 64F RO_FCVT_L_D RO_FCVT_LU_D -+ double original_val = drs1(); -+ switch (instr_.Rs2Value()) { -+ case 0b00000: { // RO_FCVT_W_D -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+ case 0b00001: { // RO_FCVT_WU_D -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: { // RO_FCVT_L_D -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+ case 0b00011: { // RO_FCVT_LU_D -+ set_rd(RoundF2IHelper(original_val, instr_.RoundMode())); -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+ case RO_FCVT_D_W: { // RO_FCVT_D_WU , 64F RO_FCVT_D_L RO_FCVT_D_LU -+ switch (instr_.Rs2Value()) { -+ case 0b00000: { // RO_FCVT_D_W -+ set_drd((int32_t)rs1()); -+ break; -+ } -+ case 0b00001: { // RO_FCVT_D_WU -+ set_drd((uint32_t)rs1()); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case 0b00010: { // RO_FCVT_D_L -+ set_drd((int64_t)rs1()); -+ break; -+ } -+ case 0b00011: { // RO_FCVT_D_LU -+ set_drd((uint64_t)rs1()); -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_FMV_D_X: { -+ if (instr_.Funct3Value() == 0b000 && instr_.Rs2Value() == 0b00000) { -+ // Since FMV preserves source bit-pattern, no need to canonize -+ set_drd(bit_cast(rs1())); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+#endif /* V8_TARGET_ARCH_64_BIT */ -+ default: { -+ UNSUPPORTED(); -+ } -+ } -+} -+ -+void Simulator::DecodeRVR4Type() { -+ switch (instr_.InstructionBits() & kR4TypeMask) { -+ // TODO: use F Extension macro block -+ case RO_FMADD_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2, float frs3) { -+ if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return std::fma(frs1, frs2, frs3); -+ } -+ }; -+ set_frd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ case RO_FMSUB_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2, float frs3) { -+ if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs1 * frs2, frs3)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return std::fma(frs1, frs2, -frs3); -+ } -+ }; -+ set_frd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ case RO_FNMSUB_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2, float frs3) { -+ if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs3, frs1 * frs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return -std::fma(frs1, frs2, -frs3); -+ } -+ }; -+ set_frd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ case RO_FNMADD_S: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](float frs1, float frs2, float frs3) { -+ if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return -std::fma(frs1, frs2, frs3); -+ } -+ }; -+ set_frd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ // TODO: use F Extension macro block -+ case RO_FMADD_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2, double drs3) { -+ if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return std::fma(drs1, drs2, drs3); -+ } -+ }; -+ set_drd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ case RO_FMSUB_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2, double drs3) { -+ if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs1 * drs2, drs3)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return std::fma(drs1, drs2, -drs3); -+ } -+ }; -+ set_drd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ case RO_FNMSUB_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2, double drs3) { -+ if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs3, drs1 * drs2)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return -std::fma(drs1, drs2, -drs3); -+ } -+ }; -+ set_drd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ case RO_FNMADD_D: { -+ // TODO: use rm value (round mode) -+ auto fn = [this](double drs1, double drs2, double drs3) { -+ if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) { -+ this->set_fflags(kInvalidOperation); -+ return std::numeric_limits::quiet_NaN(); -+ } else { -+ return -std::fma(drs1, drs2, drs3); -+ } -+ }; -+ set_drd(CanonicalizeFPUOp3(fn)); -+ break; -+ } -+ default: -+ UNSUPPORTED(); -+ } -+} -+ -+void Simulator::DecodeRVIType() { -+ switch (instr_.InstructionBits() & kITypeMask) { -+ case RO_JALR: { -+ set_rd(get_pc() + kInstrSize); -+ // Note: No need to shift 2 for JALR's imm12, but set lowest bit to 0. -+ int64_t next_pc = (rs1() + imm12()) & ~reg_t(1); -+ set_pc(next_pc); -+ break; -+ } -+ case RO_LB: { -+ int64_t addr = rs1() + imm12(); -+ int8_t val = ReadMem(addr, instr_.instr()); -+ set_rd(sext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+ case RO_LH: { -+ int64_t addr = rs1() + imm12(); -+ int16_t val = ReadMem(addr, instr_.instr()); -+ set_rd(sext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+ case RO_LW: { -+ int64_t addr = rs1() + imm12(); -+ int32_t val = ReadMem(addr, instr_.instr()); -+ set_rd(sext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+ case RO_LBU: { -+ int64_t addr = rs1() + imm12(); -+ uint8_t val = ReadMem(addr, instr_.instr()); -+ set_rd(zext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+ case RO_LHU: { -+ int64_t addr = rs1() + imm12(); -+ uint16_t val = ReadMem(addr, instr_.instr()); -+ set_rd(zext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_LWU: { -+ int64_t addr = rs1() + imm12(); -+ uint32_t val = ReadMem(addr, instr_.instr()); -+ set_rd(zext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+ case RO_LD: { -+ int64_t addr = rs1() + imm12(); -+ int64_t val = ReadMem(addr, instr_.instr()); -+ set_rd(sext_xlen(val), false); -+ TraceMemRd(addr, val, get_register(rd_reg())); -+ break; -+ } -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ case RO_ADDI: { -+ set_rd(sext_xlen(rs1() + imm12())); -+ break; -+ } -+ case RO_SLTI: { -+ set_rd(sreg_t(rs1()) < sreg_t(imm12())); -+ break; -+ } -+ case RO_SLTIU: { -+ set_rd(reg_t(rs1()) < reg_t(imm12())); -+ break; -+ } -+ case RO_XORI: { -+ set_rd(imm12() ^ rs1()); -+ break; -+ } -+ case RO_ORI: { -+ set_rd(imm12() | rs1()); -+ break; -+ } -+ case RO_ANDI: { -+ set_rd(imm12() & rs1()); -+ break; -+ } -+ case RO_SLLI: { -+ require(shamt() < xlen); -+ set_rd(sext_xlen(rs1() << shamt())); -+ break; -+ } -+ case RO_SRLI: { // RO_SRAI -+ if (!instr_.IsArithShift()) { -+ require(shamt() < xlen); -+ set_rd(sext_xlen(zext_xlen(rs1()) >> shamt())); -+ } else { -+ require(shamt() < xlen); -+ set_rd(sext_xlen(sext_xlen(rs1()) >> shamt())); -+ } -+ break; -+ } -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_ADDIW: { -+ set_rd(sext32(rs1() + imm12())); -+ break; -+ } -+ case RO_SLLIW: { -+ set_rd(sext32(rs1() << shamt32())); -+ break; -+ } -+ case RO_SRLIW: { // RO_SRAIW -+ if (!instr_.IsArithShift()) { -+ set_rd(sext32(uint32_t(rs1()) >> shamt32())); -+ } else { -+ set_rd(sext32(int32_t(rs1()) >> shamt32())); -+ } -+ break; -+ } -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ case RO_FENCE: { -+ // DO nothing in sumulator -+ break; -+ } -+ case RO_ECALL: { // RO_EBREAK -+ if (instr_.Imm12Value() == 0) { // ECALL -+ SoftwareInterrupt(); -+ } else if (instr_.Imm12Value() == 1) { // EBREAK -+ SoftwareInterrupt(); -+ } else { -+ UNSUPPORTED(); -+ } -+ break; -+ } -+ // TODO: use Zifencei Standard Extension macro block -+ case RO_FENCE_I: { -+ // spike: flush icache. -+ break; -+ } -+ // TODO: use Zicsr Standard Extension macro block -+ case RO_CSRRW: { -+ if (rd_reg() != zero_reg) { -+ set_rd(zext_xlen(read_csr_value(csr_reg()))); -+ } -+ write_csr_value(csr_reg(), rs1()); -+ break; -+ } -+ case RO_CSRRS: { -+ set_rd(zext_xlen(read_csr_value(csr_reg()))); -+ if (rs1_reg() != zero_reg) { -+ set_csr_bits(csr_reg(), rs1()); -+ } -+ break; -+ } -+ case RO_CSRRC: { -+ set_rd(zext_xlen(read_csr_value(csr_reg()))); -+ if (rs1_reg() != zero_reg) { -+ clear_csr_bits(csr_reg(), rs1()); -+ } -+ break; -+ } -+ case RO_CSRRWI: { -+ if (rd_reg() != zero_reg) { -+ set_rd(zext_xlen(read_csr_value(csr_reg()))); -+ } -+ write_csr_value(csr_reg(), imm5CSR()); -+ break; -+ } -+ case RO_CSRRSI: { -+ set_rd(zext_xlen(read_csr_value(csr_reg()))); -+ if (imm5CSR() != 0) { -+ set_csr_bits(csr_reg(), imm5CSR()); -+ } -+ break; -+ } -+ case RO_CSRRCI: { -+ set_rd(zext_xlen(read_csr_value(csr_reg()))); -+ if (imm5CSR() != 0) { -+ clear_csr_bits(csr_reg(), imm5CSR()); -+ } -+ break; -+ } -+ // TODO: use F Extension macro block -+ case RO_FLW: { -+ int64_t addr = rs1() + imm12(); -+ float val = ReadMem(addr, instr_.instr()); -+ set_frd(val, false); -+ TraceMemRd(addr, val, get_fpu_register(frd_reg())); -+ break; -+ } -+ // TODO: use D Extension macro block -+ case RO_FLD: { -+ int64_t addr = rs1() + imm12(); -+ double val = ReadMem(addr, instr_.instr()); -+ set_drd(val, false); -+ TraceMemRd(addr, val, get_fpu_register(frd_reg())); -+ break; -+ } -+ default: -+ UNSUPPORTED(); -+ } -+} -+ -+void Simulator::DecodeRVSType() { -+ switch (instr_.InstructionBits() & kSTypeMask) { -+ case RO_SB: -+ WriteMem(rs1() + s_imm12(), (uint8_t)rs2(), instr_.instr()); -+ break; -+ case RO_SH: -+ WriteMem(rs1() + s_imm12(), (uint16_t)rs2(), instr_.instr()); -+ break; -+ case RO_SW: -+ WriteMem(rs1() + s_imm12(), (uint32_t)rs2(), instr_.instr()); -+ break; -+#ifdef V8_TARGET_ARCH_64_BIT -+ case RO_SD: -+ WriteMem(rs1() + s_imm12(), (uint64_t)rs2(), instr_.instr()); -+ break; -+#endif /*V8_TARGET_ARCH_64_BIT*/ -+ // TODO: use F Extension macro block -+ case RO_FSW: { -+ WriteMem(rs1() + s_imm12(), -+ (uint32_t)get_fpu_register_word(rs2_reg()), -+ instr_.instr()); -+ break; -+ } -+ // TODO: use D Extension macro block -+ case RO_FSD: { -+ WriteMem(rs1() + s_imm12(), drs2(), instr_.instr()); -+ break; -+ } -+ default: -+ UNSUPPORTED(); -+ } -+} -+ -+void Simulator::DecodeRVBType() { -+ switch (instr_.InstructionBits() & kBTypeMask) { -+ case RO_BEQ: -+ if (rs1() == rs2()) { -+ int64_t next_pc = get_pc() + boffset(); -+ set_pc(next_pc); -+ } -+ break; -+ case RO_BNE: -+ if (rs1() != rs2()) { -+ int64_t next_pc = get_pc() + boffset(); -+ set_pc(next_pc); -+ } -+ break; -+ case RO_BLT: -+ if (rs1() < rs2()) { -+ int64_t next_pc = get_pc() + boffset(); -+ set_pc(next_pc); -+ } -+ break; -+ case RO_BGE: -+ if (rs1() >= rs2()) { -+ int64_t next_pc = get_pc() + boffset(); -+ set_pc(next_pc); -+ } -+ break; -+ case RO_BLTU: -+ if ((reg_t)rs1() < (reg_t)rs2()) { -+ int64_t next_pc = get_pc() + boffset(); -+ set_pc(next_pc); -+ } -+ break; -+ case RO_BGEU: -+ if ((reg_t)rs1() >= (reg_t)rs2()) { -+ int64_t next_pc = get_pc() + boffset(); -+ set_pc(next_pc); -+ } -+ break; -+ default: -+ UNSUPPORTED(); -+ } -+} -+void Simulator::DecodeRVUType() { -+ // U Type doesn't have additoinal mask -+ switch (instr_.BaseOpcodeFieldRaw()) { -+ case RO_LUI: -+ set_rd(u_imm()); -+ break; -+ case RO_AUIPC: -+ set_rd(sext_xlen(u_imm() + get_pc())); -+ break; -+ default: -+ UNSUPPORTED(); -+ } -+} -+void Simulator::DecodeRVJType() { -+ // J Type doesn't have additional mask -+ switch (instr_.BaseOpcodeValue()) { -+ case RO_JAL: { -+ set_rd(get_pc() + kInstrSize); -+ int64_t next_pc = get_pc() + imm20J(); -+ set_pc(next_pc); -+ break; -+ } -+ default: -+ UNSUPPORTED(); -+ } -+} -+ -+// Executes the current instruction. -+void Simulator::InstructionDecode(Instruction* instr) { -+ if (v8::internal::FLAG_check_icache) { -+ CheckICache(i_cache(), instr); -+ } -+ pc_modified_ = false; -+ -+ v8::internal::EmbeddedVector buffer; -+ -+ if (::v8::internal::FLAG_trace_sim) { -+ SNPrintF(trace_buf_, " "); -+ disasm::NameConverter converter; -+ disasm::Disassembler dasm(converter); -+ // Use a reasonably large buffer. -+ dasm.InstructionDecode(buffer, reinterpret_cast(instr)); -+ -+ // PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n", -+ // reinterpret_cast(instr), buffer.begin()); -+ } -+ -+ instr_ = instr; -+ switch (instr_.InstructionType()) { -+ case Instruction::kRType: -+ DecodeRVRType(); -+ break; -+ case Instruction::kR4Type: -+ DecodeRVR4Type(); -+ break; -+ case Instruction::kIType: -+ DecodeRVIType(); -+ break; -+ case Instruction::kSType: -+ DecodeRVSType(); -+ break; -+ case Instruction::kBType: -+ DecodeRVBType(); -+ break; -+ case Instruction::kUType: -+ DecodeRVUType(); -+ break; -+ case Instruction::kJType: -+ DecodeRVJType(); -+ break; -+ default: -+ if (::v8::internal::FLAG_trace_sim) { -+ std::cout << "Unrecognized instruction [@pc=0x" << std::hex -+ << registers_[pc] << "]: 0x" << instr->InstructionBits() -+ << std::endl; -+ } -+ UNSUPPORTED(); -+ } -+ -+ if (::v8::internal::FLAG_trace_sim) { -+ PrintF(" 0x%012" PRIxPTR " %-44s %s\n", -+ reinterpret_cast(instr), buffer.begin(), -+ trace_buf_.begin()); -+ } -+ -+ if (!pc_modified_) { -+ set_register(pc, reinterpret_cast(instr) + kInstrSize); -+ } -+} -+ -+void Simulator::Execute() { -+ // Get the PC to simulate. Cannot use the accessor here as we need the -+ // raw PC value and not the one used as input to arithmetic instructions. -+ int64_t program_counter = get_pc(); -+ while (program_counter != end_sim_pc) { -+ Instruction* instr = reinterpret_cast(program_counter); -+ icount_++; -+ if (icount_ == static_cast(::v8::internal::FLAG_stop_sim_at)) { -+ RiscvDebugger dbg(this); -+ dbg.Debug(); -+ } else { -+ InstructionDecode(instr); -+ } -+ CheckBreakpoints(); -+ program_counter = get_pc(); -+ } -+} -+ -+void Simulator::CallInternal(Address entry) { -+ // Adjust JS-based stack limit to C-based stack limit. -+ isolate_->stack_guard()->AdjustStackLimitForSimulator(); -+ -+ // Prepare to execute the code at entry. -+ set_register(pc, static_cast(entry)); -+ // Put down marker for end of simulation. The simulator will stop simulation -+ // when the PC reaches this value. By saving the "end simulation" value into -+ // the LR the simulation stops when returning to this call point. -+ set_register(ra, end_sim_pc); -+ -+ // Remember the values of callee-saved registers. -+ // The code below assumes that r9 is not used as sb (static base) in -+ // simulator code and therefore is regarded as a callee-saved register. -+ int64_t s0_val = get_register(s0); -+ int64_t s1_val = get_register(s1); -+ int64_t s2_val = get_register(s2); -+ int64_t s3_val = get_register(s3); -+ int64_t s4_val = get_register(s4); -+ int64_t s5_val = get_register(s5); -+ int64_t s6_val = get_register(s6); -+ int64_t s7_val = get_register(s7); -+ int64_t gp_val = get_register(gp); -+ int64_t sp_val = get_register(sp); -+ int64_t fp_val = get_register(fp); -+ -+ // Set up the callee-saved registers with a known value. To be able to check -+ // that they are preserved properly across JS execution. -+ int64_t callee_saved_value = icount_; -+ set_register(s0, callee_saved_value); -+ set_register(s1, callee_saved_value); -+ set_register(s2, callee_saved_value); -+ set_register(s3, callee_saved_value); -+ set_register(s4, callee_saved_value); -+ set_register(s5, callee_saved_value); -+ set_register(s6, callee_saved_value); -+ set_register(s7, callee_saved_value); -+ set_register(gp, callee_saved_value); -+ set_register(fp, callee_saved_value); -+ -+ // Start the simulation. -+ Execute(); -+ -+ // Check that the callee-saved registers have been preserved. -+ CHECK_EQ(callee_saved_value, get_register(s0)); -+ CHECK_EQ(callee_saved_value, get_register(s1)); -+ CHECK_EQ(callee_saved_value, get_register(s2)); -+ CHECK_EQ(callee_saved_value, get_register(s3)); -+ CHECK_EQ(callee_saved_value, get_register(s4)); -+ CHECK_EQ(callee_saved_value, get_register(s5)); -+ CHECK_EQ(callee_saved_value, get_register(s6)); -+ CHECK_EQ(callee_saved_value, get_register(s7)); -+ CHECK_EQ(callee_saved_value, get_register(gp)); -+ CHECK_EQ(callee_saved_value, get_register(fp)); -+ -+ // Restore callee-saved registers with the original value. -+ set_register(s0, s0_val); -+ set_register(s1, s1_val); -+ set_register(s2, s2_val); -+ set_register(s3, s3_val); -+ set_register(s4, s4_val); -+ set_register(s5, s5_val); -+ set_register(s6, s6_val); -+ set_register(s7, s7_val); -+ set_register(gp, gp_val); -+ set_register(sp, sp_val); -+ set_register(fp, fp_val); -+} -+ -+intptr_t Simulator::CallImpl(Address entry, int argument_count, -+ const intptr_t* arguments) { -+ constexpr int kRegisterPassedArguments = 8; -+ // Set up arguments. -+ -+ // First four arguments passed in registers in both ABI's. -+ int reg_arg_count = std::min(kRegisterPassedArguments, argument_count); -+ if (reg_arg_count > 0) set_register(a0, arguments[0]); -+ if (reg_arg_count > 1) set_register(a1, arguments[1]); -+ if (reg_arg_count > 2) set_register(a2, arguments[2]); -+ if (reg_arg_count > 3) set_register(a3, arguments[3]); -+ -+ // Up to eight arguments passed in registers in N64 ABI. -+ // TODO(plind): N64 ABI calls these regs a4 - a7. Clarify this. -+ if (reg_arg_count > 4) set_register(a4, arguments[4]); -+ if (reg_arg_count > 5) set_register(a5, arguments[5]); -+ if (reg_arg_count > 6) set_register(a6, arguments[6]); -+ if (reg_arg_count > 7) set_register(a7, arguments[7]); -+ -+ if (::v8::internal::FLAG_trace_sim) { -+ std::cout << "CallImpl: reg_arg_count = " << reg_arg_count << std::hex -+ << " entry-pc (JSEntry) = 0x" << entry << " a0 (Isolate) = 0x" -+ << get_register(a0) << " a1 (orig_func/new_target) = 0x" -+ << get_register(a1) << " a2 (func/target) = 0x" -+ << get_register(a2) << " a3 (receiver) = 0x" << get_register(a3) -+ << " a4 (argc) = 0x" << get_register(a4) << " a5 (argv) = 0x" -+ << get_register(a5) << std::endl; -+ } -+ -+ // Remaining arguments passed on stack. -+ int64_t original_stack = get_register(sp); -+ // Compute position of stack on entry to generated code. -+ int stack_args_count = argument_count - reg_arg_count; -+ int stack_args_size = stack_args_count * sizeof(*arguments) + kCArgsSlotsSize; -+ int64_t entry_stack = original_stack - stack_args_size; -+ -+ if (base::OS::ActivationFrameAlignment() != 0) { -+ entry_stack &= -base::OS::ActivationFrameAlignment(); -+ } -+ // Store remaining arguments on stack, from low to high memory. -+ intptr_t* stack_argument = reinterpret_cast(entry_stack); -+ memcpy(stack_argument + kCArgSlotCount, arguments + reg_arg_count, -+ stack_args_count * sizeof(*arguments)); -+ set_register(sp, entry_stack); -+ -+ CallInternal(entry); -+ -+ // Pop stack passed arguments. -+ CHECK_EQ(entry_stack, get_register(sp)); -+ set_register(sp, original_stack); -+ -+ // return get_register(a0); -+ // RISCV uses a0 to return result -+ return get_register(a0); -+} -+ -+double Simulator::CallFP(Address entry, double d0, double d1) { -+ set_fpu_register_double(fa0, d0); -+ set_fpu_register_double(fa1, d1); -+ CallInternal(entry); -+ return get_fpu_register_double(fa0); -+} -+ -+uintptr_t Simulator::PushAddress(uintptr_t address) { -+ int64_t new_sp = get_register(sp) - sizeof(uintptr_t); -+ uintptr_t* stack_slot = reinterpret_cast(new_sp); -+ *stack_slot = address; -+ set_register(sp, new_sp); -+ return new_sp; -+} -+ -+uintptr_t Simulator::PopAddress() { -+ int64_t current_sp = get_register(sp); -+ uintptr_t* stack_slot = reinterpret_cast(current_sp); -+ uintptr_t address = *stack_slot; -+ set_register(sp, current_sp + sizeof(uintptr_t)); -+ return address; -+} -+ -+Simulator::LocalMonitor::LocalMonitor() -+ : access_state_(MonitorAccess::Open), -+ tagged_addr_(0), -+ size_(TransactionSize::None) {} -+ -+void Simulator::LocalMonitor::Clear() { -+ access_state_ = MonitorAccess::Open; -+ tagged_addr_ = 0; -+ size_ = TransactionSize::None; -+} -+ -+void Simulator::LocalMonitor::NotifyLoad() { -+ if (access_state_ == MonitorAccess::RMW) { -+ // A non linked load could clear the local monitor. As a result, it's -+ // most strict to unconditionally clear the local monitor on load. -+ Clear(); -+ } -+} -+ -+void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr, -+ TransactionSize size) { -+ access_state_ = MonitorAccess::RMW; -+ tagged_addr_ = addr; -+ size_ = size; -+} -+ -+void Simulator::LocalMonitor::NotifyStore() { -+ if (access_state_ == MonitorAccess::RMW) { -+ // A non exclusive store could clear the local monitor. As a result, it's -+ // most strict to unconditionally clear the local monitor on store. -+ Clear(); -+ } -+} -+ -+bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr, -+ TransactionSize size) { -+ if (access_state_ == MonitorAccess::RMW) { -+ if (addr == tagged_addr_ && size_ == size) { -+ Clear(); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ DCHECK(access_state_ == MonitorAccess::Open); -+ return false; -+ } -+} -+ -+Simulator::GlobalMonitor::LinkedAddress::LinkedAddress() -+ : access_state_(MonitorAccess::Open), -+ tagged_addr_(0), -+ next_(nullptr), -+ prev_(nullptr), -+ failure_counter_(0) {} -+ -+void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() { -+ access_state_ = MonitorAccess::Open; -+ tagged_addr_ = 0; -+} -+ -+void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked( -+ uintptr_t addr) { -+ access_state_ = MonitorAccess::RMW; -+ tagged_addr_ = addr; -+} -+ -+void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() { -+ if (access_state_ == MonitorAccess::RMW) { -+ // A non exclusive store could clear the global monitor. As a result, it's -+ // most strict to unconditionally clear global monitors on store. -+ Clear_Locked(); -+ } -+} -+ -+bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked( -+ uintptr_t addr, bool is_requesting_thread) { -+ if (access_state_ == MonitorAccess::RMW) { -+ if (is_requesting_thread) { -+ if (addr == tagged_addr_) { -+ Clear_Locked(); -+ // Introduce occasional sc/scd failures. This is to simulate the -+ // behavior of hardware, which can randomly fail due to background -+ // cache evictions. -+ if (failure_counter_++ >= kMaxFailureCounter) { -+ failure_counter_ = 0; -+ return false; -+ } else { -+ return true; -+ } -+ } -+ } else if ((addr & kExclusiveTaggedAddrMask) == -+ (tagged_addr_ & kExclusiveTaggedAddrMask)) { -+ // Check the masked addresses when responding to a successful lock by -+ // another thread so the implementation is more conservative (i.e. the -+ // granularity of locking is as large as possible.) -+ Clear_Locked(); -+ return false; -+ } -+ } -+ return false; -+} -+ -+void Simulator::GlobalMonitor::NotifyLoadLinked_Locked( -+ uintptr_t addr, LinkedAddress* linked_address) { -+ linked_address->NotifyLoadLinked_Locked(addr); -+ PrependProcessor_Locked(linked_address); -+} -+ -+void Simulator::GlobalMonitor::NotifyStore_Locked( -+ LinkedAddress* linked_address) { -+ // Notify each thread of the store operation. -+ for (LinkedAddress* iter = head_; iter; iter = iter->next_) { -+ iter->NotifyStore_Locked(); -+ } -+} -+ -+bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked( -+ uintptr_t addr, LinkedAddress* linked_address) { -+ DCHECK(IsProcessorInLinkedList_Locked(linked_address)); -+ if (linked_address->NotifyStoreConditional_Locked(addr, true)) { -+ // Notify the other processors that this StoreConditional succeeded. -+ for (LinkedAddress* iter = head_; iter; iter = iter->next_) { -+ if (iter != linked_address) { -+ iter->NotifyStoreConditional_Locked(addr, false); -+ } -+ } -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked( -+ LinkedAddress* linked_address) const { -+ return head_ == linked_address || linked_address->next_ || -+ linked_address->prev_; -+} -+ -+void Simulator::GlobalMonitor::PrependProcessor_Locked( -+ LinkedAddress* linked_address) { -+ if (IsProcessorInLinkedList_Locked(linked_address)) { -+ return; -+ } -+ -+ if (head_) { -+ head_->prev_ = linked_address; -+ } -+ linked_address->prev_ = nullptr; -+ linked_address->next_ = head_; -+ head_ = linked_address; -+} -+ -+void Simulator::GlobalMonitor::RemoveLinkedAddress( -+ LinkedAddress* linked_address) { -+ base::MutexGuard lock_guard(&mutex); -+ if (!IsProcessorInLinkedList_Locked(linked_address)) { -+ return; -+ } -+ -+ if (linked_address->prev_) { -+ linked_address->prev_->next_ = linked_address->next_; -+ } else { -+ head_ = linked_address->next_; -+ } -+ if (linked_address->next_) { -+ linked_address->next_->prev_ = linked_address->prev_; -+ } -+ linked_address->prev_ = nullptr; -+ linked_address->next_ = nullptr; -+} -+ -+#undef SScanF -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // USE_SIMULATOR -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/simulator-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/riscv64/simulator-riscv64.h -@@ -0,0 +1,764 @@ -+// Copyright 2020 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. -+ -+// Copyright(c) 2010 - 2017, -+// The Regents of the University of California(Regents).All Rights Reserved. -+// -+// Redistribution and use in source and binary forms, -+// with or without modification, -+// are permitted provided that the following -+// conditions are met : 1. Redistributions of source code must retain the -+// above copyright notice, this list of conditions and the following -+// disclaimer.2. Redistributions in binary form must reproduce the above -+// copyright notice, this list of conditions and the following disclaimer in -+// the -+// documentation and / -+// or -+// other materials provided with the distribution.3. Neither the name of -+// the Regents nor the names of its contributors may be used to endorse -+// or -+// promote products derived from -+// this software without specific prior written permission. -+// -+// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, -+// INDIRECT, SPECIAL, -+// INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, -+// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, -+// EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+// -+// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, -+// INCLUDING, BUT NOT LIMITED TO, -+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -+// PARTICULAR PURPOSE.THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, -+// IF ANY, -+// PROVIDED HEREUNDER IS PROVIDED -+// "AS IS".REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, -+// SUPPORT, UPDATES, ENHANCEMENTS, -+// OR MODIFICATIONS. -+ -+// The original source code covered by the above license above has been -+// modified significantly by the v8 project authors. -+ -+// Declares a Simulator for RISC-V instructions if we are not generating a -+// native RISC-V binary. This Simulator allows us to run and debug RISC-V code -+// generation on regular desktop machines. V8 calls into generated code via the -+// GeneratedCode wrapper, which will start execution in the Simulator or -+// forwards to the real entry on a RISC-V HW platform. -+ -+#ifndef V8_EXECUTION_RISCV_SIMULATOR_RISCV_H_ -+#define V8_EXECUTION_RISCV_SIMULATOR_RISCV_H_ -+ -+// globals.h defines USE_SIMULATOR. -+#include "src/common/globals.h" -+ -+template -+int Compare(const T& a, const T& b) { -+ if (a == b) -+ return 0; -+ else if (a < b) -+ return -1; -+ else -+ return 1; -+} -+ -+// Returns the negative absolute value of its argument. -+template ::value>::type> -+T Nabs(T a) { -+ return a < 0 ? a : -a; -+} -+ -+#if defined(USE_SIMULATOR) -+// Running with a simulator. -+ -+#include "src/base/hashmap.h" -+#include "src/codegen/assembler.h" -+#include "src/codegen/riscv64/constants-riscv64.h" -+#include "src/execution/simulator-base.h" -+#include "src/utils/allocation.h" -+ -+namespace v8 { -+namespace internal { -+ -+// ----------------------------------------------------------------------------- -+// Utility types and functions for RISCV -+// TODO: Add Spike License here -+#ifdef V8_TARGET_ARCH_32_BIT -+using sreg_t = int32_t; -+using reg_t = uint32_t; -+#define xlen 32 -+#elif V8_TARGET_ARCH_64_BIT -+using sreg_t = int64_t; -+using reg_t = uint64_t; -+#define xlen 64 -+#else -+#error "Cannot detect Riscv's bitwidth" -+#endif -+ -+#define sext32(x) ((sreg_t)(int32_t)(x)) -+#define zext32(x) ((reg_t)(uint32_t)(x)) -+#define sext_xlen(x) (((sreg_t)(x) << (64 - xlen)) >> (64 - xlen)) -+#define zext_xlen(x) (((reg_t)(x) << (64 - xlen)) >> (64 - xlen)) -+ -+#define BIT(n) (0x1LL << n) -+#define QUIET_BIT_S(nan) (bit_cast(nan) & BIT(22)) -+#define QUIET_BIT_D(nan) (bit_cast(nan) & BIT(51)) -+static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); } -+static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); } -+#undef QUIET_BIT_S -+#undef QUIET_BIT_D -+ -+inline uint64_t mulhu(uint64_t a, uint64_t b) { -+ __uint128_t full_result = ((__uint128_t)a) * ((__uint128_t)b); -+ return full_result >> 64; -+} -+ -+inline int64_t mulh(int64_t a, int64_t b) { -+ __int128_t full_result = ((__int128_t)a) * ((__int128_t)b); -+ return full_result >> 64; -+} -+ -+inline int64_t mulhsu(int64_t a, uint64_t b) { -+ __int128_t full_result = ((__int128_t)a) * ((__uint128_t)b); -+ return full_result >> 64; -+} -+ -+// Floating point helpers -+#define F32_SIGN ((uint32_t)1 << 31) -+union u32_f32 { -+ uint32_t u; -+ float f; -+}; -+inline float fsgnj32(float rs1, float rs2, bool n, bool x) { -+ u32_f32 a = {.f = rs1}, b = {.f = rs2}; -+ u32_f32 res; -+ res.u = -+ (a.u & ~F32_SIGN) | ((((x) ? a.u : (n) ? F32_SIGN : 0) ^ b.u) & F32_SIGN); -+ return res.f; -+} -+#define F64_SIGN ((uint64_t)1 << 63) -+union u64_f64 { -+ uint64_t u; -+ double d; -+}; -+inline double fsgnj64(double rs1, double rs2, bool n, bool x) { -+ u64_f64 a = {.d = rs1}, b = {.d = rs2}; -+ u64_f64 res; -+ res.u = -+ (a.u & ~F64_SIGN) | ((((x) ? a.u : (n) ? F64_SIGN : 0) ^ b.u) & F64_SIGN); -+ return res.d; -+} -+ -+inline bool is_boxed_float(int64_t v) { -+ return (uint32_t)((v >> 32) + 1) == 0; -+} -+inline int64_t box_float(float v) { -+ return (0xFFFFFFFF00000000 | bit_cast(v)); -+} -+ -+// ----------------------------------------------------------------------------- -+// Utility functions -+ -+class CachePage { -+ public: -+ static const int LINE_VALID = 0; -+ static const int LINE_INVALID = 1; -+ -+ static const int kPageShift = 12; -+ static const int kPageSize = 1 << kPageShift; -+ static const int kPageMask = kPageSize - 1; -+ static const int kLineShift = 2; // The cache line is only 4 bytes right now. -+ static const int kLineLength = 1 << kLineShift; -+ static const int kLineMask = kLineLength - 1; -+ -+ CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); } -+ -+ char* ValidityByte(int offset) { -+ return &validity_map_[offset >> kLineShift]; -+ } -+ -+ char* CachedData(int offset) { return &data_[offset]; } -+ -+ private: -+ char data_[kPageSize]; // The cached data. -+ static const int kValidityMapSize = kPageSize >> kLineShift; -+ char validity_map_[kValidityMapSize]; // One byte per line. -+}; -+ -+class SimInstructionBase : public InstructionBase { -+ public: -+ Type InstructionType() const { return type_; } -+ inline Instruction* instr() const { return instr_; } -+ inline int32_t operand() const { return operand_; } -+ -+ protected: -+ SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {} -+ explicit SimInstructionBase(Instruction* instr) {} -+ -+ int32_t operand_; -+ Instruction* instr_; -+ Type type_; -+ -+ private: -+ DISALLOW_ASSIGN(SimInstructionBase); -+}; -+ -+class SimInstruction : public InstructionGetters { -+ public: -+ SimInstruction() {} -+ -+ explicit SimInstruction(Instruction* instr) { *this = instr; } -+ -+ SimInstruction& operator=(Instruction* instr) { -+ operand_ = *reinterpret_cast(instr); -+ instr_ = instr; -+ type_ = InstructionBase::InstructionType(); -+ DCHECK(reinterpret_cast(&operand_) == this); -+ return *this; -+ } -+}; -+ -+class Simulator : public SimulatorBase { -+ public: -+ friend class RiscvDebugger; -+ -+ // Registers are declared in order. See SMRL chapter 2. -+ enum Register { -+ no_reg = -1, -+ zero_reg = 0, -+ ra, -+ sp, -+ gp, -+ tp, -+ t0, -+ t1, -+ t2, -+ s0, -+ s1, -+ a0, -+ a1, -+ a2, -+ a3, -+ a4, -+ a5, -+ a6, -+ a7, -+ s2, -+ s3, -+ s4, -+ s5, -+ s6, -+ s7, -+ s8, -+ s9, -+ s10, -+ s11, -+ t3, -+ t4, -+ t5, -+ t6, -+ pc, // pc must be the last register. -+ kNumSimuRegisters, -+ // aliases -+ fp = s0 -+ }; -+ -+ // Coprocessor registers. -+ // Generated code will always use doubles. So we will only use even registers. -+ enum FPURegister { -+ ft0, -+ ft1, -+ ft2, -+ ft3, -+ ft4, -+ ft5, -+ ft6, -+ ft7, -+ fs0, -+ fs1, -+ fa0, -+ fa1, -+ fa2, -+ fa3, -+ fa4, -+ fa5, -+ fa6, -+ fa7, -+ fs2, -+ fs3, -+ fs4, -+ fs5, -+ fs6, -+ fs7, -+ fs8, -+ fs9, -+ fs10, -+ fs11, -+ ft8, -+ ft9, -+ ft10, -+ ft11, -+ kNumFPURegisters -+ }; -+ -+ explicit Simulator(Isolate* isolate); -+ ~Simulator(); -+ -+ // The currently executing Simulator instance. Potentially there can be one -+ // for each native thread. -+ V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate); -+ -+ // Accessors for register state. Reading the pc value adheres to the RISC-V -+ // architecture specification and is off by a 8 from the currently executing -+ // instruction. -+ void set_register(int reg, int64_t value); -+ void set_register_word(int reg, int32_t value); -+ void set_dw_register(int dreg, const int* dbl); -+ int64_t get_register(int reg) const; -+ double get_double_from_register_pair(int reg); -+ -+ // Same for FPURegisters. -+ void set_fpu_register(int fpureg, int64_t value); -+ void set_fpu_register_word(int fpureg, int32_t value); -+ void set_fpu_register_hi_word(int fpureg, int32_t value); -+ void set_fpu_register_float(int fpureg, float value); -+ void set_fpu_register_double(int fpureg, double value); -+ -+ int64_t get_fpu_register(int fpureg) const; -+ int32_t get_fpu_register_word(int fpureg) const; -+ int32_t get_fpu_register_signed_word(int fpureg) const; -+ int32_t get_fpu_register_hi_word(int fpureg) const; -+ float get_fpu_register_float(int fpureg) const; -+ double get_fpu_register_double(int fpureg) const; -+ -+ // RV CSR manipulation -+ uint32_t read_csr_value(uint32_t csr); -+ void write_csr_value(uint32_t csr, uint64_t value); -+ void set_csr_bits(uint32_t csr, uint64_t flags); -+ void clear_csr_bits(uint32_t csr, uint64_t flags); -+ -+ void set_fflags(uint32_t flags) { set_csr_bits(csr_fflags, flags); } -+ void clear_fflags(int32_t flags) { clear_csr_bits(csr_fflags, flags); } -+ -+ inline uint32_t get_dynamic_rounding_mode(); -+ inline bool test_fflags_bits(uint32_t mask); -+ -+ float RoundF2FHelper(float input_val, int rmode); -+ double RoundF2FHelper(double input_val, int rmode); -+ template -+ I_TYPE RoundF2IHelper(F_TYPE original, int rmode); -+ -+ template -+ T FMaxMinHelper(T a, T b, MaxMinKind kind); -+ -+ template -+ bool CompareFHelper(T input1, T input2, FPUCondition cc); -+ -+ // Special case of set_register and get_register to access the raw PC value. -+ void set_pc(int64_t value); -+ int64_t get_pc() const; -+ -+ Address get_sp() const { return static_cast
(get_register(sp)); } -+ -+ // Accessor to the internal simulator stack area. -+ uintptr_t StackLimit(uintptr_t c_limit) const; -+ -+ // Executes RISC-V instructions until the PC reaches end_sim_pc. -+ void Execute(); -+ -+ template -+ Return Call(Address entry, Args... args) { -+ return VariadicCall(this, &Simulator::CallImpl, entry, args...); -+ } -+ -+ // Alternative: call a 2-argument double function. -+ double CallFP(Address entry, double d0, double d1); -+ -+ // Push an address onto the JS stack. -+ uintptr_t PushAddress(uintptr_t address); -+ -+ // Pop an address from the JS stack. -+ uintptr_t PopAddress(); -+ -+ // Debugger input. -+ void set_last_debugger_input(char* input); -+ char* last_debugger_input() { return last_debugger_input_; } -+ -+ // Redirection support. -+ static void SetRedirectInstruction(Instruction* instruction); -+ -+ // ICache checking. -+ static bool ICacheMatch(void* one, void* two); -+ static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start, -+ size_t size); -+ -+ // Returns true if pc register contains one of the 'special_values' defined -+ // below (bad_ra, end_sim_pc). -+ bool has_bad_pc() const; -+ -+ private: -+ enum special_values { -+ // Known bad pc value to ensure that the simulator does not execute -+ // without being properly setup. -+ bad_ra = -1, -+ // A pc value used to signal the simulator to stop execution. Generally -+ // the ra is set to this value on transition from native C code to -+ // simulated execution, so that the simulator can "return" to the native -+ // C code. -+ end_sim_pc = -2, -+ // Unpredictable value. -+ Unpredictable = 0xbadbeaf -+ }; -+ -+ V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count, -+ const intptr_t* arguments); -+ -+ // Unsupported instructions use Format to print an error and stop execution. -+ void Format(Instruction* instr, const char* format); -+ -+ // Helpers for data value tracing. -+ enum TraceType { -+ BYTE, -+ HALF, -+ WORD, -+ DWORD, -+ FLOAT, -+ DOUBLE, -+ // FLOAT_DOUBLE, -+ // WORD_DWORD -+ }; -+ -+ // RISCV Memory read/write methods -+ template -+ T ReadMem(int64_t addr, Instruction* instr); -+ template -+ void WriteMem(int64_t addr, T value, Instruction* instr); -+ template -+ T amo(int64_t addr, OP f, Instruction* instr, TraceType t) { -+ auto lhs = ReadMem(addr, instr); -+ // FIXME: trace memory read for AMO -+ WriteMem(addr, (T)f(lhs), instr); -+ return lhs; -+ } -+ -+ // Helper for debugging memory access. -+ inline void DieOrDebug(); -+ -+ void TraceRegWr(int64_t value, TraceType t = DWORD); -+ void TraceMemWr(int64_t addr, int64_t value, TraceType t); -+ template -+ void TraceMemRd(int64_t addr, T value, int64_t reg_value); -+ template -+ void TraceMemWr(int64_t addr, T value); -+ -+ SimInstruction instr_; -+ -+ // RISCV utlity API to access register value -+ inline int32_t rs1_reg() const { return instr_.Rs1Value(); } -+ inline int64_t rs1() const { return get_register(rs1_reg()); } -+ inline float frs1() const { return get_fpu_register_float(rs1_reg()); } -+ inline double drs1() const { return get_fpu_register_double(rs1_reg()); } -+ inline int32_t rs2_reg() const { return instr_.Rs2Value(); } -+ inline int64_t rs2() const { return get_register(rs2_reg()); } -+ inline float frs2() const { return get_fpu_register_float(rs2_reg()); } -+ inline double drs2() const { return get_fpu_register_double(rs2_reg()); } -+ inline int32_t rs3_reg() const { return instr_.Rs3Value(); } -+ inline int64_t rs3() const { return get_register(rs3_reg()); } -+ inline float frs3() const { return get_fpu_register_float(rs3_reg()); } -+ inline double drs3() const { return get_fpu_register_double(rs3_reg()); } -+ inline int32_t rd_reg() const { return instr_.RdValue(); } -+ inline int32_t frd_reg() const { return instr_.RdValue(); } -+ inline int16_t boffset() const { return instr_.BranchOffset(); } -+ inline int16_t imm12() const { return instr_.Imm12Value(); } -+ inline int32_t imm20J() const { return instr_.Imm20JValue(); } -+ inline int32_t imm5CSR() const { return instr_.Rs1Value(); } -+ inline int16_t csr_reg() const { return instr_.CsrValue(); } -+ -+ inline void set_rd(int64_t value, bool trace = true) { -+ set_register(rd_reg(), value); -+ if (trace) TraceRegWr(get_register(rd_reg()), DWORD); -+ } -+ inline void set_frd(float value, bool trace = true) { -+ set_fpu_register_float(rd_reg(), value); -+ if (trace) TraceRegWr(get_fpu_register_word(rd_reg()), FLOAT); -+ } -+ inline void set_drd(double value, bool trace = true) { -+ set_fpu_register_double(rd_reg(), value); -+ if (trace) TraceRegWr(get_fpu_register(rd_reg()), DOUBLE); -+ } -+ inline int16_t shamt() const { return (imm12() & 0x3F); } -+ inline int16_t shamt32() const { return (imm12() & 0x1F); } -+ inline int32_t s_imm12() const { return instr_.StoreOffset(); } -+ inline int32_t u_imm() const { return instr_.Imm20UValue() << 12; } -+ inline void require(bool check) { -+ if (!check) { -+ SignalException(kIllegalInstruction); -+ } -+ } -+ -+ template -+ inline T CanonicalizeFPUOp3(Func fn) { -+ DCHECK(std::is_floating_point::value); -+ T src1 = std::is_same::value ? frs1() : drs1(); -+ T src2 = std::is_same::value ? frs2() : drs2(); -+ T src3 = std::is_same::value ? frs3() : drs3(); -+ auto alu_out = fn(src1, src2, src3); -+ // if any input or result is NaN, the result is quiet_NaN -+ if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) || -+ std::isnan(src3)) { -+ // signaling_nan sets kInvalidOperation bit -+ if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(src3)) -+ set_fflags(kInvalidOperation); -+ alu_out = std::numeric_limits::quiet_NaN(); -+ } -+ return alu_out; -+ } -+ -+ template -+ inline T CanonicalizeFPUOp2(Func fn) { -+ DCHECK(std::is_floating_point::value); -+ T src1 = std::is_same::value ? frs1() : drs1(); -+ T src2 = std::is_same::value ? frs2() : drs2(); -+ auto alu_out = fn(src1, src2); -+ // if any input or result is NaN, the result is quiet_NaN -+ if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2)) { -+ // signaling_nan sets kInvalidOperation bit -+ if (isSnan(alu_out) || isSnan(src1) || isSnan(src2)) -+ set_fflags(kInvalidOperation); -+ alu_out = std::numeric_limits::quiet_NaN(); -+ } -+ return alu_out; -+ } -+ -+ template -+ inline T CanonicalizeFPUOp1(Func fn) { -+ DCHECK(std::is_floating_point::value); -+ T src1 = std::is_same::value ? frs1() : drs1(); -+ auto alu_out = fn(src1); -+ // if any input or result is NaN, the result is quiet_NaN -+ if (std::isnan(alu_out) || std::isnan(src1)) { -+ // signaling_nan sets kInvalidOperation bit -+ if (isSnan(alu_out) || isSnan(src1)) set_fflags(kInvalidOperation); -+ alu_out = std::numeric_limits::quiet_NaN(); -+ } -+ return alu_out; -+ } -+ -+ template -+ inline float CanonicalizeDoubleToFloatOperation(Func fn) { -+ float alu_out = fn(drs1()); -+ if (std::isnan(alu_out) || std::isnan(drs1())) -+ alu_out = std::numeric_limits::quiet_NaN(); -+ return alu_out; -+ } -+ -+ template -+ inline float CanonicalizeFloatToDoubleOperation(Func fn) { -+ double alu_out = fn(frs1()); -+ if (std::isnan(alu_out) || std::isnan(frs1())) -+ alu_out = std::numeric_limits::quiet_NaN(); -+ return alu_out; -+ } -+ -+ // RISCV decoding routine -+ void DecodeRVRType(); -+ void DecodeRVR4Type(); -+ void DecodeRVRFPType(); // Special routine for R/OP_FP type -+ void DecodeRVRAType(); // Special routine for R/AMO type -+ void DecodeRVIType(); -+ void DecodeRVSType(); -+ void DecodeRVBType(); -+ void DecodeRVUType(); -+ void DecodeRVJType(); -+ -+ // Used for breakpoints and traps. -+ void SoftwareInterrupt(); -+ -+ // Debug helpers -+ -+ // Simulator breakpoints. -+ struct Breakpoint { -+ Instruction* location; -+ bool enabled; -+ bool is_tbreak; -+ }; -+ std::vector breakpoints_; -+ void SetBreakpoint(Instruction* breakpoint, bool is_tbreak); -+ void ListBreakpoints(); -+ void CheckBreakpoints(); -+ -+ // Stop helper functions. -+ bool IsWatchpoint(uint64_t code); -+ void PrintWatchpoint(uint64_t code); -+ void HandleStop(uint64_t code); -+ bool IsStopInstruction(Instruction* instr); -+ bool IsEnabledStop(uint64_t code); -+ void EnableStop(uint64_t code); -+ void DisableStop(uint64_t code); -+ void IncreaseStopCounter(uint64_t code); -+ void PrintStopInfo(uint64_t code); -+ -+ // Executes one instruction. -+ void InstructionDecode(Instruction* instr); -+ -+ // ICache. -+ static void CheckICache(base::CustomMatcherHashMap* i_cache, -+ Instruction* instr); -+ static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start, -+ size_t size); -+ static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache, -+ void* page); -+ -+ enum Exception { -+ none, -+ kIntegerOverflow, -+ kIntegerUnderflow, -+ kDivideByZero, -+ kNumExceptions, -+ // RISCV illegual instruction exception -+ kIllegalInstruction, -+ }; -+ -+ // Exceptions. -+ void SignalException(Exception e); -+ -+ // Handle arguments and return value for runtime FP functions. -+ void GetFpArgs(double* x, double* y, int32_t* z); -+ void SetFpResult(const double& result); -+ -+ void CallInternal(Address entry); -+ -+ // Architecture state. -+ // Registers. -+ int64_t registers_[kNumSimuRegisters]; -+ // Coprocessor Registers. -+ int64_t FPUregisters_[kNumFPURegisters]; -+ // Floating-point control and status register. -+ uint32_t FCSR_; -+ -+ // Simulator support. -+ // Allocate 1MB for stack. -+ size_t stack_size_; -+ char* stack_; -+ bool pc_modified_; -+ int64_t icount_; -+ int break_count_; -+ EmbeddedVector trace_buf_; -+ -+ // Debugger input. -+ char* last_debugger_input_; -+ -+ v8::internal::Isolate* isolate_; -+ -+ // Stop is disabled if bit 31 is set. -+ static const uint32_t kStopDisabledBit = 1 << 31; -+ -+ // A stop is enabled, meaning the simulator will stop when meeting the -+ // instruction, if bit 31 of watched_stops_[code].count is unset. -+ // The value watched_stops_[code].count & ~(1 << 31) indicates how many times -+ // the breakpoint was hit or gone through. -+ struct StopCountAndDesc { -+ uint32_t count; -+ char* desc; -+ }; -+ StopCountAndDesc watched_stops_[kMaxStopCode + 1]; -+ -+ // Synchronization primitives. -+ enum class MonitorAccess { -+ Open, -+ RMW, -+ }; -+ -+ enum class TransactionSize { -+ None = 0, -+ Word = 4, -+ DoubleWord = 8, -+ }; -+ -+ // The least-significant bits of the address are ignored. The number of bits -+ // is implementation-defined, between 3 and minimum page size. -+ static const uintptr_t kExclusiveTaggedAddrMask = ~((1 << 3) - 1); -+ -+ class LocalMonitor { -+ public: -+ LocalMonitor(); -+ -+ // These functions manage the state machine for the local monitor, but do -+ // not actually perform loads and stores. NotifyStoreConditional only -+ // returns true if the store conditional is allowed; the global monitor will -+ // still have to be checked to see whether the memory should be updated. -+ void NotifyLoad(); -+ void NotifyLoadLinked(uintptr_t addr, TransactionSize size); -+ void NotifyStore(); -+ bool NotifyStoreConditional(uintptr_t addr, TransactionSize size); -+ -+ private: -+ void Clear(); -+ -+ MonitorAccess access_state_; -+ uintptr_t tagged_addr_; -+ TransactionSize size_; -+ }; -+ -+ class GlobalMonitor { -+ public: -+ class LinkedAddress { -+ public: -+ LinkedAddress(); -+ -+ private: -+ friend class GlobalMonitor; -+ // These functions manage the state machine for the global monitor, but do -+ // not actually perform loads and stores. -+ void Clear_Locked(); -+ void NotifyLoadLinked_Locked(uintptr_t addr); -+ void NotifyStore_Locked(); -+ bool NotifyStoreConditional_Locked(uintptr_t addr, -+ bool is_requesting_thread); -+ -+ MonitorAccess access_state_; -+ uintptr_t tagged_addr_; -+ LinkedAddress* next_; -+ LinkedAddress* prev_; -+ // A scd can fail due to background cache evictions. Rather than -+ // simulating this, we'll just occasionally introduce cases where an -+ // store conditional fails. This will happen once after every -+ // kMaxFailureCounter exclusive stores. -+ static const int kMaxFailureCounter = 5; -+ int failure_counter_; -+ }; -+ -+ // Exposed so it can be accessed by Simulator::{Read,Write}Ex*. -+ base::Mutex mutex; -+ -+ void NotifyLoadLinked_Locked(uintptr_t addr, LinkedAddress* linked_address); -+ void NotifyStore_Locked(LinkedAddress* linked_address); -+ bool NotifyStoreConditional_Locked(uintptr_t addr, -+ LinkedAddress* linked_address); -+ -+ // Called when the simulator is destroyed. -+ void RemoveLinkedAddress(LinkedAddress* linked_address); -+ -+ static GlobalMonitor* Get(); -+ -+ private: -+ // Private constructor. Call {GlobalMonitor::Get()} to get the singleton. -+ GlobalMonitor() = default; -+ friend class base::LeakyObject; -+ -+ bool IsProcessorInLinkedList_Locked(LinkedAddress* linked_address) const; -+ void PrependProcessor_Locked(LinkedAddress* linked_address); -+ -+ LinkedAddress* head_ = nullptr; -+ }; -+ -+ LocalMonitor local_monitor_; -+ GlobalMonitor::LinkedAddress global_monitor_thread_; -+}; -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // defined(USE_SIMULATOR) -+#endif // V8_EXECUTION_RISCV_SIMULATOR_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/simulator-base.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/execution/simulator-base.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/simulator-base.h -@@ -89,9 +89,10 @@ class SimulatorBase { - static typename std::enable_if::value, intptr_t>::type - ConvertArg(T arg) { - static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize"); --#if V8_TARGET_ARCH_MIPS64 -- // The MIPS64 calling convention is to sign extend all values, even unsigned -- // ones. -+#if V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_RISCV64 -+ // The MIPS64 and RISCV64 calling convention is to sign extend all values, -+ // even unsigned ones. -+ // FIXME (RISCV): what about RISCV calling contention? - using signed_t = typename std::make_signed::type; - return static_cast(static_cast(arg)); - #else -@@ -125,6 +126,7 @@ class SimulatorBase { - // - V8_TARGET_ARCH_PPC: svc (Supervisor Call) - // - V8_TARGET_ARCH_PPC64: svc (Supervisor Call) - // - V8_TARGET_ARCH_S390: svc (Supervisor Call) -+// - V8_TARGET_ARCH_RISCV64: ecall (Supervisor Call) - class Redirection { - public: - Redirection(Address external_function, ExternalReference::Type type); -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/simulator.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/execution/simulator.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/execution/simulator.h -@@ -26,6 +26,10 @@ - #include "src/execution/mips64/simulator-mips64.h" - #elif V8_TARGET_ARCH_S390 - #include "src/execution/s390/simulator-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/execution/riscv64/simulator-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/execution/riscv/simulator-riscv.h" - #else - #error Unsupported target architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/flags/flag-definitions.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/flags/flag-definitions.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/flags/flag-definitions.h -@@ -1182,6 +1182,7 @@ DEFINE_BOOL(partial_constant_pool, true, - DEFINE_STRING(sim_arm64_optional_features, "none", - "enable optional features on the simulator for testing: none or " - "all") -+DEFINE_BOOL(debug_riscv, false, "enable debug prints") - - // Controlling source positions for Torque/CSA code. - DEFINE_BOOL(enable_source_at_csa_bind, false, -@@ -1372,7 +1373,7 @@ DEFINE_BOOL(check_icache, false, - "Check icache flushes in ARM and MIPS simulator") - DEFINE_INT(stop_sim_at, 0, "Simulator stop after x number of instructions") - #if defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_MIPS64) || \ -- defined(V8_TARGET_ARCH_PPC64) -+ defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_RISCV64) - DEFINE_INT(sim_stack_alignment, 16, - "Stack alignment in bytes in simulator. This must be a power of two " - "and it must be at least 16. 16 is default.") -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/heap/base/asm/riscv64/push_registers_asm.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/heap/base/asm/riscv64/push_registers_asm.cc -@@ -0,0 +1,47 @@ -+// Copyright 2020 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. -+ -+// Push all callee-saved registers to get them on the stack for conservative -+// stack scanning. -+// -+// See asm/x64/push_registers_clang.cc for why the function is not generated -+// using clang. -+// -+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the -+// GN toolchain (e.g. ChromeOS) and not provide them. -+asm( -+ ".global PushAllRegistersAndIterateStack \n" -+ ".type PushAllRegistersAndIterateStack, %function \n" -+ ".hidden PushAllRegistersAndIterateStack \n" -+ "PushAllRegistersAndIterateStack: \n" -+ // Push all callee-saved registers and save return address. -+ " addi sp, sp, -96 \n" -+ " sd ra, 88(sp) \n" -+ " sd s8, 80(sp) \n" -+ " sd sp, 72(sp) \n" -+ " sd gp, 64(sp) \n" -+ " sd s7, 56(sp) \n" -+ " sd s6, 48(sp) \n" -+ " sd s5, 40(sp) \n" -+ " sd s4, 32(sp) \n" -+ " sd s3, 24(sp) \n" -+ " sd s2, 16(sp) \n" -+ " sd s1, 8(sp) \n" -+ " sd s0, 0(sp) \n" -+ // Maintain frame pointer. -+ " mv s8, sp \n" -+ // Pass 1st parameter (a0) unchanged (Stack*). -+ // Pass 2nd parameter (a1) unchanged (StackVisitor*). -+ // Save 3rd parameter (a2; IterateStackCallback). -+ " mv a3, a2 \n" -+ " mv a2, sp \n" -+ // Call the callback. -+ " jalr a3 \n" -+ // Load return address. -+ " ld ra, 88(sp) \n" -+ // Restore frame pointer. -+ " ld s8, 80(sp) \n" -+ " addi sp, sp, 96 \n" -+ " jr ra \n"); -+ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc -@@ -1348,7 +1348,8 @@ void InterpreterAssembler::TraceBytecode - - // static - bool InterpreterAssembler::TargetSupportsUnalignedAccess() { --#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -+#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_RISCV64 || \ -+ V8_TARGET_ARCH_RISCV - return false; - #elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_S390 || \ - V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC || \ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/libsampler/sampler.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/libsampler/sampler.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/libsampler/sampler.cc -@@ -442,6 +442,12 @@ void SignalHandler::FillRegisterState(vo - state->sp = reinterpret_cast(ucontext->uc_mcontext.gregs[15]); - state->fp = reinterpret_cast(ucontext->uc_mcontext.gregs[11]); - state->lr = reinterpret_cast(ucontext->uc_mcontext.gregs[14]); -+#elif V8_HOST_ARCH_RISCV64 || V8_HOST_ARCH_RISCV -+ // Spec CH.25 RISC-V Assembly Programmer’s Handbook -+ state->pc = reinterpret_cast(mcontext.__gregs[REG_PC]); -+ state->sp = reinterpret_cast(mcontext.__gregs[REG_SP]); -+ state->fp = reinterpret_cast(mcontext.__gregs[REG_S0]); -+ state->lr = reinterpret_cast(mcontext.__gregs[REG_RA]); - #endif // V8_HOST_ARCH_* - #elif V8_OS_IOS - -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/logging/log.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/logging/log.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/logging/log.cc -@@ -594,6 +594,14 @@ void LowLevelLogger::LogCodeInfo() { - const char arch[] = "arm64"; - #elif V8_TARGET_ARCH_S390 - const char arch[] = "s390"; -+#elif V8_TARGET_ARCH_RISCV64 -+ // FIXME (RISCV) porting: need more specific arch strings based on cpu -+ // features -+ const char arch[] = "riscv64"; -+#elif V8_TARGET_ARCH_RISCV -+ // FIXME (RISCV) porting: need more specific arch strings based on cpu -+ // features -+ const char arch[] = "riscv"; - #else - const char arch[] = "unknown"; - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/objects/backing-store.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/objects/backing-store.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/objects/backing-store.cc -@@ -29,7 +29,8 @@ constexpr bool kUseGuardRegions = true; - constexpr bool kUseGuardRegions = false; - #endif - --#if V8_TARGET_ARCH_MIPS64 -+#if V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_RISCV64 -+// FIXME(RISCV): Check this value - // MIPS64 has a user space of 2^40 bytes on most processors, - // address space limits needs to be smaller. - constexpr size_t kAddressSpaceLimit = 0x8000000000L; // 512 GiB -@@ -39,6 +40,10 @@ constexpr size_t kAddressSpaceLimit = 0x - constexpr size_t kAddressSpaceLimit = 0xC0000000; // 3 GiB - #endif - -+#if V8_TARGET_ARCH_RISCV -+#erro RISCV(32) architecture not supported -+#endif -+ - constexpr uint64_t kOneGiB = 1024 * 1024 * 1024; - constexpr uint64_t kNegativeGuardSize = 2 * kOneGiB; - -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/objects/code.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/objects/code.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/objects/code.cc -@@ -234,7 +234,7 @@ bool Code::IsIsolateIndependent(Isolate* - RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL))); - - #if defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_PPC64) || \ -- defined(V8_TARGET_ARCH_MIPS64) -+ defined(V8_TARGET_ARCH_MIPS64) || defined(V8_TARGET_ARCH_RISCV64) - return RelocIterator(*this, kModeMask).done(); - #elif defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \ - defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS) || \ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/objects/code.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/objects/code.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/objects/code.h -@@ -461,6 +461,10 @@ class Code : public HeapObject { - : (COMPRESS_POINTERS_BOOL ? 16 : 28); - #elif V8_TARGET_ARCH_S390X - static constexpr int kHeaderPaddingSize = COMPRESS_POINTERS_BOOL ? 16 : 28; -+#elif V8_TARGET_ARCH_RISCV64 -+ static constexpr int kHeaderPaddingSize = 28; -+#elif V8_TARGET_ARCH_RISCV -+#error riscv32 unsupported yet - #else - #error Unknown architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/profiler/tick-sample.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/profiler/tick-sample.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/profiler/tick-sample.cc -@@ -125,6 +125,13 @@ bool SimulatorHelper::FillRegisters(Isol - state->sp = reinterpret_cast(simulator->get_register(Simulator::sp)); - state->fp = reinterpret_cast(simulator->get_register(Simulator::fp)); - state->lr = reinterpret_cast(simulator->get_register(Simulator::ra)); -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+ if (!simulator->has_bad_pc()) { -+ state->pc = reinterpret_cast(simulator->get_pc()); -+ } -+ state->sp = reinterpret_cast(simulator->get_register(Simulator::sp)); -+ state->fp = reinterpret_cast(simulator->get_register(Simulator::fp)); -+ state->lr = reinterpret_cast(simulator->get_register(Simulator::ra)); - #endif - if (state->sp == 0 || state->fp == 0) { - // It possible that the simulator is interrupted while it is updating -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/regexp-macro-assembler-arch.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/regexp/regexp-macro-assembler-arch.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/regexp-macro-assembler-arch.h -@@ -23,6 +23,10 @@ - #include "src/regexp/mips64/regexp-macro-assembler-mips64.h" - #elif V8_TARGET_ARCH_S390 - #include "src/regexp/s390/regexp-macro-assembler-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/regexp/riscv64/regexp-macro-assembler-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/regexp/riscv/regexp-macro-assembler-riscv.h" - #else - #error Unsupported target architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/regexp-macro-assembler.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/regexp/regexp-macro-assembler.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/regexp-macro-assembler.h -@@ -44,6 +44,7 @@ class RegExpMacroAssembler { - kARMImplementation, - kARM64Implementation, - kMIPSImplementation, -+ kRISCVImplementation, - kS390Implementation, - kPPCImplementation, - kX64Implementation, -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/regexp.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/regexp/regexp.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/regexp.cc -@@ -815,6 +815,9 @@ bool RegExpImpl::Compile(Isolate* isolat - #elif V8_TARGET_ARCH_MIPS64 - macro_assembler.reset(new RegExpMacroAssemblerMIPS(isolate, zone, mode, - output_register_count)); -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+ macro_assembler.reset(new RegExpMacroAssemblerRISCV(isolate, zone, mode, -+ output_register_count)); - #else - #error "Unsupported architecture" - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/riscv64/regexp-macro-assembler-riscv64.cc -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/riscv64/regexp-macro-assembler-riscv64.cc -@@ -0,0 +1,1265 @@ -+// Copyright 2012 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. -+ -+#if V8_TARGET_ARCH_RISCV64 -+ -+#include "src/regexp/riscv64/regexp-macro-assembler-riscv64.h" -+ -+#include "src/codegen/assembler-inl.h" -+#include "src/codegen/macro-assembler.h" -+#include "src/logging/log.h" -+#include "src/objects/objects-inl.h" -+#include "src/regexp/regexp-macro-assembler.h" -+#include "src/regexp/regexp-stack.h" -+#include "src/snapshot/embedded/embedded-data.h" -+#include "src/strings/unicode.h" -+ -+namespace v8 { -+namespace internal { -+ -+/* clang-format off -+ * -+ * This assembler uses the following register assignment convention -+ * - t4 : Temporarily stores the index of capture start after a matching pass -+ * for a global regexp. -+ * - s4 : Pointer to current Code object including heap object tag. -+ * - s1 : Current position in input, as negative offset from end of string. -+ * Please notice that this is the byte offset, not the character offset! -+ * - s2 : Currently loaded character. Must be loaded using -+ * LoadCurrentCharacter before using any of the dispatch methods. -+ * - t0 : Points to tip of backtrack stack -+ * - t1 : Unused. -+ * - t2 : End of input (points to byte after last character in input). -+ * - fp : Frame pointer. Used to access arguments, local variables and -+ * RegExp registers. -+ * - sp : Points to tip of C stack. -+ * -+ * The remaining registers are free for computations. -+ * Each call to a public method should retain this convention. -+ * -+ * The stack will have the following structure: -+ * FIXME(RISCV): Verify that this stack description is correct -+ * -+ * - fp[80] Isolate* isolate (address of the current isolate) kIsolate -+ * kStackFrameHeader -+ * --- sp when called --- -+ * - fp[72] ra Return from RegExp code (ra). kReturnAddress -+ * - fp[64] s9, old-fp Old fp, callee saved(s9). -+ * - fp[0..63] fp..s7 Callee-saved registers fp..s7. -+ * --- frame pointer ---- -+ * - fp[-8] direct_call (1 = direct call from JS, 0 = from runtime) kDirectCall -+ * - fp[-16] stack_base (Top of backtracking stack). kStackHighEnd -+ * - fp[-24] capture array size (may fit multiple sets of matches) kNumOutputRegisters -+ * - fp[-32] int* capture_array (int[num_saved_registers_], for output). kRegisterOutput -+ * - fp[-40] end of input (address of end of string). kInputEnd -+ * - fp[-48] start of input (address of first character in string). kInputStart -+ * - fp[-56] start index (character index of start). kStartIndex -+ * - fp[-64] void* input_string (location of a handle containing the string). kInputString -+ * - fp[-72] success counter (only for global regexps to count matches). kSuccessfulCaptures -+ * - fp[-80] Offset of location before start of input (effectively character kStringStartMinusOne -+ * position -1). Used to initialize capture registers to a -+ * non-position. -+ * --------- The following output registers are 32-bit values. --------- -+ * - fp[-88] register 0 (Only positions must be stored in the first kRegisterZero -+ * - register 1 num_saved_registers_ registers) -+ * - ... -+ * - register num_registers-1 -+ * --- sp --- -+ * -+ * The first num_saved_registers_ registers are initialized to point to -+ * "character -1" in the string (i.e., char_size() bytes before the first -+ * character of the string). The remaining registers start out as garbage. -+ * -+ * The data up to the return address must be placed there by the calling -+ * code and the remaining arguments are passed in registers, e.g. by calling the -+ * code entry as cast to a function with the signature: -+ * int (*match)(String input_string, -+ * int start_index, -+ * Address start, -+ * Address end, -+ * int* capture_output_array, -+ * int num_capture_registers, -+ * byte* stack_area_base, -+ * bool direct_call = false, -+ * Isolate* isolate); -+ * The call is performed by NativeRegExpMacroAssembler::Execute() -+ * (in regexp-macro-assembler.cc) via the GeneratedCode wrapper. -+ * -+ * clang-format on -+ */ -+ -+#define __ ACCESS_MASM(masm_) -+ -+const int RegExpMacroAssemblerRISCV::kRegExpCodeSize; -+ -+RegExpMacroAssemblerRISCV::RegExpMacroAssemblerRISCV(Isolate* isolate, -+ Zone* zone, Mode mode, -+ int registers_to_save) -+ : NativeRegExpMacroAssembler(isolate, zone), -+ masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, -+ NewAssemblerBuffer(kRegExpCodeSize))), -+ mode_(mode), -+ num_registers_(registers_to_save), -+ num_saved_registers_(registers_to_save), -+ entry_label_(), -+ start_label_(), -+ success_label_(), -+ backtrack_label_(), -+ exit_label_(), -+ internal_failure_label_() { -+ masm_->set_root_array_available(false); -+ -+ DCHECK_EQ(0, registers_to_save % 2); -+ __ jmp(&entry_label_); // We'll write the entry code later. -+ // If the code gets too big or corrupted, an internal exception will be -+ // raised, and we will exit right away. -+ __ bind(&internal_failure_label_); -+ __ li(a0, Operand(FAILURE)); -+ __ Ret(); -+ __ bind(&start_label_); // And then continue from here. -+} -+ -+RegExpMacroAssemblerRISCV::~RegExpMacroAssemblerRISCV() { -+ delete masm_; -+ // Unuse labels in case we throw away the assembler without calling GetCode. -+ entry_label_.Unuse(); -+ start_label_.Unuse(); -+ success_label_.Unuse(); -+ backtrack_label_.Unuse(); -+ exit_label_.Unuse(); -+ check_preempt_label_.Unuse(); -+ stack_overflow_label_.Unuse(); -+ internal_failure_label_.Unuse(); -+} -+ -+int RegExpMacroAssemblerRISCV::stack_limit_slack() { -+ return RegExpStack::kStackLimitSlack; -+} -+ -+void RegExpMacroAssemblerRISCV::AdvanceCurrentPosition(int by) { -+ if (by != 0) { -+ __ Add64(current_input_offset(), current_input_offset(), -+ Operand(by * char_size())); -+ } -+} -+ -+void RegExpMacroAssemblerRISCV::AdvanceRegister(int reg, int by) { -+ DCHECK_LE(0, reg); -+ DCHECK_GT(num_registers_, reg); -+ if (by != 0) { -+ __ Ld(a0, register_location(reg)); -+ __ Add64(a0, a0, Operand(by)); -+ __ Sd(a0, register_location(reg)); -+ } -+} -+ -+void RegExpMacroAssemblerRISCV::Backtrack() { -+ CheckPreemption(); -+ if (has_backtrack_limit()) { -+ Label next; -+ __ Ld(a0, MemOperand(frame_pointer(), kBacktrackCount)); -+ __ Add64(a0, a0, Operand(1)); -+ __ Sd(a0, MemOperand(frame_pointer(), kBacktrackCount)); -+ __ Branch(&next, ne, a0, Operand(backtrack_limit())); -+ -+ // Exceeded limits are treated as a failed match. -+ Fail(); -+ -+ __ bind(&next); -+ } -+ // Pop Code offset from backtrack stack, add Code and jump to location. -+ Pop(a0); -+ __ Add64(a0, a0, code_pointer()); -+ __ Jump(a0); -+} -+ -+void RegExpMacroAssemblerRISCV::Bind(Label* label) { __ bind(label); } -+ -+void RegExpMacroAssemblerRISCV::CheckCharacter(uint32_t c, Label* on_equal) { -+ BranchOrBacktrack(on_equal, eq, current_character(), Operand(c)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckCharacterGT(uc16 limit, -+ Label* on_greater) { -+ BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckAtStart(int cp_offset, -+ Label* on_at_start) { -+ __ Ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ __ Add64(a0, current_input_offset(), -+ Operand(-char_size() + cp_offset * char_size())); -+ BranchOrBacktrack(on_at_start, eq, a0, Operand(a1)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckNotAtStart(int cp_offset, -+ Label* on_not_at_start) { -+ __ Ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ __ Add64(a0, current_input_offset(), -+ Operand(-char_size() + cp_offset * char_size())); -+ BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckCharacterLT(uc16 limit, Label* on_less) { -+ BranchOrBacktrack(on_less, lt, current_character(), Operand(limit)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckGreedyLoop(Label* on_equal) { -+ Label backtrack_non_equal; -+ __ Lw(a0, MemOperand(backtrack_stackpointer(), 0)); -+ __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0)); -+ __ Add64(backtrack_stackpointer(), backtrack_stackpointer(), -+ Operand(kIntSize)); -+ __ bind(&backtrack_non_equal); -+ BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckNotBackReferenceIgnoreCase( -+ int start_reg, bool read_backward, bool unicode, Label* on_no_match) { -+ Label fallthrough; -+ __ Ld(a0, register_location(start_reg)); // Index of start of capture. -+ __ Ld(a1, register_location(start_reg + 1)); // Index of end of capture. -+ __ Sub64(a1, a1, a0); // Length of capture. -+ -+ // At this point, the capture registers are either both set or both cleared. -+ // If the capture length is zero, then the capture is either empty or cleared. -+ // Fall through in both cases. -+ __ Branch(&fallthrough, eq, a1, Operand(zero_reg)); -+ -+ if (read_backward) { -+ __ Ld(t1, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ __ Add64(t1, t1, a1); -+ BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1)); -+ } else { -+ __ Add64(t1, a1, current_input_offset()); -+ // Check that there are enough characters left in the input. -+ BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg)); -+ } -+ -+ if (mode_ == LATIN1) { -+ Label success; -+ Label fail; -+ Label loop_check; -+ -+ // a0 - offset of start of capture. -+ // a1 - length of capture. -+ __ Add64(a0, a0, Operand(end_of_input_address())); -+ __ Add64(a2, end_of_input_address(), Operand(current_input_offset())); -+ if (read_backward) { -+ __ Sub64(a2, a2, Operand(a1)); -+ } -+ __ Add64(a1, a0, Operand(a1)); -+ -+ // a0 - Address of start of capture. -+ // a1 - Address of end of capture. -+ // a2 - Address of current input position. -+ -+ Label loop; -+ __ bind(&loop); -+ __ Lbu(a3, MemOperand(a0, 0)); -+ __ addi(a0, a0, char_size()); -+ __ Lbu(a4, MemOperand(a2, 0)); -+ __ addi(a2, a2, char_size()); -+ -+ __ Branch(&loop_check, eq, a4, Operand(a3)); -+ -+ // Mismatch, try case-insensitive match (converting letters to lower-case). -+ __ Or(a3, a3, Operand(0x20)); // Convert capture character to lower-case. -+ __ Or(a4, a4, Operand(0x20)); // Also convert input character. -+ __ Branch(&fail, ne, a4, Operand(a3)); -+ __ Sub64(a3, a3, Operand('a')); -+ __ Branch(&loop_check, Uless_equal, a3, Operand('z' - 'a')); -+ // Latin-1: Check for values in range [224,254] but not 247. -+ __ Sub64(a3, a3, Operand(224 - 'a')); -+ // Weren't Latin-1 letters. -+ __ Branch(&fail, Ugreater, a3, Operand(254 - 224)); -+ // Check for 247. -+ __ Branch(&fail, eq, a3, Operand(247 - 224)); -+ -+ __ bind(&loop_check); -+ __ Branch(&loop, lt, a0, Operand(a1)); -+ __ jmp(&success); -+ -+ __ bind(&fail); -+ GoTo(on_no_match); -+ -+ __ bind(&success); -+ // Compute new value of character position after the matched part. -+ __ Sub64(current_input_offset(), a2, end_of_input_address()); -+ if (read_backward) { -+ __ Ld(t1, register_location(start_reg)); // Index of start of capture. -+ __ Ld(a2, register_location(start_reg + 1)); // Index of end of capture. -+ __ Add64(current_input_offset(), current_input_offset(), Operand(t1)); -+ __ Sub64(current_input_offset(), current_input_offset(), Operand(a2)); -+ } -+ } else { -+ DCHECK(mode_ == UC16); -+ // Put regexp engine registers on stack. -+ RegList regexp_registers_to_retain = current_input_offset().bit() | -+ current_character().bit() | -+ backtrack_stackpointer().bit(); -+ __ MultiPush(regexp_registers_to_retain); -+ -+ int argument_count = 4; -+ __ PrepareCallCFunction(argument_count, a2); -+ -+ // a0 - offset of start of capture. -+ // a1 - length of capture. -+ -+ // Put arguments into arguments registers. -+ // Parameters are -+ // a0: Address byte_offset1 - Address captured substring's start. -+ // a1: Address byte_offset2 - Address of current character position. -+ // a2: size_t byte_length - length of capture in bytes(!). -+ // a3: Isolate* isolate. -+ -+ // Address of start of capture. -+ __ Add64(a0, a0, Operand(end_of_input_address())); -+ // Length of capture. -+ __ mv(a2, a1); -+ // Save length in callee-save register for use on return. -+ __ mv(s3, a1); -+ // Address of current input position. -+ __ Add64(a1, current_input_offset(), Operand(end_of_input_address())); -+ if (read_backward) { -+ __ Sub64(a1, a1, Operand(s3)); -+ } -+ // Isolate. -+ __ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate()))); -+ -+ { -+ AllowExternalCallThatCantCauseGC scope(masm_); -+ ExternalReference function = -+ unicode ? ExternalReference::re_case_insensitive_compare_unicode( -+ isolate()) -+ : ExternalReference::re_case_insensitive_compare_non_unicode( -+ isolate()); -+ __ CallCFunction(function, argument_count); -+ } -+ -+ // Restore regexp engine registers. -+ __ MultiPop(regexp_registers_to_retain); -+ __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); -+ __ Ld(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); -+ -+ // Check if function returned non-zero for success or zero for failure. -+ BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg)); -+ // On success, increment position by length of capture. -+ if (read_backward) { -+ __ Sub64(current_input_offset(), current_input_offset(), Operand(s3)); -+ } else { -+ __ Add64(current_input_offset(), current_input_offset(), Operand(s3)); -+ } -+ } -+ -+ __ bind(&fallthrough); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckNotBackReference(int start_reg, -+ bool read_backward, -+ Label* on_no_match) { -+ Label fallthrough; -+ -+ // Find length of back-referenced capture. -+ __ Ld(a0, register_location(start_reg)); -+ __ Ld(a1, register_location(start_reg + 1)); -+ __ Sub64(a1, a1, a0); // Length to check. -+ -+ // At this point, the capture registers are either both set or both cleared. -+ // If the capture length is zero, then the capture is either empty or cleared. -+ // Fall through in both cases. -+ __ Branch(&fallthrough, eq, a1, Operand(zero_reg)); -+ -+ if (read_backward) { -+ __ Ld(t1, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ __ Add64(t1, t1, a1); -+ BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1)); -+ } else { -+ __ Add64(t1, a1, current_input_offset()); -+ // Check that there are enough characters left in the input. -+ BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg)); -+ } -+ -+ // Compute pointers to match string and capture string. -+ __ Add64(a0, a0, Operand(end_of_input_address())); -+ __ Add64(a2, end_of_input_address(), Operand(current_input_offset())); -+ if (read_backward) { -+ __ Sub64(a2, a2, Operand(a1)); -+ } -+ __ Add64(a1, a1, Operand(a0)); -+ -+ Label loop; -+ __ bind(&loop); -+ if (mode_ == LATIN1) { -+ __ Lbu(a3, MemOperand(a0, 0)); -+ __ addi(a0, a0, char_size()); -+ __ Lbu(a4, MemOperand(a2, 0)); -+ __ addi(a2, a2, char_size()); -+ } else { -+ DCHECK(mode_ == UC16); -+ __ Lhu(a3, MemOperand(a0, 0)); -+ __ addi(a0, a0, char_size()); -+ __ Lhu(a4, MemOperand(a2, 0)); -+ __ addi(a2, a2, char_size()); -+ } -+ BranchOrBacktrack(on_no_match, ne, a3, Operand(a4)); -+ __ Branch(&loop, lt, a0, Operand(a1)); -+ -+ // Move current character position to position after match. -+ __ Sub64(current_input_offset(), a2, end_of_input_address()); -+ if (read_backward) { -+ __ Ld(t1, register_location(start_reg)); // Index of start of capture. -+ __ Ld(a2, register_location(start_reg + 1)); // Index of end of capture. -+ __ Add64(current_input_offset(), current_input_offset(), Operand(t1)); -+ __ Sub64(current_input_offset(), current_input_offset(), Operand(a2)); -+ } -+ __ bind(&fallthrough); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckNotCharacter(uint32_t c, -+ Label* on_not_equal) { -+ BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckCharacterAfterAnd(uint32_t c, -+ uint32_t mask, -+ Label* on_equal) { -+ __ And(a0, current_character(), Operand(mask)); -+ Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c); -+ BranchOrBacktrack(on_equal, eq, a0, rhs); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckNotCharacterAfterAnd(uint32_t c, -+ uint32_t mask, -+ Label* on_not_equal) { -+ __ And(a0, current_character(), Operand(mask)); -+ Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c); -+ BranchOrBacktrack(on_not_equal, ne, a0, rhs); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckNotCharacterAfterMinusAnd( -+ uc16 c, uc16 minus, uc16 mask, Label* on_not_equal) { -+ DCHECK_GT(String::kMaxUtf16CodeUnit, minus); -+ __ Sub64(a0, current_character(), Operand(minus)); -+ __ And(a0, a0, Operand(mask)); -+ BranchOrBacktrack(on_not_equal, ne, a0, Operand(c)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckCharacterInRange(uc16 from, uc16 to, -+ Label* on_in_range) { -+ __ Sub64(a0, current_character(), Operand(from)); -+ // Unsigned lower-or-same condition. -+ BranchOrBacktrack(on_in_range, Uless_equal, a0, Operand(to - from)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckCharacterNotInRange( -+ uc16 from, uc16 to, Label* on_not_in_range) { -+ __ Sub64(a0, current_character(), Operand(from)); -+ // Unsigned higher condition. -+ BranchOrBacktrack(on_not_in_range, Ugreater, a0, Operand(to - from)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckBitInTable(Handle table, -+ Label* on_bit_set) { -+ __ li(a0, Operand(table)); -+ if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) { -+ __ And(a1, current_character(), Operand(kTableSize - 1)); -+ __ Add64(a0, a0, a1); -+ } else { -+ __ Add64(a0, a0, current_character()); -+ } -+ -+ __ Lbu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize)); -+ BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg)); -+} -+ -+bool RegExpMacroAssemblerRISCV::CheckSpecialCharacterClass(uc16 type, -+ Label* on_no_match) { -+ // Range checks (c in min..max) are generally implemented by an unsigned -+ // (c - min) <= (max - min) check. -+ switch (type) { -+ case 's': -+ // Match space-characters. -+ if (mode_ == LATIN1) { -+ // One byte space characters are '\t'..'\r', ' ' and \u00a0. -+ Label success; -+ __ Branch(&success, eq, current_character(), Operand(' ')); -+ // Check range 0x09..0x0D. -+ __ Sub64(a0, current_character(), Operand('\t')); -+ __ Branch(&success, Uless_equal, a0, Operand('\r' - '\t')); -+ // \u00a0 (NBSP). -+ BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00A0 - '\t')); -+ __ bind(&success); -+ return true; -+ } -+ return false; -+ case 'S': -+ // The emitted code for generic character classes is good enough. -+ return false; -+ case 'd': -+ // Match Latin1 digits ('0'..'9'). -+ __ Sub64(a0, current_character(), Operand('0')); -+ BranchOrBacktrack(on_no_match, Ugreater, a0, Operand('9' - '0')); -+ return true; -+ case 'D': -+ // Match non Latin1-digits. -+ __ Sub64(a0, current_character(), Operand('0')); -+ BranchOrBacktrack(on_no_match, Uless_equal, a0, Operand('9' - '0')); -+ return true; -+ case '.': { -+ // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029). -+ __ Xor(a0, current_character(), Operand(0x01)); -+ // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C. -+ __ Sub64(a0, a0, Operand(0x0B)); -+ BranchOrBacktrack(on_no_match, Uless_equal, a0, Operand(0x0C - 0x0B)); -+ if (mode_ == UC16) { -+ // Compare original value to 0x2028 and 0x2029, using the already -+ // computed (current_char ^ 0x01 - 0x0B). I.e., check for -+ // 0x201D (0x2028 - 0x0B) or 0x201E. -+ __ Sub64(a0, a0, Operand(0x2028 - 0x0B)); -+ BranchOrBacktrack(on_no_match, Uless_equal, a0, Operand(1)); -+ } -+ return true; -+ } -+ case 'n': { -+ // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029). -+ __ Xor(a0, current_character(), Operand(0x01)); -+ // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C. -+ __ Sub64(a0, a0, Operand(0x0B)); -+ if (mode_ == LATIN1) { -+ BranchOrBacktrack(on_no_match, Ugreater, a0, Operand(0x0C - 0x0B)); -+ } else { -+ Label done; -+ BranchOrBacktrack(&done, Uless_equal, a0, Operand(0x0C - 0x0B)); -+ // Compare original value to 0x2028 and 0x2029, using the already -+ // computed (current_char ^ 0x01 - 0x0B). I.e., check for -+ // 0x201D (0x2028 - 0x0B) or 0x201E. -+ __ Sub64(a0, a0, Operand(0x2028 - 0x0B)); -+ BranchOrBacktrack(on_no_match, Ugreater, a0, Operand(1)); -+ __ bind(&done); -+ } -+ return true; -+ } -+ case 'w': { -+ if (mode_ != LATIN1) { -+ // Table is 256 entries, so all Latin1 characters can be tested. -+ BranchOrBacktrack(on_no_match, Ugreater, current_character(), -+ Operand('z')); -+ } -+ ExternalReference map = -+ ExternalReference::re_word_character_map(isolate()); -+ __ li(a0, Operand(map)); -+ __ Add64(a0, a0, current_character()); -+ __ Lbu(a0, MemOperand(a0, 0)); -+ BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg)); -+ return true; -+ } -+ case 'W': { -+ Label done; -+ if (mode_ != LATIN1) { -+ // Table is 256 entries, so all Latin1 characters can be tested. -+ __ Branch(&done, Ugreater, current_character(), Operand('z')); -+ } -+ ExternalReference map = -+ ExternalReference::re_word_character_map(isolate()); -+ __ li(a0, Operand(map)); -+ __ Add64(a0, a0, current_character()); -+ __ Lbu(a0, MemOperand(a0, 0)); -+ BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg)); -+ if (mode_ != LATIN1) { -+ __ bind(&done); -+ } -+ return true; -+ } -+ case '*': -+ // Match any character. -+ return true; -+ // No custom implementation (yet): s(UC16), S(UC16). -+ default: -+ return false; -+ } -+} -+ -+void RegExpMacroAssemblerRISCV::Fail() { -+ __ li(a0, Operand(FAILURE)); -+ __ jmp(&exit_label_); -+} -+ -+Handle RegExpMacroAssemblerRISCV::GetCode(Handle source) { -+ Label return_a0; -+ if (masm_->has_exception()) { -+ // If the code gets corrupted due to long regular expressions and lack of -+ // space on trampolines, an internal exception flag is set. If this case -+ // is detected, we will jump into exit sequence right away. -+ __ bind_to(&entry_label_, internal_failure_label_.pos()); -+ } else { -+ // Finalize code - write the entry point code now we know how many -+ // registers we need. -+ -+ // Entry code: -+ __ bind(&entry_label_); -+ -+ // Tell the system that we have a stack frame. Because the type is MANUAL, -+ // no is generated. -+ FrameScope scope(masm_, StackFrame::MANUAL); -+ -+ // Actually emit code to start a new stack frame. -+ // Push arguments -+ // Save callee-save registers. -+ // Start new stack frame. -+ // Store link register in existing stack-cell. -+ // Order here should correspond to order of offset constants in header file. -+ // TODO(plind): we save fp..s11, but ONLY use s3 here - use the regs -+ // or dont save. -+ // -+ // FIXME (RISCV): how about saving only s*registers that are actually used? -+ RegList registers_to_retain = -+ fp.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | -+ s6.bit() | s7.bit() | s8.bit() /*| s9.bit() | s10.bit() | s11.bit()*/; -+ DCHECK(NumRegs(registers_to_retain) == kNumCalleeRegsToRetain); -+ -+ // The remaining arguments are passed in registers, e.g.by calling the code -+ // entry as cast to a function with the signature: -+ // -+ // *int(*match)(String input_string, // a0 -+ // int start_index, // a1 -+ // Address start, // a2 -+ // Address end, // a3 -+ // int*capture_output_array, // a4 -+ // int num_capture_registers, // a5 -+ // byte* stack_area_base, // a6 -+ // bool direct_call = false, // a7 -+ // Isolate * isolate); // on the stack -+ RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit() | -+ a4.bit() | a5.bit() | a6.bit() | a7.bit(); -+ -+ // According to MultiPush implementation, registers will be pushed in the -+ // order of ra, fp, then s8, ..., s1, and finally a7,...a0 -+ __ MultiPush(ra.bit() | registers_to_retain | argument_registers); -+ -+ // Set frame pointer in space for it if this is not a direct call -+ // from generated code. -+ __ Add64(frame_pointer(), sp, -+ Operand(NumRegs(argument_registers) * kPointerSize)); -+ -+ STATIC_ASSERT(kSuccessfulCaptures == kInputString - kSystemPointerSize); -+ __ mv(a0, zero_reg); -+ __ push(a0); // Make room for success counter and initialize it to 0. -+ STATIC_ASSERT(kStringStartMinusOne == -+ kSuccessfulCaptures - kSystemPointerSize); -+ __ push(a0); // Make room for "string start - 1" constant. -+ STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); -+ __ push(a0); // The backtrack counter -+ -+ // Check if we have space on the stack for registers. -+ Label stack_limit_hit; -+ Label stack_ok; -+ -+ ExternalReference stack_limit = -+ ExternalReference::address_of_jslimit(masm_->isolate()); -+ __ li(a0, Operand(stack_limit)); -+ __ Ld(a0, MemOperand(a0)); -+ __ Sub64(a0, sp, a0); -+ Operand extra_space_for_variables(num_registers_ * kPointerSize); -+ -+ // Handle it if the stack pointer is already below the stack limit. -+ __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg)); -+ // Check if there is room for the variable number of registers above -+ // the stack limit. -+ __ Branch(&stack_ok, Ugreater_equal, a0, extra_space_for_variables); -+ // Exit with OutOfMemory exception. There is not enough space on the stack -+ // for our working registers. -+ __ li(a0, Operand(EXCEPTION)); -+ __ jmp(&return_a0); -+ -+ __ bind(&stack_limit_hit); -+ CallCheckStackGuardState(a0, extra_space_for_variables); -+ // If returned value is non-zero, we exit with the returned value as result. -+ __ Branch(&return_a0, ne, a0, Operand(zero_reg)); -+ -+ __ bind(&stack_ok); -+ // Allocate space on stack for registers. -+ __ Sub64(sp, sp, Operand(num_registers_ * kPointerSize)); -+ // Load string end. -+ __ Ld(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); -+ // Load input start. -+ __ Ld(a0, MemOperand(frame_pointer(), kInputStart)); -+ // Find negative length (offset of start relative to end). -+ __ Sub64(current_input_offset(), a0, end_of_input_address()); -+ // Set a0 to address of char before start of the input string -+ // (effectively string position -1). -+ __ Ld(a1, MemOperand(frame_pointer(), kStartIndex)); -+ __ Sub64(a0, current_input_offset(), Operand(char_size())); -+ __ slli(t1, a1, (mode_ == UC16) ? 1 : 0); -+ __ Sub64(a0, a0, t1); -+ // Store this value in a local variable, for use when clearing -+ // position registers. -+ __ Sd(a0, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ -+ // Initialize code pointer register -+ __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); -+ -+ Label load_char_start_regexp, start_regexp; -+ // Load newline if index is at start, previous character otherwise. -+ __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg)); -+ __ li(current_character(), Operand('\n')); -+ __ jmp(&start_regexp); -+ -+ // Global regexp restarts matching here. -+ __ bind(&load_char_start_regexp); -+ // Load previous char as initial value of current character register. -+ LoadCurrentCharacterUnchecked(-1, 1); -+ __ bind(&start_regexp); -+ -+ // Initialize on-stack registers. -+ if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. -+ // Fill saved registers with initial value = start offset - 1. -+ if (num_saved_registers_ > 8) { -+ // Address of register 0. -+ __ Add64(a1, frame_pointer(), Operand(kRegisterZero)); -+ __ li(a2, Operand(num_saved_registers_)); -+ Label init_loop; -+ __ bind(&init_loop); -+ __ Sd(a0, MemOperand(a1)); -+ __ Add64(a1, a1, Operand(-kPointerSize)); -+ __ Sub64(a2, a2, Operand(1)); -+ __ Branch(&init_loop, ne, a2, Operand(zero_reg)); -+ } else { -+ for (int i = 0; i < num_saved_registers_; i++) { -+ __ Sd(a0, register_location(i)); -+ } -+ } -+ } -+ -+ // Initialize backtrack stack pointer. -+ __ Ld(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); -+ -+ __ jmp(&start_label_); -+ -+ // Exit code: -+ if (success_label_.is_linked()) { -+ // Save captures when successful. -+ __ bind(&success_label_); -+ if (num_saved_registers_ > 0) { -+ // Copy captures to output. -+ __ Ld(a1, MemOperand(frame_pointer(), kInputStart)); -+ __ Ld(a0, MemOperand(frame_pointer(), kRegisterOutput)); -+ __ Ld(a2, MemOperand(frame_pointer(), kStartIndex)); -+ __ Sub64(a1, end_of_input_address(), a1); -+ // a1 is length of input in bytes. -+ if (mode_ == UC16) { -+ __ srli(a1, a1, 1); -+ } -+ // a1 is length of input in characters. -+ __ Add64(a1, a1, Operand(a2)); -+ // a1 is length of string in characters. -+ -+ DCHECK_EQ(0, num_saved_registers_ % 2); -+ // Always an even number of capture registers. This allows us to -+ // unroll the loop once to add an operation between a load of a register -+ // and the following use of that register. -+ for (int i = 0; i < num_saved_registers_; i += 2) { -+ __ Ld(a2, register_location(i)); -+ __ Ld(a3, register_location(i + 1)); -+ if (i == 0 && global_with_zero_length_check()) { -+ // Keep capture start in a4 for the zero-length check later. -+ __ mv(t4, a2); -+ } -+ if (mode_ == UC16) { -+ __ srai(a2, a2, 1); -+ __ Add64(a2, a2, a1); -+ __ srai(a3, a3, 1); -+ __ Add64(a3, a3, a1); -+ } else { -+ __ Add64(a2, a1, Operand(a2)); -+ __ Add64(a3, a1, Operand(a3)); -+ } -+ // V8 expects the output to be an int32_t array. -+ __ Sw(a2, MemOperand(a0)); -+ __ Add64(a0, a0, kIntSize); -+ __ Sw(a3, MemOperand(a0)); -+ __ Add64(a0, a0, kIntSize); -+ } -+ } -+ -+ if (global()) { -+ // Restart matching if the regular expression is flagged as global. -+ __ Ld(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); -+ __ Ld(a1, MemOperand(frame_pointer(), kNumOutputRegisters)); -+ __ Ld(a2, MemOperand(frame_pointer(), kRegisterOutput)); -+ // Increment success counter. -+ __ Add64(a0, a0, 1); -+ __ Sd(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); -+ // Capture results have been stored, so the number of remaining global -+ // output registers is reduced by the number of stored captures. -+ __ Sub64(a1, a1, num_saved_registers_); -+ // Check whether we have enough room for another set of capture results. -+ __ Branch(&return_a0, lt, a1, Operand(num_saved_registers_)); -+ -+ __ Sd(a1, MemOperand(frame_pointer(), kNumOutputRegisters)); -+ // Advance the location for output. -+ __ Add64(a2, a2, num_saved_registers_ * kIntSize); -+ __ Sd(a2, MemOperand(frame_pointer(), kRegisterOutput)); -+ -+ // Prepare a0 to initialize registers with its value in the next run. -+ __ Ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ -+ if (global_with_zero_length_check()) { -+ // Special case for zero-length matches. -+ // t4: capture start index -+ // Not a zero-length match, restart. -+ __ Branch(&load_char_start_regexp, ne, current_input_offset(), -+ Operand(t4)); -+ // Offset from the end is zero if we already reached the end. -+ __ Branch(&exit_label_, eq, current_input_offset(), -+ Operand(zero_reg)); -+ // Advance current position after a zero-length match. -+ Label advance; -+ __ bind(&advance); -+ __ Add64(current_input_offset(), current_input_offset(), -+ Operand((mode_ == UC16) ? 2 : 1)); -+ if (global_unicode()) CheckNotInSurrogatePair(0, &advance); -+ } -+ -+ __ Branch(&load_char_start_regexp); -+ } else { -+ __ li(a0, Operand(SUCCESS)); -+ } -+ } -+ // Exit and return a0. -+ __ bind(&exit_label_); -+ if (global()) { -+ __ Ld(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); -+ } -+ -+ __ bind(&return_a0); -+ // Skip sp past regexp registers and local variables.. -+ __ mv(sp, frame_pointer()); -+ -+ // Restore registers fp..s11 and return (restoring ra to pc). -+ __ MultiPop(registers_to_retain | ra.bit()); -+ -+ __ Ret(); -+ -+ // Backtrack code (branch target for conditional backtracks). -+ if (backtrack_label_.is_linked()) { -+ __ bind(&backtrack_label_); -+ Backtrack(); -+ } -+ -+ Label exit_with_exception; -+ -+ // Preempt-code. -+ if (check_preempt_label_.is_linked()) { -+ SafeCallTarget(&check_preempt_label_); -+ // Put regexp engine registers on stack. -+ RegList regexp_registers_to_retain = current_input_offset().bit() | -+ current_character().bit() | -+ backtrack_stackpointer().bit(); -+ __ MultiPush(regexp_registers_to_retain); -+ CallCheckStackGuardState(a0); -+ __ MultiPop(regexp_registers_to_retain); -+ // If returning non-zero, we should end execution with the given -+ // result as return value. -+ __ Branch(&return_a0, ne, a0, Operand(zero_reg)); -+ -+ // String might have moved: Reload end of string from frame. -+ __ Ld(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); -+ __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); -+ SafeReturn(); -+ } -+ -+ // Backtrack stack overflow code. -+ if (stack_overflow_label_.is_linked()) { -+ SafeCallTarget(&stack_overflow_label_); -+ // Reached if the backtrack-stack limit has been hit. -+ // Put regexp engine registers on stack first. -+ RegList regexp_registers = -+ current_input_offset().bit() | current_character().bit(); -+ __ MultiPush(regexp_registers); -+ -+ // Call GrowStack(backtrack_stackpointer(), &stack_base) -+ static const int num_arguments = 3; -+ __ PrepareCallCFunction(num_arguments, a0); -+ __ mv(a0, backtrack_stackpointer()); -+ __ Add64(a1, frame_pointer(), Operand(kStackHighEnd)); -+ __ li(a2, Operand(ExternalReference::isolate_address(masm_->isolate()))); -+ ExternalReference grow_stack = -+ ExternalReference::re_grow_stack(masm_->isolate()); -+ __ CallCFunction(grow_stack, num_arguments); -+ // Restore regexp registers. -+ __ MultiPop(regexp_registers); -+ // If return nullptr, we have failed to grow the stack, and -+ // must exit with a stack-overflow exception. -+ __ Branch(&exit_with_exception, eq, a0, Operand(zero_reg)); -+ // Otherwise use return value as new stack pointer. -+ __ mv(backtrack_stackpointer(), a0); -+ // Restore saved registers and continue. -+ __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); -+ __ Ld(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); -+ SafeReturn(); -+ } -+ -+ if (exit_with_exception.is_linked()) { -+ // If any of the code above needed to exit with an exception. -+ __ bind(&exit_with_exception); -+ // Exit with Result EXCEPTION(-1) to signal thrown exception. -+ __ li(a0, Operand(EXCEPTION)); -+ __ jmp(&return_a0); -+ } -+ } -+ -+ CodeDesc code_desc; -+ masm_->GetCode(isolate(), &code_desc); -+ Handle code = -+ Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP) -+ .set_self_reference(masm_->CodeObject()) -+ .Build(); -+ LOG(masm_->isolate(), -+ RegExpCodeCreateEvent(Handle::cast(code), source)); -+ return Handle::cast(code); -+} -+ -+void RegExpMacroAssemblerRISCV::GoTo(Label* to) { -+ if (to == nullptr) { -+ Backtrack(); -+ return; -+ } -+ __ jmp(to); -+ return; -+} -+ -+void RegExpMacroAssemblerRISCV::IfRegisterGE(int reg, int comparand, -+ Label* if_ge) { -+ __ Ld(a0, register_location(reg)); -+ BranchOrBacktrack(if_ge, ge, a0, Operand(comparand)); -+} -+ -+void RegExpMacroAssemblerRISCV::IfRegisterLT(int reg, int comparand, -+ Label* if_lt) { -+ __ Ld(a0, register_location(reg)); -+ BranchOrBacktrack(if_lt, lt, a0, Operand(comparand)); -+} -+ -+void RegExpMacroAssemblerRISCV::IfRegisterEqPos(int reg, Label* if_eq) { -+ __ Ld(a0, register_location(reg)); -+ BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset())); -+} -+ -+RegExpMacroAssembler::IrregexpImplementation -+RegExpMacroAssemblerRISCV::Implementation() { -+ return kRISCVImplementation; -+} -+ -+void RegExpMacroAssemblerRISCV::PopCurrentPosition() { -+ Pop(current_input_offset()); -+} -+ -+void RegExpMacroAssemblerRISCV::PopRegister(int register_index) { -+ Pop(a0); -+ __ Sd(a0, register_location(register_index)); -+} -+ -+void RegExpMacroAssemblerRISCV::PushBacktrack(Label* label) { -+ if (label->is_bound()) { -+ int target = label->pos(); -+ __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag)); -+ } else { -+ Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); -+ Label after_constant; -+ __ Branch(&after_constant); -+ int offset = masm_->pc_offset(); -+ int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag; -+ __ emit(0); -+ masm_->label_at_put(label, offset); -+ __ bind(&after_constant); -+ if (is_int16(cp_offset)) { -+ __ Lwu(a0, MemOperand(code_pointer(), cp_offset)); -+ } else { -+ __ Add64(a0, code_pointer(), cp_offset); -+ __ Lwu(a0, MemOperand(a0, 0)); -+ } -+ } -+ Push(a0); -+ CheckStackLimit(); -+} -+ -+void RegExpMacroAssemblerRISCV::PushCurrentPosition() { -+ Push(current_input_offset()); -+} -+ -+void RegExpMacroAssemblerRISCV::PushRegister(int register_index, -+ StackCheckFlag check_stack_limit) { -+ __ Ld(a0, register_location(register_index)); -+ Push(a0); -+ if (check_stack_limit) CheckStackLimit(); -+} -+ -+void RegExpMacroAssemblerRISCV::ReadCurrentPositionFromRegister(int reg) { -+ __ Ld(current_input_offset(), register_location(reg)); -+} -+ -+void RegExpMacroAssemblerRISCV::ReadStackPointerFromRegister(int reg) { -+ __ Ld(backtrack_stackpointer(), register_location(reg)); -+ __ Ld(a0, MemOperand(frame_pointer(), kStackHighEnd)); -+ __ Add64(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0)); -+} -+ -+void RegExpMacroAssemblerRISCV::SetCurrentPositionFromEnd(int by) { -+ Label after_position; -+ __ Branch(&after_position, ge, current_input_offset(), -+ Operand(-by * char_size())); -+ __ li(current_input_offset(), -by * char_size()); -+ // On RegExp code entry (where this operation is used), the character before -+ // the current position is expected to be already loaded. -+ // We have advanced the position, so it's safe to read backwards. -+ LoadCurrentCharacterUnchecked(-1, 1); -+ __ bind(&after_position); -+} -+ -+void RegExpMacroAssemblerRISCV::SetRegister(int register_index, int to) { -+ DCHECK(register_index >= num_saved_registers_); // Reserved for positions! -+ __ li(a0, Operand(to)); -+ __ Sd(a0, register_location(register_index)); -+} -+ -+bool RegExpMacroAssemblerRISCV::Succeed() { -+ __ jmp(&success_label_); -+ return global(); -+} -+ -+void RegExpMacroAssemblerRISCV::WriteCurrentPositionToRegister(int reg, -+ int cp_offset) { -+ if (cp_offset == 0) { -+ __ Sd(current_input_offset(), register_location(reg)); -+ } else { -+ __ Add64(a0, current_input_offset(), Operand(cp_offset * char_size())); -+ __ Sd(a0, register_location(reg)); -+ } -+} -+ -+void RegExpMacroAssemblerRISCV::ClearRegisters(int reg_from, int reg_to) { -+ DCHECK(reg_from <= reg_to); -+ __ Ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ for (int reg = reg_from; reg <= reg_to; reg++) { -+ __ Sd(a0, register_location(reg)); -+ } -+} -+ -+void RegExpMacroAssemblerRISCV::WriteStackPointerToRegister(int reg) { -+ __ Ld(a1, MemOperand(frame_pointer(), kStackHighEnd)); -+ __ Sub64(a0, backtrack_stackpointer(), a1); -+ __ Sd(a0, register_location(reg)); -+} -+ -+bool RegExpMacroAssemblerRISCV::CanReadUnaligned() { return false; } -+ -+// Private methods: -+ -+void RegExpMacroAssemblerRISCV::CallCheckStackGuardState(Register scratch, -+ Operand extra_space) { -+ DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins()); -+ DCHECK(!masm_->options().isolate_independent_code); -+ -+ int stack_alignment = base::OS::ActivationFrameAlignment(); -+ -+ // Align the stack pointer and save the original sp value on the stack. -+ __ mv(scratch, sp); -+ __ Sub64(sp, sp, Operand(kPointerSize)); -+ DCHECK(base::bits::IsPowerOfTwo(stack_alignment)); -+ __ And(sp, sp, Operand(-stack_alignment)); -+ __ Sd(scratch, MemOperand(sp)); -+ -+ __ li(a3, extra_space); -+ __ mv(a2, frame_pointer()); -+ // Code of self. -+ __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE); -+ -+ // We need to make room for the return address on the stack. -+ DCHECK(IsAligned(stack_alignment, kPointerSize)); -+ __ Sub64(sp, sp, Operand(stack_alignment)); -+ -+ // The stack pointer now points to cell where the return address will be -+ // written. Arguments are in registers, meaning we treat the return address as -+ // argument 5. Since DirectCEntry will handle allocating space for the C -+ // argument slots, we don't need to care about that here. This is how the -+ // stack will look (sp meaning the value of sp at this moment): -+ // [sp + 3] - empty slot if needed for alignment. -+ // [sp + 2] - saved sp. -+ // [sp + 1] - second word reserved for return value. -+ // [sp + 0] - first word reserved for return value. -+ -+ // a0 will point to the return address, placed by DirectCEntry. -+ __ mv(a0, sp); -+ -+ ExternalReference stack_guard_check = -+ ExternalReference::re_check_stack_guard_state(masm_->isolate()); -+ __ li(t6, Operand(stack_guard_check)); -+ -+ EmbeddedData d = EmbeddedData::FromBlob(); -+ CHECK(Builtins::IsIsolateIndependent(Builtins::kDirectCEntry)); -+ Address entry = d.InstructionStartOfBuiltin(Builtins::kDirectCEntry); -+ __ li(kScratchReg, Operand(entry, RelocInfo::OFF_HEAP_TARGET)); -+ __ Call(kScratchReg); -+ -+ // DirectCEntry allocated space for the C argument slots so we have to -+ // drop them with the return address from the stack with loading saved sp. -+ // At this point stack must look: -+ // [sp + 7] - empty slot if needed for alignment. -+ // [sp + 6] - saved sp. -+ // [sp + 5] - second word reserved for return value. -+ // [sp + 4] - first word reserved for return value. -+ // [sp + 3] - C argument slot. -+ // [sp + 2] - C argument slot. -+ // [sp + 1] - C argument slot. -+ // [sp + 0] - C argument slot. -+ __ Ld(sp, MemOperand(sp, stack_alignment + kCArgsSlotsSize)); -+ -+ __ li(code_pointer(), Operand(masm_->CodeObject())); -+} -+ -+// Helper function for reading a value out of a stack frame. -+template -+static T& frame_entry(Address re_frame, int frame_offset) { -+ return reinterpret_cast(Memory(re_frame + frame_offset)); -+} -+ -+template -+static T* frame_entry_address(Address re_frame, int frame_offset) { -+ return reinterpret_cast(re_frame + frame_offset); -+} -+ -+int64_t RegExpMacroAssemblerRISCV::CheckStackGuardState(Address* return_address, -+ Address raw_code, -+ Address re_frame, -+ uintptr_t extra_space) { -+ Code re_code = Code::cast(Object(raw_code)); -+ return NativeRegExpMacroAssembler::CheckStackGuardState( -+ frame_entry(re_frame, kIsolate), -+ static_cast(frame_entry(re_frame, kStartIndex)), -+ static_cast( -+ frame_entry(re_frame, kDirectCall)), -+ return_address, re_code, -+ frame_entry_address
(re_frame, kInputString), -+ frame_entry_address(re_frame, kInputStart), -+ frame_entry_address(re_frame, kInputEnd), -+ extra_space); -+} -+ -+MemOperand RegExpMacroAssemblerRISCV::register_location(int register_index) { -+ DCHECK(register_index < (1 << 30)); -+ if (num_registers_ <= register_index) { -+ num_registers_ = register_index + 1; -+ } -+ return MemOperand(frame_pointer(), -+ kRegisterZero - register_index * kPointerSize); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckPosition(int cp_offset, -+ Label* on_outside_input) { -+ if (cp_offset >= 0) { -+ BranchOrBacktrack(on_outside_input, ge, current_input_offset(), -+ Operand(-cp_offset * char_size())); -+ } else { -+ __ Ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne)); -+ __ Add64(a0, current_input_offset(), Operand(cp_offset * char_size())); -+ BranchOrBacktrack(on_outside_input, le, a0, Operand(a1)); -+ } -+} -+ -+void RegExpMacroAssemblerRISCV::BranchOrBacktrack(Label* to, -+ Condition condition, -+ Register rs, -+ const Operand& rt) { -+ if (condition == al) { // Unconditional. -+ if (to == nullptr) { -+ Backtrack(); -+ return; -+ } -+ __ jmp(to); -+ return; -+ } -+ if (to == nullptr) { -+ __ Branch(&backtrack_label_, condition, rs, rt); -+ return; -+ } -+ __ Branch(to, condition, rs, rt); -+} -+ -+void RegExpMacroAssemblerRISCV::SafeCall(Label* to, Condition cond, Register rs, -+ const Operand& rt) { -+ __ BranchAndLink(to, cond, rs, rt); -+} -+ -+void RegExpMacroAssemblerRISCV::SafeReturn() { -+ __ pop(ra); -+ __ Add64(t1, ra, Operand(masm_->CodeObject())); -+ __ Jump(t1); -+} -+ -+void RegExpMacroAssemblerRISCV::SafeCallTarget(Label* name) { -+ __ bind(name); -+ __ Sub64(ra, ra, Operand(masm_->CodeObject())); -+ __ push(ra); -+} -+ -+void RegExpMacroAssemblerRISCV::Push(Register source) { -+ DCHECK(source != backtrack_stackpointer()); -+ __ Add64(backtrack_stackpointer(), backtrack_stackpointer(), -+ Operand(-kIntSize)); -+ __ Sw(source, MemOperand(backtrack_stackpointer())); -+} -+ -+void RegExpMacroAssemblerRISCV::Pop(Register target) { -+ DCHECK(target != backtrack_stackpointer()); -+ __ Lw(target, MemOperand(backtrack_stackpointer())); -+ __ Add64(backtrack_stackpointer(), backtrack_stackpointer(), kIntSize); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckPreemption() { -+ // Check for preemption. -+ ExternalReference stack_limit = -+ ExternalReference::address_of_jslimit(masm_->isolate()); -+ __ li(a0, Operand(stack_limit)); -+ __ Ld(a0, MemOperand(a0)); -+ SafeCall(&check_preempt_label_, Uless_equal, sp, Operand(a0)); -+} -+ -+void RegExpMacroAssemblerRISCV::CheckStackLimit() { -+ ExternalReference stack_limit = -+ ExternalReference::address_of_regexp_stack_limit_address( -+ masm_->isolate()); -+ -+ __ li(a0, Operand(stack_limit)); -+ __ Ld(a0, MemOperand(a0)); -+ SafeCall(&stack_overflow_label_, Uless_equal, backtrack_stackpointer(), -+ Operand(a0)); -+} -+ -+void RegExpMacroAssemblerRISCV::LoadCurrentCharacterUnchecked(int cp_offset, -+ int characters) { -+ Register offset = current_input_offset(); -+ if (cp_offset != 0) { -+ // t4 is not being used to store the capture start index at this point. -+ __ Add64(t4, current_input_offset(), Operand(cp_offset * char_size())); -+ offset = t4; -+ } -+ // We assume that we cannot do unaligned loads on RISC-V, so this function -+ // must only be used to load a single character at a time. -+ DCHECK_EQ(1, characters); -+ __ Add64(t1, end_of_input_address(), Operand(offset)); -+ if (mode_ == LATIN1) { -+ __ Lbu(current_character(), MemOperand(t1, 0)); -+ } else { -+ DCHECK(mode_ == UC16); -+ __ Lhu(current_character(), MemOperand(t1, 0)); -+ } -+} -+ -+#undef __ -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_TARGET_ARCH_RISCV64 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/riscv64/regexp-macro-assembler-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/regexp/riscv64/regexp-macro-assembler-riscv64.h -@@ -0,0 +1,214 @@ -+// Copyright 2011 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. -+ -+#ifndef V8_REGEXP_RISCV_REGEXP_MACRO_ASSEMBLER_RISCV_H_ -+#define V8_REGEXP_RISCV_REGEXP_MACRO_ASSEMBLER_RISCV_H_ -+ -+#include "src/codegen/macro-assembler.h" -+#include "src/codegen/riscv64/assembler-riscv64.h" -+#include "src/regexp/regexp-macro-assembler.h" -+ -+namespace v8 { -+namespace internal { -+ -+class V8_EXPORT_PRIVATE RegExpMacroAssemblerRISCV -+ : public NativeRegExpMacroAssembler { -+ public: -+ RegExpMacroAssemblerRISCV(Isolate* isolate, Zone* zone, Mode mode, -+ int registers_to_save); -+ virtual ~RegExpMacroAssemblerRISCV(); -+ virtual int stack_limit_slack(); -+ virtual void AdvanceCurrentPosition(int by); -+ virtual void AdvanceRegister(int reg, int by); -+ virtual void Backtrack(); -+ virtual void Bind(Label* label); -+ virtual void CheckAtStart(int cp_offset, Label* on_at_start); -+ virtual void CheckCharacter(uint32_t c, Label* on_equal); -+ virtual void CheckCharacterAfterAnd(uint32_t c, uint32_t mask, -+ Label* on_equal); -+ virtual void CheckCharacterGT(uc16 limit, Label* on_greater); -+ virtual void CheckCharacterLT(uc16 limit, Label* on_less); -+ // A "greedy loop" is a loop that is both greedy and with a simple -+ // body. It has a particularly simple implementation. -+ virtual void CheckGreedyLoop(Label* on_tos_equals_current_position); -+ virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start); -+ virtual void CheckNotBackReference(int start_reg, bool read_backward, -+ Label* on_no_match); -+ virtual void CheckNotBackReferenceIgnoreCase(int start_reg, -+ bool read_backward, bool unicode, -+ Label* on_no_match); -+ virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal); -+ virtual void CheckNotCharacterAfterAnd(uint32_t c, uint32_t mask, -+ Label* on_not_equal); -+ virtual void CheckNotCharacterAfterMinusAnd(uc16 c, uc16 minus, uc16 mask, -+ Label* on_not_equal); -+ virtual void CheckCharacterInRange(uc16 from, uc16 to, Label* on_in_range); -+ virtual void CheckCharacterNotInRange(uc16 from, uc16 to, -+ Label* on_not_in_range); -+ virtual void CheckBitInTable(Handle table, Label* on_bit_set); -+ -+ // Checks whether the given offset from the current position is before -+ // the end of the string. -+ virtual void CheckPosition(int cp_offset, Label* on_outside_input); -+ virtual bool CheckSpecialCharacterClass(uc16 type, Label* on_no_match); -+ virtual void Fail(); -+ virtual Handle GetCode(Handle source); -+ virtual void GoTo(Label* label); -+ virtual void IfRegisterGE(int reg, int comparand, Label* if_ge); -+ virtual void IfRegisterLT(int reg, int comparand, Label* if_lt); -+ virtual void IfRegisterEqPos(int reg, Label* if_eq); -+ virtual IrregexpImplementation Implementation(); -+ virtual void LoadCurrentCharacterUnchecked(int cp_offset, -+ int character_count); -+ virtual void PopCurrentPosition(); -+ virtual void PopRegister(int register_index); -+ virtual void PushBacktrack(Label* label); -+ virtual void PushCurrentPosition(); -+ virtual void PushRegister(int register_index, -+ StackCheckFlag check_stack_limit); -+ virtual void ReadCurrentPositionFromRegister(int reg); -+ virtual void ReadStackPointerFromRegister(int reg); -+ virtual void SetCurrentPositionFromEnd(int by); -+ virtual void SetRegister(int register_index, int to); -+ virtual bool Succeed(); -+ virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); -+ virtual void ClearRegisters(int reg_from, int reg_to); -+ virtual void WriteStackPointerToRegister(int reg); -+ virtual bool CanReadUnaligned(); -+ -+ // Called from RegExp if the stack-guard is triggered. -+ // If the code object is relocated, the return address is fixed before -+ // returning. -+ // {raw_code} is an Address because this is called via ExternalReference. -+ static int64_t CheckStackGuardState(Address* return_address, Address raw_code, -+ Address re_frame, uintptr_t extra_space); -+ -+ void print_regexp_frame_constants(); -+ -+ private: -+ // Offsets from frame_pointer() of function parameters and stored registers. -+ static const int kFramePointer = 0; -+ -+ // Above the frame pointer - Stored registers and stack passed parameters. -+ // Registers s1 to s8, fp, and ra. -+ static const int kStoredRegisters = kFramePointer; -+ // Return address (stored from link register, read into pc on return). -+ -+ // This 9 is 8 s-regs (s1..s8) plus fp. -+ static const int kNumCalleeRegsToRetain = 9; -+ static const int kReturnAddress = -+ kStoredRegisters + kNumCalleeRegsToRetain * kPointerSize; -+ -+ // Stack frame header. -+ static const int kStackFrameHeader = kReturnAddress; -+ // Stack parameters placed by caller. -+ static const int kIsolate = kStackFrameHeader + kPointerSize; -+ -+ // Below the frame pointer. -+ // Register parameters stored by setup code. -+ static const int kDirectCall = kFramePointer - kPointerSize; -+ static const int kStackHighEnd = kDirectCall - kPointerSize; -+ static const int kNumOutputRegisters = kStackHighEnd - kPointerSize; -+ static const int kRegisterOutput = kNumOutputRegisters - kPointerSize; -+ static const int kInputEnd = kRegisterOutput - kPointerSize; -+ static const int kInputStart = kInputEnd - kPointerSize; -+ static const int kStartIndex = kInputStart - kPointerSize; -+ static const int kInputString = kStartIndex - kPointerSize; -+ // When adding local variables remember to push space for them in -+ // the frame in GetCode. -+ static const int kSuccessfulCaptures = kInputString - kPointerSize; -+ static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize; -+ static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; -+ // First register address. Following registers are below it on the stack. -+ static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; -+ -+ // Initial size of code buffer. -+ static const int kRegExpCodeSize = 1024; -+ -+ // Check whether preemption has been requested. -+ void CheckPreemption(); -+ -+ // Check whether we are exceeding the stack limit on the backtrack stack. -+ void CheckStackLimit(); -+ -+ // Generate a call to CheckStackGuardState. -+ void CallCheckStackGuardState(Register scratch, -+ Operand extra_space_for_variables = Operand(0L)); -+ -+ // The ebp-relative location of a regexp register. -+ MemOperand register_location(int register_index); -+ -+ // Register holding the current input position as negative offset from -+ // the end of the string. -+ inline Register current_input_offset() { return s1; } -+ -+ // The register containing the current character after LoadCurrentCharacter. -+ inline Register current_character() { return s2; } -+ -+ // Register holding address of the end of the input string. -+ inline Register end_of_input_address() { return t2; } -+ -+ // Register holding the frame address. Local variables, parameters and -+ // regexp registers are addressed relative to this. -+ inline Register frame_pointer() { return fp; } -+ -+ // The register containing the backtrack stack top. Provides a meaningful -+ // name to the register. -+ inline Register backtrack_stackpointer() { return t0; } -+ -+ // Register holding pointer to the current code object. -+ inline Register code_pointer() { return s4; } -+ -+ // Byte size of chars in the string to match (decided by the Mode argument). -+ inline int char_size() { return static_cast(mode_); } -+ -+ // Equivalent to a conditional branch to the label, unless the label -+ // is nullptr, in which case it is a conditional Backtrack. -+ void BranchOrBacktrack(Label* to, Condition condition, Register rs, -+ const Operand& rt); -+ -+ // Call and return internally in the generated code in a way that -+ // is GC-safe (i.e., doesn't leave absolute code addresses on the stack) -+ inline void SafeCall(Label* to, Condition cond, Register rs, -+ const Operand& rt); -+ inline void SafeReturn(); -+ inline void SafeCallTarget(Label* name); -+ -+ // Pushes the value of a register on the backtrack stack. Decrements the -+ // stack pointer by a word size and stores the register's value there. -+ inline void Push(Register source); -+ -+ // Pops a value from the backtrack stack. Reads the word at the stack pointer -+ // and increments it by a word size. -+ inline void Pop(Register target); -+ -+ Isolate* isolate() const { return masm_->isolate(); } -+ -+ MacroAssembler* masm_; -+ -+ // Which mode to generate code for (Latin1 or UC16). -+ Mode mode_; -+ -+ // One greater than maximal register index actually used. -+ int num_registers_; -+ -+ // Number of registers to output at the end (the saved registers -+ // are always 0..num_saved_registers_-1). -+ int num_saved_registers_; -+ -+ // Labels used internally. -+ Label entry_label_; -+ Label start_label_; -+ Label success_label_; -+ Label backtrack_label_; -+ Label exit_label_; -+ Label check_preempt_label_; -+ Label stack_overflow_label_; -+ Label internal_failure_label_; -+}; -+ -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_REGEXP_RISCV_REGEXP_MACRO_ASSEMBLER_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/runtime/runtime-atomics.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/runtime/runtime-atomics.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/runtime/runtime-atomics.cc -@@ -19,7 +19,8 @@ namespace internal { - - // Other platforms have CSA support, see builtins-sharedarraybuffer-gen.h. - #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ -- V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X -+ V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X || \ -+ V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV - - namespace { - -@@ -568,6 +569,6 @@ RUNTIME_FUNCTION(Runtime_AtomicsXor) { U - - #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 - // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X -- -+ // || V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV - } // namespace internal - } // namespace v8 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/snapshot/deserializer.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/snapshot/deserializer.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/snapshot/deserializer.h -@@ -29,9 +29,10 @@ class Object; - - // Used for platforms with embedded constant pools to trigger deserialization - // of objects found in code. --#if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \ -- defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390) || \ -- defined(V8_TARGET_ARCH_PPC64) || V8_EMBEDDED_CONSTANT_POOL -+#if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \ -+ defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390) || \ -+ defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_RISCV64) || \ -+ defined(V8_TARGET_ARCH_RISCV) || V8_EMBEDDED_CONSTANT_POOL - #define V8_CODE_EMBEDS_OBJECT_POINTER 1 - #else - #define V8_CODE_EMBEDS_OBJECT_POINTER 0 -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/baseline/liftoff-assembler-defs.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/wasm/baseline/liftoff-assembler-defs.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/baseline/liftoff-assembler-defs.h -@@ -69,6 +69,23 @@ constexpr RegList kLiftoffAssemblerFpCac - d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d16, d17, - d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29); - -+#elif V8_TARGET_ARCH_RISCV64 -+ -+// Any change of kLiftoffAssemblerGpCacheRegs also need to update -+// kPushedGpRegs in frame-constants-riscv64.h -+constexpr RegList kLiftoffAssemblerGpCacheRegs = -+ Register::ListOf(a0, a1, a2, a3, a4, a5, a6, a7, t0, t1, t2, s7); -+ -+// Any change of kLiftoffAssemblerGpCacheRegs also need to update -+// kPushedFpRegs in frame-constants-riscv64.h -+constexpr RegList kLiftoffAssemblerFpCacheRegs = -+ DoubleRegister::ListOf(ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7, fa0, fa1, -+ fa2, fa3, fa4, fa5, fa6, fa7, ft8, ft9, ft10, ft11); -+ -+#elif V8_TARGET_ARCH_RISCV -+ -+#error RISCV (32) architecture not supported yet -+ - #else - - constexpr RegList kLiftoffAssemblerGpCacheRegs = 0xff; -@@ -116,6 +133,18 @@ constexpr Condition kUnsignedLessEqual = - constexpr Condition kUnsignedGreaterThan = hi; - constexpr Condition kUnsignedGreaterEqual = hs; - -+#elif V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV -+constexpr Condition kEqual = eq; -+constexpr Condition kUnequal = ne; -+constexpr Condition kSignedLessThan = lt; -+constexpr Condition kSignedLessEqual = le; -+constexpr Condition kSignedGreaterThan = gt; -+constexpr Condition kSignedGreaterEqual = ge; -+constexpr Condition kUnsignedLessThan = ult; -+constexpr Condition kUnsignedLessEqual = ule; -+constexpr Condition kUnsignedGreaterThan = ugt; -+constexpr Condition kUnsignedGreaterEqual = uge; -+ - #else - - // On unimplemented platforms, just make this compile. -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/baseline/liftoff-assembler.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/wasm/baseline/liftoff-assembler.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/baseline/liftoff-assembler.h -@@ -1353,6 +1353,10 @@ class LiftoffStackSlots { - #include "src/wasm/baseline/mips64/liftoff-assembler-mips64.h" - #elif V8_TARGET_ARCH_S390 - #include "src/wasm/baseline/s390/liftoff-assembler-s390.h" -+#elif V8_TARGET_ARCH_RISCV64 -+#include "src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h" -+#elif V8_TARGET_ARCH_RISCV -+#include "src/wasm/baseline/riscv/liftoff-assembler-riscv.h" - #else - #error Unsupported architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h -@@ -0,0 +1,2335 @@ -+// Copyright 2017 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. -+ -+#ifndef V8_WASM_BASELINE_RISCV_LIFTOFF_ASSEMBLER_RISCV_H_ -+#define V8_WASM_BASELINE_RISCV_LIFTOFF_ASSEMBLER_RISCV_H_ -+ -+#include "src/wasm/baseline/liftoff-assembler.h" -+ -+namespace v8 { -+namespace internal { -+namespace wasm { -+ -+namespace liftoff { -+ -+// Liftoff Frames. -+// -+// slot Frame -+// +--------------------+--------------------------- -+// n+4 | optional padding slot to keep the stack 16 byte aligned. -+// n+3 | parameter n | -+// ... | ... | -+// 4 | parameter 1 | or parameter 2 -+// 3 | parameter 0 | or parameter 1 -+// 2 | (result address) | or parameter 0 -+// -----+--------------------+--------------------------- -+// 1 | return addr (ra) | -+// 0 | previous frame (fp)| -+// -----+--------------------+ <-- frame ptr (fp) -+// -1 | 0xa: WASM | -+// -2 | instance | -+// -----+--------------------+--------------------------- -+// -3 | slot 0 | ^ -+// -4 | slot 1 | | -+// | | Frame slots -+// | | | -+// | | v -+// | optional padding slot to keep the stack 16 byte aligned. -+// -----+--------------------+ <-- stack ptr (sp) -+// -+ -+// fp-8 holds the stack marker, fp-16 is the instance parameter. -+constexpr int kInstanceOffset = 16; -+ -+inline MemOperand GetStackSlot(int offset) { return MemOperand(fp, -offset); } -+ -+inline MemOperand GetInstanceOperand() { return GetStackSlot(kInstanceOffset); } -+ -+inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, MemOperand src, -+ ValueType type) { -+ switch (type.kind()) { -+ case ValueType::kI32: -+ assm->Lw(dst.gp(), src); -+ break; -+ case ValueType::kI64: -+ assm->Ld(dst.gp(), src); -+ break; -+ case ValueType::kF32: -+ assm->LoadFloat(dst.fp(), src); -+ break; -+ case ValueType::kF64: -+ assm->LoadDouble(dst.fp(), src); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+inline void Store(LiftoffAssembler* assm, Register base, int32_t offset, -+ LiftoffRegister src, ValueType type) { -+ MemOperand dst(base, offset); -+ switch (type.kind()) { -+ case ValueType::kI32: -+ assm->Usw(src.gp(), dst); -+ break; -+ case ValueType::kI64: -+ assm->Usd(src.gp(), dst); -+ break; -+ case ValueType::kF32: -+ assm->UStoreFloat(src.fp(), dst, t5); -+ break; -+ case ValueType::kF64: -+ assm->UStoreDouble(src.fp(), dst, t5); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+inline void push(LiftoffAssembler* assm, LiftoffRegister reg, ValueType type) { -+ switch (type.kind()) { -+ case ValueType::kI32: -+ assm->addi(sp, sp, -kSystemPointerSize); -+ assm->Sw(reg.gp(), MemOperand(sp, 0)); -+ break; -+ case ValueType::kI64: -+ assm->push(reg.gp()); -+ break; -+ case ValueType::kF32: -+ assm->addi(sp, sp, -kSystemPointerSize); -+ assm->StoreFloat(reg.fp(), MemOperand(sp, 0)); -+ break; -+ case ValueType::kF64: -+ assm->addi(sp, sp, -kSystemPointerSize); -+ assm->StoreDouble(reg.fp(), MemOperand(sp, 0)); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+#if defined(V8_TARGET_BIG_ENDIAN) -+inline void ChangeEndiannessLoad(LiftoffAssembler* assm, LiftoffRegister dst, -+ LoadType type, LiftoffRegList pinned) { -+ bool is_float = false; -+ LiftoffRegister tmp = dst; -+ switch (type.value()) { -+ case LoadType::kI64Load8U: -+ case LoadType::kI64Load8S: -+ case LoadType::kI32Load8U: -+ case LoadType::kI32Load8S: -+ // No need to change endianness for byte size. -+ return; -+ case LoadType::kF32Load: -+ is_float = true; -+ tmp = assm->GetUnusedRegister(kGpReg, pinned); -+ assm->emit_type_conversion(kExprI32ReinterpretF32, tmp, dst); -+ V8_FALLTHROUGH; -+ case LoadType::kI64Load32U: -+ assm->TurboAssembler::ByteSwapUnsigned(tmp.gp(), tmp.gp(), 4); -+ break; -+ case LoadType::kI32Load: -+ case LoadType::kI64Load32S: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4); -+ break; -+ case LoadType::kI32Load16S: -+ case LoadType::kI64Load16S: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2); -+ break; -+ case LoadType::kI32Load16U: -+ case LoadType::kI64Load16U: -+ assm->TurboAssembler::ByteSwapUnsigned(tmp.gp(), tmp.gp(), 2); -+ break; -+ case LoadType::kF64Load: -+ is_float = true; -+ tmp = assm->GetUnusedRegister(kGpReg, pinned); -+ assm->emit_type_conversion(kExprI64ReinterpretF64, tmp, dst); -+ V8_FALLTHROUGH; -+ case LoadType::kI64Load: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 8); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+ if (is_float) { -+ switch (type.value()) { -+ case LoadType::kF32Load: -+ assm->emit_type_conversion(kExprF32ReinterpretI32, dst, tmp); -+ break; -+ case LoadType::kF64Load: -+ assm->emit_type_conversion(kExprF64ReinterpretI64, dst, tmp); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+} -+ -+inline void ChangeEndiannessStore(LiftoffAssembler* assm, LiftoffRegister src, -+ StoreType type, LiftoffRegList pinned) { -+ bool is_float = false; -+ LiftoffRegister tmp = src; -+ switch (type.value()) { -+ case StoreType::kI64Store8: -+ case StoreType::kI32Store8: -+ // No need to change endianness for byte size. -+ return; -+ case StoreType::kF32Store: -+ is_float = true; -+ tmp = assm->GetUnusedRegister(kGpReg, pinned); -+ assm->emit_type_conversion(kExprI32ReinterpretF32, tmp, src); -+ V8_FALLTHROUGH; -+ case StoreType::kI32Store: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4); -+ break; -+ case StoreType::kI32Store16: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2); -+ break; -+ case StoreType::kF64Store: -+ is_float = true; -+ tmp = assm->GetUnusedRegister(kGpReg, pinned); -+ assm->emit_type_conversion(kExprI64ReinterpretF64, tmp, src); -+ V8_FALLTHROUGH; -+ case StoreType::kI64Store: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 8); -+ break; -+ case StoreType::kI64Store32: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4); -+ break; -+ case StoreType::kI64Store16: -+ assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+ if (is_float) { -+ switch (type.value()) { -+ case StoreType::kF32Store: -+ assm->emit_type_conversion(kExprF32ReinterpretI32, src, tmp); -+ break; -+ case StoreType::kF64Store: -+ assm->emit_type_conversion(kExprF64ReinterpretI64, src, tmp); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ } -+} -+#endif // V8_TARGET_BIG_ENDIAN -+ -+} // namespace liftoff -+ -+int LiftoffAssembler::PrepareStackFrame() { -+ int offset = pc_offset(); -+ // When constant that represents size of stack frame can't be represented -+ // as 16bit we need three instructions to add it to sp, so we reserve space -+ // for this case. -+ Add64(sp, sp, Operand(0L)); -+ nop(); -+ nop(); -+ return offset; -+} -+ -+void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, -+ int stack_param_delta) { -+ UseScratchRegisterScope temps(this); -+ Register scratch = temps.Acquire(); -+ -+ // Push the return address and frame pointer to complete the stack frame. -+ Ld(scratch, MemOperand(fp, 8)); -+ Push(scratch); -+ Ld(scratch, MemOperand(fp, 0)); -+ Push(scratch); -+ -+ // Shift the whole frame upwards. -+ int slot_count = num_callee_stack_params + 2; -+ for (int i = slot_count - 1; i >= 0; --i) { -+ Ld(scratch, MemOperand(sp, i * 8)); -+ Sd(scratch, MemOperand(fp, (i - stack_param_delta) * 8)); -+ } -+ -+ // Set the new stack and frame pointer. -+ Add64(sp, fp, -stack_param_delta * 8); -+ Pop(ra, fp); -+} -+ -+void LiftoffAssembler::PatchPrepareStackFrame(int offset, int frame_size) { -+ // We can't run out of space, just pass anything big enough to not cause the -+ // assembler to try to grow the buffer. -+ constexpr int kAvailableSpace = 256; -+ TurboAssembler patching_assembler( -+ nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, -+ ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace)); -+ // If bytes can be represented as 16bit, addi will be generated and two -+ // nops will stay untouched. Otherwise, lui-ori sequence will load it to -+ // register and, as third instruction, daddu will be generated. -+ patching_assembler.Add64(sp, sp, Operand(-frame_size)); -+} -+ -+void LiftoffAssembler::FinishCode() {} -+ -+void LiftoffAssembler::AbortCompilation() {} -+ -+// static -+constexpr int LiftoffAssembler::StaticStackFrameSize() { -+ return liftoff::kInstanceOffset; -+} -+ -+int LiftoffAssembler::SlotSizeForType(ValueType type) { -+ switch (type.kind()) { -+ case ValueType::kS128: -+ return type.element_size_bytes(); -+ default: -+ return kStackSlotSize; -+ } -+} -+ -+bool LiftoffAssembler::NeedsAlignment(ValueType type) { -+ switch (type.kind()) { -+ case ValueType::kS128: -+ return true; -+ default: -+ // No alignment because all other types are kStackSlotSize. -+ return false; -+ } -+} -+ -+void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value, -+ RelocInfo::Mode rmode) { -+ switch (value.type().kind()) { -+ case ValueType::kI32: -+ TurboAssembler::li(reg.gp(), Operand(value.to_i32(), rmode)); -+ break; -+ case ValueType::kI64: -+ TurboAssembler::li(reg.gp(), Operand(value.to_i64(), rmode)); -+ break; -+ case ValueType::kF32: -+ TurboAssembler::LoadFPRImmediate(reg.fp(), -+ value.to_f32_boxed().get_bits()); -+ break; -+ case ValueType::kF64: -+ TurboAssembler::LoadFPRImmediate(reg.fp(), -+ value.to_f64_boxed().get_bits()); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+void LiftoffAssembler::LoadFromInstance(Register dst, uint32_t offset, -+ int size) { -+ DCHECK_LE(offset, kMaxInt); -+ Ld(dst, liftoff::GetInstanceOperand()); -+ DCHECK(size == 4 || size == 8); -+ if (size == 4) { -+ Lw(dst, MemOperand(dst, offset)); -+ } else { -+ Ld(dst, MemOperand(dst, offset)); -+ } -+} -+ -+void LiftoffAssembler::LoadTaggedPointerFromInstance(Register dst, -+ uint32_t offset) { -+ LoadFromInstance(dst, offset, kTaggedSize); -+} -+ -+void LiftoffAssembler::SpillInstance(Register instance) { -+ Sd(instance, liftoff::GetInstanceOperand()); -+} -+ -+void LiftoffAssembler::FillInstanceInto(Register dst) { -+ Ld(dst, liftoff::GetInstanceOperand()); -+} -+ -+void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr, -+ Register offset_reg, -+ int32_t offset_imm, -+ LiftoffRegList pinned) { -+ STATIC_ASSERT(kTaggedSize == kInt64Size); -+ Load(LiftoffRegister(dst), src_addr, offset_reg, -+ static_cast(offset_imm), LoadType::kI64Load, pinned); -+} -+ -+void LiftoffAssembler::StoreTaggedPointer(Register dst_addr, -+ int32_t offset_imm, -+ LiftoffRegister src, -+ LiftoffRegList pinned) { -+ bailout(kRefTypes, "GlobalSet"); -+} -+ -+void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, -+ Register offset_reg, uint32_t offset_imm, -+ LoadType type, LiftoffRegList pinned, -+ uint32_t* protected_load_pc, bool is_load_mem) { -+ Register src = no_reg; -+ if (offset_reg != no_reg) { -+ src = GetUnusedRegister(kGpReg, pinned).gp(); -+ emit_ptrsize_add(src, src_addr, offset_reg); -+ } -+ MemOperand src_op = (offset_reg != no_reg) ? MemOperand(src, offset_imm) -+ : MemOperand(src_addr, offset_imm); -+ -+ if (protected_load_pc) *protected_load_pc = pc_offset(); -+ switch (type.value()) { -+ case LoadType::kI32Load8U: -+ case LoadType::kI64Load8U: -+ Lbu(dst.gp(), src_op); -+ break; -+ case LoadType::kI32Load8S: -+ case LoadType::kI64Load8S: -+ Lb(dst.gp(), src_op); -+ break; -+ case LoadType::kI32Load16U: -+ case LoadType::kI64Load16U: -+ TurboAssembler::Ulhu(dst.gp(), src_op); -+ break; -+ case LoadType::kI32Load16S: -+ case LoadType::kI64Load16S: -+ TurboAssembler::Ulh(dst.gp(), src_op); -+ break; -+ case LoadType::kI64Load32U: -+ TurboAssembler::Ulwu(dst.gp(), src_op); -+ break; -+ case LoadType::kI32Load: -+ case LoadType::kI64Load32S: -+ TurboAssembler::Ulw(dst.gp(), src_op); -+ break; -+ case LoadType::kI64Load: -+ TurboAssembler::Uld(dst.gp(), src_op); -+ break; -+ case LoadType::kF32Load: -+ TurboAssembler::ULoadFloat(dst.fp(), src_op, t5); -+ break; -+ case LoadType::kF64Load: -+ TurboAssembler::ULoadDouble(dst.fp(), src_op, t5); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+#if defined(V8_TARGET_BIG_ENDIAN) -+ if (is_load_mem) { -+ pinned.set(src_op.rm()); -+ liftoff::ChangeEndiannessLoad(this, dst, type, pinned); -+ } -+#endif -+} -+ -+void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister src, -+ StoreType type, LiftoffRegList pinned, -+ uint32_t* protected_store_pc, bool is_store_mem) { -+ Register dst = no_reg; -+ MemOperand dst_op = MemOperand(dst_addr, offset_imm); -+ if (offset_reg != no_reg) { -+ if (is_store_mem) { -+ pinned.set(src); -+ } -+ dst = GetUnusedRegister(kGpReg, pinned).gp(); -+ emit_ptrsize_add(dst, dst_addr, offset_reg); -+ dst_op = MemOperand(dst, offset_imm); -+ } -+ -+#if defined(V8_TARGET_BIG_ENDIAN) -+ if (is_store_mem) { -+ pinned.set(dst_op.rm()); -+ LiftoffRegister tmp = GetUnusedRegister(src.reg_class(), pinned); -+ // Save original value. -+ Move(tmp, src, type.value_type()); -+ -+ src = tmp; -+ pinned.set(tmp); -+ liftoff::ChangeEndiannessStore(this, src, type, pinned); -+ } -+#endif -+ -+ if (protected_store_pc) *protected_store_pc = pc_offset(); -+ -+ // FIXME (RISCV): current implementation treats all stores as unaligned -+ switch (type.value()) { -+ case StoreType::kI32Store8: -+ case StoreType::kI64Store8: -+ Sb(src.gp(), dst_op); -+ break; -+ case StoreType::kI32Store16: -+ case StoreType::kI64Store16: -+ TurboAssembler::Ush(src.gp(), dst_op); -+ break; -+ case StoreType::kI32Store: -+ case StoreType::kI64Store32: -+ TurboAssembler::Usw(src.gp(), dst_op); -+ break; -+ case StoreType::kI64Store: -+ TurboAssembler::Usd(src.gp(), dst_op); -+ break; -+ case StoreType::kF32Store: -+ TurboAssembler::UStoreFloat(src.fp(), dst_op, t5); -+ break; -+ case StoreType::kF64Store: -+ TurboAssembler::UStoreDouble(src.fp(), dst_op, t5); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+void LiftoffAssembler::AtomicLoad(LiftoffRegister dst, Register src_addr, -+ Register offset_reg, uint32_t offset_imm, -+ LoadType type, LiftoffRegList pinned) { -+ bailout(kAtomics, "AtomicLoad"); -+} -+ -+void LiftoffAssembler::AtomicStore(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister src, -+ StoreType type, LiftoffRegList pinned) { -+ bailout(kAtomics, "AtomicStore"); -+} -+ -+void LiftoffAssembler::AtomicAdd(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister value, -+ LiftoffRegister result, StoreType type) { -+ bailout(kAtomics, "AtomicAdd"); -+} -+ -+void LiftoffAssembler::AtomicSub(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister value, -+ LiftoffRegister result, StoreType type) { -+ bailout(kAtomics, "AtomicSub"); -+} -+ -+void LiftoffAssembler::AtomicAnd(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister value, -+ LiftoffRegister result, StoreType type) { -+ bailout(kAtomics, "AtomicAnd"); -+} -+ -+void LiftoffAssembler::AtomicOr(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister value, -+ LiftoffRegister result, StoreType type) { -+ bailout(kAtomics, "AtomicOr"); -+} -+ -+void LiftoffAssembler::AtomicXor(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, LiftoffRegister value, -+ LiftoffRegister result, StoreType type) { -+ bailout(kAtomics, "AtomicXor"); -+} -+ -+void LiftoffAssembler::AtomicExchange(Register dst_addr, Register offset_reg, -+ uint32_t offset_imm, -+ LiftoffRegister value, -+ LiftoffRegister result, StoreType type) { -+ bailout(kAtomics, "AtomicExchange"); -+} -+ -+void LiftoffAssembler::AtomicCompareExchange( -+ Register dst_addr, Register offset_reg, uint32_t offset_imm, -+ LiftoffRegister expected, LiftoffRegister new_value, LiftoffRegister result, -+ StoreType type) { -+ bailout(kAtomics, "AtomicCompareExchange"); -+} -+ -+void LiftoffAssembler::AtomicFence() { sync(); } -+ -+void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, -+ uint32_t caller_slot_idx, -+ ValueType type) { -+ MemOperand src(fp, kSystemPointerSize * (caller_slot_idx + 1)); -+ liftoff::Load(this, dst, src, type); -+} -+ -+void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, -+ uint32_t caller_slot_idx, -+ ValueType type) { -+ int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); -+ liftoff::Store(this, fp, offset, src, type); -+} -+ -+void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, -+ ValueType type) { -+ liftoff::Load(this, dst, MemOperand(sp, offset), type); -+} -+ -+void LiftoffAssembler::MoveStackValue(uint32_t dst_offset, uint32_t src_offset, -+ ValueType type) { -+ DCHECK_NE(dst_offset, src_offset); -+ LiftoffRegister reg = GetUnusedRegister(reg_class_for(type), {}); -+ Fill(reg, src_offset, type); -+ Spill(dst_offset, reg, type); -+} -+ -+void LiftoffAssembler::Move(Register dst, Register src, ValueType type) { -+ DCHECK_NE(dst, src); -+ // TODO(ksreten): Handle different sizes here. -+ TurboAssembler::Move(dst, src); -+} -+ -+void LiftoffAssembler::Move(DoubleRegister dst, DoubleRegister src, -+ ValueType type) { -+ DCHECK_NE(dst, src); -+ TurboAssembler::Move(dst, src); -+} -+ -+void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueType type) { -+ RecordUsedSpillOffset(offset); -+ MemOperand dst = liftoff::GetStackSlot(offset); -+ switch (type.kind()) { -+ case ValueType::kI32: -+ Sw(reg.gp(), dst); -+ break; -+ case ValueType::kI64: -+ Sd(reg.gp(), dst); -+ break; -+ case ValueType::kF32: -+ StoreFloat(reg.fp(), dst); -+ break; -+ case ValueType::kF64: -+ TurboAssembler::StoreDouble(reg.fp(), dst); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+void LiftoffAssembler::Spill(int offset, WasmValue value) { -+ RecordUsedSpillOffset(offset); -+ MemOperand dst = liftoff::GetStackSlot(offset); -+ switch (value.type().kind()) { -+ case ValueType::kI32: { -+ LiftoffRegister tmp = GetUnusedRegister(kGpReg, {}); -+ TurboAssembler::li(tmp.gp(), Operand(value.to_i32())); -+ Sw(tmp.gp(), dst); -+ break; -+ } -+ case ValueType::kI64: { -+ LiftoffRegister tmp = GetUnusedRegister(kGpReg, {}); -+ TurboAssembler::li(tmp.gp(), value.to_i64()); -+ Sd(tmp.gp(), dst); -+ break; -+ } -+ default: -+ // kWasmF32 and kWasmF64 are unreachable, since those -+ // constants are not tracked. -+ UNREACHABLE(); -+ } -+} -+ -+void LiftoffAssembler::Fill(LiftoffRegister reg, int offset, ValueType type) { -+ MemOperand src = liftoff::GetStackSlot(offset); -+ switch (type.kind()) { -+ case ValueType::kI32: -+ Lw(reg.gp(), src); -+ break; -+ case ValueType::kI64: -+ Ld(reg.gp(), src); -+ break; -+ case ValueType::kF32: -+ LoadFloat(reg.fp(), src); -+ break; -+ case ValueType::kF64: -+ TurboAssembler::LoadDouble(reg.fp(), src); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+} -+ -+void LiftoffAssembler::FillI64Half(Register, int offset, RegPairHalf) { -+ UNREACHABLE(); -+} -+ -+void LiftoffAssembler::FillStackSlotsWithZero(int start, int size) { -+ DCHECK_LT(0, size); -+ RecordUsedSpillOffset(start + size); -+ -+ if (size <= 12 * kStackSlotSize) { -+ // Special straight-line code for up to 12 slots. Generates one -+ // instruction per slot (<= 12 instructions total). -+ uint32_t remainder = size; -+ for (; remainder >= kStackSlotSize; remainder -= kStackSlotSize) { -+ Sd(zero_reg, liftoff::GetStackSlot(start + remainder)); -+ } -+ DCHECK(remainder == 4 || remainder == 0); -+ if (remainder) { -+ Sw(zero_reg, liftoff::GetStackSlot(start + remainder)); -+ } -+ } else { -+ // General case for bigger counts (12 instructions). -+ // Use a0 for start address (inclusive), a1 for end address (exclusive). -+ Push(a1, a0); -+ Add64(a0, fp, Operand(-start - size)); -+ Add64(a1, fp, Operand(-start)); -+ -+ Label loop; -+ bind(&loop); -+ Sd(zero_reg, MemOperand(a0)); -+ addi(a0, a0, kSystemPointerSize); -+ BranchShort(&loop, ne, a0, Operand(a1)); -+ -+ Pop(a1, a0); -+ } -+} -+ -+void LiftoffAssembler::emit_i64_clz(LiftoffRegister dst, LiftoffRegister src) { -+ TurboAssembler::Clz64(dst.gp(), src.gp()); -+} -+ -+void LiftoffAssembler::emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src) { -+ TurboAssembler::Ctz64(dst.gp(), src.gp()); -+} -+ -+bool LiftoffAssembler::emit_i64_popcnt(LiftoffRegister dst, -+ LiftoffRegister src) { -+ TurboAssembler::Popcnt64(dst.gp(), src.gp()); -+ return true; -+} -+ -+void LiftoffAssembler::emit_i32_mul(Register dst, Register lhs, Register rhs) { -+ TurboAssembler::Mul32(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_i32_divs(Register dst, Register lhs, Register rhs, -+ Label* trap_div_by_zero, -+ Label* trap_div_unrepresentable) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); -+ -+ // Check if lhs == kMinInt and rhs == -1, since this case is unrepresentable. -+ TurboAssembler::CompareI(kScratchReg, lhs, Operand(kMinInt), ne); -+ TurboAssembler::CompareI(kScratchReg2, rhs, Operand(-1), ne); -+ add(kScratchReg, kScratchReg, kScratchReg2); -+ TurboAssembler::Branch(trap_div_unrepresentable, eq, kScratchReg, -+ Operand(zero_reg)); -+ -+ TurboAssembler::Div32(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_i32_divu(Register dst, Register lhs, Register rhs, -+ Label* trap_div_by_zero) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); -+ TurboAssembler::Divu32(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_i32_rems(Register dst, Register lhs, Register rhs, -+ Label* trap_div_by_zero) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); -+ TurboAssembler::Mod32(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_i32_remu(Register dst, Register lhs, Register rhs, -+ Label* trap_div_by_zero) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); -+ TurboAssembler::Modu32(dst, lhs, rhs); -+} -+ -+#define I32_BINOP(name, instruction) \ -+ void LiftoffAssembler::emit_i32_##name(Register dst, Register lhs, \ -+ Register rhs) { \ -+ instruction(dst, lhs, rhs); \ -+ } -+ -+// clang-format off -+I32_BINOP(add, addw) -+I32_BINOP(sub, subw) -+I32_BINOP(and, and_) -+I32_BINOP(or, or_) -+I32_BINOP(xor, xor_) -+// clang-format on -+ -+#undef I32_BINOP -+ -+#define I32_BINOP_I(name, instruction) \ -+ void LiftoffAssembler::emit_i32_##name##i(Register dst, Register lhs, \ -+ int32_t imm) { \ -+ instruction(dst, lhs, Operand(imm)); \ -+ } -+ -+// clang-format off -+I32_BINOP_I(add, Add32) -+I32_BINOP_I(and, And) -+I32_BINOP_I(or, Or) -+I32_BINOP_I(xor, Xor) -+// clang-format on -+ -+#undef I32_BINOP_I -+ -+void LiftoffAssembler::emit_i32_clz(Register dst, Register src) { -+ TurboAssembler::Clz32(dst, src); -+} -+ -+void LiftoffAssembler::emit_i32_ctz(Register dst, Register src) { -+ TurboAssembler::Ctz32(dst, src); -+} -+ -+bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { -+ TurboAssembler::Popcnt32(dst, src); -+ return true; -+} -+ -+#define I32_SHIFTOP(name, instruction) \ -+ void LiftoffAssembler::emit_i32_##name(Register dst, Register src, \ -+ Register amount) { \ -+ instruction(dst, src, amount); \ -+ } -+#define I32_SHIFTOP_I(name, instruction) \ -+ void LiftoffAssembler::emit_i32_##name##i(Register dst, Register src, \ -+ int amount) { \ -+ instruction(dst, src, amount); \ -+ } -+ -+I32_SHIFTOP(shl, sllw) -+I32_SHIFTOP(sar, sraw) -+I32_SHIFTOP(shr, srlw) -+ -+I32_SHIFTOP_I(shl, slliw) -+I32_SHIFTOP_I(sar, sraiw) -+I32_SHIFTOP_I(shr, srliw) -+ -+#undef I32_SHIFTOP -+#undef I32_SHIFTOP_I -+ -+void LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ TurboAssembler::Mul64(dst.gp(), lhs.gp(), rhs.gp()); -+} -+ -+bool LiftoffAssembler::emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs, -+ Label* trap_div_by_zero, -+ Label* trap_div_unrepresentable) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs.gp(), Operand(zero_reg)); -+ -+ // Check if lhs == MinInt64 and rhs == -1, since this case is unrepresentable. -+ TurboAssembler::CompareI(kScratchReg, lhs.gp(), -+ Operand(std::numeric_limits::min()), ne); -+ TurboAssembler::CompareI(kScratchReg2, rhs.gp(), Operand(-1), ne); -+ add(kScratchReg, kScratchReg, kScratchReg2); -+ TurboAssembler::Branch(trap_div_unrepresentable, eq, kScratchReg, -+ Operand(zero_reg)); -+ -+ TurboAssembler::Div64(dst.gp(), lhs.gp(), rhs.gp()); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs, -+ Label* trap_div_by_zero) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs.gp(), Operand(zero_reg)); -+ TurboAssembler::Divu64(dst.gp(), lhs.gp(), rhs.gp()); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs, -+ Label* trap_div_by_zero) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs.gp(), Operand(zero_reg)); -+ TurboAssembler::Mod64(dst.gp(), lhs.gp(), rhs.gp()); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs, -+ Label* trap_div_by_zero) { -+ TurboAssembler::Branch(trap_div_by_zero, eq, rhs.gp(), Operand(zero_reg)); -+ TurboAssembler::Modu64(dst.gp(), lhs.gp(), rhs.gp()); -+ return true; -+} -+ -+#define I64_BINOP(name, instruction) \ -+ void LiftoffAssembler::emit_i64_##name( \ -+ LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { \ -+ instruction(dst.gp(), lhs.gp(), rhs.gp()); \ -+ } -+ -+// clang-format off -+I64_BINOP(add, add) -+I64_BINOP(sub, sub) -+I64_BINOP(and, and_) -+I64_BINOP(or, or_) -+I64_BINOP(xor, xor_) -+// clang-format on -+ -+#undef I64_BINOP -+ -+#define I64_BINOP_I(name, instruction) \ -+ void LiftoffAssembler::emit_i64_##name##i( \ -+ LiftoffRegister dst, LiftoffRegister lhs, int32_t imm) { \ -+ instruction(dst.gp(), lhs.gp(), Operand(imm)); \ -+ } -+ -+// clang-format off -+I64_BINOP_I(add, Add64) -+I64_BINOP_I(and, And) -+I64_BINOP_I(or, Or) -+I64_BINOP_I(xor, Xor) -+// clang-format on -+ -+#undef I64_BINOP_I -+ -+#define I64_SHIFTOP(name, instruction) \ -+ void LiftoffAssembler::emit_i64_##name( \ -+ LiftoffRegister dst, LiftoffRegister src, Register amount) { \ -+ instruction(dst.gp(), src.gp(), amount); \ -+ } -+#define I64_SHIFTOP_I(name, instruction) \ -+ void LiftoffAssembler::emit_i64_##name##i(LiftoffRegister dst, \ -+ LiftoffRegister src, int amount) { \ -+ DCHECK(is_uint6(amount)); \ -+ instruction(dst.gp(), src.gp(), amount); \ -+ } -+ -+I64_SHIFTOP(shl, sll) -+I64_SHIFTOP(sar, sra) -+I64_SHIFTOP(shr, srl) -+ -+I64_SHIFTOP_I(shl, slli) -+I64_SHIFTOP_I(sar, srai) -+I64_SHIFTOP_I(shr, srli) -+ -+#undef I64_SHIFTOP -+#undef I64_SHIFTOP_I -+ -+void LiftoffAssembler::emit_u32_to_intptr(Register dst, Register src) { -+ addw(dst, src, zero_reg); -+} -+ -+void LiftoffAssembler::emit_f32_neg(DoubleRegister dst, DoubleRegister src) { -+ TurboAssembler::Neg_s(dst, src); -+} -+ -+void LiftoffAssembler::emit_f64_neg(DoubleRegister dst, DoubleRegister src) { -+ TurboAssembler::Neg_d(dst, src); -+} -+ -+void LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs, -+ DoubleRegister rhs) { -+ TurboAssembler::Float32Min(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs, -+ DoubleRegister rhs) { -+ TurboAssembler::Float32Max(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs, -+ DoubleRegister rhs) { -+ bailout(kComplexOperation, "f32_copysign"); -+} -+ -+void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs, -+ DoubleRegister rhs) { -+ TurboAssembler::Float64Min(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs, -+ DoubleRegister rhs) { -+ TurboAssembler::Float64Max(dst, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs, -+ DoubleRegister rhs) { -+ bailout(kComplexOperation, "f64_copysign"); -+} -+ -+#define FP_BINOP(name, instruction) \ -+ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \ -+ DoubleRegister rhs) { \ -+ instruction(dst, lhs, rhs); \ -+ } -+#define FP_UNOP(name, instruction) \ -+ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ -+ instruction(dst, src); \ -+ } -+#define FP_UNOP_RETURN_TRUE(name, instruction) \ -+ bool LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ -+ instruction(dst, src, kScratchDoubleReg); \ -+ return true; \ -+ } -+ -+FP_BINOP(f32_add, fadd_s) -+FP_BINOP(f32_sub, fsub_s) -+FP_BINOP(f32_mul, fmul_s) -+FP_BINOP(f32_div, fdiv_s) -+FP_UNOP(f32_abs, fabs_s) -+FP_UNOP_RETURN_TRUE(f32_ceil, Ceil_s_s) -+FP_UNOP_RETURN_TRUE(f32_floor, Floor_s_s) -+FP_UNOP_RETURN_TRUE(f32_trunc, Trunc_s_s) -+FP_UNOP_RETURN_TRUE(f32_nearest_int, Round_s_s) -+FP_UNOP(f32_sqrt, fsqrt_s) -+FP_BINOP(f64_add, fadd_d) -+FP_BINOP(f64_sub, fsub_d) -+FP_BINOP(f64_mul, fmul_d) -+FP_BINOP(f64_div, fdiv_d) -+FP_UNOP(f64_abs, fabs_d) -+FP_UNOP_RETURN_TRUE(f64_ceil, Ceil_d_d) -+FP_UNOP_RETURN_TRUE(f64_floor, Floor_d_d) -+FP_UNOP_RETURN_TRUE(f64_trunc, Trunc_d_d) -+FP_UNOP_RETURN_TRUE(f64_nearest_int, Round_d_d) -+FP_UNOP(f64_sqrt, fsqrt_d) -+ -+#undef FP_BINOP -+#undef FP_UNOP -+#undef FP_UNOP_RETURN_TRUE -+ -+bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, -+ LiftoffRegister dst, -+ LiftoffRegister src, Label* trap) { -+ switch (opcode) { -+ case kExprI32ConvertI64: -+ // According to WebAssembly spec, if I64 value does not fit the range of -+ // I32, the value is undefined. Therefore, We use sign extension to -+ // implement I64 to I32 truncation -+ TurboAssembler::SignExtendWord(dst.gp(), src.gp()); -+ return true; -+ case kExprI32SConvertF32: -+ case kExprI32UConvertF32: -+ case kExprI32SConvertF64: -+ case kExprI32UConvertF64: -+ case kExprI64SConvertF32: -+ case kExprI64UConvertF32: -+ case kExprI64SConvertF64: -+ case kExprI64UConvertF64: -+ case kExprF32ConvertF64: { -+ // real conversion, if src is out-of-bound of target integer types, -+ // kScratchReg is set to 0 -+ switch (opcode) { -+ case kExprI32SConvertF32: -+ Trunc_w_s(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI32UConvertF32: -+ Trunc_uw_s(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI32SConvertF64: -+ Trunc_w_d(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI32UConvertF64: -+ Trunc_uw_d(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI64SConvertF32: -+ Trunc_l_s(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI64UConvertF32: -+ Trunc_ul_s(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI64SConvertF64: -+ Trunc_l_d(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprI64UConvertF64: -+ Trunc_ul_d(dst.gp(), src.fp(), kScratchReg); -+ break; -+ case kExprF32ConvertF64: -+ fcvt_s_d(dst.fp(), src.fp()); -+ // FIXME (?): what if double cannot be represented by float? -+ // Trunc_s_d(dst.gp(), src.fp(), kScratchReg); -+ break; -+ default: -+ UNREACHABLE(); -+ } -+ -+ // Checking if trap. -+ TurboAssembler::Branch(trap, eq, kScratchReg, Operand(zero_reg)); -+ -+ return true; -+ } -+ case kExprI32ReinterpretF32: -+ TurboAssembler::ExtractLowWordFromF64(dst.gp(), src.fp()); -+ return true; -+ case kExprI64SConvertI32: -+ TurboAssembler::SignExtendWord(dst.gp(), src.gp()); -+ return true; -+ case kExprI64UConvertI32: -+ TurboAssembler::ZeroExtendWord(dst.gp(), src.gp()); -+ return true; -+ case kExprI64ReinterpretF64: -+ fmv_x_d(dst.gp(), src.fp()); -+ return true; -+ case kExprF32SConvertI32: { -+ TurboAssembler::Cvt_s_w(dst.fp(), src.gp()); -+ return true; -+ } -+ case kExprF32UConvertI32: -+ TurboAssembler::Cvt_s_uw(dst.fp(), src.gp()); -+ return true; -+ case kExprF32ReinterpretI32: -+ fmv_w_x(dst.fp(), src.gp()); -+ return true; -+ case kExprF64SConvertI32: { -+ TurboAssembler::Cvt_d_w(dst.fp(), src.gp()); -+ return true; -+ } -+ case kExprF64UConvertI32: -+ TurboAssembler::Cvt_d_uw(dst.fp(), src.gp()); -+ return true; -+ case kExprF64ConvertF32: -+ fcvt_d_s(dst.fp(), src.fp()); -+ return true; -+ case kExprF64ReinterpretI64: -+ fmv_d_x(dst.fp(), src.gp()); -+ return true; -+ case kExprI32SConvertSatF32: -+ bailout(kNonTrappingFloatToInt, "kExprI32SConvertSatF32"); -+ return true; -+ case kExprI32UConvertSatF32: -+ bailout(kNonTrappingFloatToInt, "kExprI32UConvertSatF32"); -+ return true; -+ case kExprI32SConvertSatF64: -+ bailout(kNonTrappingFloatToInt, "kExprI32SConvertSatF64"); -+ return true; -+ case kExprI32UConvertSatF64: -+ bailout(kNonTrappingFloatToInt, "kExprI32UConvertSatF64"); -+ return true; -+ case kExprI64SConvertSatF32: -+ bailout(kNonTrappingFloatToInt, "kExprI64SConvertSatF32"); -+ return true; -+ case kExprI64UConvertSatF32: -+ bailout(kNonTrappingFloatToInt, "kExprI64UConvertSatF32"); -+ return true; -+ case kExprI64SConvertSatF64: -+ bailout(kNonTrappingFloatToInt, "kExprI64SConvertSatF64"); -+ return true; -+ case kExprI64UConvertSatF64: -+ bailout(kNonTrappingFloatToInt, "kExprI64UConvertSatF64"); -+ return true; -+ default: -+ return false; -+ } -+} -+ -+void LiftoffAssembler::emit_i32_signextend_i8(Register dst, Register src) { -+ slliw(dst, src, 32 - 8); -+ sraiw(dst, dst, 32 - 8); -+} -+ -+void LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) { -+ slliw(dst, src, 32 - 16); -+ sraiw(dst, dst, 32 - 16); -+} -+ -+void LiftoffAssembler::emit_i64_signextend_i8(LiftoffRegister dst, -+ LiftoffRegister src) { -+ slli(dst.gp(), src.gp(), 64 - 8); -+ srai(dst.gp(), dst.gp(), 64 - 8); -+} -+ -+void LiftoffAssembler::emit_i64_signextend_i16(LiftoffRegister dst, -+ LiftoffRegister src) { -+ slli(dst.gp(), src.gp(), 64 - 16); -+ srai(dst.gp(), dst.gp(), 64 - 16); -+} -+ -+void LiftoffAssembler::emit_i64_signextend_i32(LiftoffRegister dst, -+ LiftoffRegister src) { -+ slli(dst.gp(), src.gp(), 64 - 32); -+ srai(dst.gp(), dst.gp(), 64 - 32); -+} -+ -+void LiftoffAssembler::emit_jump(Label* label) { -+ TurboAssembler::Branch(label); -+} -+ -+void LiftoffAssembler::emit_jump(Register target) { -+ TurboAssembler::Jump(target); -+} -+ -+void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label, -+ ValueType type, Register lhs, -+ Register rhs) { -+ if (rhs != no_reg) { -+ TurboAssembler::Branch(label, cond, lhs, Operand(rhs)); -+ } else { -+ TurboAssembler::Branch(label, cond, lhs, Operand(zero_reg)); -+ } -+} -+ -+void LiftoffAssembler::emit_i32_eqz(Register dst, Register src) { -+ TurboAssembler::Sltu(dst, src, 1); -+} -+ -+void LiftoffAssembler::emit_i32_set_cond(Condition cond, Register dst, -+ Register lhs, Register rhs) { -+ TurboAssembler::CompareI(dst, lhs, Operand(rhs), cond); -+} -+ -+void LiftoffAssembler::emit_i64_eqz(Register dst, LiftoffRegister src) { -+ TurboAssembler::Sltu(dst, src.gp(), 1); -+} -+ -+void LiftoffAssembler::emit_i64_set_cond(Condition cond, Register dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ TurboAssembler::CompareI(dst, lhs.gp(), Operand(rhs.gp()), cond); -+} -+ -+static FPUCondition ConditionToConditionCmpFPU(Condition condition) { -+ switch (condition) { -+ case kEqual: -+ return EQ; -+ case kUnequal: -+ return NE; -+ case kUnsignedLessThan: -+ return LT; -+ case kUnsignedGreaterEqual: -+ return GE; -+ case kUnsignedLessEqual: -+ return LE; -+ case kUnsignedGreaterThan: -+ return GT; -+ default: -+ break; -+ } -+ UNREACHABLE(); -+} -+ -+void LiftoffAssembler::emit_f32_set_cond(Condition cond, Register dst, -+ DoubleRegister lhs, -+ DoubleRegister rhs) { -+ FPUCondition fcond = ConditionToConditionCmpFPU(cond); -+ TurboAssembler::CompareF32(dst, fcond, lhs, rhs); -+} -+ -+void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, -+ DoubleRegister lhs, -+ DoubleRegister rhs) { -+ FPUCondition fcond = ConditionToConditionCmpFPU(cond); -+ TurboAssembler::CompareF64(dst, fcond, lhs, rhs); -+} -+ -+bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition, -+ LiftoffRegister true_value, -+ LiftoffRegister false_value, -+ ValueType type) { -+ return false; -+} -+ -+void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, -+ Register offset_reg, uint32_t offset_imm, -+ LoadType type, -+ LoadTransformationKind transform, -+ uint32_t* protected_load_pc) { -+ bailout(kSimd, "load extend and load splat unimplemented"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shuffle(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs, -+ const uint8_t shuffle[16], -+ bool is_swizzle) { -+ bailout(kSimd, "emit_i8x16_shuffle"); -+} -+ -+void LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_swizzle"); -+} -+ -+void LiftoffAssembler::emit_i8x16_splat(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i8x16_splat"); -+} -+ -+void LiftoffAssembler::emit_i16x8_splat(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_splat"); -+} -+ -+void LiftoffAssembler::emit_i32x4_splat(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_splat"); -+} -+ -+void LiftoffAssembler::emit_i64x2_splat(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i64x2_splat"); -+} -+ -+void LiftoffAssembler::emit_f32x4_splat(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_splat"); -+} -+ -+void LiftoffAssembler::emit_f64x2_splat(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_splat"); -+} -+ -+void LiftoffAssembler::emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_eq"); -+} -+ -+void LiftoffAssembler::emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_ne"); -+} -+ -+void LiftoffAssembler::emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_gt_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_gt_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_ge_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_ge_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_eq"); -+} -+ -+void LiftoffAssembler::emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_ne"); -+} -+ -+void LiftoffAssembler::emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_gt_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_gt_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_ge_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_ge_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_eq"); -+} -+ -+void LiftoffAssembler::emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_ne"); -+} -+ -+void LiftoffAssembler::emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_gt_s"); -+} -+ -+void LiftoffAssembler::emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_gt_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_ge_s"); -+} -+ -+void LiftoffAssembler::emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_ge_u"); -+} -+ -+void LiftoffAssembler::emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_eq"); -+} -+ -+void LiftoffAssembler::emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_ne"); -+} -+ -+void LiftoffAssembler::emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_lt"); -+} -+ -+void LiftoffAssembler::emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_le"); -+} -+ -+void LiftoffAssembler::emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_eq"); -+} -+ -+void LiftoffAssembler::emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_ne"); -+} -+ -+void LiftoffAssembler::emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_lt"); -+} -+ -+void LiftoffAssembler::emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_le"); -+} -+ -+void LiftoffAssembler::emit_s128_const(LiftoffRegister dst, -+ const uint8_t imms[16]) { -+ bailout(kSimd, "emit_s128_const"); -+} -+ -+void LiftoffAssembler::emit_s128_not(LiftoffRegister dst, LiftoffRegister src) { -+ bailout(kSimd, "emit_s128_not"); -+} -+ -+void LiftoffAssembler::emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_s128_and"); -+} -+ -+void LiftoffAssembler::emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_s128_or"); -+} -+ -+void LiftoffAssembler::emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_s128_xor"); -+} -+ -+void LiftoffAssembler::emit_s128_and_not(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_s128_and_not"); -+} -+ -+void LiftoffAssembler::emit_s128_select(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ LiftoffRegister mask) { -+ bailout(kSimd, "emit_s128_select"); -+} -+ -+void LiftoffAssembler::emit_i8x16_neg(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i8x16_neg"); -+} -+ -+void LiftoffAssembler::emit_v8x16_anytrue(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i8x16_anytrue"); -+} -+ -+void LiftoffAssembler::emit_v8x16_alltrue(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i8x16_alltrue"); -+} -+ -+void LiftoffAssembler::emit_i8x16_bitmask(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i8x16_bitmask"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_shl"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs, -+ int32_t rhs) { -+ bailout(kSimd, "emit_i8x16_shli"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shr_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_shr_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shri_s(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i8x16_shri_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shr_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_shr_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_shri_u(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i8x16_shri_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_add"); -+} -+ -+void LiftoffAssembler::emit_i8x16_add_saturate_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_add_saturate_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_add_saturate_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_add_saturate_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_sub"); -+} -+ -+void LiftoffAssembler::emit_i8x16_sub_saturate_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_sub_saturate_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_sub_saturate_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_sub_saturate_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_mul"); -+} -+ -+void LiftoffAssembler::emit_i8x16_min_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_min_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_min_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_min_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_max_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_max_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_max_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_max_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_neg(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_neg"); -+} -+ -+void LiftoffAssembler::emit_v16x8_anytrue(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_anytrue"); -+} -+ -+void LiftoffAssembler::emit_v16x8_alltrue(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_alltrue"); -+} -+ -+void LiftoffAssembler::emit_i16x8_bitmask(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_bitmask"); -+} -+ -+void LiftoffAssembler::emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_shl"); -+} -+ -+void LiftoffAssembler::emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs, -+ int32_t rhs) { -+ bailout(kSimd, "emit_i16x8_shli"); -+} -+ -+void LiftoffAssembler::emit_i16x8_shr_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_shr_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_shri_s(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i16x8_shri_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_shr_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_shr_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_shri_u(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i16x8_shri_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_add"); -+} -+ -+void LiftoffAssembler::emit_i16x8_add_saturate_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_add_saturate_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_add_saturate_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_add_saturate_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_sub"); -+} -+ -+void LiftoffAssembler::emit_i16x8_sub_saturate_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_sub_saturate_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_sub_saturate_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_sub_saturate_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_mul"); -+} -+ -+void LiftoffAssembler::emit_i16x8_min_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_min_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_min_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_min_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_max_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_max_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_max_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_max_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_neg(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_neg"); -+} -+ -+void LiftoffAssembler::emit_v32x4_anytrue(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_v32x4_anytrue"); -+} -+ -+void LiftoffAssembler::emit_v32x4_alltrue(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_v32x4_alltrue"); -+} -+ -+void LiftoffAssembler::emit_i32x4_bitmask(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_bitmask"); -+} -+ -+void LiftoffAssembler::emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_shl"); -+} -+ -+void LiftoffAssembler::emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs, -+ int32_t rhs) { -+ bailout(kSimd, "emit_i32x4_shli"); -+} -+ -+void LiftoffAssembler::emit_i32x4_shr_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_shr_s"); -+} -+ -+void LiftoffAssembler::emit_i32x4_shri_s(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i32x4_shri_s"); -+} -+ -+void LiftoffAssembler::emit_i32x4_shr_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_shr_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_shri_u(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i32x4_shri_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_add"); -+} -+ -+void LiftoffAssembler::emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_sub"); -+} -+ -+void LiftoffAssembler::emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_mul"); -+} -+ -+void LiftoffAssembler::emit_i32x4_min_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_min_s"); -+} -+ -+void LiftoffAssembler::emit_i32x4_min_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_min_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_max_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_max_s"); -+} -+ -+void LiftoffAssembler::emit_i32x4_max_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i32x4_max_u"); -+} -+ -+void LiftoffAssembler::emit_i64x2_neg(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i64x2_neg"); -+} -+ -+void LiftoffAssembler::emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i64x2_shl"); -+} -+ -+void LiftoffAssembler::emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs, -+ int32_t rhs) { -+ bailout(kSimd, "emit_i64x2_shli"); -+} -+ -+void LiftoffAssembler::emit_i64x2_shr_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i64x2_shr_s"); -+} -+ -+void LiftoffAssembler::emit_i64x2_shri_s(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i64x2_shri_s"); -+} -+ -+void LiftoffAssembler::emit_i64x2_shr_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i64x2_shr_u"); -+} -+ -+void LiftoffAssembler::emit_i64x2_shri_u(LiftoffRegister dst, -+ LiftoffRegister lhs, int32_t rhs) { -+ bailout(kSimd, "emit_i64x2_shri_u"); -+} -+ -+void LiftoffAssembler::emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i64x2_add"); -+} -+ -+void LiftoffAssembler::emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i64x2_sub"); -+} -+ -+void LiftoffAssembler::emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i64x2_mul"); -+} -+ -+void LiftoffAssembler::emit_f32x4_abs(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_abs"); -+} -+ -+void LiftoffAssembler::emit_f32x4_neg(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_neg"); -+} -+ -+void LiftoffAssembler::emit_f32x4_sqrt(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_sqrt"); -+} -+ -+bool LiftoffAssembler::emit_f32x4_ceil(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_ceil"); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_f32x4_floor(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_floor"); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_f32x4_trunc(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_trunc"); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_f32x4_nearest_int(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_nearest_int"); -+ return true; -+} -+ -+void LiftoffAssembler::emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_add"); -+} -+ -+void LiftoffAssembler::emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_sub"); -+} -+ -+void LiftoffAssembler::emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_mul"); -+} -+ -+void LiftoffAssembler::emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_div"); -+} -+ -+void LiftoffAssembler::emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_min"); -+} -+ -+void LiftoffAssembler::emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_max"); -+} -+ -+void LiftoffAssembler::emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_pmin"); -+} -+ -+void LiftoffAssembler::emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f32x4_pmax"); -+} -+ -+void LiftoffAssembler::emit_f64x2_abs(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_abs"); -+} -+ -+void LiftoffAssembler::emit_f64x2_neg(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_neg"); -+} -+ -+void LiftoffAssembler::emit_f64x2_sqrt(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_sqrt"); -+} -+ -+bool LiftoffAssembler::emit_f64x2_ceil(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_ceil"); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_f64x2_floor(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_floor"); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_f64x2_trunc(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_trunc"); -+ return true; -+} -+ -+bool LiftoffAssembler::emit_f64x2_nearest_int(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f64x2_nearest_int"); -+ return true; -+} -+ -+void LiftoffAssembler::emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_add"); -+} -+ -+void LiftoffAssembler::emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_sub"); -+} -+ -+void LiftoffAssembler::emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_mul"); -+} -+ -+void LiftoffAssembler::emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_div"); -+} -+ -+void LiftoffAssembler::emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_min"); -+} -+ -+void LiftoffAssembler::emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_max"); -+} -+ -+void LiftoffAssembler::emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_pmin"); -+} -+ -+void LiftoffAssembler::emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_f64x2_pmax"); -+} -+ -+void LiftoffAssembler::emit_i32x4_sconvert_f32x4(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_sconvert_f32x4"); -+} -+ -+void LiftoffAssembler::emit_i32x4_uconvert_f32x4(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_uconvert_f32x4"); -+} -+ -+void LiftoffAssembler::emit_f32x4_sconvert_i32x4(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_sconvert_i32x4"); -+} -+ -+void LiftoffAssembler::emit_f32x4_uconvert_i32x4(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_f32x4_uconvert_i32x4"); -+} -+ -+void LiftoffAssembler::emit_i8x16_sconvert_i16x8(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_sconvert_i16x8"); -+} -+ -+void LiftoffAssembler::emit_i8x16_uconvert_i16x8(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_uconvert_i16x8"); -+} -+ -+void LiftoffAssembler::emit_i16x8_sconvert_i32x4(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_sconvert_i32x4"); -+} -+ -+void LiftoffAssembler::emit_i16x8_uconvert_i32x4(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_uconvert_i32x4"); -+} -+ -+void LiftoffAssembler::emit_i16x8_sconvert_i8x16_low(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_sconvert_i8x16_low"); -+} -+ -+void LiftoffAssembler::emit_i16x8_sconvert_i8x16_high(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_sconvert_i8x16_high"); -+} -+ -+void LiftoffAssembler::emit_i16x8_uconvert_i8x16_low(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_uconvert_i8x16_low"); -+} -+ -+void LiftoffAssembler::emit_i16x8_uconvert_i8x16_high(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_uconvert_i8x16_high"); -+} -+ -+void LiftoffAssembler::emit_i32x4_sconvert_i16x8_low(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_sconvert_i16x8_low"); -+} -+ -+void LiftoffAssembler::emit_i32x4_sconvert_i16x8_high(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_sconvert_i16x8_high"); -+} -+ -+void LiftoffAssembler::emit_i32x4_uconvert_i16x8_low(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_uconvert_i16x8_low"); -+} -+ -+void LiftoffAssembler::emit_i32x4_uconvert_i16x8_high(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_uconvert_i16x8_high"); -+} -+ -+void LiftoffAssembler::emit_i8x16_rounding_average_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i8x16_rounding_average_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_rounding_average_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ LiftoffRegister rhs) { -+ bailout(kSimd, "emit_i16x8_rounding_average_u"); -+} -+ -+void LiftoffAssembler::emit_i8x16_abs(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i8x16_abs"); -+} -+ -+void LiftoffAssembler::emit_i16x8_abs(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i16x8_abs"); -+} -+ -+void LiftoffAssembler::emit_i32x4_abs(LiftoffRegister dst, -+ LiftoffRegister src) { -+ bailout(kSimd, "emit_i32x4_abs"); -+} -+ -+void LiftoffAssembler::emit_i8x16_extract_lane_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i8x16_extract_lane_s"); -+} -+ -+void LiftoffAssembler::emit_i8x16_extract_lane_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i8x16_extract_lane_u"); -+} -+ -+void LiftoffAssembler::emit_i16x8_extract_lane_s(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i16x8_extract_lane_s"); -+} -+ -+void LiftoffAssembler::emit_i16x8_extract_lane_u(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i16x8_extract_lane_u"); -+} -+ -+void LiftoffAssembler::emit_i32x4_extract_lane(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i32x4_extract_lane"); -+} -+ -+void LiftoffAssembler::emit_i64x2_extract_lane(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i64x2_extract_lane"); -+} -+ -+void LiftoffAssembler::emit_f32x4_extract_lane(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_f32x4_extract_lane"); -+} -+ -+void LiftoffAssembler::emit_f64x2_extract_lane(LiftoffRegister dst, -+ LiftoffRegister lhs, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_f64x2_extract_lane"); -+} -+ -+void LiftoffAssembler::emit_i8x16_replace_lane(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i8x16_replace_lane"); -+} -+ -+void LiftoffAssembler::emit_i16x8_replace_lane(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i16x8_replace_lane"); -+} -+ -+void LiftoffAssembler::emit_i32x4_replace_lane(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i32x4_replace_lane"); -+} -+ -+void LiftoffAssembler::emit_i64x2_replace_lane(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_i64x2_replace_lane"); -+} -+ -+void LiftoffAssembler::emit_f32x4_replace_lane(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_f32x4_replace_lane"); -+} -+ -+void LiftoffAssembler::emit_f64x2_replace_lane(LiftoffRegister dst, -+ LiftoffRegister src1, -+ LiftoffRegister src2, -+ uint8_t imm_lane_idx) { -+ bailout(kSimd, "emit_f64x2_replace_lane"); -+} -+ -+void LiftoffAssembler::StackCheck(Label* ool_code, Register limit_address) { -+ TurboAssembler::Uld(limit_address, MemOperand(limit_address)); -+ TurboAssembler::Branch(ool_code, ule, sp, Operand(limit_address)); -+} -+ -+void LiftoffAssembler::CallTrapCallbackForTesting() { -+ PrepareCallCFunction(0, GetUnusedRegister(kGpReg, {}).gp()); -+ CallCFunction(ExternalReference::wasm_call_trap_callback_for_testing(), 0); -+} -+ -+void LiftoffAssembler::AssertUnreachable(AbortReason reason) { -+ if (emit_debug_code()) Abort(reason); -+} -+ -+void LiftoffAssembler::PushRegisters(LiftoffRegList regs) { -+ LiftoffRegList gp_regs = regs & kGpCacheRegList; -+ unsigned num_gp_regs = gp_regs.GetNumRegsSet(); -+ if (num_gp_regs) { -+ unsigned offset = num_gp_regs * kSystemPointerSize; -+ Add64(sp, sp, Operand(-offset)); -+ while (!gp_regs.is_empty()) { -+ LiftoffRegister reg = gp_regs.GetFirstRegSet(); -+ offset -= kSystemPointerSize; -+ Sd(reg.gp(), MemOperand(sp, offset)); -+ gp_regs.clear(reg); -+ } -+ DCHECK_EQ(offset, 0); -+ } -+ LiftoffRegList fp_regs = regs & kFpCacheRegList; -+ unsigned num_fp_regs = fp_regs.GetNumRegsSet(); -+ if (num_fp_regs) { -+ Add64(sp, sp, Operand(-(num_fp_regs * kStackSlotSize))); -+ unsigned offset = 0; -+ while (!fp_regs.is_empty()) { -+ LiftoffRegister reg = fp_regs.GetFirstRegSet(); -+ TurboAssembler::StoreDouble(reg.fp(), MemOperand(sp, offset)); -+ fp_regs.clear(reg); -+ offset += sizeof(double); -+ } -+ DCHECK_EQ(offset, num_fp_regs * sizeof(double)); -+ } -+} -+ -+void LiftoffAssembler::PopRegisters(LiftoffRegList regs) { -+ LiftoffRegList fp_regs = regs & kFpCacheRegList; -+ unsigned fp_offset = 0; -+ while (!fp_regs.is_empty()) { -+ LiftoffRegister reg = fp_regs.GetFirstRegSet(); -+ TurboAssembler::LoadDouble(reg.fp(), MemOperand(sp, fp_offset)); -+ fp_regs.clear(reg); -+ fp_offset += sizeof(double); -+ } -+ if (fp_offset) Add64(sp, sp, Operand(fp_offset)); -+ LiftoffRegList gp_regs = regs & kGpCacheRegList; -+ unsigned gp_offset = 0; -+ while (!gp_regs.is_empty()) { -+ LiftoffRegister reg = gp_regs.GetLastRegSet(); -+ Ld(reg.gp(), MemOperand(sp, gp_offset)); -+ gp_regs.clear(reg); -+ gp_offset += kSystemPointerSize; -+ } -+ Add64(sp, sp, Operand(gp_offset)); -+} -+ -+void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) { -+ TurboAssembler::DropAndRet(static_cast(num_stack_slots)); -+} -+ -+void LiftoffAssembler::CallC(const wasm::FunctionSig* sig, -+ const LiftoffRegister* args, -+ const LiftoffRegister* rets, -+ ValueType out_argument_type, int stack_bytes, -+ ExternalReference ext_ref) { -+ Add64(sp, sp, Operand(-stack_bytes)); -+ -+ int arg_bytes = 0; -+ for (ValueType param_type : sig->parameters()) { -+ liftoff::Store(this, sp, arg_bytes, *args++, param_type); -+ arg_bytes += param_type.element_size_bytes(); -+ } -+ DCHECK_LE(arg_bytes, stack_bytes); -+ -+ // Pass a pointer to the buffer with the arguments to the C function. -+ // On RISC-V, the first argument is passed in {a0}. -+ constexpr Register kFirstArgReg = a0; -+ mv(kFirstArgReg, sp); -+ -+ // Now call the C function. -+ constexpr int kNumCCallArgs = 1; -+ PrepareCallCFunction(kNumCCallArgs, kScratchReg); -+ CallCFunction(ext_ref, kNumCCallArgs); -+ -+ // Move return value to the right register. -+ const LiftoffRegister* next_result_reg = rets; -+ if (sig->return_count() > 0) { -+ DCHECK_EQ(1, sig->return_count()); -+ constexpr Register kReturnReg = a0; -+ if (kReturnReg != next_result_reg->gp()) { -+ Move(*next_result_reg, LiftoffRegister(kReturnReg), sig->GetReturn(0)); -+ } -+ ++next_result_reg; -+ } -+ -+ // Load potential output value from the buffer on the stack. -+ if (out_argument_type != kWasmStmt) { -+ liftoff::Load(this, *next_result_reg, MemOperand(sp, 0), out_argument_type); -+ } -+ -+ Add64(sp, sp, Operand(stack_bytes)); -+} -+ -+void LiftoffAssembler::CallNativeWasmCode(Address addr) { -+ Call(addr, RelocInfo::WASM_CALL); -+} -+ -+void LiftoffAssembler::TailCallNativeWasmCode(Address addr) { -+ Jump(addr, RelocInfo::WASM_CALL); -+} -+ -+void LiftoffAssembler::CallIndirect(const wasm::FunctionSig* sig, -+ compiler::CallDescriptor* call_descriptor, -+ Register target) { -+ if (target == no_reg) { -+ pop(kScratchReg); -+ Call(kScratchReg); -+ } else { -+ Call(target); -+ } -+} -+ -+void LiftoffAssembler::TailCallIndirect(Register target) { -+ if (target == no_reg) { -+ Pop(kScratchReg); -+ Jump(kScratchReg); -+ } else { -+ Jump(target); -+ } -+} -+ -+void LiftoffAssembler::CallRuntimeStub(WasmCode::RuntimeStubId sid) { -+ // A direct call to a wasm runtime stub defined in this module. -+ // Just encode the stub index. This will be patched at relocation. -+ Call(static_cast
(sid), RelocInfo::WASM_STUB_CALL); -+} -+ -+void LiftoffAssembler::AllocateStackSlot(Register addr, uint32_t size) { -+ Add64(sp, sp, Operand(-size)); -+ TurboAssembler::Move(addr, sp); -+} -+ -+void LiftoffAssembler::DeallocateStackSlot(uint32_t size) { -+ Add64(sp, sp, Operand(size)); -+} -+ -+void LiftoffStackSlots::Construct() { -+ for (auto& slot : slots_) { -+ const LiftoffAssembler::VarState& src = slot.src_; -+ switch (src.loc()) { -+ case LiftoffAssembler::VarState::kStack: -+ asm_->Ld(kScratchReg, liftoff::GetStackSlot(slot.src_offset_)); -+ asm_->push(kScratchReg); -+ break; -+ case LiftoffAssembler::VarState::kRegister: -+ liftoff::push(asm_, src.reg(), src.type()); -+ break; -+ case LiftoffAssembler::VarState::kIntConst: { -+ asm_->li(kScratchReg, Operand(src.i32_const())); -+ asm_->push(kScratchReg); -+ break; -+ } -+ } -+ } -+} -+ -+} // namespace wasm -+} // namespace internal -+} // namespace v8 -+ -+#endif // V8_WASM_BASELINE_RISCV_LIFTOFF_ASSEMBLER_RISCV_H_ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/jump-table-assembler.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/wasm/jump-table-assembler.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/jump-table-assembler.cc -@@ -307,6 +307,40 @@ void JumpTableAssembler::NopBytes(int by - } - } - -+#elif V8_TARGET_ARCH_RISCV64 -+void JumpTableAssembler::EmitLazyCompileJumpSlot(uint32_t func_index, -+ Address lazy_compile_target) { -+ int start = pc_offset(); -+ li(kWasmCompileLazyFuncIndexRegister, func_index); // max. 2 instr -+ // Jump produces max. 9 instructions (8 for li + 1 for jr) -+ Jump(lazy_compile_target, RelocInfo::NONE); -+ int nop_bytes = start + kLazyCompileTableSlotSize - pc_offset(); -+ DCHECK_EQ(nop_bytes % kInstrSize, 0); -+ for (int i = 0; i < nop_bytes; i += kInstrSize) nop(); -+} -+ -+bool JumpTableAssembler::EmitJumpSlot(Address target) { -+ PatchAndJump(target); -+ return true; -+} -+ -+void JumpTableAssembler::EmitFarJumpSlot(Address target) { -+ JumpToInstructionStream(target); -+} -+ -+// static -+void JumpTableAssembler::PatchFarJumpSlot(Address slot, Address target) { -+ UNREACHABLE(); -+} -+ -+void JumpTableAssembler::NopBytes(int bytes) { -+ DCHECK_LE(0, bytes); -+ DCHECK_EQ(0, bytes % kInstrSize); -+ for (; bytes > 0; bytes -= kInstrSize) { -+ nop(); -+ } -+} -+ - #else - #error Unknown architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/jump-table-assembler.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/wasm/jump-table-assembler.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/jump-table-assembler.h -@@ -215,6 +215,11 @@ class V8_EXPORT_PRIVATE JumpTableAssembl - static constexpr int kJumpTableSlotSize = 8 * kInstrSize; - static constexpr int kFarJumpTableSlotSize = 6 * kInstrSize; - static constexpr int kLazyCompileTableSlotSize = 8 * kInstrSize; -+#elif V8_TARGET_ARCH_RISCV64 -+ static constexpr int kJumpTableLineSize = 6 * kInstrSize; -+ static constexpr int kJumpTableSlotSize = 6 * kInstrSize; -+ static constexpr int kFarJumpTableSlotSize = 9 * kInstrSize; -+ static constexpr int kLazyCompileTableSlotSize = 9 * kInstrSize; - #else - #error Unknown architecture. - #endif -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/wasm-linkage.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/wasm/wasm-linkage.h -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/wasm-linkage.h -@@ -102,6 +102,22 @@ constexpr Register kGpReturnRegisters[] - constexpr DoubleRegister kFpParamRegisters[] = {d0, d2}; - constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2}; - -+#elif V8_TARGET_ARCH_RISCV64 -+// =========================================================================== -+// == riscv64 ================================================================= -+// =========================================================================== -+// Note that kGpParamRegisters and kFpParamRegisters are used in -+// Builtins::Generate_WasmCompileLazy (builtins-riscv64.cc) -+constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6, a7}; -+constexpr Register kGpReturnRegisters[] = {a0, a1}; -+constexpr DoubleRegister kFpParamRegisters[] = {fa0, fa1, fa2, fa3, -+ fa4, fa5, fa6}; -+constexpr DoubleRegister kFpReturnRegisters[] = {fa0, fa1}; -+ -+#elif V8_TARGET_ARCH_RISCV -+ -+#error RISCV(32) architecture not supported -+ - #else - // =========================================================================== - // == unknown ================================================================ -Index: qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/wasm-serialization.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.17.orig/src/3rdparty/chromium/v8/src/wasm/wasm-serialization.cc -+++ qtwebengine-everywhere-src-5.15.17/src/3rdparty/chromium/v8/src/wasm/wasm-serialization.cc -@@ -368,7 +368,8 @@ bool NativeModuleSerializer::WriteCode(c - writer->WriteVector(code->source_positions()); - writer->WriteVector(code->protected_instructions_data()); - #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM || \ -- V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X -+ V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X || \ -+ V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_RISCV32 - // On platforms that don't support misaligned word stores, copy to an aligned - // buffer if necessary so we can relocate the serialized code. - std::unique_ptr aligned_buffer; diff --git a/riscv.patch b/riscv.patch deleted file mode 100644 index 9561450..0000000 --- a/riscv.patch +++ /dev/null @@ -1,520 +0,0 @@ -riscv64 support patch taken from Opensuse: -https://build.opensuse.org/package/show/openSUSE:Factory:RISCV/libqt5-qtwebengine?rev=110 - -Index: qtwebengine-everywhere-src-5.15.19/configure.pri -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/configure.pri -+++ qtwebengine-everywhere-src-5.15.19/configure.pri -@@ -157,6 +157,7 @@ defineTest(qtConfTest_detectArch) { - contains(QT_ARCH, "arm")|contains(QT_ARCH, "arm64"): return(true) - contains(QT_ARCH, "mips"): return(true) - contains(QT_ARCH, "mips64"): return(true) -+ contains(QT_ARCH, "riscv64"): return(true) - qtLog("Architecture not supported.") - return(false) - } -Index: qtwebengine-everywhere-src-5.15.19/mkspecs/features/functions.prf -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/mkspecs/features/functions.prf -+++ qtwebengine-everywhere-src-5.15.19/mkspecs/features/functions.prf -@@ -112,6 +112,7 @@ defineReplace(gnArch) { - contains(qtArch, "mips"): return(mipsel) - contains(qtArch, "mips64"): return(mips64el) - contains(qtArch, "mips64el"): return(mips64el) -+ contains(qtArch, "riscv64"): return(riscv64) - return(unknown) - } - -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/base/process/launch_posix.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/base/process/launch_posix.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/base/process/launch_posix.cc -@@ -704,7 +704,7 @@ NOINLINE pid_t CloneAndLongjmpInChild(un - alignas(16) char stack_buf[PTHREAD_STACK_MIN]; - #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ - defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_S390_FAMILY) || \ -- defined(ARCH_CPU_PPC64_FAMILY) -+ defined(ARCH_CPU_PPC64_FAMILY) || defined(ARCH_CPU_RISCV_FAMILY) - // The stack grows downward. - void* stack = stack_buf + sizeof(stack_buf); - #else -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/build/build_config.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/build/build_config.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/build/build_config.h -@@ -193,6 +193,11 @@ - #define ARCH_CPU_32_BITS 1 - #define ARCH_CPU_BIG_ENDIAN 1 - #endif -+#elif defined(__riscv) && __riscv_xlen == 64 -+#define ARCH_CPU_RISCV_FAMILY 1 -+#define ARCH_CPU_RISCV64 1 -+#define ARCH_CPU_64_BITS 1 -+#define ARCH_CPU_LITTLE_ENDIAN 1 - #else - #error Please add support for your architecture in build/build_config.h - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn -@@ -290,3 +290,20 @@ gcc_toolchain("mips64") { - is_clang = false - } - } -+ -+gcc_toolchain("riscv64") { -+ cc = "gcc" -+ cxx = "g++" -+ -+ readelf = "readelf" -+ nm = "nm" -+ ar = "ar" -+ ld = cxx -+ -+ toolchain_args = { -+ current_cpu = "riscv64" -+ current_os = "linux" -+ is_clang = false -+ } -+} -+ -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/skia/BUILD.gn -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/skia/BUILD.gn -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/skia/BUILD.gn -@@ -821,6 +821,8 @@ skia_source_set("skia_opts") { - sources = skia_opts.none_sources - } else if (current_cpu == "s390x") { - sources = skia_opts.none_sources -+ } else if (current_cpu == "riscv64") { -+ sources = skia_opts.none_sources - } else { - assert(false, "Need to port cpu specific stuff from skia_library_opts.gyp") - } -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/angle/gni/angle.gni -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/angle/gni/angle.gni -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/angle/gni/angle.gni -@@ -54,7 +54,7 @@ angle_data_dir = "angledata" - declare_args() { - if (current_cpu == "arm64" || current_cpu == "x64" || - current_cpu == "mips64el" || current_cpu == "s390x" || -- current_cpu == "ppc64") { -+ current_cpu == "ppc64" || current_cpu == "riscv64") { - angle_64bit_current_cpu = true - } else if (current_cpu == "arm" || current_cpu == "x86" || - current_cpu == "mipsel" || current_cpu == "s390" || -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/angle/include/platform/PlatformMethods.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/angle/include/platform/PlatformMethods.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/angle/include/platform/PlatformMethods.h -@@ -9,6 +9,7 @@ - #ifndef ANGLE_PLATFORMMETHODS_H - #define ANGLE_PLATFORMMETHODS_H - -+#include - #include - #include - #include -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/blink/renderer/platform/heap/asm/BUILD.gn -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/blink/renderer/platform/heap/asm/BUILD.gn -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/blink/renderer/platform/heap/asm/BUILD.gn -@@ -38,6 +38,8 @@ if (current_cpu == "x86" || current_cpu - sources = [ "SaveRegisters_mips64.S" ] - } else if (current_cpu == "ppc64") { - sources = [ "SaveRegisters_ppc64.S" ] -+ } else if (current_cpu == "riscv64") { -+ sources = [ "SaveRegisters_riscv64.S" ] - } - - if (current_cpu == "arm") { -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/blink/renderer/platform/heap/asm/SaveRegisters_riscv64.S -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/blink/renderer/platform/heap/asm/SaveRegisters_riscv64.S -@@ -0,0 +1,45 @@ -+/* -+ * typedef void (*PushAllRegistersCallback)(ThreadState*, intptr_t*); -+ * extern "C" void PushAllRegisters(ThreadState*, PushAllRegistersCallback) -+ */ -+ -+.type PushAllRegisters, %function -+.global PushAllRegisters -+.hidden PushAllRegisters -+PushAllRegisters: -+ /* Push all callee-saves registers to get them -+ * on the stack for conservative stack scanning. -+ * Reserve space for callee-saved registers and return address. -+ */ -+ addi sp,sp,-112 -+ /* Save the callee-saved registers and the return address. */ -+ sd ra,0(sp) -+ sd s0,8(sp) -+ sd s1,16(sp) -+ sd s2,24(sp) -+ sd s3,32(sp) -+ sd s4,40(sp) -+ sd s5,48(sp) -+ sd s6,56(sp) -+ sd s7,64(sp) -+ sd s8,72(sp) -+ sd s9,80(sp) -+ sd s10,88(sp) -+ sd s11,96(sp) -+ /* Note: the callee-saved floating point registers do not need to be -+ * copied to the stack, because fp registers never hold heap pointers -+ * and so do not need to be kept visible to the garbage collector. -+ * Pass the first argument untouched in a0 and the -+ * stack pointer to the callback. -+ */ -+ mv ra,a1 -+ mv a1,sp -+ jalr ra -+ /* Restore return address, adjust stack and return. -+ * Note: the copied registers do not need to be reloaded here, -+ * because they were preserved by the called routine. -+ */ -+ ld ra,0(sp) -+ addi sp,sp,112 -+ ret -+.size PushAllRegisters, . - PushAllRegisters -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/boringssl/src/include/openssl/base.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/boringssl/src/include/openssl/base.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/boringssl/src/include/openssl/base.h -@@ -105,6 +105,8 @@ extern "C" { - #elif defined(__mips__) && defined(__LP64__) - #define OPENSSL_64_BIT - #define OPENSSL_MIPS64 -+#elif defined(__riscv) && __SIZEOF_POINTER__ == 8 -+#define OPENSSL_64_BIT - #elif defined(__pnacl__) - #define OPENSSL_32_BIT - #define OPENSSL_PNACL -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/dav1d/config/linux/riscv64/config.h -=================================================================== ---- /dev/null -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/dav1d/config/linux/riscv64/config.h -@@ -0,0 +1,38 @@ -+/* -+ * Autogenerated by the Meson build system. -+ * Do not edit, your changes will be lost. -+ */ -+ -+#pragma once -+ -+#define ARCH_AARCH64 0 -+ -+#define ARCH_ARM 0 -+ -+#define ARCH_PPC64LE 0 -+ -+#define ARCH_X86 0 -+ -+#define ARCH_X86_32 0 -+ -+#define ARCH_X86_64 0 -+ -+#define CONFIG_16BPC 1 -+ -+#define CONFIG_8BPC 1 -+ -+// #define CONFIG_LOG 1 -- Logging is controlled by Chromium -+ -+#define ENDIANNESS_BIG 0 -+ -+#define HAVE_ASM 0 -+ -+#define HAVE_AS_FUNC 0 -+ -+#define HAVE_CLOCK_GETTIME 1 -+ -+#define HAVE_GETAUXVAL 1 -+ -+#define HAVE_POSIX_MEMALIGN 1 -+ -+#define HAVE_UNISTD_H 1 -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/lss/linux_syscall_support.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/lss/linux_syscall_support.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/lss/linux_syscall_support.h -@@ -88,7 +88,7 @@ - */ - #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ - defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ -- defined(__aarch64__) || defined(__s390__)) \ -+ defined(__aarch64__) || defined(__s390__) || defined(__riscv)) \ - && (defined(__linux) || defined(__ANDROID__)) - - #ifndef SYS_CPLUSPLUS -@@ -301,7 +301,7 @@ struct kernel_old_sigaction { - } __attribute__((packed,aligned(4))); - #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) - #define kernel_old_sigaction kernel_sigaction --#elif defined(__aarch64__) -+#elif defined(__aarch64__) || defined(__riscv) - // No kernel_old_sigaction defined for arm64. - #endif - -@@ -341,7 +341,9 @@ struct kernel_sigaction { - void (*sa_sigaction_)(int, siginfo_t *, void *); - }; - unsigned long sa_flags; -+#ifndef __riscv - void (*sa_restorer)(void); -+#endif - struct kernel_sigset_t sa_mask; - #endif - }; -@@ -519,7 +521,7 @@ struct kernel_stat { - int st_blocks; - int st_pad4[14]; - }; --#elif defined(__aarch64__) -+#elif defined(__aarch64__) || defined(__riscv) - struct kernel_stat { - unsigned long st_dev; - unsigned long st_ino; -@@ -1065,7 +1067,7 @@ struct kernel_statfs { - #define __NR_getrandom (__NR_SYSCALL_BASE + 384) - #endif - /* End of ARM 3/EABI definitions */ --#elif defined(__aarch64__) -+#elif defined(__aarch64__) || defined(__riscv) - #ifndef __NR_setxattr - #define __NR_setxattr 5 - #endif -@@ -1880,7 +1882,7 @@ struct kernel_statfs { - - #undef LSS_RETURN - #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ -- || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__)) -+ || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) || defined(__riscv)) - /* Failing system calls return a negative result in the range of - * -1..-4095. These are "errno" values with the sign inverted. - */ -@@ -3373,6 +3375,122 @@ struct kernel_statfs { - } - LSS_RETURN(int, __ret); - } -+ #elif defined(__riscv) -+ #undef LSS_REG -+ #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a -+ #undef LSS_BODY -+ #define LSS_BODY(type,name,args...) \ -+ register int64_t __res_a0 __asm__("a0"); \ -+ register int64_t __a7 __asm__("a7") = __NR_##name; \ -+ int64_t __res; \ -+ __asm__ __volatile__ ("scall\n" \ -+ : "=r"(__res_a0) \ -+ : "r"(__a7) , ## args \ -+ : "memory"); \ -+ __res = __res_a0; \ -+ LSS_RETURN(type, __res) -+ #undef _syscall0 -+ #define _syscall0(type, name) \ -+ type LSS_NAME(name)(void) { \ -+ LSS_BODY(type, name); \ -+ } -+ #undef _syscall1 -+ #define _syscall1(type, name, type1, arg1) \ -+ type LSS_NAME(name)(type1 arg1) { \ -+ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ -+ } -+ #undef _syscall2 -+ #define _syscall2(type, name, type1, arg1, type2, arg2) \ -+ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ -+ LSS_REG(0, arg1); LSS_REG(1, arg2); \ -+ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ -+ } -+ #undef _syscall3 -+ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ -+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ -+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ -+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ -+ } -+ #undef _syscall4 -+ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ -+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ -+ LSS_REG(3, arg4); \ -+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ -+ } -+ #undef _syscall5 -+ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ -+ type5,arg5) \ -+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ -+ type5 arg5) { \ -+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ -+ LSS_REG(3, arg4); LSS_REG(4, arg5); \ -+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ -+ "r"(__r4)); \ -+ } -+ #undef _syscall6 -+ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ -+ type5,arg5,type6,arg6) \ -+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ -+ type5 arg5, type6 arg6) { \ -+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ -+ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ -+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ -+ "r"(__r4), "r"(__r5)); \ -+ } -+ -+ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, -+ int flags, void *arg, int *parent_tidptr, -+ void *newtls, int *child_tidptr) { -+ int64_t __res; -+ { -+ register int64_t __res_a0 __asm__("a0"); -+ register uint64_t __flags __asm__("a0") = flags; -+ register void *__stack __asm__("a1") = child_stack; -+ register void *__ptid __asm__("a2") = parent_tidptr; -+ register void *__tls __asm__("a3") = newtls; -+ register int *__ctid __asm__("a4") = child_tidptr; -+ __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be -+ * used by the child. -+ */ -+ "addi %2,%2,-16\n" -+ "sd %1, 0(%2)\n" -+ "sd %4, 8(%2)\n" -+ -+ /* %a0 = syscall(%a0 = flags, -+ * %a1 = child_stack, -+ * %a2 = parent_tidptr, -+ * %a3 = newtls, -+ * %a4 = child_tidptr) -+ */ -+ "li a7, %8\n" -+ "scall\n" -+ -+ /* if (%a0 != 0) -+ * return %a0; -+ */ -+ "bnez %0, 1f\n" -+ -+ /* In the child, now. Call "fn(arg)". -+ */ -+ "ld a1, 0(sp)\n" -+ "ld a0, 8(sp)\n" -+ "jalr a1\n" -+ -+ /* Call _exit(%a0). -+ */ -+ "li a7, %9\n" -+ "scall\n" -+ "1:\n" -+ : "=r" (__res_a0) -+ : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), -+ "r"(__ptid), "r"(__tls), "r"(__ctid), -+ "i"(__NR_clone), "i"(__NR_exit) -+ : "cc", "memory"); -+ __res = __res_a0; -+ } -+ LSS_RETURN(int, __res); -+ } - #endif - #define __NR__exit __NR_exit - #define __NR__gettid __NR_gettid -@@ -4181,7 +4299,7 @@ struct kernel_statfs { - LSS_SC_BODY(4, int, 8, d, type, protocol, sv); - } - #endif -- #if defined(__ARM_EABI__) || defined (__aarch64__) -+ #if defined(__ARM_EABI__) || defined (__aarch64__) || defined(__riscv) - LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, - int, flags) - LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, -@@ -4503,7 +4621,7 @@ struct kernel_statfs { - // TODO: define this in an arch-independant way instead of inlining the clone - // syscall body. - --# if defined(__aarch64__) -+# if defined(__aarch64__) || defined(__riscv) - LSS_INLINE pid_t LSS_NAME(fork)(void) { - // No fork syscall on aarch64 - implement by means of the clone syscall. - // Note that this does not reset glibc's cached view of the PID/TID, so -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/swiftshader/third_party/llvm-10.0/BUILD.gn -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/swiftshader/third_party/llvm-10.0/BUILD.gn -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/swiftshader/third_party/llvm-10.0/BUILD.gn -@@ -149,6 +149,7 @@ swiftshader_llvm_source_set("swiftshader - deps += [ ":swiftshader_llvm_ppc" ] - } else if (current_cpu == "x86" || current_cpu == "x64") { - deps += [ ":swiftshader_llvm_x86" ] -+ } else if (current_cpu == "riscv64") { - } else { - assert(false, "Unsupported current_cpu") - } -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/differ_block.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/differ_block.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/differ_block.cc -@@ -30,7 +30,7 @@ bool VectorDifference(const uint8_t* ima - static bool (*diff_proc)(const uint8_t*, const uint8_t*) = nullptr; - - if (!diff_proc) { --#if defined(WEBRTC_ARCH_ARM_FAMILY) || defined(WEBRTC_ARCH_MIPS_FAMILY) -+#if defined(WEBRTC_ARCH_ARM_FAMILY) || defined(WEBRTC_ARCH_MIPS_FAMILY) || defined(WEBRTC_ARCH_RISCV_FAMILY) - // For ARM and MIPS processors, always use C version. - // TODO(hclam): Implement a NEON version. - diff_proc = &VectorDifference_C; -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/webrtc/rtc_base/system/arch.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/chromium/third_party/webrtc/rtc_base/system/arch.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/chromium/third_party/webrtc/rtc_base/system/arch.h -@@ -50,6 +50,10 @@ - #elif defined(__EMSCRIPTEN__) - #define WEBRTC_ARCH_32_BITS - #define WEBRTC_ARCH_LITTLE_ENDIAN -+#elif defined(__riscv) && __riscv_xlen == 64 -+#define WEBRTC_ARCH_RISCV_FAMILY -+#define WEBRTC_ARCH_64_BITS -+#define WEBRTC_ARCH_LITTLE_ENDIAN - #else - #error Please add support for your architecture in rtc_base/system/arch.h - #endif -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/gn/tools/gn/args.cc -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/gn/tools/gn/args.cc -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/gn/tools/gn/args.cc -@@ -329,6 +329,7 @@ void Args::SetSystemVarsLocked(Scope* de - static const char kMips64[] = "mips64el"; - static const char kS390X[] = "s390x"; - static const char kPPC64[] = "ppc64"; -+ static const char kRiscv64[] = "riscv64"; - const char* arch = nullptr; - - // Set the host CPU architecture based on the underlying OS, not -@@ -353,6 +354,8 @@ void Args::SetSystemVarsLocked(Scope* de - // This allows us to use the same toolchain as ppc64 BE - // and specific flags are included using the host_byteorder logic. - arch = kPPC64; -+ else if (os_arch == "riscv64") -+ arch = kRiscv64; - else - CHECK(false) << "OS architecture not handled. (" << os_arch << ")"; - -Index: qtwebengine-everywhere-src-5.15.19/src/3rdparty/gn/util/build_config.h -=================================================================== ---- qtwebengine-everywhere-src-5.15.19.orig/src/3rdparty/gn/util/build_config.h -+++ qtwebengine-everywhere-src-5.15.19/src/3rdparty/gn/util/build_config.h -@@ -172,6 +172,16 @@ - #define ARCH_CPU_32_BITS 1 - #define ARCH_CPU_BIG_ENDIAN 1 - #endif -+#elif defined(__riscv) -+#define ARCH_CPU_RISCV_FAMILY 1 -+#if __riscv_xlen == 64 -+#define ARCH_CPU_RISCV64 1 -+#define ARCH_CPU_64_BITS 1 -+#else -+#define ARCH_CPU_RISCV32 1 -+#define ARCH_CPU_32_BITS 1 -+#endif -+#define ARCH_CPU_LITTLE_ENDIAN 1 - #else - #error Please add support for your architecture in build_config.h - #endif diff --git a/sources b/sources index 2936db1..b4bf324 100644 --- a/sources +++ b/sources @@ -1,2 +1,5 @@ -SHA512 (qtwebengine-everywhere-src-5.15.19-clean.tar.xz) = cfc6f7bab4e2731fdc07097228a254eb7f20ee195b7ee6f1571253688fb421942fb85c859e0a50f2ac8077a5c65bf60443bdeef80984eac938291cacf7eb2752 SHA512 (pulseaudio-12.2-headers.tar.gz) = a5a9bcbb16030b3bc83cc0cc8f5e7f90e0723d3e83258a5c77eacb32eaa267118a73fa7814fbcc99a24e4907916a2b371ebb6dedc4f45541c3acf6c834fd35be +SHA512 (qtwebengine-everywhere-src-5.15.8-clean.tar.xz) = 0ded6ec6106a79e66796fa65b9574debf59e602aecbfdd0cdf0aeb6d17530177c0a8650078402c426abfebcd40c97d1501f4277541c86f2c576543052f627c04 +SHA512 (python2.7-2.7.18-19.el9.1.src.rpm) = e6d738b2880b833ea80aec709f7bcf20dac2e8c59d45f1627f61245b3aa9be845888152232e9f08145723514eb29aeada3d5d99641aabe9ec9af2a5c15f32777 +SHA512 (python2.7-2.7.18-19.el9.1.aarch64.rpm) = 66c8487a3323bb854ff79242287ae5d290315609b4f79fb985626e52d96286d6dfd2da9a8257e23be036b72adabbbec08d53db339935d5d6e8b6018417bbc769 +SHA512 (python2.7-2.7.18-19.el9.1.x86_64.rpm) = 55f03b17f649a2da9edae67c1ca7c84738a023fc3ab2e7d6060db8a2b8ddf20099147533f3d50ce3dfafec5ca988f75ff229e67d331bcb669c879802ab6555a9