Upgrade VIXL version from 6.3.0 to 7.0.0

+ add CODEOWNERS file

Issue: https://gitee.com/openharmony/third_party_vixl/issues/IAXCEZ

Signed-off-by: Aleksei Sidorov <aleksei.sidorov@huawei.com>
Change-Id: I17900177ef59b7891419ccde5a92b13995b2221f
This commit is contained in:
Aleksei Sidorov
2024-10-11 16:53:45 +03:00
parent a9128289ff
commit e0ff24ec3b
268 changed files with 15131 additions and 7300 deletions
+1
View File
@@ -104,6 +104,7 @@ ohos_static_library("libvixl") {
"src/aarch64/assembler-sve-aarch64.cc",
"src/aarch64/cpu-aarch64.cc",
"src/aarch64/cpu-features-auditor-aarch64.cc",
"src/aarch64/debugger-aarch64.cc",
"src/aarch64/decoder-aarch64.cc",
"src/aarch64/disasm-aarch64.cc",
"src/aarch64/instructions-aarch64.cc",
+1
View File
@@ -70,6 +70,7 @@ if (NOT PANDA_MINIMAL_VIXL)
src/aarch64/pointer-auth-aarch64.cc
src/aarch64/cpu-features-auditor-aarch64.cc
#src/aarch64/macro-assembler-sve-aarch64.cc
src/aarch64/debugger-aarch64.cc
src/aarch64/simulator-aarch64.cc )
endif()
+15
View File
@@ -0,0 +1,15 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
* @Prof1983
.* @Prof1983
+4 -4
View File
@@ -1,4 +1,4 @@
VIXL: ARMv8 Runtime Code Generation Library 6.3.0
VIXL: ARMv8 Runtime Code Generation Library 7.0.0
=================================================
Contents:
@@ -48,7 +48,7 @@ Requirements
To build VIXL the following software is required:
1. Python 2.7
1. Python 3.5+
2. SCons 2.0
3. GCC 4.8+ or Clang 4.0+
@@ -61,8 +61,8 @@ software is also required:
1. Git
2. [Google's `cpplint.py`][cpplint]
3. clang-format-4.0
4. clang-tidy-4.0
3. clang-format 11+
4. clang-tidy 11+
Refer to the 'Usage' section for details.
+1 -1
View File
@@ -187,7 +187,7 @@ def simulator_validator(env):
'AArch64. Set `target` to include `aarch64` or `a64`.')
# Default variables may depend on each other, therefore we need this dictionnary
# Default variables may depend on each other, therefore we need this dictionary
# to be ordered.
vars_default_handlers = OrderedDict({
# variable_name : [ 'default val', 'handler', 'validator']
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,13 +24,12 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
using namespace vixl;
using namespace vixl::aarch64;
+1 -2
View File
@@ -24,14 +24,13 @@
// 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.
#include "bench-utils.h"
#include "globals-vixl.h"
#include "aarch64/instructions-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "aarch64/simulator-aarch64.h"
#include "bench-utils.h"
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
using namespace vixl;
+4 -3
View File
@@ -24,12 +24,13 @@
// 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.
#include "bench-utils.h"
#include <vector>
#include "globals-vixl.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "bench-utils.h"
#include "aarch64/macro-assembler-aarch64.h"
using namespace vixl;
using namespace vixl::aarch64;
@@ -306,7 +307,7 @@ void BenchCodeGenerator::BindPendingLabels(uint64_t bind_mask) {
void BenchCodeGenerator::BindAllPendingLabels() {
while (!labels_.empty()) {
// BindPendingLables generates a branch over each block of bound labels.
// BindPendingLabels generates a branch over each block of bound labels.
// This will be repeated for each call here, but the effect is minimal and
// (empirically) we rarely accumulate more than 64 pending labels anyway.
BindPendingLabels(UINT64_MAX);
+5 -4
View File
@@ -27,14 +27,14 @@
#ifndef VIXL_AARCH64_BENCH_UTILS_H_
#define VIXL_AARCH64_BENCH_UTILS_H_
#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <list>
#include <vector>
#include "globals-vixl.h"
#include "aarch64/macro-assembler-aarch64.h"
class BenchTimer {
@@ -90,7 +90,8 @@ class BenchCLI {
}
char* end;
unsigned long run_time = strtoul(argv[1], &end, 0); // NOLINT(runtime/int)
unsigned long run_time = // NOLINT(google-runtime-int)
strtoul(argv[1], &end, 0);
if ((end == argv[1]) || (run_time > UINT32_MAX)) {
PrintUsage(argv[0]);
status_ = kExitFailure;
@@ -242,7 +243,7 @@ class BenchCodeGenerator {
vixl::aarch64::MacroAssembler* masm_;
// State for *rand48(), used to randomise code generation.
unsigned short rand_state_[3]; // NOLINT(runtime/int)
unsigned short rand_state_[3]; // NOLINT(google-runtime-int)
uint32_t rnd_;
int rnd_bits_;
+1
View File
@@ -6,3 +6,4 @@ You can also have a look at the ['getting started' page](../getting-started-aarc
* [Extending and customizing the disassembler](extending-the-disassembler.md)
* [Using VIM YouCompleteMe with VIXL](ycm.md)
* [Debugging with the VIXL Simulator](simulator-debugger.md)
+114
View File
@@ -0,0 +1,114 @@
Debugging with the VIXL Simulator
=================================
The VIXL AArch64 simulator contains a basic debugger which can be used to debug
simulated applications. The debugger supports basic debugging features such as
setting breakpoints, stepping through simulated instructions and printing
simulator specific information, for example: printing the values of a register
or printing instructions at specified addresses.
Using the Debugger
------------------
In order to use the debugger it first needs to be enabled in the simulator.
```C++
Decoder decoder;
Simulator simulator(&decoder);
simulator.SetDebuggerEnabled(true);
```
Once enabled, the debugger will be activated whenever a breakpoint (brk) is
encountered by the simulator. For example:
```asm
add x1, x0, #5
mov x2, #2
brk 0 // Debugger activated here.
sub x3, x1, x2
```
Further breakpoints can be set either programmatically or interactively in the
debugger itself. For example, to set breakpoints programmatically:
```C++
// 'func' is an AARCH64 assembly function.
extern "C" void func();
Debugger* debugger = simulator.GetDebugger();
// Register a breakpoint at a fixed (absolute) address.
debugger->RegisterBreakpoint(0x00007ffbc6d38000);
// Register a breakpoint to an already existing assembly function.
debugger->RegisterBreakpoint(reinterpret_cast<uint64_t>(&func));
```
Or to set breakpoints interactively once the debugger has been activated:
```sh
sim> break 0x00007ffbc6d38000
```
The debugger has a variety of useful commands to control program flow (e.g:
step, next, continue) and inspect features of the running simulator (e.g:
print, trace). To view a list of all supported commands
use "help" at the debugger prompt.
```sh
sim> help
```
Extending the Debugger
----------------------
The debugger can be extended with custom commands to allow for greater
flexibility in debugging individual applications. This could be used for a
variety of applications, for example printing out object specific information
from an address.
To create a custom debugger command, extend the DebuggerCmd class located in
debugger-aarch64.h and implement its methods.
```C++
class PrintObjectCmd : public DebuggerCmd {
public:
PrintObjectCmd(Simulator* sim)
: DebuggerCmd(sim,
"printobject",
"po",
"<address>",
"Print a custom object located at the given address.")
{}
// Called when the command word is given to the interactive debugger.
DebugReturn Action(const std::vector<std::string>& args) override {
// We want exactly 1 argument (an address) given to the printobject
// command.
if (args.size() != 1) {
fprintf(ostream_, "Error: incorrect command format.");
return DebugContinue;
}
auto addr = Debugger::ParseUint64String(args.front());
if (addr) {
fprintf(ostream_, "Error: could not get address from string.");
return DebugContinue;
}
// Convert the address given to a custom object and then print it.
CustomObject object = reinterpret_cast<CustomObject>(*addr);
object.print();
}
};
```
Then simply register the new command with the debugger.
```C++
Debugger* debugger = simulator.GetDebugger();
debugger->RegisterCmd<PrintObjectCmd>();
```
+3 -1
View File
@@ -84,6 +84,8 @@ void GenerateAdd2Vectors(MacroAssembler* masm) {
}
#ifndef TEST_EXAMPLES
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
void PrintVector(const uint8_t* vec, unsigned num) {
unsigned i;
printf("( ");
@@ -95,9 +97,9 @@ void PrintVector(const uint8_t* vec, unsigned num) {
}
printf(" )\n");
}
#endif
#ifndef TEST_EXAMPLES
int main(void) {
MacroAssembler masm;
+3 -2
View File
@@ -24,9 +24,10 @@
// 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.
#include "custom-disassembler.h"
#include <regex>
#include "custom-disassembler.h"
#include "examples.h"
using namespace vixl;
@@ -106,7 +107,7 @@ void CustomDisassembler::AppendCodeRelativeCodeAddressToOutput(
// We override this method to add a comment to some instructions. Helpers from
// the vixl::Instruction class can be used to analyse the instruction being
// disasssembled.
// disassembled.
void CustomDisassembler::Visit(Metadata* metadata, const Instruction* instr) {
vixl::aarch64::Disassembler::Visit(metadata, instr);
const std::string& form = (*metadata)["form"];
+87
View File
@@ -0,0 +1,87 @@
// Copyright 2023, VIXL authors
// 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 ARM Limited 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 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.
#include "examples.h"
#include "aarch64/disasm-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "aarch64/simulator-aarch64.h"
using namespace vixl;
using namespace vixl::aarch64;
#define __ masm->
void GenerateDebugExample(MacroAssembler* masm) {
// Create a breakpoint here to break into the debugger.
__ Brk(0);
// Do some arithmetic.
__ Add(x1, x0, 5);
__ Mov(x2, 2);
__ Sub(x3, x1, x2);
__ Ret();
}
#ifndef TEST_EXAMPLES
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
int main(void) {
MacroAssembler masm;
// Generate the code for the example function.
Label debug_example;
masm.Bind(&debug_example);
GenerateDebugExample(&masm);
masm.FinalizeCode();
Instruction* start = masm.GetLabelAddress<Instruction*>(&debug_example);
// Disassemble the generated code.
PrintDisassembler disassembler(stdout);
disassembler.DisassembleBuffer(start, masm.GetSizeOfCodeGenerated());
Decoder decoder;
Simulator simulator(&decoder);
simulator.SetColouredTrace(true);
simulator.SetDebuggerEnabled(true);
int32_t input_a = 1;
int32_t input_b = 2;
simulator.WriteWRegister(0, input_a);
simulator.WriteWRegister(1, input_b);
simulator.RunFrom(start);
printf("The final result is %ld\n", simulator.ReadXRegister(3));
return 0;
}
#else
int main(void) { return 0; }
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
#endif // TEST_EXAMPLES
+1
View File
@@ -30,6 +30,7 @@
#include <string.h>
#include "code-buffer-vixl.h"
#include "aarch64/decoder-aarch64.h"
#include "aarch64/disasm-aarch64.h"
+6 -4
View File
@@ -24,11 +24,11 @@
// 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.
#include "executable-memory.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "aarch64/simulator-aarch64.h"
#include "executable-memory.h"
using namespace vixl;
using namespace vixl::aarch64;
@@ -59,7 +59,7 @@ int main() {
simulator.WriteXRegister(0, 0x8899aabbccddeeff);
simulator.RunFrom(masm.GetLabelAddress<Instruction *>(&demo));
printf("x0 = %" PRIx64 "\n", simulator.ReadXRegister(0));
printf("x0 = 0x%" PRIx64 "\n", simulator.ReadXRegister(0));
#else
byte* code = masm.GetBuffer()->GetStartAddress<byte*>();
@@ -70,7 +70,9 @@ int main() {
memory.GetEntryPoint<uint64_t (*)(uint64_t)>(demo);
uint64_t input_value = 0x8899aabbccddeeff;
uint64_t output_value = (*demo_function)(input_value);
printf("native: demo(0x%016lx) = 0x%016lx\n", input_value, output_value);
printf("native: demo(0x%" PRIx64 ") = 0x%" PRIx64 "\n",
input_value,
output_value);
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
return 0;
+2
View File
@@ -84,6 +84,8 @@ int64_t LiteralExample(int64_t a, int64_t b) {
b,
simulator.ReadXRegister(0));
free(code);
return simulator.ReadXRegister(0);
}
#endif
+1 -1
View File
@@ -75,7 +75,7 @@ void GenerateNEONMatrixMultiply(MacroAssembler* masm) {
__ Ld1(v16.V4S(), v17.V4S(), v18.V4S(), v19.V4S(), MemOperand(x2));
// Initialise vectors of the output matrix with zeros.
// This is only for the purposes of showing how this can be achived
// This is only for the purposes of showing how this can be achieved
// but technically this is not required because we overwrite all lanes
// of the output vectors.
__ Movi(v0.V16B(), 0);
+2 -1
View File
@@ -24,10 +24,11 @@
// 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.
#include "non-const-visitor.h"
#include <regex>
#include "examples.h"
#include "non-const-visitor.h"
using namespace vixl;
using namespace vixl::aarch64;
+159
View File
@@ -0,0 +1,159 @@
// Copyright 2023, VIXL authors
// 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 ARM Limited 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 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.
#include "examples.h"
#include "aarch64/disasm-aarch64.h"
#include "aarch64/macro-assembler-aarch64.h"
#include "aarch64/simulator-aarch64.h"
using namespace vixl;
using namespace vixl::aarch64;
#define __ masm->
enum Result { FAILURE, SUCCESS };
// This will be called via a runtime call.
extern "C" int example_1() { return SUCCESS; }
// This will never be called, instead it will be intercepted and 'callback'
// will be called.
uint32_t example_2() { return FAILURE; }
uint32_t example_3(uint32_t num, float f) {
USE(f);
return num;
}
// This will be called instead of example_2.
uint32_t callback(uint64_t original_target) {
USE(original_target);
return SUCCESS;
}
void GenerateInterceptionExamples(MacroAssembler* masm) {
// Preserve lr, since the calls will overwrite it.
__ Push(xzr, lr);
// example_1 will be intercepted and called through a runtime call.
__ Mov(x16, reinterpret_cast<uint64_t>(example_1));
__ Blr(x16);
__ Mov(w1, w0);
// example_2 will be intercepted and callback will be called instead.
__ Mov(x16, reinterpret_cast<uint64_t>(example_2));
__ Blr(x16);
__ Mov(w2, w0);
// Pass FAILURE as a parameter.
__ Mov(x0, FAILURE);
__ Fmov(s0, 3.5);
// example_3 will be intercepted and lambda callback will be called instead.
__ Mov(x16, reinterpret_cast<uint64_t>(example_3));
__ Blr(x16);
__ Mov(w3, w0);
// Restore lr and return.
__ Pop(lr, xzr);
__ Ret();
}
#ifndef TEST_EXAMPLES
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
int main(void) {
MacroAssembler masm;
// Generate the code for the example function.
Label call_simulator_interception;
masm.Bind(&call_simulator_interception);
GenerateInterceptionExamples(&masm);
masm.FinalizeCode();
Instruction* start =
masm.GetLabelAddress<Instruction*>(&call_simulator_interception);
// Disassemble the generated code.
PrintDisassembler disassembler(stdout);
disassembler.DisassembleBuffer(start, masm.GetSizeOfCodeGenerated());
Decoder decoder;
Simulator simulator(&decoder);
// Register interceptions to the branches, example_1 will be called via a
// runtime call and callback will be called instead of example_2.
simulator.RegisterBranchInterception(example_1);
simulator.RegisterBranchInterception(example_2, callback);
// Lambda callbacks can be used to arbitrarily modify the simulator.
simulator.RegisterBranchInterception(
example_3, [&simulator](uint64_t original_target) {
USE(original_target);
ABI abi;
uint32_t param1 = simulator.ReadGenericOperand<uint32_t>(
abi.GetNextParameterGenericOperand<uint32_t>());
float param2 = simulator.ReadGenericOperand<float>(
abi.GetNextParameterGenericOperand<float>());
if (param1 == FAILURE && param2 == 3.5) {
simulator.WriteWRegister(0, SUCCESS);
} else {
simulator.WriteWRegister(0, FAILURE);
}
});
simulator.RunFrom(start);
uint32_t result_1 = simulator.ReadWRegister(1);
if (result_1 == SUCCESS) {
printf("SUCCESS: example_1 was called via a runtime call.\n");
} else {
printf("ERROR: example_1 was not called.\n");
}
uint32_t result_2 = simulator.ReadWRegister(2);
if (result_2 == SUCCESS) {
printf("SUCCESS: callback was called instead of example_2.\n");
} else {
printf("ERROR: example_2 was called incorrectly.\n");
}
uint32_t result_3 = simulator.ReadWRegister(0);
if (result_3 == SUCCESS) {
printf("SUCCESS: Lambda callback called instead of example_3.\n");
} else {
printf("ERROR: example_3 was called instead of the lambda.\n");
}
return 0;
}
#else
// TODO: Support running natively.
int main(void) { return 0; }
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
#endif // TEST_EXAMPLES
+4 -4
View File
@@ -348,7 +348,7 @@ DataTypeValue Dt_U_opc1_opc2_1_Decode(uint32_t value, unsigned* lane) {
*lane = (value >> 2) & 1;
return Untyped32;
}
*lane = -1;
*lane = ~0U;
return kDataTypeValueInvalid;
}
@@ -365,7 +365,7 @@ DataTypeValue Dt_opc1_opc2_1_Decode(uint32_t value, unsigned* lane) {
*lane = (value >> 2) & 1;
return Untyped32;
}
*lane = -1;
*lane = ~0U;
return kDataTypeValueInvalid;
}
@@ -382,7 +382,7 @@ DataTypeValue Dt_imm4_1_Decode(uint32_t value, unsigned* lane) {
*lane = (value >> 3) & 1;
return Untyped32;
}
*lane = -1;
*lane = ~0U;
return kDataTypeValueInvalid;
}
@@ -60977,7 +60977,7 @@ void Disassembler::DecodeA32(uint32_t instr) {
Condition condition((instr >> 28) & 0xf);
unsigned rd = (instr >> 12) & 0xf;
uint32_t imm = ImmediateA32::Decode(instr & 0xfff);
Location location(-imm, kA32PcDelta);
Location location(UnsignedNegate(imm), kA32PcDelta);
// ADR{<c>}{<q>} <Rd>, <label> ; A2
adr(condition, Best, Register(rd), &location);
break;
+6
View File
@@ -36,6 +36,12 @@ extern "C" {
#include "aarch32/constants-aarch32.h"
#include "aarch32/operands-aarch32.h"
// Microsoft Visual C++ defines a `mvn` macro that conflicts with our own
// definition.
#if defined(_MSC_VER) && defined(mvn)
#undef mvn
#endif
namespace vixl {
namespace aarch32 {
+2 -2
View File
@@ -651,7 +651,7 @@ bool ImmediateT32::IsImmediateT32(uint32_t imm) {
(((imm & 0xff00) == 0) || ((imm & 0xff) == 0)))
return true;
/* isolate least-significant set bit */
uint32_t lsb = imm & -imm;
uint32_t lsb = imm & UnsignedNegate(imm);
/* if imm is less than lsb*256 then it fits, but instead we test imm/256 to
* avoid overflow (underflow is always a successful case) */
return ((imm >> 8) < lsb);
@@ -702,7 +702,7 @@ bool ImmediateA32::IsImmediateA32(uint32_t imm) {
* that the least-significant set bit is always an even bit */
imm = imm | ((imm >> 1) & 0x55555555);
/* isolate least-significant set bit (always even) */
uint32_t lsb = imm & -imm;
uint32_t lsb = imm & UnsignedNegate(imm);
/* if imm is less than lsb*256 then it fits, but instead we test imm/256 to
* avoid overflow (underflow is always a successful case) */
return ((imm >> 8) < lsb);
+5 -1
View File
@@ -40,6 +40,8 @@ extern "C" {
#if !defined(__linux__) && defined(__arm__)
#define HARDFLOAT gnu__attribute__((noinline, pcs("aapcs-vfp")))
#elif defined(_MSC_VER)
#define HARDFLOAT __declspec(noinline)
#else
#define HARDFLOAT __attribute__((noinline))
#endif
@@ -1041,7 +1043,9 @@ class Sign {
const char* GetName() const { return (IsPlus() ? "" : "-"); }
bool IsPlus() const { return sign_ == plus; }
bool IsMinus() const { return sign_ == minus; }
int32_t ApplyTo(uint32_t value) { return IsPlus() ? value : -value; }
int32_t ApplyTo(uint32_t value) {
return IsPlus() ? value : UnsignedNegate(value);
}
private:
SignType sign_;
+1 -1
View File
@@ -230,7 +230,7 @@ class Location : public LocationBase<int32_t> {
protected:
// Types passed to LocationBase. Must be distinct for unbound Locations (not
// relevant for bound locations, as they don't have a correspoding
// relevant for bound locations, as they don't have a corresponding
// PoolObject).
static const int kRawLocation = 0; // Will not be used by the pool manager.
static const int kVeneerType = 1;
+4 -4
View File
@@ -270,8 +270,8 @@ MemOperand MacroAssembler::MemOperandComputationHelper(
uint32_t load_store_offset = offset & extra_offset_mask;
uint32_t add_offset = offset & ~extra_offset_mask;
if ((add_offset != 0) &&
(IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
if ((add_offset != 0) && (IsModifiedImmediate(offset) ||
IsModifiedImmediate(UnsignedNegate(offset)))) {
load_store_offset = 0;
add_offset = offset;
}
@@ -292,7 +292,7 @@ MemOperand MacroAssembler::MemOperandComputationHelper(
// of ADR -- to get behaviour like loads and stores. This ADR can handle
// at least as much offset as the load_store_offset so it can replace it.
uint32_t sub_pc_offset = (-offset) & 0xfff;
uint32_t sub_pc_offset = UnsignedNegate(offset) & 0xfff;
load_store_offset = (offset + sub_pc_offset) & extra_offset_mask;
add_offset = (offset + sub_pc_offset) & ~extra_offset_mask;
@@ -614,7 +614,7 @@ void MacroAssembler::Printf(const char* format,
Vmsr(FPSCR, tmp);
Pop(tmp);
Msr(APSR_nzcvqg, tmp);
// Restore the regsisters.
// Restore the registers.
if (Has32DRegs()) Vpop(Untyped64, DRegisterList(d16, 16));
Vpop(Untyped64, DRegisterList(d0, 8));
Pop(RegisterList(saved_registers_mask));
+2 -2
View File
@@ -190,7 +190,7 @@ class Operand {
}
private:
// Forbid implicitely creating operands around types that cannot be encoded
// Forbid implicitly creating operands around types that cannot be encoded
// into a uint32_t without loss.
#if __cplusplus >= 201103L
Operand(int64_t) = delete; // NOLINT(runtime/explicit)
@@ -615,7 +615,7 @@ class ImmediateVorn : public ImmediateVorr {
// - a shifted index register <Rm>, <shift> #<amount>
//
// The index register may have an associated {+/-} sign,
// which if ommitted, defaults to + .
// which if omitted, defaults to + .
//
// We have two constructors for the offset:
//
+2 -2
View File
@@ -159,8 +159,8 @@ template <>
inline GenericOperand ABI::GetReturnGenericOperand<void>() const {
return GenericOperand();
}
}
} // namespace vixl::aarch64
} // namespace aarch64
} // namespace vixl
#endif // VIXL_AARCH64_ABI_AARCH64_H_
+551 -13
View File
@@ -25,9 +25,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "assembler-aarch64.h"
#include <cmath>
#include "assembler-aarch64.h"
#include "macro-assembler-aarch64.h"
namespace vixl {
@@ -1939,6 +1940,542 @@ void Assembler::hint(int imm7) {
}
// MTE.
void Assembler::addg(const Register& xd,
const Register& xn,
int offset,
int tag_offset) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));
Emit(0x91800000 | RdSP(xd) | RnSP(xn) |
ImmUnsignedField<21, 16>(offset / kMTETagGranuleInBytes) |
ImmUnsignedField<13, 10>(tag_offset));
}
void Assembler::gmi(const Register& xd,
const Register& xn,
const Register& xm) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
Emit(0x9ac01400 | Rd(xd) | RnSP(xn) | Rm(xm));
}
void Assembler::irg(const Register& xd,
const Register& xn,
const Register& xm) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
Emit(0x9ac01000 | RdSP(xd) | RnSP(xn) | Rm(xm));
}
void Assembler::ldg(const Register& xt, const MemOperand& addr) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
VIXL_ASSERT(addr.IsImmediateOffset());
int offset = static_cast<int>(addr.GetOffset());
VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));
Emit(0xd9600000 | Rt(xt) | RnSP(addr.GetBaseRegister()) |
ImmField<20, 12>(offset / static_cast<int>(kMTETagGranuleInBytes)));
}
void Assembler::StoreTagHelper(const Register& xt,
const MemOperand& addr,
Instr op) {
int offset = static_cast<int>(addr.GetOffset());
VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));
Instr addr_mode;
if (addr.IsImmediateOffset()) {
addr_mode = 2;
} else if (addr.IsImmediatePreIndex()) {
addr_mode = 3;
} else {
VIXL_ASSERT(addr.IsImmediatePostIndex());
addr_mode = 1;
}
Emit(op | RdSP(xt) | RnSP(addr.GetBaseRegister()) | (addr_mode << 10) |
ImmField<20, 12>(offset / static_cast<int>(kMTETagGranuleInBytes)));
}
void Assembler::st2g(const Register& xt, const MemOperand& addr) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
StoreTagHelper(xt, addr, 0xd9a00000);
}
void Assembler::stg(const Register& xt, const MemOperand& addr) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
StoreTagHelper(xt, addr, 0xd9200000);
}
void Assembler::stgp(const Register& xt1,
const Register& xt2,
const MemOperand& addr) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
int offset = static_cast<int>(addr.GetOffset());
VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));
Instr addr_mode;
if (addr.IsImmediateOffset()) {
addr_mode = 2;
} else if (addr.IsImmediatePreIndex()) {
addr_mode = 3;
} else {
VIXL_ASSERT(addr.IsImmediatePostIndex());
addr_mode = 1;
}
Emit(0x68000000 | RnSP(addr.GetBaseRegister()) | (addr_mode << 23) |
ImmField<21, 15>(offset / static_cast<int>(kMTETagGranuleInBytes)) |
Rt2(xt2) | Rt(xt1));
}
void Assembler::stz2g(const Register& xt, const MemOperand& addr) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
StoreTagHelper(xt, addr, 0xd9e00000);
}
void Assembler::stzg(const Register& xt, const MemOperand& addr) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
StoreTagHelper(xt, addr, 0xd9600000);
}
void Assembler::subg(const Register& xd,
const Register& xn,
int offset,
int tag_offset) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
VIXL_ASSERT(IsMultiple(offset, kMTETagGranuleInBytes));
Emit(0xd1800000 | RdSP(xd) | RnSP(xn) |
ImmUnsignedField<21, 16>(offset / kMTETagGranuleInBytes) |
ImmUnsignedField<13, 10>(tag_offset));
}
void Assembler::subp(const Register& xd,
const Register& xn,
const Register& xm) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
Emit(0x9ac00000 | Rd(xd) | RnSP(xn) | RmSP(xm));
}
void Assembler::subps(const Register& xd,
const Register& xn,
const Register& xm) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMTE));
Emit(0xbac00000 | Rd(xd) | RnSP(xn) | RmSP(xm));
}
void Assembler::cpye(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d800400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyen(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d80c400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyern(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d808400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyewn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d804400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfe(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19800400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfen(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1980c400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfern(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19808400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfewn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19804400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfm(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19400400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfmn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1940c400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfmrn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19408400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfmwn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19404400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfp(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19000400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfpn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1900c400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfprn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19008400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyfpwn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x19004400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpym(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d400400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpymn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d40c400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpymrn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d408400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpymwn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d404400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyp(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d000400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpypn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d00c400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpyprn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d008400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::cpypwn(const Register& rd,
const Register& rs,
const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero() && !rs.IsZero());
Emit(0x1d004400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::sete(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x19c08400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::seten(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x19c0a400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setge(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x1dc08400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setgen(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x1dc0a400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setgm(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x1dc04400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setgmn(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x1dc06400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setgp(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x1dc00400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setgpn(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x1dc02400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setm(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x19c04400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setmn(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x19c06400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setp(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x19c00400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::setpn(const Register& rd,
const Register& rn,
const Register& rs) {
VIXL_ASSERT(CPUHas(CPUFeatures::kMOPS));
VIXL_ASSERT(!AreAliased(rd, rn, rs));
VIXL_ASSERT(!rd.IsZero() && !rn.IsZero());
Emit(0x19c02400 | Rd(rd) | Rn(rn) | Rs(rs));
}
void Assembler::abs(const Register& rd, const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));
VIXL_ASSERT(rd.IsSameSizeAndType(rn));
Emit(0x5ac02000 | SF(rd) | Rd(rd) | Rn(rn));
}
void Assembler::cnt(const Register& rd, const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));
VIXL_ASSERT(rd.IsSameSizeAndType(rn));
Emit(0x5ac01c00 | SF(rd) | Rd(rd) | Rn(rn));
}
void Assembler::ctz(const Register& rd, const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));
VIXL_ASSERT(rd.IsSameSizeAndType(rn));
Emit(0x5ac01800 | SF(rd) | Rd(rd) | Rn(rn));
}
#define MINMAX(V) \
V(smax, 0x11c00000, 0x1ac06000, true) \
V(smin, 0x11c80000, 0x1ac06800, true) \
V(umax, 0x11c40000, 0x1ac06400, false) \
V(umin, 0x11cc0000, 0x1ac06c00, false)
#define VIXL_DEFINE_ASM_FUNC(FN, IMMOP, REGOP, SIGNED) \
void Assembler::FN(const Register& rd, \
const Register& rn, \
const Operand& op) { \
VIXL_ASSERT(rd.IsSameSizeAndType(rn)); \
Instr i = SF(rd) | Rd(rd) | Rn(rn); \
if (op.IsImmediate()) { \
int64_t imm = op.GetImmediate(); \
i |= SIGNED ? ImmField<17, 10>(imm) : ImmUnsignedField<17, 10>(imm); \
Emit(IMMOP | i); \
} else { \
VIXL_ASSERT(op.IsPlainRegister()); \
VIXL_ASSERT(op.GetRegister().IsSameSizeAndType(rd)); \
Emit(REGOP | i | Rm(op.GetRegister())); \
} \
}
MINMAX(VIXL_DEFINE_ASM_FUNC)
#undef VIXL_DEFINE_ASM_FUNC
// NEON structure loads and stores.
Instr Assembler::LoadStoreStructAddrModeField(const MemOperand& addr) {
Instr addr_field = RnSP(addr.GetBaseRegister());
@@ -2752,7 +3289,7 @@ void Assembler::fmov(const VRegister& vd, Float16 imm) {
Emit(FMOV_h_imm | Rd(vd) | ImmFP16(imm));
} else {
VIXL_ASSERT(CPUHas(CPUFeatures::kNEON, CPUFeatures::kNEONHalf));
VIXL_ASSERT(vd.Is4H() | vd.Is8H());
VIXL_ASSERT(vd.Is4H() || vd.Is8H());
Instr q = vd.Is8H() ? NEON_Q : 0;
uint32_t encoded_imm = FP16ToImm8(imm);
Emit(q | NEONModifiedImmediate_FMOV | ImmNEONabcdefgh(encoded_imm) |
@@ -2782,7 +3319,8 @@ void Assembler::fmov(const Register& rd, const VRegister& vn) {
void Assembler::fmov(const VRegister& vd, const Register& rn) {
VIXL_ASSERT(CPUHas(CPUFeatures::kFP));
VIXL_ASSERT(CPUHas(CPUFeatures::kFP) ||
(vd.Is1D() && CPUHas(CPUFeatures::kNEON)));
VIXL_ASSERT(vd.Is1H() || vd.Is1S() || vd.Is1D());
VIXL_ASSERT((vd.GetSizeInBits() == rn.GetSizeInBits()) || vd.Is1H());
FPIntegerConvertOp op;
@@ -5311,9 +5849,9 @@ Instr Assembler::ImmFP16(Float16 imm) {
uint32_t Assembler::FP32ToImm8(float imm) {
VIXL_ASSERT(IsImmFP32(imm));
// bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
uint32_t bits = FloatToRawbits(imm);
VIXL_ASSERT(IsImmFP32(bits));
// bit7: a000.0000
uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
// bit6: 0b00.0000
@@ -5329,10 +5867,10 @@ Instr Assembler::ImmFP32(float imm) { return FP32ToImm8(imm) << ImmFP_offset; }
uint32_t Assembler::FP64ToImm8(double imm) {
VIXL_ASSERT(IsImmFP64(imm));
// bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
// 0000.0000.0000.0000.0000.0000.0000.0000
uint64_t bits = DoubleToRawbits(imm);
VIXL_ASSERT(IsImmFP64(bits));
// bit7: a000.0000
uint64_t bit7 = ((bits >> 63) & 0x1) << 7;
// bit6: 0b00.0000
@@ -5886,10 +6424,9 @@ bool Assembler::IsImmFP16(Float16 imm) {
}
bool Assembler::IsImmFP32(float imm) {
bool Assembler::IsImmFP32(uint32_t bits) {
// Valid values will have the form:
// aBbb.bbbc.defg.h000.0000.0000.0000.0000
uint32_t bits = FloatToRawbits(imm);
// bits[19..0] are cleared.
if ((bits & 0x7ffff) != 0) {
return false;
@@ -5910,11 +6447,10 @@ bool Assembler::IsImmFP32(float imm) {
}
bool Assembler::IsImmFP64(double imm) {
bool Assembler::IsImmFP64(uint64_t bits) {
// Valid values will have the form:
// aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
// 0000.0000.0000.0000.0000.0000.0000.0000
uint64_t bits = DoubleToRawbits(imm);
// bits[47..0] are cleared.
if ((bits & 0x0000ffffffffffff) != 0) {
return false;
@@ -5936,16 +6472,18 @@ bool Assembler::IsImmFP64(double imm) {
bool Assembler::IsImmLSPair(int64_t offset, unsigned access_size_in_bytes_log2) {
const auto access_size_in_bytes = 1U << access_size_in_bytes_log2;
VIXL_ASSERT(access_size_in_bytes_log2 <= kQRegSizeInBytesLog2);
return IsMultiple(offset, 1 << access_size_in_bytes_log2) &&
IsInt7(offset / (1 << access_size_in_bytes_log2));
return IsMultiple(offset, access_size_in_bytes) &&
IsInt7(offset / access_size_in_bytes);
}
bool Assembler::IsImmLSScaled(int64_t offset, unsigned access_size_in_bytes_log2) {
const auto access_size_in_bytes = 1U << access_size_in_bytes_log2;
VIXL_ASSERT(access_size_in_bytes_log2 <= kQRegSizeInBytesLog2);
return IsMultiple(offset, 1 << access_size_in_bytes_log2) &&
IsUint12(offset / (1 << access_size_in_bytes_log2));
return IsMultiple(offset, access_size_in_bytes) &&
IsUint12(offset / access_size_in_bytes);
}
+182 -4
View File
@@ -33,6 +33,7 @@
#include "../globals-vixl.h"
#include "../invalset-vixl.h"
#include "../utils-vixl.h"
#include "operands-aarch64.h"
namespace vixl {
@@ -6926,6 +6927,176 @@ class Assembler : public vixl::internal::AssemblerBase {
const ZRegister& zm,
int index);
// Add with Tag.
void addg(const Register& xd, const Register& xn, int offset, int tag_offset);
// Tag Mask Insert.
void gmi(const Register& xd, const Register& xn, const Register& xm);
// Insert Random Tag.
void irg(const Register& xd, const Register& xn, const Register& xm = xzr);
// Load Allocation Tag.
void ldg(const Register& xt, const MemOperand& addr);
void StoreTagHelper(const Register& xt, const MemOperand& addr, Instr op);
// Store Allocation Tags.
void st2g(const Register& xt, const MemOperand& addr);
// Store Allocation Tag.
void stg(const Register& xt, const MemOperand& addr);
// Store Allocation Tag and Pair of registers.
void stgp(const Register& xt1, const Register& xt2, const MemOperand& addr);
// Store Allocation Tags, Zeroing.
void stz2g(const Register& xt, const MemOperand& addr);
// Store Allocation Tag, Zeroing.
void stzg(const Register& xt, const MemOperand& addr);
// Subtract with Tag.
void subg(const Register& xd, const Register& xn, int offset, int tag_offset);
// Subtract Pointer.
void subp(const Register& xd, const Register& xn, const Register& xm);
// Subtract Pointer, setting Flags.
void subps(const Register& xd, const Register& xn, const Register& xm);
// Compare with Tag.
void cmpp(const Register& xn, const Register& xm) { subps(xzr, xn, xm); }
// Memory Copy.
void cpye(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, reads and writes non-temporal.
void cpyen(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, reads non-temporal.
void cpyern(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, writes non-temporal.
void cpyewn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only.
void cpyfe(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, reads and writes non-temporal.
void cpyfen(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, reads non-temporal.
void cpyfern(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, writes non-temporal.
void cpyfewn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only.
void cpyfm(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, reads and writes non-temporal.
void cpyfmn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, reads non-temporal.
void cpyfmrn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, writes non-temporal.
void cpyfmwn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only.
void cpyfp(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, reads and writes non-temporal.
void cpyfpn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, reads non-temporal.
void cpyfprn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy Forward-only, writes non-temporal.
void cpyfpwn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy.
void cpym(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, reads and writes non-temporal.
void cpymn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, reads non-temporal.
void cpymrn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, writes non-temporal.
void cpymwn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy.
void cpyp(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, reads and writes non-temporal.
void cpypn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, reads non-temporal.
void cpyprn(const Register& rd, const Register& rs, const Register& rn);
// Memory Copy, writes non-temporal.
void cpypwn(const Register& rd, const Register& rs, const Register& rn);
// Memory Set.
void sete(const Register& rd, const Register& rn, const Register& rs);
// Memory Set, non-temporal.
void seten(const Register& rd, const Register& rn, const Register& rs);
// Memory Set with tag setting.
void setge(const Register& rd, const Register& rn, const Register& rs);
// Memory Set with tag setting, non-temporal.
void setgen(const Register& rd, const Register& rn, const Register& rs);
// Memory Set with tag setting.
void setgm(const Register& rd, const Register& rn, const Register& rs);
// Memory Set with tag setting, non-temporal.
void setgmn(const Register& rd, const Register& rn, const Register& rs);
// Memory Set with tag setting.
void setgp(const Register& rd, const Register& rn, const Register& rs);
// Memory Set with tag setting, non-temporal.
void setgpn(const Register& rd, const Register& rn, const Register& rs);
// Memory Set.
void setm(const Register& rd, const Register& rn, const Register& rs);
// Memory Set, non-temporal.
void setmn(const Register& rd, const Register& rn, const Register& rs);
// Memory Set.
void setp(const Register& rd, const Register& rn, const Register& rs);
// Memory Set, non-temporal.
void setpn(const Register& rd, const Register& rn, const Register& rs);
// Absolute value.
void abs(const Register& rd, const Register& rn);
// Count bits.
void cnt(const Register& rd, const Register& rn);
// Count Trailing Zeros.
void ctz(const Register& rd, const Register& rn);
// Signed Maximum.
void smax(const Register& rd, const Register& rn, const Operand& op);
// Signed Minimum.
void smin(const Register& rd, const Register& rn, const Operand& op);
// Unsigned Maximum.
void umax(const Register& rd, const Register& rn, const Operand& op);
// Unsigned Minimum.
void umin(const Register& rd, const Register& rn, const Operand& op);
// Emit generic instructions.
// Emit raw instructions into the instruction stream.
@@ -7244,8 +7415,9 @@ class Assembler : public vixl::internal::AssemblerBase {
}
static Instr ImmLSPair(int64_t imm7, unsigned access_size_in_bytes_log2) {
VIXL_ASSERT(IsMultiple(imm7, 1 << access_size_in_bytes_log2));
int64_t scaled_imm7 = imm7 / (1 << access_size_in_bytes_log2);
const auto access_size_in_bytes = 1U << access_size_in_bytes_log2;
VIXL_ASSERT(IsMultiple(imm7, access_size_in_bytes));
int64_t scaled_imm7 = imm7 / access_size_in_bytes;
VIXL_ASSERT(IsInt7(scaled_imm7));
return TruncateToUint7(scaled_imm7) << ImmLSPair_offset;
}
@@ -7370,8 +7542,14 @@ class Assembler : public vixl::internal::AssemblerBase {
static bool IsImmAddSub(int64_t immediate);
static bool IsImmConditionalCompare(int64_t immediate);
static bool IsImmFP16(Float16 imm);
static bool IsImmFP32(float imm);
static bool IsImmFP64(double imm);
static bool IsImmFP32(float imm) { return IsImmFP32(FloatToRawbits(imm)); }
static bool IsImmFP32(uint32_t bits);
static bool IsImmFP64(double imm) { return IsImmFP64(DoubleToRawbits(imm)); }
static bool IsImmFP64(uint64_t bits);
static bool IsImmLogical(uint64_t value,
unsigned width,
unsigned* n = NULL,
+1 -1
View File
@@ -6505,7 +6505,7 @@ void Assembler::fmov(const ZRegister& zd, const PRegisterM& pg, double imm) {
void Assembler::fmov(const ZRegister& zd, double imm) {
if (IsPositiveZero(imm)) {
dup(zd, imm);
dup(zd, 0);
} else {
fdup(zd, imm);
}
+9 -1
View File
@@ -523,7 +523,15 @@ enum DataCacheOp {
CVAP = CacheOpEncoder<3, 7, 12, 1>::value,
CVADP = CacheOpEncoder<3, 7, 13, 1>::value,
CIVAC = CacheOpEncoder<3, 7, 14, 1>::value,
ZVA = CacheOpEncoder<3, 7, 4, 1>::value
ZVA = CacheOpEncoder<3, 7, 4, 1>::value,
GVA = CacheOpEncoder<3, 7, 4, 3>::value,
GZVA = CacheOpEncoder<3, 7, 4, 4>::value,
CGVAC = CacheOpEncoder<3, 7, 10, 3>::value,
CGDVAC = CacheOpEncoder<3, 7, 10, 5>::value,
CGVAP = CacheOpEncoder<3, 7, 12, 3>::value,
CGDVAP = CacheOpEncoder<3, 7, 12, 5>::value,
CIGVAC = CacheOpEncoder<3, 7, 14, 3>::value,
CIGDVAC = CacheOpEncoder<3, 7, 14, 5>::value
};
// Some SVE instructions support a predicate constraint pattern. This is
+71 -17
View File
@@ -48,6 +48,7 @@ const IDRegister::Field AA64PFR0::kCSV3(60);
const IDRegister::Field AA64PFR1::kBT(0);
const IDRegister::Field AA64PFR1::kSSBS(4);
const IDRegister::Field AA64PFR1::kMTE(8);
const IDRegister::Field AA64PFR1::kSME(24);
const IDRegister::Field AA64ISAR0::kAES(4);
const IDRegister::Field AA64ISAR0::kSHA1(8);
@@ -78,7 +79,10 @@ const IDRegister::Field AA64ISAR1::kBF16(44);
const IDRegister::Field AA64ISAR1::kDGH(48);
const IDRegister::Field AA64ISAR1::kI8MM(52);
const IDRegister::Field AA64ISAR2::kWFXT(0);
const IDRegister::Field AA64ISAR2::kRPRES(4);
const IDRegister::Field AA64ISAR2::kMOPS(16);
const IDRegister::Field AA64ISAR2::kCSSC(52);
const IDRegister::Field AA64MMFR0::kECV(60);
@@ -97,6 +101,14 @@ const IDRegister::Field AA64ZFR0::kI8MM(44);
const IDRegister::Field AA64ZFR0::kF32MM(52);
const IDRegister::Field AA64ZFR0::kF64MM(56);
const IDRegister::Field AA64SMFR0::kSMEf32f32(32, 1);
const IDRegister::Field AA64SMFR0::kSMEb16f32(34, 1);
const IDRegister::Field AA64SMFR0::kSMEf16f32(35, 1);
const IDRegister::Field AA64SMFR0::kSMEi8i32(36);
const IDRegister::Field AA64SMFR0::kSMEf64f64(48, 1);
const IDRegister::Field AA64SMFR0::kSMEi16i64(52);
const IDRegister::Field AA64SMFR0::kSMEfa64(63, 1);
CPUFeatures AA64PFR0::GetCPUFeatures() const {
CPUFeatures f;
if (Get(kFP) >= 0) f.Combine(CPUFeatures::kFP);
@@ -119,6 +131,8 @@ CPUFeatures AA64PFR1::GetCPUFeatures() const {
if (Get(kSSBS) >= 2) f.Combine(CPUFeatures::kSSBSControl);
if (Get(kMTE) >= 1) f.Combine(CPUFeatures::kMTEInstructions);
if (Get(kMTE) >= 2) f.Combine(CPUFeatures::kMTE);
if (Get(kMTE) >= 3) f.Combine(CPUFeatures::kMTE3);
if (Get(kSME) >= 1) f.Combine(CPUFeatures::kSME);
return f;
}
@@ -155,6 +169,7 @@ CPUFeatures AA64ISAR1::GetCPUFeatures() const {
if (Get(kSB) >= 1) f.Combine(CPUFeatures::kSB);
if (Get(kSPECRES) >= 1) f.Combine(CPUFeatures::kSPECRES);
if (Get(kBF16) >= 1) f.Combine(CPUFeatures::kBF16);
if (Get(kBF16) >= 2) f.Combine(CPUFeatures::kEBF16);
if (Get(kDGH) >= 1) f.Combine(CPUFeatures::kDGH);
if (Get(kI8MM) >= 1) f.Combine(CPUFeatures::kI8MM);
@@ -180,7 +195,10 @@ CPUFeatures AA64ISAR1::GetCPUFeatures() const {
CPUFeatures AA64ISAR2::GetCPUFeatures() const {
CPUFeatures f;
if (Get(kWFXT) >= 2) f.Combine(CPUFeatures::kWFXT);
if (Get(kRPRES) >= 1) f.Combine(CPUFeatures::kRPRES);
if (Get(kMOPS) >= 1) f.Combine(CPUFeatures::kMOPS);
if (Get(kCSSC) >= 1) f.Combine(CPUFeatures::kCSSC);
return f;
}
@@ -213,6 +231,7 @@ CPUFeatures AA64ZFR0::GetCPUFeatures() const {
if (Get(kSM4) >= 1) f.Combine(CPUFeatures::kSVESM4);
if (Get(kSHA3) >= 1) f.Combine(CPUFeatures::kSVESHA3);
if (Get(kBF16) >= 1) f.Combine(CPUFeatures::kSVEBF16);
if (Get(kBF16) >= 2) f.Combine(CPUFeatures::kSVE_EBF16);
if (Get(kBitPerm) >= 1) f.Combine(CPUFeatures::kSVEBitPerm);
if (Get(kAES) >= 1) f.Combine(CPUFeatures::kSVEAES);
if (Get(kAES) >= 2) f.Combine(CPUFeatures::kSVEPmull128);
@@ -220,6 +239,18 @@ CPUFeatures AA64ZFR0::GetCPUFeatures() const {
return f;
}
CPUFeatures AA64SMFR0::GetCPUFeatures() const {
CPUFeatures f;
if (Get(kSMEf32f32) >= 1) f.Combine(CPUFeatures::kSMEf32f32);
if (Get(kSMEb16f32) >= 1) f.Combine(CPUFeatures::kSMEb16f32);
if (Get(kSMEf16f32) >= 1) f.Combine(CPUFeatures::kSMEf16f32);
if (Get(kSMEi8i32) >= 15) f.Combine(CPUFeatures::kSMEi8i32);
if (Get(kSMEf64f64) >= 1) f.Combine(CPUFeatures::kSMEf64f64);
if (Get(kSMEi16i64) >= 15) f.Combine(CPUFeatures::kSMEi16i64);
if (Get(kSMEfa64) >= 1) f.Combine(CPUFeatures::kSMEfa64);
return f;
}
int IDRegister::Get(IDRegister::Field field) const {
int msb = field.GetMsb();
int lsb = field.GetLsb();
@@ -248,11 +279,11 @@ CPUFeatures CPU::InferCPUFeaturesFromOS(
CPUFeatures::QueryIDRegistersOption option) {
CPUFeatures features;
#if VIXL_USE_LINUX_HWCAP
#ifdef VIXL_USE_LINUX_HWCAP
// Map each set bit onto a feature. Ideally, we'd use HWCAP_* macros rather
// than explicit bits, but explicit bits allow us to identify features that
// the toolchain doesn't know about.
static const CPUFeatures::Feature kFeatureBits[] =
static const CPUFeatures::Feature kFeatureBitsLow[] =
{// Bits 0-7
CPUFeatures::kFP,
CPUFeatures::kNEON,
@@ -288,8 +319,11 @@ CPUFeatures CPU::InferCPUFeaturesFromOS(
CPUFeatures::kSSBSControl,
CPUFeatures::kSB,
CPUFeatures::kPAuth,
CPUFeatures::kPAuthGeneric,
// Bits 32-39
CPUFeatures::kPAuthGeneric};
VIXL_STATIC_ASSERT(ArrayLength(kFeatureBitsLow) < 64);
static const CPUFeatures::Feature kFeatureBitsHigh[] =
{// Bits 0-7
CPUFeatures::kDCCVADP,
CPUFeatures::kSVE2,
CPUFeatures::kSVEAES,
@@ -298,7 +332,7 @@ CPUFeatures CPU::InferCPUFeaturesFromOS(
CPUFeatures::kSVESHA3,
CPUFeatures::kSVESM4,
CPUFeatures::kAXFlag,
// Bits 40-47
// Bits 8-15
CPUFeatures::kFrintToFixedSizedInt,
CPUFeatures::kSVEI8MM,
CPUFeatures::kSVEF32MM,
@@ -307,24 +341,43 @@ CPUFeatures CPU::InferCPUFeaturesFromOS(
CPUFeatures::kI8MM,
CPUFeatures::kBF16,
CPUFeatures::kDGH,
// Bits 48+
// Bits 16-23
CPUFeatures::kRNG,
CPUFeatures::kBTI,
CPUFeatures::kMTE,
CPUFeatures::kECV,
CPUFeatures::kAFP,
CPUFeatures::kRPRES};
CPUFeatures::kRPRES,
CPUFeatures::kMTE3,
CPUFeatures::kSME,
// Bits 24-31
CPUFeatures::kSMEi16i64,
CPUFeatures::kSMEf64f64,
CPUFeatures::kSMEi8i32,
CPUFeatures::kSMEf16f32,
CPUFeatures::kSMEb16f32,
CPUFeatures::kSMEf32f32,
CPUFeatures::kSMEfa64,
CPUFeatures::kWFXT,
// Bits 32-39
CPUFeatures::kEBF16,
CPUFeatures::kSVE_EBF16};
VIXL_STATIC_ASSERT(ArrayLength(kFeatureBitsHigh) < 64);
uint64_t hwcap_low32 = getauxval(AT_HWCAP);
uint64_t hwcap_high32 = getauxval(AT_HWCAP2);
VIXL_ASSERT(IsUint32(hwcap_low32));
VIXL_ASSERT(IsUint32(hwcap_high32));
uint64_t hwcap = hwcap_low32 | (hwcap_high32 << 32);
auto combine_features = [&features](uint64_t hwcap,
const CPUFeatures::Feature* feature_array,
size_t features_size) {
for (size_t i = 0; i < features_size; i++) {
if (hwcap & (UINT64_C(1) << i)) features.Combine(feature_array[i]);
}
};
uint64_t hwcap_low = getauxval(AT_HWCAP);
uint64_t hwcap_high = getauxval(AT_HWCAP2);
combine_features(hwcap_low, kFeatureBitsLow, ArrayLength(kFeatureBitsLow));
combine_features(hwcap_high, kFeatureBitsHigh, ArrayLength(kFeatureBitsHigh));
VIXL_STATIC_ASSERT(ArrayLength(kFeatureBits) < 64);
for (size_t i = 0; i < ArrayLength(kFeatureBits); i++) {
if (hwcap & (UINT64_C(1) << i)) features.Combine(kFeatureBits[i]);
}
// MTE support from HWCAP2 signifies FEAT_MTE1 and FEAT_MTE2 support
if (features.Has(CPUFeatures::kMTE)) {
features.Combine(CPUFeatures::kMTEInstructions);
@@ -425,7 +478,7 @@ int CPU::ReadSVEVectorLengthInBits() {
}
void CPU::EnsureIAndDCacheCoherency(void *address, size_t length) {
void CPU::EnsureIAndDCacheCoherency(void* address, size_t length) {
#ifdef __aarch64__
// Implement the cache synchronisation for all targets where AArch64 is the
// host, even if we're building the simulator for an AAarch64 host. This
@@ -523,5 +576,6 @@ void CPU::EnsureIAndDCacheCoherency(void *address, size_t length) {
#endif
}
} // namespace aarch64
} // namespace vixl
+30 -8
View File
@@ -31,6 +31,7 @@
#include "../globals-vixl.h"
#include "instructions-aarch64.h"
#include "simulator-aarch64.h"
#ifndef VIXL_INCLUDE_TARGET_AARCH64
// The supporting .cc file is only compiled when the A64 target is selected.
@@ -56,24 +57,24 @@ class IDRegister {
public:
enum Type { kUnsigned, kSigned };
static const int kMaxWidthInBits = 4;
// This needs to be constexpr so that fields have "constant initialisation".
// This avoids initialisation order problems when these values are used to
// (dynamically) initialise static variables, etc.
explicit constexpr Field(int lsb, Type type = kUnsigned)
: lsb_(lsb), type_(type) {}
explicit constexpr Field(int lsb,
int bitWidth = kMaxWidthInBits,
Type type = kUnsigned)
: lsb_(lsb), bitWidth_(bitWidth), type_(type) {}
static const int kMaxWidthInBits = 4;
int GetWidthInBits() const {
// All current ID fields have four bits.
return kMaxWidthInBits;
}
int GetWidthInBits() const { return bitWidth_; }
int GetLsb() const { return lsb_; }
int GetMsb() const { return lsb_ + GetWidthInBits() - 1; }
Type GetType() const { return type_; }
private:
int lsb_;
int bitWidth_;
Type type_;
};
@@ -113,6 +114,7 @@ class AA64PFR1 : public IDRegister {
static const Field kBT;
static const Field kSSBS;
static const Field kMTE;
static const Field kSME;
};
class AA64ISAR0 : public IDRegister {
@@ -167,7 +169,10 @@ class AA64ISAR2 : public IDRegister {
CPUFeatures GetCPUFeatures() const;
private:
static const Field kWFXT;
static const Field kRPRES;
static const Field kMOPS;
static const Field kCSSC;
};
class AA64MMFR0 : public IDRegister {
@@ -219,6 +224,22 @@ class AA64ZFR0 : public IDRegister {
static const Field kF64MM;
};
class AA64SMFR0 : public IDRegister {
public:
explicit AA64SMFR0(uint64_t value) : IDRegister(value) {}
CPUFeatures GetCPUFeatures() const;
private:
static const Field kSMEf32f32;
static const Field kSMEb16f32;
static const Field kSMEf16f32;
static const Field kSMEi8i32;
static const Field kSMEf64f64;
static const Field kSMEi16i64;
static const Field kSMEfa64;
};
class CPU {
public:
// Initialise CPU support.
@@ -285,6 +306,7 @@ class CPU {
V(AA64MMFR1, "ID_AA64MMFR1_EL1") \
/* These registers are RES0 in the baseline Arm8.0. We can always safely */ \
/* read them, but some compilers don't accept the symbolic names. */ \
V(AA64SMFR0, "S3_0_C0_C4_5") \
V(AA64ISAR2, "S3_0_C0_C6_2") \
V(AA64MMFR2, "S3_0_C0_C7_2") \
V(AA64ZFR0, "S3_0_C0_C4_4")
+107 -5
View File
@@ -24,12 +24,13 @@
// 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.
#include "cpu-features-auditor-aarch64.h"
#include "cpu-features.h"
#include "globals-vixl.h"
#include "utils-vixl.h"
#include "decoder-aarch64.h"
#include "cpu-features-auditor-aarch64.h"
#include "decoder-aarch64.h"
namespace vixl {
namespace aarch64 {
@@ -505,8 +506,6 @@ void CPUFeaturesAuditor::VisitFPImmediate(const Instruction* instr) {
void CPUFeaturesAuditor::VisitFPIntegerConvert(const Instruction* instr) {
RecordInstructionFeaturesScope scope(this);
// All of these instructions require FP.
scope.Record(CPUFeatures::kFP);
switch (instr->Mask(FPIntegerConvertMask)) {
case FCVTAS_wh:
case FCVTAS_xh:
@@ -536,17 +535,23 @@ void CPUFeaturesAuditor::VisitFPIntegerConvert(const Instruction* instr) {
case SCVTF_hx:
case UCVTF_hw:
case UCVTF_hx:
scope.Record(CPUFeatures::kFP);
scope.Record(CPUFeatures::kFPHalf);
return;
case FMOV_dx:
scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
return;
case FMOV_d1_x:
case FMOV_x_d1:
scope.Record(CPUFeatures::kFP);
scope.Record(CPUFeatures::kNEON);
return;
case FJCVTZS:
scope.Record(CPUFeatures::kFP);
scope.Record(CPUFeatures::kJSCVT);
return;
default:
// No special CPU features.
scope.Record(CPUFeatures::kFP);
return;
}
}
@@ -1305,6 +1310,16 @@ void CPUFeaturesAuditor::VisitSystem(const Instruction* instr) {
} else if (instr->Mask(SystemSysMask) == SYS) {
switch (instr->GetSysOp()) {
// DC instruction variants.
case CGVAC:
case CGDVAC:
case CGVAP:
case CGDVAP:
case CIGVAC:
case CIGDVAC:
case GVA:
case GZVA:
scope.Record(CPUFeatures::kMTE);
break;
case CVAP:
scope.Record(CPUFeatures::kDCPoP);
break;
@@ -1315,6 +1330,7 @@ void CPUFeaturesAuditor::VisitSystem(const Instruction* instr) {
case CVAC:
case CVAU:
case CIVAC:
case ZVA:
// No special CPU features.
break;
}
@@ -1723,6 +1739,92 @@ void CPUFeaturesAuditor::Visit(Metadata* metadata, const Instruction* instr) {
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
{"sudot_z_zzzi_s"_h,
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
{"addg_64_addsub_immtags"_h, CPUFeatures::kMTE},
{"gmi_64g_dp_2src"_h, CPUFeatures::kMTE},
{"irg_64i_dp_2src"_h, CPUFeatures::kMTE},
{"ldg_64loffset_ldsttags"_h, CPUFeatures::kMTE},
{"st2g_64soffset_ldsttags"_h, CPUFeatures::kMTE},
{"st2g_64spost_ldsttags"_h, CPUFeatures::kMTE},
{"st2g_64spre_ldsttags"_h, CPUFeatures::kMTE},
{"stgp_64_ldstpair_off"_h, CPUFeatures::kMTE},
{"stgp_64_ldstpair_post"_h, CPUFeatures::kMTE},
{"stgp_64_ldstpair_pre"_h, CPUFeatures::kMTE},
{"stg_64soffset_ldsttags"_h, CPUFeatures::kMTE},
{"stg_64spost_ldsttags"_h, CPUFeatures::kMTE},
{"stg_64spre_ldsttags"_h, CPUFeatures::kMTE},
{"stz2g_64soffset_ldsttags"_h, CPUFeatures::kMTE},
{"stz2g_64spost_ldsttags"_h, CPUFeatures::kMTE},
{"stz2g_64spre_ldsttags"_h, CPUFeatures::kMTE},
{"stzg_64soffset_ldsttags"_h, CPUFeatures::kMTE},
{"stzg_64spost_ldsttags"_h, CPUFeatures::kMTE},
{"stzg_64spre_ldsttags"_h, CPUFeatures::kMTE},
{"subg_64_addsub_immtags"_h, CPUFeatures::kMTE},
{"subps_64s_dp_2src"_h, CPUFeatures::kMTE},
{"subp_64s_dp_2src"_h, CPUFeatures::kMTE},
{"cpyen_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyern_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyewn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpye_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfen_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfern_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfewn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfe_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfmn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfmrn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfmwn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfm_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfpn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfprn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfpwn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyfp_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpymn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpymrn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpymwn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpym_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpypn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyprn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpypwn_cpy_memcms"_h, CPUFeatures::kMOPS},
{"cpyp_cpy_memcms"_h, CPUFeatures::kMOPS},
{"seten_set_memcms"_h, CPUFeatures::kMOPS},
{"sete_set_memcms"_h, CPUFeatures::kMOPS},
{"setgen_set_memcms"_h,
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
{"setge_set_memcms"_h,
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
{"setgmn_set_memcms"_h,
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
{"setgm_set_memcms"_h,
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
{"setgpn_set_memcms"_h,
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
{"setgp_set_memcms"_h,
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
{"setmn_set_memcms"_h, CPUFeatures::kMOPS},
{"setm_set_memcms"_h, CPUFeatures::kMOPS},
{"setpn_set_memcms"_h, CPUFeatures::kMOPS},
{"setp_set_memcms"_h, CPUFeatures::kMOPS},
{"abs_32_dp_1src"_h, CPUFeatures::kCSSC},
{"abs_64_dp_1src"_h, CPUFeatures::kCSSC},
{"cnt_32_dp_1src"_h, CPUFeatures::kCSSC},
{"cnt_64_dp_1src"_h, CPUFeatures::kCSSC},
{"ctz_32_dp_1src"_h, CPUFeatures::kCSSC},
{"ctz_64_dp_1src"_h, CPUFeatures::kCSSC},
{"smax_32_dp_2src"_h, CPUFeatures::kCSSC},
{"smax_64_dp_2src"_h, CPUFeatures::kCSSC},
{"smin_32_dp_2src"_h, CPUFeatures::kCSSC},
{"smin_64_dp_2src"_h, CPUFeatures::kCSSC},
{"umax_32_dp_2src"_h, CPUFeatures::kCSSC},
{"umax_64_dp_2src"_h, CPUFeatures::kCSSC},
{"umin_32_dp_2src"_h, CPUFeatures::kCSSC},
{"umin_64_dp_2src"_h, CPUFeatures::kCSSC},
{"smax_32_minmax_imm"_h, CPUFeatures::kCSSC},
{"smax_64_minmax_imm"_h, CPUFeatures::kCSSC},
{"smin_32_minmax_imm"_h, CPUFeatures::kCSSC},
{"smin_64_minmax_imm"_h, CPUFeatures::kCSSC},
{"umax_32u_minmax_imm"_h, CPUFeatures::kCSSC},
{"umax_64u_minmax_imm"_h, CPUFeatures::kCSSC},
{"umin_32u_minmax_imm"_h, CPUFeatures::kCSSC},
{"umin_64u_minmax_imm"_h, CPUFeatures::kCSSC},
};
if (features.count(form_hash) > 0) {
@@ -32,6 +32,7 @@
#include <unordered_map>
#include "cpu-features.h"
#include "decoder-aarch64.h"
#include "decoder-visitor-map-aarch64.h"
+521
View File
@@ -0,0 +1,521 @@
// Copyright 2023, VIXL authors
// 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 ARM Limited 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 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.
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
#include "debugger-aarch64.h"
#include <cerrno>
#include <cmath>
#include <cstring>
#include <errno.h>
#include <limits>
#include <unistd.h>
namespace vixl {
namespace aarch64 {
Debugger::Debugger(Simulator* sim)
: sim_(sim)
#ifdef VIXL_USE_PANDA_ALLOC
, debugger_cmds_(sim->GetAllocator().Adapter())
, breakpoints_(sim->GetAllocator().Adapter())
#endif
, input_stream_(&std::cin)
, ostream_(sim->GetOutputStream()) {
// Register all basic debugger commands.
RegisterCmd<HelpCmd>();
RegisterCmd<BreakCmd>();
RegisterCmd<StepCmd>();
RegisterCmd<ContinueCmd>();
RegisterCmd<PrintCmd>();
RegisterCmd<TraceCmd>();
RegisterCmd<GdbCmd>();
}
template <class T>
void Debugger::RegisterCmd() {
#ifndef VIXL_USE_PANDA_ALLOC
auto new_command = std::make_unique<T>(sim_);
#else
auto* new_command = sim_->GetAllocator().New<T>(sim_);
#endif
// Check that the new command word and alias, don't already exist.
std::string_view new_cmd_word = new_command->GetCommandWord();
std::string_view new_cmd_alias = new_command->GetCommandAlias();
for (const auto& cmd : debugger_cmds_) {
std::string_view cmd_word = cmd->GetCommandWord();
std::string_view cmd_alias = cmd->GetCommandAlias();
if (new_cmd_word == cmd_word) {
VIXL_ABORT_WITH_MSG("Command word matches an existing command word.");
} else if (new_cmd_word == cmd_alias) {
VIXL_ABORT_WITH_MSG("Command word matches an existing command alias.");
}
if (new_cmd_alias != "") {
if (new_cmd_alias == cmd_word) {
VIXL_ABORT_WITH_MSG("Command alias matches an existing command word.");
} else if (new_cmd_alias == cmd_alias) {
VIXL_ABORT_WITH_MSG("Command alias matches an existing command alias.");
}
}
}
#ifndef VIXL_USE_PANDA_ALLOC
debugger_cmds_.push_back(std::move(new_command));
#else
debugger_cmds_.push_back(new_command);
#endif
}
bool Debugger::IsAtBreakpoint() const {
return IsBreakpoint(reinterpret_cast<uint64_t>(sim_->ReadPc()));
}
void Debugger::Debug() {
DebugReturn done = DebugContinue;
while (done == DebugContinue) {
// Disassemble the next instruction to execute.
#ifndef PANDA_BUILD
PrintDisassembler print_disasm = PrintDisassembler(ostream_);
#else
PrintDisassembler print_disasm = PrintDisassembler(sim_->GetAllocator(), ostream_);
#endif
print_disasm.Disassemble(sim_->ReadPc());
// Read the command line.
fprintf(ostream_, "sim> ");
std::string line;
std::getline(*input_stream_, line);
// Remove all control characters from the command string.
line.erase(std::remove_if(line.begin(),
line.end(),
[](char c) { return std::iscntrl(c); }),
line.end());
// Assume input from std::cin has already been output (e.g: by a terminal)
// but input from elsewhere (e.g: from a testing input stream) has not.
if (input_stream_ != &std::cin) {
fprintf(ostream_, "%s\n", line.c_str());
}
// Parse the command into tokens.
std::vector<std::string> tokenized_cmd = Tokenize(line);
if (!tokenized_cmd.empty()) {
done = ExecDebugCommand(tokenized_cmd);
}
}
}
std::optional<uint64_t> Debugger::ParseUint64String(std::string_view uint64_str,
int base) {
// Clear any previous errors.
errno = 0;
// strtoull uses 0 to indicate that no conversion was possible so first
// check that the string isn't zero.
if (IsZeroUint64String(uint64_str, base)) {
return 0;
}
// Cannot use stoi as it might not be possible to use exceptions.
char* end;
uint64_t value = std::strtoull(uint64_str.data(), &end, base);
if (value == 0 || *end != '\0' || errno == ERANGE) {
return std::nullopt;
}
return value;
}
std::optional<Debugger::RegisterParsedFormat> Debugger::ParseRegString(
std::string_view reg_str) {
// A register should only have 2 (e.g: X0) or 3 (e.g: X31) characters.
if (reg_str.size() < 2 || reg_str.size() > 3) {
return std::nullopt;
}
// Check for aliases of registers.
if (reg_str == "lr") {
return {{'X', kLinkRegCode}};
} else if (reg_str == "sp") {
return {{'X', kSpRegCode}};
}
unsigned max_reg_num;
char reg_prefix = std::toupper(reg_str.front());
switch (reg_prefix) {
case 'W':
VIXL_FALLTHROUGH();
case 'X':
max_reg_num = kNumberOfRegisters - 1;
break;
case 'V':
max_reg_num = kNumberOfVRegisters - 1;
break;
case 'Z':
max_reg_num = kNumberOfZRegisters - 1;
break;
case 'P':
max_reg_num = kNumberOfPRegisters - 1;
break;
default:
return std::nullopt;
}
std::string_view str_code = reg_str.substr(1, reg_str.size());
auto reg_code = ParseUint64String(str_code, 10);
if (!reg_code) {
return std::nullopt;
}
if (*reg_code > max_reg_num) {
return std::nullopt;
}
return {{reg_prefix, *reg_code}};
}
void Debugger::PrintUsage() {
for (const auto& cmd : debugger_cmds_) {
// Print commands in the following format:
// foo / f
// foo <arg>
// A description of the foo command.
//
std::string_view cmd_word = cmd->GetCommandWord();
std::string_view cmd_alias = cmd->GetCommandAlias();
if (cmd_alias != "") {
fprintf(ostream_, "%s / %s\n", cmd_word.data(), cmd_alias.data());
} else {
fprintf(ostream_, "%s\n", cmd_word.data());
}
std::string_view args_str = cmd->GetArgsString();
if (args_str != "") {
fprintf(ostream_, "\t%s %s\n", cmd_word.data(), args_str.data());
}
std::string_view description = cmd->GetDescription();
if (description != "") {
fprintf(ostream_, "\t%s\n", description.data());
}
}
}
std::vector<std::string> Debugger::Tokenize(std::string_view input_line,
char separator) {
std::vector<std::string> words;
if (input_line.empty()) {
return words;
}
for (auto separator_pos = input_line.find(separator);
separator_pos != input_line.npos;
separator_pos = input_line.find(separator)) {
// Skip consecutive, repeated separators.
if (separator_pos != 0) {
words.push_back(std::string{input_line.substr(0, separator_pos)});
}
// Remove characters up to and including the separator.
input_line.remove_prefix(separator_pos + 1);
}
// Add the rest of the string to the vector.
words.push_back(std::string{input_line});
return words;
}
DebugReturn Debugger::ExecDebugCommand(
const std::vector<std::string>& tokenized_cmd) {
std::string cmd_word = tokenized_cmd.front();
for (const auto& cmd : debugger_cmds_) {
if (cmd_word == cmd->GetCommandWord() ||
cmd_word == cmd->GetCommandAlias()) {
const std::vector<std::string> args(tokenized_cmd.begin() + 1,
tokenized_cmd.end());
// Call the handler for the command and pass the arguments.
return cmd->Action(args);
}
}
fprintf(ostream_, "Error: command '%s' not found\n", cmd_word.c_str());
return DebugContinue;
}
bool Debugger::IsZeroUint64String(std::string_view uint64_str, int base) {
// Remove any hex prefixes.
if (base == 0 || base == 16) {
std::string_view prefix = uint64_str.substr(0, 2);
if (prefix == "0x" || prefix == "0X") {
uint64_str.remove_prefix(2);
}
}
if (uint64_str.empty()) {
return false;
}
// Check all remaining digits in the string for anything other than zero.
for (char c : uint64_str) {
if (c != '0') {
return false;
}
}
return true;
}
DebuggerCmd::DebuggerCmd(Simulator* sim,
std::string_view cmd_word,
std::string_view cmd_alias,
std::string_view args_str,
std::string_view description)
:
#ifdef PANDA_BUILD
allocator_(sim->GetAllocator()),
#endif
sim_(sim),
ostream_(sim->GetOutputStream()),
command_word_(cmd_word, allocator_.Adapter()),
command_alias_(cmd_alias, allocator_.Adapter()),
args_str_(args_str, allocator_.Adapter()),
description_(description, allocator_.Adapter()) {}
DebugReturn HelpCmd::Action(const std::vector<std::string>& args) {
USE(args);
sim_->GetDebugger()->PrintUsage();
return DebugContinue;
}
DebugReturn BreakCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 1) {
fprintf(ostream_, "Error: Use `break <address>` to set a breakpoint\n");
return DebugContinue;
}
std::string arg = args.front();
auto break_addr = Debugger::ParseUint64String(arg);
if (!break_addr) {
fprintf(ostream_, "Error: Use `break <address>` to set a breakpoint\n");
return DebugContinue;
}
if (sim_->GetDebugger()->IsBreakpoint(*break_addr)) {
sim_->GetDebugger()->RemoveBreakpoint(*break_addr);
fprintf(ostream_,
"Breakpoint successfully removed at: 0x%" PRIx64 "\n",
*break_addr);
} else {
sim_->GetDebugger()->RegisterBreakpoint(*break_addr);
fprintf(ostream_,
"Breakpoint successfully added at: 0x%" PRIx64 "\n",
*break_addr);
}
return DebugContinue;
}
DebugReturn StepCmd::Action(const std::vector<std::string>& args) {
if (args.size() > 1) {
fprintf(ostream_,
"Error: use `step [number]` to step an optional number of"
" instructions\n");
return DebugContinue;
}
// Step 1 instruction by default.
std::optional<uint64_t> number_of_instructions_to_execute{1};
if (args.size() == 1) {
// Parse the argument to step that number of instructions.
std::string arg = args.front();
number_of_instructions_to_execute = Debugger::ParseUint64String(arg);
if (!number_of_instructions_to_execute) {
fprintf(ostream_,
"Error: use `step [number]` to step an optional number of"
" instructions\n");
return DebugContinue;
}
}
while (!sim_->IsSimulationFinished() &&
*number_of_instructions_to_execute > 0) {
sim_->ExecuteInstruction();
(*number_of_instructions_to_execute)--;
// The first instruction has already been printed by Debug() so only
// enable instruction tracing after the first instruction has been
// executed.
sim_->SetTraceParameters(sim_->GetTraceParameters() | LOG_DISASM);
}
// Disable instruction tracing after all instructions have been executed.
sim_->SetTraceParameters(sim_->GetTraceParameters() & ~LOG_DISASM);
if (sim_->IsSimulationFinished()) {
fprintf(ostream_,
"Debugger at the end of simulation, leaving simulator...\n");
return DebugExit;
}
return DebugContinue;
}
DebugReturn ContinueCmd::Action(const std::vector<std::string>& args) {
USE(args);
fprintf(ostream_, "Continuing...\n");
if (sim_->GetDebugger()->IsAtBreakpoint()) {
// This breakpoint has already been hit, so execute it before continuing.
sim_->ExecuteInstruction();
}
return DebugExit;
}
DebugReturn PrintCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 1) {
fprintf(ostream_,
"Error: use `print <register|all>` to print the contents of a"
" specific register or all registers.\n");
return DebugContinue;
}
if (args.front() == "all") {
sim_->PrintRegisters();
sim_->PrintZRegisters();
} else if (args.front() == "system") {
sim_->PrintSystemRegisters();
} else if (args.front() == "ffr") {
sim_->PrintFFR();
} else {
auto reg = Debugger::ParseRegString(args.front());
if (!reg) {
fprintf(ostream_,
"Error: incorrect register format, use e.g: X0, x0, etc...\n");
return DebugContinue;
}
// Ensure the stack pointer is printed instead of the zero register.
if ((*reg).second == kSpRegCode) {
(*reg).second = kSPRegInternalCode;
}
// Registers are printed in different ways depending on their type.
switch ((*reg).first) {
case 'W':
sim_->PrintRegister(
(*reg).second,
static_cast<Simulator::PrintRegisterFormat>(
Simulator::PrintRegisterFormat::kPrintWReg |
Simulator::PrintRegisterFormat::kPrintRegPartial));
break;
case 'X':
sim_->PrintRegister((*reg).second,
Simulator::PrintRegisterFormat::kPrintXReg);
break;
case 'V':
sim_->PrintVRegister((*reg).second);
break;
case 'Z':
sim_->PrintZRegister((*reg).second);
break;
case 'P':
sim_->PrintPRegister((*reg).second);
break;
default:
// ParseRegString should only allow valid register characters.
VIXL_UNREACHABLE();
}
}
return DebugContinue;
}
DebugReturn TraceCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 0) {
fprintf(ostream_, "Error: use `trace` to toggle tracing of registers.\n");
return DebugContinue;
}
int trace_params = sim_->GetTraceParameters();
if ((trace_params & LOG_ALL) != LOG_ALL) {
fprintf(ostream_,
"Enabling disassembly, registers and memory write tracing\n");
sim_->SetTraceParameters(trace_params | LOG_ALL);
} else {
fprintf(ostream_,
"Disabling disassembly, registers and memory write tracing\n");
sim_->SetTraceParameters(trace_params & ~LOG_ALL);
}
return DebugContinue;
}
DebugReturn GdbCmd::Action(const std::vector<std::string>& args) {
if (args.size() != 0) {
fprintf(ostream_,
"Error: use `gdb` to enter GDB from the simulator debugger.\n");
return DebugContinue;
}
HostBreakpoint();
return DebugContinue;
}
} // namespace aarch64
} // namespace vixl
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
+282
View File
@@ -0,0 +1,282 @@
// Copyright 2023, VIXL authors
// 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 ARM Limited 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 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.
#ifndef VIXL_AARCH64_DEBUGGER_AARCH64_H_
#define VIXL_AARCH64_DEBUGGER_AARCH64_H_
#include <optional>
#include <unordered_set>
#include <vector>
#include "../globals-vixl.h"
#include "../utils-vixl.h"
#include "cpu-features.h"
#include "abi-aarch64.h"
#include "cpu-features-auditor-aarch64.h"
#include "disasm-aarch64.h"
#include "instructions-aarch64.h"
#include "simulator-aarch64.h"
#include "simulator-constants-aarch64.h"
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
namespace vixl {
namespace aarch64 {
class Simulator;
enum DebugReturn { DebugContinue, DebugExit };
// A debugger command that performs some action when used by the simulator
// debugger.
class DebuggerCmd {
public:
DebuggerCmd(Simulator* sim,
std::string_view cmd_word,
std::string_view cmd_alias,
std::string_view usage,
std::string_view description);
virtual ~DebuggerCmd() {}
// Perform some action based on the arguments passed in. Returns true if the
// debugger should exit after the action, false otherwise.
virtual DebugReturn Action(const std::vector<std::string>& args) = 0;
// Return the command word.
std::string_view GetCommandWord() { return command_word_; }
// Return the alias for this command. Returns an empty string if this command
// has no alias.
std::string_view GetCommandAlias() { return command_alias_; }
// Return this commands usage.
std::string_view GetArgsString() { return args_str_; }
// Return this commands description.
std::string_view GetDescription() { return description_; }
protected:
AllocatorWrapper allocator_;
// Simulator which this command will be performed on.
Simulator* sim_;
// Stream to output the result of the command to.
FILE* ostream_;
// Command word that, when given to the interactive debugger, calls Action.
String command_word_;
// Optional alias for the command_word.
String command_alias_;
// Optional string showing the arguments that can be passed to the command.
String args_str_;
// Optional description of the command.
String description_;
};
//
// Base debugger command handlers:
//
class HelpCmd : public DebuggerCmd {
public:
HelpCmd(Simulator* sim)
: DebuggerCmd(sim, "help", "h", "", "Display this help message.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
class BreakCmd : public DebuggerCmd {
public:
BreakCmd(Simulator* sim)
: DebuggerCmd(sim,
"break",
"b",
"<address>",
"Set or remove a breakpoint.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
class StepCmd : public DebuggerCmd {
public:
StepCmd(Simulator* sim)
: DebuggerCmd(sim,
"step",
"s",
"[<n>]",
"Step n instructions, default step 1 instruction.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
class ContinueCmd : public DebuggerCmd {
public:
ContinueCmd(Simulator* sim)
: DebuggerCmd(sim,
"continue",
"c",
"",
"Exit the debugger and continue executing instructions.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
class PrintCmd : public DebuggerCmd {
public:
PrintCmd(Simulator* sim)
: DebuggerCmd(sim,
"print",
"p",
"<register|all|system>",
"Print the contents of a register, all registers or all"
" system registers.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
class TraceCmd : public DebuggerCmd {
public:
TraceCmd(Simulator* sim)
: DebuggerCmd(sim,
"trace",
"t",
"",
"Start/stop memory and register tracing.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
class GdbCmd : public DebuggerCmd {
public:
GdbCmd(Simulator* sim)
: DebuggerCmd(sim,
"gdb",
"g",
"",
"Enter an already running instance of gdb.") {}
DebugReturn Action(const std::vector<std::string>& args) override;
};
// A debugger for the Simulator which takes input from the user in order to
// control the running of the Simulator.
class Debugger {
public:
// A pair consisting of a register character (e.g: W, X, V) and a register
// code (e.g: 0, 1 ...31) which represents a single parsed register.
//
// Note: the register character is guaranteed to be upper case.
using RegisterParsedFormat = std::pair<char, unsigned>;
Debugger(Simulator* sim);
// Set the input stream, from which commands are read, to a custom stream.
void SetInputStream(std::istream* stream) { input_stream_ = stream; }
// Register a new command for the debugger.
template <class T>
void RegisterCmd();
// Set a breakpoint at the given address.
void RegisterBreakpoint(uint64_t addr) { breakpoints_.insert(addr); }
// Remove a breakpoint at the given address.
void RemoveBreakpoint(uint64_t addr) { breakpoints_.erase(addr); }
// Return true if the address is the location of a breakpoint.
bool IsBreakpoint(uint64_t addr) const {
return (breakpoints_.find(addr) != breakpoints_.end());
}
// Return true if the simulator pc is a breakpoint.
bool IsAtBreakpoint() const;
// Main loop for the debugger. Keep prompting for user inputted debugger
// commands and try to execute them until a command is given that exits the
// interactive debugger.
void Debug();
// Get an unsigned integer value from a string and return it in 'value'.
// Base is used to determine the numeric base of the number to be read,
// i.e: 8 for octal, 10 for decimal, 16 for hexadecimal and 0 for
// auto-detect. Return true if an integer value was found, false otherwise.
static std::optional<uint64_t> ParseUint64String(std::string_view uint64_str,
int base = 0);
// Get a register from a string and return it in 'reg'. Return true if a
// valid register character and code (e.g: W0, X29, V31) was found, false
// otherwise.
static std::optional<RegisterParsedFormat> ParseRegString(
std::string_view reg_str);
// Print the usage of each debugger command.
void PrintUsage();
private:
// Split a string based on the separator given (a single space character by
// default) and return as a std::vector of strings.
static std::vector<std::string> Tokenize(std::string_view input_line,
char separator = ' ');
// Try to execute a single debugger command.
DebugReturn ExecDebugCommand(const std::vector<std::string>& tokenized_cmd);
// Return true if the string is zero, i.e: all characters in the string
// (other than prefixes) are zero.
static bool IsZeroUint64String(std::string_view uint64_str, int base);
// The simulator that this debugger acts on.
Simulator* sim_;
// A vector of all commands recognised by the debugger.
#ifndef VIXL_USE_PANDA_ALLOC
std::vector<std::unique_ptr<DebuggerCmd>> debugger_cmds_;
#else
Vector<DebuggerCmd*> debugger_cmds_;
#endif
// A list of all instruction addresses that, when executed by the
// simulator, will start the interactive debugger if it hasn't already.
UnorderedSet<uint64_t> breakpoints_;
// Input stream from which commands are read. Default is std::cin.
std::istream* input_stream_;
// Output stream from the simulator.
FILE* ostream_;
};
} // namespace aarch64
} // namespace vixl
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
#endif // VIXL_AARCH64_DEBUGGER_AARCH64_H_
+35 -25
View File
@@ -24,12 +24,13 @@
// 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.
#include "decoder-aarch64.h"
#include <string>
#include "../globals-vixl.h"
#include "../utils-vixl.h"
#include "decoder-aarch64.h"
#include "decoder-constants-aarch64.h"
namespace vixl {
@@ -149,9 +150,9 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
}
void Decoder::VisitNamedInstruction(const Instruction* instr,
const std::string& name) {
const std::string_view name) {
std::list<DecoderVisitor*>::iterator it;
Metadata m = {{"form", name}};
Metadata m = {{"form", std::string(name)}};
for (it = visitors_.begin(); it != visitors_.end(); it++) {
(*it)->Visit(&m, instr);
}
@@ -194,10 +195,10 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
// masked result.
uint64_t signature = (static_cast<uint64_t>(y) << 32) | x;
switch (signature) {
INSTANTIATE_TEMPLATE_M(00000001);
INSTANTIATE_TEMPLATE_M(00000002);
INSTANTIATE_TEMPLATE_M(00000010);
INSTANTIATE_TEMPLATE_M(0000001f);
INSTANTIATE_TEMPLATE_M(00000060);
INSTANTIATE_TEMPLATE_M(000000df);
INSTANTIATE_TEMPLATE_M(00000100);
INSTANTIATE_TEMPLATE_M(00000200);
INSTANTIATE_TEMPLATE_M(00000400);
@@ -218,10 +219,10 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(00003800);
INSTANTIATE_TEMPLATE_M(00003c00);
INSTANTIATE_TEMPLATE_M(00013000);
INSTANTIATE_TEMPLATE_M(00020000);
INSTANTIATE_TEMPLATE_M(00020010);
INSTANTIATE_TEMPLATE_M(000203e0);
INSTANTIATE_TEMPLATE_M(000303e0);
INSTANTIATE_TEMPLATE_M(00040000);
INSTANTIATE_TEMPLATE_M(00040010);
INSTANTIATE_TEMPLATE_M(00060000);
INSTANTIATE_TEMPLATE_M(00061000);
INSTANTIATE_TEMPLATE_M(00070000);
@@ -232,19 +233,22 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(000f0010);
INSTANTIATE_TEMPLATE_M(00100000);
INSTANTIATE_TEMPLATE_M(00180000);
INSTANTIATE_TEMPLATE_M(001d1c00);
INSTANTIATE_TEMPLATE_M(001b1c00);
INSTANTIATE_TEMPLATE_M(001f0000);
INSTANTIATE_TEMPLATE_M(001f0018);
INSTANTIATE_TEMPLATE_M(001f2000);
INSTANTIATE_TEMPLATE_M(001f3000);
INSTANTIATE_TEMPLATE_M(00400000);
INSTANTIATE_TEMPLATE_M(00400018);
INSTANTIATE_TEMPLATE_M(00400800);
INSTANTIATE_TEMPLATE_M(00403000);
INSTANTIATE_TEMPLATE_M(00500000);
INSTANTIATE_TEMPLATE_M(00500800);
INSTANTIATE_TEMPLATE_M(00583000);
INSTANTIATE_TEMPLATE_M(005f0000);
INSTANTIATE_TEMPLATE_M(00800000);
INSTANTIATE_TEMPLATE_M(00800400);
INSTANTIATE_TEMPLATE_M(00800c1e);
INSTANTIATE_TEMPLATE_M(00800c1d);
INSTANTIATE_TEMPLATE_M(0080101f);
INSTANTIATE_TEMPLATE_M(00801c00);
INSTANTIATE_TEMPLATE_M(00803000);
@@ -257,15 +261,15 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(00c00200);
INSTANTIATE_TEMPLATE_M(00c00400);
INSTANTIATE_TEMPLATE_M(00c00c00);
INSTANTIATE_TEMPLATE_M(00c00c1c);
INSTANTIATE_TEMPLATE_M(00c00c19);
INSTANTIATE_TEMPLATE_M(00c01000);
INSTANTIATE_TEMPLATE_M(00c01400);
INSTANTIATE_TEMPLATE_M(00c01c00);
INSTANTIATE_TEMPLATE_M(00c02000);
INSTANTIATE_TEMPLATE_M(00c03000);
INSTANTIATE_TEMPLATE_M(00c03c00);
INSTANTIATE_TEMPLATE_M(00c70000);
INSTANTIATE_TEMPLATE_M(00c83000);
INSTANTIATE_TEMPLATE_M(00cf0000);
INSTANTIATE_TEMPLATE_M(00d00200);
INSTANTIATE_TEMPLATE_M(00d80800);
INSTANTIATE_TEMPLATE_M(00d81800);
@@ -275,9 +279,9 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(00d92400);
INSTANTIATE_TEMPLATE_M(00d93000);
INSTANTIATE_TEMPLATE_M(00db0000);
INSTANTIATE_TEMPLATE_M(00db2000);
INSTANTIATE_TEMPLATE_M(00dc0000);
INSTANTIATE_TEMPLATE_M(00dc2000);
INSTANTIATE_TEMPLATE_M(00dd2000);
INSTANTIATE_TEMPLATE_M(00df0000);
INSTANTIATE_TEMPLATE_M(40000000);
INSTANTIATE_TEMPLATE_M(40000010);
@@ -286,12 +290,11 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(40002010);
INSTANTIATE_TEMPLATE_M(40003000);
INSTANTIATE_TEMPLATE_M(40003c00);
INSTANTIATE_TEMPLATE_M(400f0000);
INSTANTIATE_TEMPLATE_M(400f0400);
INSTANTIATE_TEMPLATE_M(401f2000);
INSTANTIATE_TEMPLATE_M(40400800);
INSTANTIATE_TEMPLATE_M(40400c00);
INSTANTIATE_TEMPLATE_M(40403c00);
INSTANTIATE_TEMPLATE_M(405f0000);
INSTANTIATE_TEMPLATE_M(40800000);
INSTANTIATE_TEMPLATE_M(40800c00);
INSTANTIATE_TEMPLATE_M(40802000);
@@ -299,9 +302,10 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(40803400);
INSTANTIATE_TEMPLATE_M(40803c00);
INSTANTIATE_TEMPLATE_M(40c00000);
INSTANTIATE_TEMPLATE_M(40c00400);
INSTANTIATE_TEMPLATE_M(40c00800);
INSTANTIATE_TEMPLATE_M(40c00c00);
INSTANTIATE_TEMPLATE_M(40c00c10);
INSTANTIATE_TEMPLATE_M(40c01c00);
INSTANTIATE_TEMPLATE_M(40c02000);
INSTANTIATE_TEMPLATE_M(40c02010);
INSTANTIATE_TEMPLATE_M(40c02c00);
@@ -313,16 +317,18 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_M(40d02010);
INSTANTIATE_TEMPLATE_M(40d80000);
INSTANTIATE_TEMPLATE_M(40d81800);
INSTANTIATE_TEMPLATE_M(40dc0000);
INSTANTIATE_TEMPLATE_M(bf20c000);
INSTANTIATE_TEMPLATE_MV(00000003, 00000000);
INSTANTIATE_TEMPLATE_MV(00000003, 00000003);
INSTANTIATE_TEMPLATE_MV(00000006, 00000000);
INSTANTIATE_TEMPLATE_MV(00000006, 00000006);
INSTANTIATE_TEMPLATE_MV(00000007, 00000000);
INSTANTIATE_TEMPLATE_MV(0000001f, 0000001f);
INSTANTIATE_TEMPLATE_MV(00000210, 00000000);
INSTANTIATE_TEMPLATE_MV(000003e0, 00000000);
INSTANTIATE_TEMPLATE_MV(000003e0, 000003e0);
INSTANTIATE_TEMPLATE_MV(000003e1, 000003e0);
INSTANTIATE_TEMPLATE_MV(000003e3, 000003e0);
INSTANTIATE_TEMPLATE_MV(000003e3, 000003e3);
INSTANTIATE_TEMPLATE_MV(000003e2, 000003e0);
INSTANTIATE_TEMPLATE_MV(000003e6, 000003e0);
INSTANTIATE_TEMPLATE_MV(000003e6, 000003e6);
INSTANTIATE_TEMPLATE_MV(00000c00, 00000000);
INSTANTIATE_TEMPLATE_MV(00000fc0, 00000000);
INSTANTIATE_TEMPLATE_MV(000013e0, 00001000);
@@ -333,11 +339,13 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_MV(00003000, 00002000);
INSTANTIATE_TEMPLATE_MV(00003000, 00003000);
INSTANTIATE_TEMPLATE_MV(00003010, 00000000);
INSTANTIATE_TEMPLATE_MV(00003c00, 00003c00);
INSTANTIATE_TEMPLATE_MV(00040010, 00000000);
INSTANTIATE_TEMPLATE_MV(00060000, 00000000);
INSTANTIATE_TEMPLATE_MV(00061000, 00000000);
INSTANTIATE_TEMPLATE_MV(00070000, 00030000);
INSTANTIATE_TEMPLATE_MV(0007309f, 0000001f);
INSTANTIATE_TEMPLATE_MV(00073ee0, 00033060);
INSTANTIATE_TEMPLATE_MV(00073f9f, 0000001f);
INSTANTIATE_TEMPLATE_MV(000f0000, 00000000);
INSTANTIATE_TEMPLATE_MV(000f0010, 00000000);
INSTANTIATE_TEMPLATE_MV(00100200, 00000000);
@@ -352,13 +360,13 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_MV(001f0000, 00100000);
INSTANTIATE_TEMPLATE_MV(001f0000, 001f0000);
INSTANTIATE_TEMPLATE_MV(001f3000, 00000000);
INSTANTIATE_TEMPLATE_MV(001f3000, 00001000);
INSTANTIATE_TEMPLATE_MV(001f3000, 001f0000);
INSTANTIATE_TEMPLATE_MV(001f300f, 0000000d);
INSTANTIATE_TEMPLATE_MV(001f301f, 0000000d);
INSTANTIATE_TEMPLATE_MV(001f33e0, 000103e0);
INSTANTIATE_TEMPLATE_MV(001f3800, 00000000);
INSTANTIATE_TEMPLATE_MV(00401000, 00400000);
INSTANTIATE_TEMPLATE_MV(00403000, 00000000);
INSTANTIATE_TEMPLATE_MV(005f3000, 001f0000);
INSTANTIATE_TEMPLATE_MV(005f3000, 001f1000);
INSTANTIATE_TEMPLATE_MV(00800010, 00000000);
@@ -381,6 +389,7 @@ BitExtractFn DecodeNode::GetBitExtractFunctionHelper(uint32_t x, uint32_t y) {
INSTANTIATE_TEMPLATE_MV(40002000, 40000000);
INSTANTIATE_TEMPLATE_MV(40003c00, 00000000);
INSTANTIATE_TEMPLATE_MV(40040000, 00000000);
INSTANTIATE_TEMPLATE_MV(401f2000, 401f0000);
INSTANTIATE_TEMPLATE_MV(40800c00, 40000400);
INSTANTIATE_TEMPLATE_MV(40c00000, 00000000);
INSTANTIATE_TEMPLATE_MV(40c00000, 00400000);
@@ -448,7 +457,7 @@ bool DecodeNode::TryCompileOptimisedDecodeTable(Decoder* decoder) {
// Set DecodeNode for when the instruction after masking doesn't match the
// value.
CompileNodeForBits(decoder, "unallocated", 0);
CompileNodeForBits(decoder, String("unallocated", GetAllocator().Adapter()), 0);
// Set DecodeNode for when it does match.
CompileNodeForBits(decoder, String(pattern_table_[0].handler, GetAllocator().Adapter()), 1);
@@ -481,7 +490,8 @@ CompiledDecodeNode* DecodeNode::Compile(Decoder* decoder) {
// Create a compiled node that contains a table with an entry for every bit
// pattern.
CreateCompiledNode(bit_extract_fn, 1U << GetSampledBitsCount());
CreateCompiledNode(bit_extract_fn,
static_cast<size_t>(1) << GetSampledBitsCount());
VIXL_ASSERT(compiled_node_ != NULL);
// When we find a pattern matches the representation, set the node's decode
@@ -537,7 +547,7 @@ DecodeNode::MaskValuePair DecodeNode::GenerateMaskValuePair(
}
uint32_t DecodeNode::GenerateOrderedPattern(uint32_t pattern) const {
const std::vector<uint8_t>& sampled_bits = GetSampledBits();
const auto& sampled_bits = GetSampledBits();
uint64_t temp = 0xffffffffffffffff;
// Place symbols into the field of set bits. Symbols are two bits wide and
+12 -12
View File
@@ -412,7 +412,7 @@ class Decoder {
List<DecoderVisitor*>::iterator old_end_;
};
void VisitNamedInstruction(const Instruction* instr, const std::string& name);
void VisitNamedInstruction(const Instruction* instr, const std::string_view name);
#ifndef PANDA_BUILD
std::list<DecoderVisitor*>* visitors() { return &visitors_; }
@@ -508,7 +508,7 @@ class CompiledDecodeNode {
// Constructor for wrappers around visitor functions. These require no
// decoding, so no bit extraction function or decode table is assigned.
explicit CompiledDecodeNode(std::string iname, Decoder* decoder)
explicit CompiledDecodeNode(const std::string_view iname, Decoder* decoder)
: bit_extract_fn_(NULL),
instruction_name_(iname),
decode_table_(NULL),
@@ -559,7 +559,7 @@ class CompiledDecodeNode {
// Visitor function that handles the instruction identified. Set only for
// leaf nodes, where no extra decoding is required, otherwise NULL.
std::string instruction_name_;
std::string_view instruction_name_;
// Mapping table from instruction bits to next decode stage.
CompiledDecodeNode** decode_table_;
@@ -574,15 +574,15 @@ class DecodeNode {
public:
// Constructor for DecodeNode wrappers around visitor functions. These are
// marked as "compiled", as there is no decoding left to do.
explicit DecodeNode(const std::string& iname, Decoder* decoder)
explicit DecodeNode(const std::string_view iname, Decoder* decoder)
:
#ifdef PANDA_BUILD
allocator_(decoder->GetAllocator()),
#endif
name_(iname, allocator_.Adapter()),
sampled_bits_(allocator_.Adapter()),
sampled_bits_(kEmptySampledBits),
instruction_name_(iname),
pattern_table_(allocator_.Adapter()),
pattern_table_(kEmptyPatternTable),
decoder_(decoder),
compiled_node_(NULL) {}
@@ -593,9 +593,9 @@ class DecodeNode {
allocator_(decoder->GetAllocator()),
#endif
name_(map.name, allocator_.Adapter()),
sampled_bits_(allocator_.Adapter()),
sampled_bits_(map.sampled_bits),
instruction_name_("node"),
pattern_table_(allocator_.Adapter()),
pattern_table_(map.mapping),
decoder_(decoder),
compiled_node_(NULL) {
// With the current two bits per symbol encoding scheme, the maximum pattern
@@ -620,7 +620,7 @@ class DecodeNode {
}
// Get the bits sampled from the instruction by this node.
const Vector<uint8_t>& GetSampledBits() const { return sampled_bits_; }
const std::vector<uint8_t>& GetSampledBits() const { return sampled_bits_; }
// Get the number of bits sampled from the instruction by this node.
size_t GetSampledBitsCount() const { return sampled_bits_.size(); }
@@ -752,15 +752,15 @@ class DecodeNode {
// Vector of bits sampled from an instruction to determine which node to look
// up next in the decode process.
Vector<uint8_t> sampled_bits_;
const std::vector<uint8_t>& sampled_bits_;
static const std::vector<uint8_t> kEmptySampledBits;
// For leaf nodes, this is the name of the instruction form that the node
// represents. For other nodes, this is always set to "node".
std::string instruction_name_;
std::string_view instruction_name_;
// Source mapping from bit pattern to name of next decode stage.
Vector<DecodePattern> pattern_table_;
const std::vector<DecodePattern>& pattern_table_;
static const std::vector<DecodePattern> kEmptyPatternTable;
// Pointer to the decoder containing this node, used to call its visitor
File diff suppressed because it is too large Load Diff
+8 -32
View File
@@ -1464,8 +1464,6 @@
{"crc32h_32c_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"crc32w_32c_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"crc32x_64c_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"gmi_64g_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"irg_64i_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"lslv_32_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"lslv_64_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
{"lsrv_32_dp_2src"_h, &VISITORCLASS::VisitDataProcessing2Source}, \
@@ -2595,7 +2593,6 @@
{"dsb_bo_barriers"_h, &VISITORCLASS::VisitSystem}, \
{"hint_hm_hints"_h, &VISITORCLASS::VisitSystem}, \
{"mrs_rs_systemmove"_h, &VISITORCLASS::VisitSystem}, \
{"msr_si_pstate"_h, &VISITORCLASS::VisitSystem}, \
{"msr_sr_systemmove"_h, &VISITORCLASS::VisitSystem}, \
{"psb_hc_hints"_h, &VISITORCLASS::VisitSystem}, \
{"sb_only_barriers"_h, &VISITORCLASS::VisitSystem}, \
@@ -2641,19 +2638,17 @@
&VISITORCLASS::VisitUnconditionalBranchToRegister}, \
{"ret_64r_branch_reg"_h, \
&VISITORCLASS::VisitUnconditionalBranchToRegister}, \
{"addg_64_addsub_immtags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bcax_vvv16_crypto4"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfcvtn_asimdmisc_4s"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfdot_asimdelem_e"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfdot_asimdsame2_d"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlal_asimdelem_f"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlal_asimdsame2_f_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlal_asimdsame2_f"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmmla_asimdsame2_e"_h, &VISITORCLASS::VisitUnimplemented}, \
{"dsb_bon_barriers"_h, &VISITORCLASS::VisitUnimplemented}, \
{"eor3_vvv16_crypto4"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ld64b_64l_memop"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ldgm_64bulk_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ldg_64loffset_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ldtrb_32_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ldtrh_32_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ldtrsb_32_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
@@ -2677,33 +2672,15 @@
{"sm3tt2b_vvv_crypto3_imm2"_h, &VISITORCLASS::VisitUnimplemented}, \
{"sm4ekey_vvv4_cryptosha512_3"_h, &VISITORCLASS::VisitUnimplemented}, \
{"sm4e_vv4_cryptosha512_2"_h, &VISITORCLASS::VisitUnimplemented}, \
{"st2g_64soffset_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"st2g_64spost_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"st2g_64spre_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"st64b_64l_memop"_h, &VISITORCLASS::VisitUnimplemented}, \
{"st64bv_64_memop"_h, &VISITORCLASS::VisitUnimplemented}, \
{"st64bv0_64_memop"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stgm_64bulk_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stgp_64_ldstpair_off"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stgp_64_ldstpair_post"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stgp_64_ldstpair_pre"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stg_64soffset_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stg_64spost_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stg_64spre_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"sttrb_32_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
{"sttrh_32_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
{"sttr_32_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
{"sttr_64_ldst_unpriv"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stz2g_64soffset_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stz2g_64spost_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stz2g_64spre_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stzgm_64bulk_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stzg_64soffset_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stzg_64spost_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"stzg_64spre_ldsttags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"subg_64_addsub_immtags"_h, &VISITORCLASS::VisitUnimplemented}, \
{"subps_64s_dp_2src"_h, &VISITORCLASS::VisitUnimplemented}, \
{"subp_64s_dp_2src"_h, &VISITORCLASS::VisitUnimplemented}, \
{"tcancel_ex_exception"_h, &VISITORCLASS::VisitUnimplemented}, \
{"tstart_br_systemresult"_h, &VISITORCLASS::VisitUnimplemented}, \
{"ttest_br_systemresult"_h, &VISITORCLASS::VisitUnimplemented}, \
@@ -2712,13 +2689,13 @@
{"xar_vvv2_crypto3_imm6"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfcvt_z_p_z_s2bf"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfcvtnt_z_p_z_s2bf"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfdot_z_zzz_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfdot_z_zzzi_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalb_z_zzz_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalb_z_zzzi_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalt_z_zzz_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalt_z_zzzi_"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmmla_z_zzz_"_h, &VISITORCLASS::VisitUnimplemented}, { \
{"bfdot_z_zzz"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfdot_z_zzzi"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalb_z_zzz"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalb_z_zzzi"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalt_z_zzz"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmlalt_z_zzzi"_h, &VISITORCLASS::VisitUnimplemented}, \
{"bfmmla_z_zzz"_h, &VISITORCLASS::VisitUnimplemented}, { \
"unallocated"_h, &VISITORCLASS::VisitUnallocated \
}
@@ -2742,7 +2719,6 @@
{"pacib1716_hi_hints"_h, &VISITORCLASS::VisitSystem}, \
{"pacibsp_hi_hints"_h, &VISITORCLASS::VisitSystem}, \
{"pacibz_hi_hints"_h, &VISITORCLASS::VisitSystem}, \
{"pssbb_only_barriers"_h, &VISITORCLASS::VisitSystem}, \
{"sev_hi_hints"_h, &VISITORCLASS::VisitSystem}, \
{"sevl_hi_hints"_h, &VISITORCLASS::VisitSystem}, \
{"ssbb_only_barriers"_h, &VISITORCLASS::VisitSystem}, \
File diff suppressed because it is too large Load Diff
+15 -2
View File
@@ -49,7 +49,7 @@ class Disassembler : public DecoderVisitor {
Disassembler();
#else
Disassembler() = delete;
Disassembler(PandaAllocator* allocator);
Disassembler(AllocatorWrapper allocator);
#endif
Disassembler(char* text_buffer, int buffer_size);
virtual ~Disassembler();
@@ -194,6 +194,10 @@ class Disassembler : public DecoderVisitor {
void Disassemble_ZdaS_ZnB_ZmB(const Instruction* instr);
void Disassemble_Vd4S_Vn16B_Vm16B(const Instruction* instr);
void DisassembleCpy(const Instruction* instr);
void DisassembleSet(const Instruction* instr);
void DisassembleMinMaxImm(const Instruction* instr);
void DisassembleSVEShiftLeftImm(const Instruction* instr);
void DisassembleSVEShiftRightImm(const Instruction* instr);
void DisassembleSVEAddSubCarry(const Instruction* instr);
@@ -235,6 +239,15 @@ class Disassembler : public DecoderVisitor {
void DisassembleNEONScalar2RegMiscOnlyD(const Instruction* instr);
void DisassembleNEONFPScalar2RegMisc(const Instruction* instr);
void DisassembleMTELoadTag(const Instruction* instr);
void DisassembleMTEStoreTag(const Instruction* instr);
void DisassembleMTEStoreTagPair(const Instruction* instr);
void Disassemble_XdSP_XnSP_Xm(const Instruction* instr);
void Disassemble_XdSP_XnSP_uimm6_uimm4(const Instruction* instr);
void Disassemble_Xd_XnSP_Xm(const Instruction* instr);
void Disassemble_Xd_XnSP_XmSP(const Instruction* instr);
void Format(const Instruction* instr,
const char* mnemonic,
const char* format0,
@@ -315,7 +328,7 @@ class PrintDisassembler : public Disassembler {
: cpu_features_auditor_(NULL),
#else
explicit PrintDisassembler(FILE* stream) = delete;
explicit PrintDisassembler(PandaAllocator* allocator, FILE* stream)
explicit PrintDisassembler(AllocatorWrapper allocator, FILE* stream)
: Disassembler(allocator), cpu_features_auditor_(NULL), allocator_(allocator),
#endif
cpu_features_prefix_("// Needs: "),
+2 -1
View File
@@ -25,6 +25,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "instructions-aarch64.h"
#include "assembler-aarch64.h"
namespace vixl {
@@ -198,6 +199,7 @@ bool Instruction::CanTakeSVEMovprfx(uint32_t form_hash,
case "decd_z_zs"_h:
case "dech_z_zs"_h:
case "decw_z_zs"_h:
case "ext_z_zi_des"_h:
case "faddp_z_p_zz"_h:
case "fmaxnmp_z_p_zz"_h:
case "fmaxp_z_p_zz"_h:
@@ -210,7 +212,6 @@ bool Instruction::CanTakeSVEMovprfx(uint32_t form_hash,
case "insr_z_v"_h:
case "smaxp_z_p_zz"_h:
case "sminp_z_p_zz"_h:
case "splice_z_p_zz_con"_h:
case "splice_z_p_zz_des"_h:
case "sqcadd_z_zz"_h:
case "sqdecd_z_zs"_h:
+72 -9
View File
@@ -119,7 +119,7 @@ const uint64_t kTTBRMask = UINT64_C(1) << 55;
// We can't define a static kZRegSize because the size depends on the
// implementation. However, it is sometimes useful to know the minimum and
// maxmimum possible sizes.
// maximum possible sizes.
const unsigned kZRegMinSize = 128;
const unsigned kZRegMinSizeLog2 = 7;
const unsigned kZRegMinSizeInBytes = kZRegMinSize / 8;
@@ -141,21 +141,25 @@ const unsigned kPRegMaxSizeLog2 = kZRegMaxSizeLog2 - 3;
const unsigned kPRegMaxSizeInBytes = kPRegMaxSize / 8;
const unsigned kPRegMaxSizeInBytesLog2 = kPRegMaxSizeLog2 - 3;
const unsigned kMTETagGranuleInBytes = 16;
const unsigned kMTETagGranuleInBytesLog2 = 4;
const unsigned kMTETagWidth = 4;
// Make these moved float constants backwards compatible
// with explicit vixl::aarch64:: namespace references.
using vixl::kDoubleMantissaBits;
using vixl::kDoubleExponentBits;
using vixl::kFloatMantissaBits;
using vixl::kFloatExponentBits;
using vixl::kFloat16MantissaBits;
using vixl::kDoubleMantissaBits;
using vixl::kFloat16ExponentBits;
using vixl::kFloat16MantissaBits;
using vixl::kFloatExponentBits;
using vixl::kFloatMantissaBits;
using vixl::kFP16PositiveInfinity;
using vixl::kFP16NegativeInfinity;
using vixl::kFP32PositiveInfinity;
using vixl::kFP16PositiveInfinity;
using vixl::kFP32NegativeInfinity;
using vixl::kFP64PositiveInfinity;
using vixl::kFP32PositiveInfinity;
using vixl::kFP64NegativeInfinity;
using vixl::kFP64PositiveInfinity;
using vixl::kFP16DefaultNaN;
using vixl::kFP32DefaultNaN;
@@ -512,6 +516,65 @@ class Instruction {
return false;
}
bool IsMOPSPrologueOf(const Instruction* instr, uint32_t mops_type) const {
VIXL_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) ||
(mops_type == "cpy"_h));
const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14;
return GetInstructionBits() == instr->Mask(~(0x3U << op_lsb));
}
bool IsMOPSMainOf(const Instruction* instr, uint32_t mops_type) const {
VIXL_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) ||
(mops_type == "cpy"_h));
const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14;
return GetInstructionBits() ==
(instr->Mask(~(0x3U << op_lsb)) | (0x1 << op_lsb));
}
bool IsMOPSEpilogueOf(const Instruction* instr, uint32_t mops_type) const {
VIXL_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) ||
(mops_type == "cpy"_h));
const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14;
return GetInstructionBits() ==
(instr->Mask(~(0x3U << op_lsb)) | (0x2 << op_lsb));
}
template <uint32_t mops_type>
bool IsConsistentMOPSTriplet() const {
VIXL_STATIC_ASSERT((mops_type == "set"_h) || (mops_type == "setg"_h) ||
(mops_type == "cpy"_h));
int64_t isize = static_cast<int64_t>(kInstructionSize);
const Instruction* prev2 = GetInstructionAtOffset(-2 * isize);
const Instruction* prev1 = GetInstructionAtOffset(-1 * isize);
const Instruction* next1 = GetInstructionAtOffset(1 * isize);
const Instruction* next2 = GetInstructionAtOffset(2 * isize);
// Use the encoding of the current instruction to determine the expected
// adjacent instructions. NB. this doesn't check if the nearby instructions
// are MOPS-type, but checks that they form a consistent triplet if they
// are. For example, 'mov x0, #0; mov x0, #512; mov x0, #1024' is a
// consistent triplet, but they are not MOPS instructions.
const int op_lsb = (mops_type == "cpy"_h) ? 22 : 14;
const uint32_t kMOPSOpfield = 0x3 << op_lsb;
const uint32_t kMOPSPrologue = 0;
const uint32_t kMOPSMain = 0x1 << op_lsb;
const uint32_t kMOPSEpilogue = 0x2 << op_lsb;
switch (Mask(kMOPSOpfield)) {
case kMOPSPrologue:
return next1->IsMOPSMainOf(this, mops_type) &&
next2->IsMOPSEpilogueOf(this, mops_type);
case kMOPSMain:
return prev1->IsMOPSPrologueOf(this, mops_type) &&
next1->IsMOPSEpilogueOf(this, mops_type);
case kMOPSEpilogue:
return prev2->IsMOPSPrologueOf(this, mops_type) &&
prev1->IsMOPSMainOf(this, mops_type);
default:
VIXL_ABORT_WITH_MSG("Undefined MOPS operation\n");
}
}
static int GetImmBranchRangeBitwidth(ImmBranchType branch_type);
VIXL_DEPRECATED(
"GetImmBranchRangeBitwidth",
@@ -764,7 +827,7 @@ class NEONFormatDecoder {
enum SubstitutionMode { kPlaceholder, kFormat };
// Construct a format decoder with increasingly specific format maps for each
// subsitution. If no format map is specified, the default is the integer
// substitution. If no format map is specified, the default is the integer
// format map.
explicit NEONFormatDecoder(const Instruction* instr) {
instrbits_ = instr->GetInstructionBits();
+22 -4
View File
@@ -167,6 +167,21 @@ SimFloat16 Simulator::UFixedToFloat16(uint64_t src,
}
uint64_t Simulator::GenerateRandomTag(uint16_t exclude) {
uint64_t rtag = nrand48(rand_state_) >> 28;
VIXL_ASSERT(IsUint4(rtag));
if (exclude == 0) {
exclude = nrand48(rand_state_) >> 27;
}
// TODO: implement this to better match the specification, which calls for a
// true random mode, and a pseudo-random mode with state (EL1.TAG) modified by
// PRNG.
return ChooseNonExcludedTag(rtag, 0, exclude);
}
void Simulator::ld1(VectorFormat vform, LogicVRegister dst, uint64_t addr) {
dst.ClearForWrite(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
@@ -2202,7 +2217,6 @@ LogicVRegister Simulator::extractnarrow(VectorFormat dstform,
offset = LaneCountFromFormat(dstform) / 2;
} else {
offset = 0;
dst.ClearForWrite(dstform);
}
for (int i = 0; i < LaneCountFromFormat(srcform); i++) {
@@ -2242,6 +2256,10 @@ LogicVRegister Simulator::extractnarrow(VectorFormat dstform,
dst.SetUint(dstform, offset + i, result);
}
}
if (!upperhalf) {
dst.ClearForWrite(dstform);
}
return dst;
}
@@ -2284,7 +2302,7 @@ LogicVRegister Simulator::absdiff(VectorFormat vform,
bool src1_gt_src2 = is_signed ? (src1.Int(vform, i) > src2.Int(vform, i))
: (src1.Uint(vform, i) > src2.Uint(vform, i));
// Always calculate the answer using unsigned arithmetic, to avoid
// implemenation-defined signed overflow.
// implementation-defined signed overflow.
if (src1_gt_src2) {
dst.SetUint(vform, i, src1.Uint(vform, i) - src2.Uint(vform, i));
} else {
@@ -7504,7 +7522,7 @@ void Simulator::SVEGatherLoadScalarPlusVectorHelper(const Instruction* instr,
// Note that these instructions don't use the Dtype encoding.
int msize_in_bytes_log2 = instr->ExtractBits(24, 23);
int scale = instr->ExtractBit(21) * msize_in_bytes_log2;
uint64_t base = ReadXRegister(instr->GetRn());
uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
LogicSVEAddressVector addr(base,
&ReadVRegister(instr->GetRm()),
vform,
@@ -7813,7 +7831,7 @@ LogicVRegister Simulator::fmatmul(VectorFormat vform,
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
// Elements outside a multiple of 4T are set to zero. This happens only
// for double precision operations, when the VL is a multiple of 128 bits,
// but not a mutiple of 256 bits.
// but not a multiple of 256 bits.
T value = (i < (T_per_segment * segment_count)) ? result[i] : 0;
srcdst.SetFloat<T>(vform, i, value);
}
+109 -43
View File
@@ -24,10 +24,10 @@
// 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.
#include <cctype>
#include "macro-assembler-aarch64.h"
#include <cctype>
namespace vixl {
namespace aarch64 {
@@ -218,9 +218,8 @@ void VeneerPool::Release() {
--monitor_;
#ifndef PANDA_BUILD
if (monitor_ == 0) {
VIXL_ASSERT(IsEmpty() ||
masm_->GetCursorOffset() <
unresolved_branches_.GetFirstLimit());
VIXL_ASSERT(IsEmpty() || masm_->GetCursorOffset() <
unresolved_branches_.GetFirstLimit());
}
#else
// Assert disabled, because we use own allocator
@@ -1152,7 +1151,7 @@ void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {
Register temp = temps.AcquireX();
Mov(temp, imm);
if (vd.Is1D()) {
mov(vd.D(), 0, temp);
fmov(vd.D(), temp);
} else {
dup(vd.V2D(), temp);
}
@@ -1188,8 +1187,14 @@ void MacroAssembler::Movi(const VRegister& vd,
void MacroAssembler::Movi(const VRegister& vd, uint64_t hi, uint64_t lo) {
// TODO: Move 128-bit values in a more efficient way.
VIXL_ASSERT(vd.Is128Bits());
Movi(vd.V2D(), lo);
if (hi != lo) {
if (hi == lo) {
Movi(vd.V2D(), lo);
return;
}
Movi(vd.V1D(), lo);
if (hi != 0) {
UseScratchRegisterScope temps(this);
// TODO: Figure out if using a temporary V register to materialise the
// immediate is better.
@@ -1502,6 +1507,70 @@ void MacroAssembler::Adds(const Register& rd,
Add(rd, rn, operand, SetFlags);
}
#define MINMAX(V) \
V(Smax, smax, IsInt8) \
V(Smin, smin, IsInt8) \
V(Umax, umax, IsUint8) \
V(Umin, umin, IsUint8)
#define VIXL_DEFINE_MASM_FUNC(MASM, ASM, RANGE) \
void MacroAssembler::MASM(const Register& rd, \
const Register& rn, \
const Operand& op) { \
VIXL_ASSERT(allow_macro_instructions_); \
if (op.IsImmediate()) { \
int64_t imm = op.GetImmediate(); \
if (!RANGE(imm)) { \
UseScratchRegisterScope temps(this); \
Register temp = temps.AcquireSameSizeAs(rd); \
Mov(temp, imm); \
MASM(rd, rn, temp); \
return; \
} \
} \
SingleEmissionCheckScope guard(this); \
ASM(rd, rn, op); \
}
MINMAX(VIXL_DEFINE_MASM_FUNC)
#undef VIXL_DEFINE_MASM_FUNC
void MacroAssembler::St2g(const Register& rt, const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
st2g(rt, addr);
}
void MacroAssembler::Stg(const Register& rt, const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
stg(rt, addr);
}
void MacroAssembler::Stgp(const Register& rt1,
const Register& rt2,
const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
stgp(rt1, rt2, addr);
}
void MacroAssembler::Stz2g(const Register& rt, const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
stz2g(rt, addr);
}
void MacroAssembler::Stzg(const Register& rt, const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
stzg(rt, addr);
}
void MacroAssembler::Ldg(const Register& rt, const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
ldg(rt, addr);
}
void MacroAssembler::Sub(const Register& rd,
const Register& rn,
@@ -1565,6 +1634,12 @@ void MacroAssembler::Fmov(VRegister vd, double imm) {
VIXL_ASSERT(allow_macro_instructions_);
// Floating point immediates are loaded through the literal pool.
MacroEmissionCheckScope guard(this);
uint64_t rawbits = DoubleToRawbits(imm);
if (rawbits == 0) {
fmov(vd.D(), xzr);
return;
}
if (vd.Is1H() || vd.Is4H() || vd.Is8H()) {
Fmov(vd, Float16(imm));
@@ -1577,27 +1652,20 @@ void MacroAssembler::Fmov(VRegister vd, double imm) {
}
VIXL_ASSERT(vd.Is1D() || vd.Is2D());
if (IsImmFP64(imm)) {
if (IsImmFP64(rawbits)) {
fmov(vd, imm);
} else {
uint64_t rawbits = DoubleToRawbits(imm);
if (vd.IsScalar()) {
if (rawbits == 0) {
fmov(vd, xzr);
} else {
ldr(vd,
} else if (vd.IsScalar()) {
ldr(vd,
#ifndef PANDA_BUILD
new Literal<double>(imm,
new Literal<double>(imm,
#else
allocator_.New<Literal<double>> (imm,
allocator_.New<Literal<double>>(imm,
#endif
&literal_pool_,
RawLiteral::kDeletedOnPlacementByPool));
}
} else {
// TODO: consider NEON support for load literal.
Movi(vd, rawbits);
}
&literal_pool_,
RawLiteral::kDeletedOnPlacementByPool));
} else {
// TODO: consider NEON support for load literal.
Movi(vd, rawbits);
}
}
@@ -1606,6 +1674,12 @@ void MacroAssembler::Fmov(VRegister vd, float imm) {
VIXL_ASSERT(allow_macro_instructions_);
// Floating point immediates are loaded through the literal pool.
MacroEmissionCheckScope guard(this);
uint32_t rawbits = FloatToRawbits(imm);
if (rawbits == 0) {
fmov(vd.S(), wzr);
return;
}
if (vd.Is1H() || vd.Is4H() || vd.Is8H()) {
Fmov(vd, Float16(imm));
@@ -1618,27 +1692,20 @@ void MacroAssembler::Fmov(VRegister vd, float imm) {
}
VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());
if (IsImmFP32(imm)) {
if (IsImmFP32(rawbits)) {
fmov(vd, imm);
} else {
uint32_t rawbits = FloatToRawbits(imm);
if (vd.IsScalar()) {
if (rawbits == 0) {
fmov(vd, wzr);
} else {
ldr(vd,
} else if (vd.IsScalar()) {
ldr(vd,
#ifndef PANDA_BUILD
new Literal<float>(imm,
new Literal<float>(imm,
#else
allocator_.New<Literal<float>>(imm,
allocator_.New<Literal<float>>(imm,
#endif
&literal_pool_,
RawLiteral::kDeletedOnPlacementByPool));
}
} else {
// TODO: consider NEON support for load literal.
Movi(vd, rawbits);
}
&literal_pool_,
RawLiteral::kDeletedOnPlacementByPool));
} else {
// TODO: consider NEON support for load literal.
Movi(vd, rawbits);
}
}
@@ -3203,7 +3270,6 @@ CPURegList* UseScratchRegisterScope::GetAvailableListFor(
return masm_->GetScratchVRegisterList();
case CPURegister::kPRegisterBank:
return masm_->GetScratchPRegisterList();
return NULL;
}
VIXL_UNREACHABLE();
return NULL;
+318 -4
View File
@@ -1828,7 +1828,7 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
V(casah, Casah) \
V(caslh, Caslh) \
V(casalh, Casalh)
// clang-format on
// clang-format on
#define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \
void MASM(const Register& rs, const Register& rt, const MemOperand& src) { \
@@ -1846,7 +1846,7 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
V(caspa, Caspa) \
V(caspl, Caspl) \
V(caspal, Caspal)
// clang-format on
// clang-format on
#define DEFINE_MACRO_ASM_FUNC(ASM, MASM) \
void MASM(const Register& rs, \
@@ -1891,7 +1891,7 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
V(MASM##alb, ASM##alb) \
V(MASM##ah, ASM##ah) \
V(MASM##alh, ASM##alh)
// clang-format on
// clang-format on
#define DEFINE_MACRO_LOAD_ASM_FUNC(MASM, ASM) \
void MASM(const Register& rs, const Register& rt, const MemOperand& src) { \
@@ -2807,6 +2807,44 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
uxtw(rd, rn);
}
void Addg(const Register& xd,
const Register& xn,
int offset,
int tag_offset) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
addg(xd, xn, offset, tag_offset);
}
void Gmi(const Register& xd, const Register& xn, const Register& xm) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
gmi(xd, xn, xm);
}
void Irg(const Register& xd, const Register& xn, const Register& xm = xzr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
irg(xd, xn, xm);
}
void Subg(const Register& xd,
const Register& xn,
int offset,
int tag_offset) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
subg(xd, xn, offset, tag_offset);
}
void Subp(const Register& xd, const Register& xn, const Register& xm) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
subp(xd, xn, xm);
}
void Subps(const Register& xd, const Register& xn, const Register& xm) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
subps(xd, xn, xm);
}
void Cmpp(const Register& xn, const Register& xm) { Subps(xzr, xn, xm); }
// NEON 3 vector register instructions.
#define NEON_3VREG_MACRO_LIST(V) \
V(add, Add) \
@@ -3182,7 +3220,6 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
#define SVE_3VREG_COMMUTATIVE_MACRO_LIST(V) \
V(add, Add) \
V(and_, And) \
V(bic, Bic) \
V(eor, Eor) \
V(mul, Mul) \
V(orr, Orr) \
@@ -3698,6 +3735,10 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
MovprfxHelperScope guard(this, zd, pg, zn);
asrd(zd, pg, zd, shift);
}
void Bic(const ZRegister& zd,
const PRegisterM& pg,
const ZRegister& zn,
const ZRegister& zm);
void Bic(const PRegisterWithLaneSize& pd,
const PRegisterZ& pg,
const PRegisterWithLaneSize& pn,
@@ -7613,6 +7654,279 @@ MacroAssembler(PandaAllocator* allocator, byte* buffer,
const ZRegister& zm,
int index);
// MTE
void St2g(const Register& rt, const MemOperand& addr);
void Stg(const Register& rt, const MemOperand& addr);
void Stgp(const Register& rt1, const Register& rt2, const MemOperand& addr);
void Stz2g(const Register& rt, const MemOperand& addr);
void Stzg(const Register& rt, const MemOperand& addr);
void Ldg(const Register& rt, const MemOperand& addr);
void Cpye(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpye(rd, rs, rn);
}
void Cpyen(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyen(rd, rs, rn);
}
void Cpyern(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyern(rd, rs, rn);
}
void Cpyewn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyewn(rd, rs, rn);
}
void Cpyfe(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfe(rd, rs, rn);
}
void Cpyfen(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfen(rd, rs, rn);
}
void Cpyfern(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfern(rd, rs, rn);
}
void Cpyfewn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfewn(rd, rs, rn);
}
void Cpyfm(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfm(rd, rs, rn);
}
void Cpyfmn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfmn(rd, rs, rn);
}
void Cpyfmrn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfmrn(rd, rs, rn);
}
void Cpyfmwn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfmwn(rd, rs, rn);
}
void Cpyfp(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfp(rd, rs, rn);
}
void Cpyfpn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfpn(rd, rs, rn);
}
void Cpyfprn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfprn(rd, rs, rn);
}
void Cpyfpwn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyfpwn(rd, rs, rn);
}
void Cpym(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpym(rd, rs, rn);
}
void Cpymn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpymn(rd, rs, rn);
}
void Cpymrn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpymrn(rd, rs, rn);
}
void Cpymwn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpymwn(rd, rs, rn);
}
void Cpyp(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyp(rd, rs, rn);
}
void Cpypn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpypn(rd, rs, rn);
}
void Cpyprn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpyprn(rd, rs, rn);
}
void Cpypwn(const Register& rd, const Register& rs, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cpypwn(rd, rs, rn);
}
void Sete(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
sete(rd, rn, rs);
}
void Seten(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
seten(rd, rn, rs);
}
void Setge(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setge(rd, rn, rs);
}
void Setgen(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setgen(rd, rn, rs);
}
void Setgm(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setgm(rd, rn, rs);
}
void Setgmn(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setgmn(rd, rn, rs);
}
void Setgp(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setgp(rd, rn, rs);
}
void Setgpn(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setgpn(rd, rn, rs);
}
void Setm(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setm(rd, rn, rs);
}
void Setmn(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setmn(rd, rn, rs);
}
void Setp(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setp(rd, rn, rs);
}
void Setpn(const Register& rd, const Register& rn, const Register& rs) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
setpn(rd, rn, rs);
}
// Macro assembler wrappers that package the MOPS instructions into a single
// call.
#define MOPS_LIST(V) \
V(Set, set, ) \
V(Setn, set, n) \
V(Setg, setg, ) \
V(Setgn, setg, n) \
V(Cpy, cpy, ) \
V(Cpyn, cpy, n) \
V(Cpyrn, cpy, rn) \
V(Cpywn, cpy, wn) \
V(Cpyf, cpyf, ) \
V(Cpyfn, cpyf, n) \
V(Cpyfrn, cpyf, rn) \
V(Cpyfwn, cpyf, wn)
#define DEFINE_MACRO_ASM_FUNC(MASM, ASMPREFIX, ASMSUFFIX) \
void MASM(const Register& ra, const Register& rb, const Register& rc) { \
ExactAssemblyScope scope(this, 3 * kInstructionSize); \
ASMPREFIX##p##ASMSUFFIX(ra, rb, rc); \
ASMPREFIX##m##ASMSUFFIX(ra, rb, rc); \
ASMPREFIX##e##ASMSUFFIX(ra, rb, rc); \
}
MOPS_LIST(DEFINE_MACRO_ASM_FUNC)
#undef DEFINE_MACRO_ASM_FUNC
void Abs(const Register& rd, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
abs(rd, rn);
}
void Cnt(const Register& rd, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
cnt(rd, rn);
}
void Ctz(const Register& rd, const Register& rn) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
ctz(rd, rn);
}
void Smax(const Register& rd, const Register& rn, const Operand& op);
void Smin(const Register& rd, const Register& rn, const Operand& op);
void Umax(const Register& rd, const Register& rn, const Operand& op);
void Umin(const Register& rd, const Register& rn, const Operand& op);
template <typename T>
Literal<T>* CreateLiteralDestroyedWithPool(T value) {
#ifndef PANDA_BUILD
+4 -2
View File
@@ -627,6 +627,7 @@ VIXL_SVE_NONCOMM_ARITH_ZZZZII_LIST(VIXL_DEFINE_MASM_FUNC)
// non-commutative and no reversed form is provided.
#define VIXL_SVE_NONCOMM_ARITH_ZPZZ_LIST(V) \
V(Addp, addp) \
V(Bic, bic) \
V(Faddp, faddp) \
V(Fmaxnmp, fmaxnmp) \
V(Fminnmp, fminnmp) \
@@ -831,11 +832,12 @@ void MacroAssembler::Fdup(const ZRegister& zd, double imm) {
Fdup(zd, static_cast<float>(imm));
break;
case kDRegSize:
if (IsImmFP64(imm)) {
uint64_t bits = DoubleToRawbits(imm);
if (IsImmFP64(bits)) {
SingleEmissionCheckScope guard(this);
fdup(zd, imm);
} else {
Dup(zd, DoubleToRawbits(imm));
Dup(zd, bits);
}
break;
}
+4 -4
View File
@@ -34,7 +34,7 @@ CPURegister CPURegList::PopLowestIndex(RegList mask) {
RegList list = list_ & mask;
if (list == 0) return NoCPUReg;
int index = CountTrailingZeros(list);
VIXL_ASSERT(((1 << index) & list) != 0);
VIXL_ASSERT(((static_cast<RegList>(1) << index) & list) != 0);
Remove(index);
return CPURegister(index, size_, type_);
}
@@ -45,7 +45,7 @@ CPURegister CPURegList::PopHighestIndex(RegList mask) {
if (list == 0) return NoCPUReg;
int index = CountLeadingZeros(list);
index = kRegListSizeInBits - 1 - index;
VIXL_ASSERT(((1 << index) & list) != 0);
VIXL_ASSERT(((static_cast<RegList>(1) << index) & list) != 0);
Remove(index);
return CPURegister(index, size_, type_);
}
@@ -457,5 +457,5 @@ bool GenericOperand::Equals(const GenericOperand& other) const {
}
return false;
}
}
} // namespace vixl::aarch64
} // namespace aarch64
} // namespace vixl
+5 -5
View File
@@ -739,7 +739,7 @@ class SVEMemOperand {
class IntegerOperand {
public:
#define VIXL_INT_TYPES(V) \
V(char) V(short) V(int) V(long) V(long long) // NOLINT(runtime/int)
V(char) V(short) V(int) V(long) V(long long) // NOLINT(google-runtime-int)
#define VIXL_DECL_INT_OVERLOADS(T) \
/* These are allowed to be implicit constructors because this is a */ \
/* wrapper class that doesn't normally perform any type conversion. */ \
@@ -877,7 +877,7 @@ class IntegerOperand {
return TryEncodeAsShiftedIntNForLane<N, 0>(zd, imm);
}
// As above, but for unsigned fields. This is usuaully a simple operation, but
// As above, but for unsigned fields. This is usually a simple operation, but
// is provided for symmetry.
template <unsigned N, unsigned kShift, typename T>
bool TryEncodeAsShiftedUintNForLane(const CPURegister& zd, T* imm) const {
@@ -913,7 +913,7 @@ class IntegerOperand {
bool IsPositiveOrZero() const { return !is_negative_; }
uint64_t GetMagnitude() const {
return is_negative_ ? -raw_bits_ : raw_bits_;
return is_negative_ ? UnsignedNegate(raw_bits_) : raw_bits_;
}
private:
@@ -997,7 +997,7 @@ class GenericOperand {
// We only support sizes up to X/D register sizes.
size_t mem_op_size_;
};
}
} // namespace vixl::aarch64
} // namespace aarch64
} // namespace vixl
#endif // VIXL_AARCH64_OPERANDS_AARCH64_H_
+2 -2
View File
@@ -26,10 +26,10 @@
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
#include "simulator-aarch64.h"
#include "utils-vixl.h"
#include "simulator-aarch64.h"
namespace vixl {
namespace aarch64 {
+8 -6
View File
@@ -67,7 +67,8 @@ class PRegisterZ;
// specialised register types can avoid run-time checks, and should therefore be
// preferred where run-time polymorphism isn't required.
//
// Type-specific modifers are typically implemented only on the derived classes.
// Type-specific modifiers are typically implemented only on the derived
// classes.
//
// The encoding is such that CPURegister objects are cheap to pass by value.
class CPURegister {
@@ -859,7 +860,7 @@ AARCH64_REGISTER_CODE_LIST(VIXL_DEFINE_REGISTERS)
AARCH64_P_REGISTER_CODE_LIST(VIXL_DEFINE_P_REGISTERS)
#undef VIXL_DEFINE_P_REGISTERS
// Most coersions simply invoke the necessary constructor.
// Most coercions simply invoke the necessary constructor.
#define VIXL_CPUREG_COERCION_LIST(U) \
U(Register, W, R) \
U(Register, X, R) \
@@ -880,7 +881,7 @@ VIXL_CPUREG_COERCION_LIST(VIXL_DEFINE_CPUREG_COERCION)
#undef VIXL_CPUREG_COERCION_LIST
#undef VIXL_DEFINE_CPUREG_COERCION
// NEON lane-format coersions always return VRegisters.
// NEON lane-format coercions always return VRegisters.
#define VIXL_CPUREG_NEON_COERCION_LIST(V) \
V(8, B) \
V(16, B) \
@@ -900,6 +901,8 @@ VIXL_CPUREG_NEON_COERCION_LIST(VIXL_DEFINE_CPUREG_NEON_COERCION)
#undef VIXL_CPUREG_NEON_COERCION_LIST
#undef VIXL_DEFINE_CPUREG_NEON_COERCION
// Semantic type coercion for sdot and udot.
// TODO: Use the qualifiers_ field to distinguish this from ::S().
VRegister VRegister::S4B() const {
VIXL_ASSERT(IsVRegister());
return SRegister(GetCode());
@@ -1138,8 +1141,7 @@ bool AreSameLaneSize(const CPURegister& reg1,
!reg4.IsValid() || (reg4.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
return match;
}
}
} // namespace vixl::aarch64
} // namespace aarch64
} // namespace vixl
#endif // VIXL_AARCH64_REGISTERS_AARCH64_H_
File diff suppressed because it is too large Load Diff
+439 -24
View File
@@ -33,10 +33,11 @@
#include "../globals-vixl.h"
#include "../utils-vixl.h"
#include "cpu-features.h"
#include "abi-aarch64.h"
#include "cpu-features-auditor-aarch64.h"
#include "debugger-aarch64.h"
#include "disasm-aarch64.h"
#include "instructions-aarch64.h"
#include "simulator-constants-aarch64.h"
@@ -53,9 +54,20 @@
#endif
#endif
// The hosts that Simulator running on may not have these flags defined.
#ifndef PROT_BTI
#define PROT_BTI 0x10
#endif
#ifndef PROT_MTE
#define PROT_MTE 0x20
#endif
namespace vixl {
namespace aarch64 {
class Simulator;
struct RuntimeCallStructHelper;
class SimStack {
public:
SimStack() {}
@@ -153,46 +165,235 @@ class SimStack {
static const size_t kDefaultUsableSize = 8 * 1024;
};
// Armv8.5 MTE helpers.
inline int GetAllocationTagFromAddress(uint64_t address) {
return static_cast<int>(ExtractUnsignedBitfield64(59, 56, address));
}
template <typename T>
T AddressUntag(T address) {
// Cast the address using a C-style cast. A reinterpret_cast would be
// appropriate, but it can't cast one integral type to another.
uint64_t bits = (uint64_t)address;
return (T)(bits & ~kAddressTagMask);
}
// A callback function, called when a function has been intercepted if a
// BranchInterception entry exists in branch_interceptions. The address of
// the intercepted function is passed to the callback. For usage see
// BranchInterception.
using InterceptionCallback = std::function<void(uint64_t)>;
class MetaDataDepot {
public:
class MetaDataMTE {
public:
explicit MetaDataMTE(int tag) : tag_(tag) {}
int GetTag() const { return tag_; }
void SetTag(int tag) {
VIXL_ASSERT(IsUint4(tag));
tag_ = tag;
}
static bool IsActive() { return is_active; }
static void SetActive(bool value) { is_active = value; }
private:
static bool is_active;
int16_t tag_;
friend class MetaDataDepot;
};
// Generate a key for metadata recording from a untagged address.
template <typename T>
uint64_t GenerateMTEkey(T address) const {
// Cast the address using a C-style cast. A reinterpret_cast would be
// appropriate, but it can't cast one integral type to another.
return (uint64_t)(AddressUntag(address)) >> kMTETagGranuleInBytesLog2;
}
template <typename R, typename T>
R GetAttribute(T map, uint64_t key) {
auto pair = map->find(key);
R value = (pair == map->end()) ? nullptr : &pair->second;
return value;
}
template <typename T>
int GetMTETag(T address, Instruction const* pc = nullptr) {
uint64_t key = GenerateMTEkey(address);
MetaDataMTE* m = GetAttribute<MetaDataMTE*>(&metadata_mte_, key);
if (!m) {
std::stringstream sstream;
sstream << std::hex << "MTE ERROR : instruction at 0x"
<< reinterpret_cast<uint64_t>(pc)
<< " touched a unallocated memory location 0x"
<< (uint64_t)(address) << ".\n";
VIXL_ABORT_WITH_MSG(sstream.str().c_str());
}
return m->GetTag();
}
template <typename T>
void SetMTETag(T address, int tag, Instruction const* pc = nullptr) {
VIXL_ASSERT(IsAligned((uintptr_t)address, kMTETagGranuleInBytes));
uint64_t key = GenerateMTEkey(address);
MetaDataMTE* m = GetAttribute<MetaDataMTE*>(&metadata_mte_, key);
if (!m) {
metadata_mte_.insert({key, MetaDataMTE(tag)});
} else {
// Overwrite
if (m->GetTag() == tag) {
std::stringstream sstream;
sstream << std::hex << "MTE WARNING : instruction at 0x"
<< reinterpret_cast<uint64_t>(pc)
<< ", the same tag is assigned to the address 0x"
<< (uint64_t)(address) << ".\n";
VIXL_WARNING(sstream.str().c_str());
}
m->SetTag(tag);
}
}
template <typename T>
size_t CleanMTETag(T address) {
VIXL_ASSERT(
IsAligned(reinterpret_cast<uintptr_t>(address), kMTETagGranuleInBytes));
uint64_t key = GenerateMTEkey(address);
return metadata_mte_.erase(key);
}
size_t GetTotalCountMTE() { return metadata_mte_.size(); }
// A pure virtual struct that allows the templated BranchInterception struct
// to be stored. For more information see BranchInterception.
struct BranchInterceptionAbstract {
virtual ~BranchInterceptionAbstract() {}
// Call the callback_ if one exists, otherwise do a RuntimeCall.
virtual void operator()(Simulator* simulator) const = 0;
};
// An entry denoting a function to intercept when branched to during
// simulator execution. When a function is intercepted the callback will be
// called if one exists otherwise the function will be passed to
// RuntimeCall.
template <typename R, typename... P>
struct BranchInterception : public BranchInterceptionAbstract {
BranchInterception(R (*function)(P...),
InterceptionCallback callback = nullptr)
: function_(function), callback_(callback) {}
void operator()(Simulator* simulator) const VIXL_OVERRIDE;
private:
// Pointer to the function that will be intercepted.
R (*function_)(P...);
// Function to be called instead of function_
InterceptionCallback callback_;
};
// Register a new BranchInterception object. If 'function' is branched to
// (e.g: "blr function") in the future; instead, if provided, 'callback' will
// be called otherwise a runtime call will be performed on 'function'.
//
// For example: this can be used to always perform runtime calls on
// non-AArch64 functions without using the macroassembler.
//
// Note: only unconditional branches to registers are currently supported to
// be intercepted, e.g: "br"/"blr".
//
// TODO: support intercepting other branch types.
template <typename R, typename... P>
void RegisterBranchInterception(R (*function)(P...),
InterceptionCallback callback = nullptr) {
uintptr_t addr = reinterpret_cast<uintptr_t>(function);
std::unique_ptr<BranchInterceptionAbstract> intercept =
std::make_unique<BranchInterception<R, P...>>(function, callback);
branch_interceptions_.insert(std::make_pair(addr, std::move(intercept)));
}
// Search for branch interceptions to the branch_target address; If one is
// found return it otherwise return nullptr.
BranchInterceptionAbstract* FindBranchInterception(uint64_t branch_target) {
// Check for interceptions to the target address, if one is found, call it.
auto search = branch_interceptions_.find(branch_target);
if (search != branch_interceptions_.end()) {
return search->second.get();
} else {
return nullptr;
}
}
void ResetState() { branch_interceptions_.clear(); }
private:
// Tag recording of each allocated memory in the tag-granule.
std::unordered_map<uint64_t, class MetaDataMTE> metadata_mte_;
// Store a map of addresses to be intercepted and their corresponding branch
// interception object, see 'BranchInterception'.
std::unordered_map<uintptr_t, std::unique_ptr<BranchInterceptionAbstract>>
branch_interceptions_;
};
// Representation of memory, with typed getters and setters for access.
class Memory {
public:
explicit Memory(SimStack::Allocated stack) : stack_(std::move(stack)) {}
explicit Memory(SimStack::Allocated stack) : stack_(std::move(stack)) {
metadata_depot_ = nullptr;
}
const SimStack::Allocated& GetStack() { return stack_; }
template <typename T>
T AddressUntag(T address) const {
// Cast the address using a C-style cast. A reinterpret_cast would be
// appropriate, but it can't cast one integral type to another.
uint64_t bits = (uint64_t)address;
return (T)(bits & ~kAddressTagMask);
template <typename A>
bool IsMTETagsMatched(A address, Instruction const* pc = nullptr) const {
if (MetaDataDepot::MetaDataMTE::IsActive()) {
// Cast the address using a C-style cast. A reinterpret_cast would be
// appropriate, but it can't cast one integral type to another.
uint64_t addr = (uint64_t)address;
int pointer_tag = GetAllocationTagFromAddress(addr);
int memory_tag = metadata_depot_->GetMTETag(AddressUntag(addr), pc);
return pointer_tag == memory_tag;
}
return true;
}
template <typename T, typename A>
T Read(A address) const {
T Read(A address, Instruction const* pc = nullptr) const {
T value;
address = AddressUntag(address);
VIXL_STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8) ||
(sizeof(value) == 16));
auto base = reinterpret_cast<const char*>(address);
auto base = reinterpret_cast<const char*>(AddressUntag(address));
if (stack_.IsAccessInGuardRegion(base, sizeof(value))) {
VIXL_ABORT_WITH_MSG("Attempt to read from stack guard region");
}
if (!IsMTETagsMatched(address, pc)) {
VIXL_ABORT_WITH_MSG("Tag mismatch.");
}
memcpy(&value, base, sizeof(value));
return value;
}
template <typename T, typename A>
void Write(A address, T value) const {
address = AddressUntag(address);
void Write(A address, T value, Instruction const* pc = nullptr) const {
VIXL_STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8) ||
(sizeof(value) == 16));
auto base = reinterpret_cast<char*>(address);
auto base = reinterpret_cast<char*>(AddressUntag(address));
if (stack_.IsAccessInGuardRegion(base, sizeof(value))) {
VIXL_ABORT_WITH_MSG("Attempt to write to stack guard region");
}
if (!IsMTETagsMatched(address, pc)) {
VIXL_ABORT_WITH_MSG("Tag mismatch.");
}
memcpy(base, &value, sizeof(value));
}
@@ -243,8 +444,15 @@ class Memory {
VIXL_UNREACHABLE();
}
void AppendMetaData(MetaDataDepot* metadata_depot) {
VIXL_ASSERT(metadata_depot != nullptr);
VIXL_ASSERT(metadata_depot_ == nullptr);
metadata_depot_ = metadata_depot;
}
private:
SimStack::Allocated stack_;
MetaDataDepot* metadata_depot_;
};
// Represent a register (r0-r31, v0-v31, z0-z31, p0-p15).
@@ -1027,6 +1235,9 @@ class SimExclusiveGlobalMonitor {
};
class Debugger;
class Simulator : public DecoderVisitor {
public:
#ifndef PANDA_BUILD
@@ -1044,6 +1255,12 @@ class Simulator : public DecoderVisitor {
#endif
~Simulator();
#ifdef PANDA_BUILD
AllocatorWrapper GetAllocator() const {
return allocator_;
}
#endif
void ResetState();
// Run the simulator.
@@ -1111,6 +1328,8 @@ class Simulator : public DecoderVisitor {
static const Instruction* kEndOfSimAddress;
// Simulation helpers.
bool IsSimulationFinished() const { return pc_ == kEndOfSimAddress; }
const Instruction* ReadPc() const { return pc_; }
VIXL_DEPRECATED("ReadPc", const Instruction* pc() const) { return ReadPc(); }
@@ -1119,7 +1338,7 @@ class Simulator : public DecoderVisitor {
void WritePc(const Instruction* new_pc,
BranchLogMode log_mode = LogBranches) {
if (log_mode == LogBranches) LogTakenBranch(new_pc);
pc_ = memory_.AddressUntag(new_pc);
pc_ = AddressUntag(new_pc);
pc_modified_ = true;
}
VIXL_DEPRECATED("WritePc", void set_pc(const Instruction* new_pc)) {
@@ -1146,6 +1365,8 @@ class Simulator : public DecoderVisitor {
bool PcIsInGuardedPage() const { return guard_pages_; }
void SetGuardedPages(bool guard_pages) { guard_pages_ = guard_pages; }
const Instruction* GetLastExecutedInstruction() const { return last_instr_; }
void ExecuteInstruction() {
// The program counter should always be aligned.
VIXL_ASSERT(IsWordAligned(pc_));
@@ -1258,6 +1479,26 @@ class Simulator : public DecoderVisitor {
void SimulateNEONFPMulByElementLong(const Instruction* instr);
void SimulateNEONComplexMulByElement(const Instruction* instr);
void SimulateNEONDotProdByElement(const Instruction* instr);
void SimulateMTEAddSubTag(const Instruction* instr);
void SimulateMTETagMaskInsert(const Instruction* instr);
void SimulateMTESubPointer(const Instruction* instr);
void SimulateMTELoadTag(const Instruction* instr);
void SimulateMTEStoreTag(const Instruction* instr);
void SimulateMTEStoreTagPair(const Instruction* instr);
void Simulate_XdSP_XnSP_Xm(const Instruction* instr);
void SimulateCpy(const Instruction* instr);
void SimulateCpyFP(const Instruction* instr);
void SimulateCpyP(const Instruction* instr);
void SimulateCpyM(const Instruction* instr);
void SimulateCpyE(const Instruction* instr);
void SimulateSetP(const Instruction* instr);
void SimulateSetM(const Instruction* instr);
void SimulateSetE(const Instruction* instr);
void SimulateSetGP(const Instruction* instr);
void SimulateSetGM(const Instruction* instr);
void SimulateSignedMinMax(const Instruction* instr);
void SimulateUnsignedMinMax(const Instruction* instr);
// Integer register accessors.
@@ -1789,12 +2030,14 @@ class Simulator : public DecoderVisitor {
template <typename T, typename A>
T MemRead(A address) const {
return memory_.Read<T>(address);
Instruction const* pc = ReadPc();
return memory_.Read<T>(address, pc);
}
template <typename T, typename A>
void MemWrite(A address, T value) const {
return memory_.Write(address, value);
Instruction const* pc = ReadPc();
return memory_.Write(address, value, pc);
}
template <typename A>
@@ -2319,7 +2562,9 @@ class Simulator : public DecoderVisitor {
void LogPWrite(int rt_code, uintptr_t address) {
if (ShouldTraceWrites()) PrintPWrite(rt_code, address);
}
void LogMemTransfer(uintptr_t dst, uintptr_t src, uint8_t value) {
if (ShouldTraceWrites()) PrintMemTransfer(dst, src, value);
}
// Helpers for the above, where the access operation is parameterised.
// - For loads, set op = "<-".
// - For stores, set op = "->".
@@ -2331,6 +2576,7 @@ class Simulator : public DecoderVisitor {
PrintRegisterFormat format,
const char* op,
uintptr_t address);
void PrintMemTransfer(uintptr_t dst, uintptr_t src, uint8_t value);
// Simple, unpredicated SVE accesses always access the whole vector, and never
// know the lane type, so these don't accept a `format`.
void PrintZAccess(int rt_code, const char* op, uintptr_t address);
@@ -2598,6 +2844,48 @@ class Simulator : public DecoderVisitor {
PointerType type);
uint64_t AddPAC(uint64_t ptr, uint64_t context, PACKey key, PointerType type);
uint64_t StripPAC(uint64_t ptr, PointerType type);
void PACHelper(int dst,
int src,
PACKey key,
decltype(&Simulator::AddPAC) pac_fn);
// Armv8.5 MTE helpers.
uint64_t ChooseNonExcludedTag(uint64_t tag,
uint64_t offset,
uint64_t exclude = 0) {
VIXL_ASSERT(IsUint4(tag) && IsUint4(offset) && IsUint16(exclude));
if (exclude == 0xffff) {
return 0;
}
if (offset == 0) {
while ((exclude & (1 << tag)) != 0) {
tag = (tag + 1) % 16;
}
}
while (offset > 0) {
offset--;
tag = (tag + 1) % 16;
while ((exclude & (1 << tag)) != 0) {
tag = (tag + 1) % 16;
}
}
return tag;
}
uint64_t GetAddressWithAllocationTag(uint64_t addr, uint64_t tag) {
VIXL_ASSERT(IsUint4(tag));
return (addr & ~(UINT64_C(0xf) << 56)) | (tag << 56);
}
// Create or remove a mapping with memory protection. Memory attributes such
// as MTE and BTI are represented by metadata in Simulator.
void* Mmap(
void* address, size_t length, int prot, int flags, int fd, off_t offset);
int Munmap(void* address, size_t length, int prot);
// The common CPUFeatures interface with the set of available features.
@@ -2666,6 +2954,7 @@ class Simulator : public DecoderVisitor {
R DoRuntimeCall(R (*function)(P...),
std::tuple<P...> arguments,
local_index_sequence<I...>) {
USE(arguments);
return function(std::get<I>(arguments)...);
}
@@ -2796,6 +3085,75 @@ class Simulator : public DecoderVisitor {
SimPRegister& GetPTrue() { return pregister_all_true_; }
template <typename T>
size_t CleanGranuleTag(T address, size_t length = kMTETagGranuleInBytes) {
size_t count = 0;
for (size_t offset = 0; offset < length; offset += kMTETagGranuleInBytes) {
count +=
meta_data_.CleanMTETag(reinterpret_cast<uintptr_t>(address) + offset);
}
size_t expected =
length / kMTETagGranuleInBytes + (length % kMTETagGranuleInBytes != 0);
// Give a warning when the memory region that is being unmapped isn't all
// either MTE protected or not.
if (count != expected) {
std::stringstream sstream;
sstream << std::hex
<< "MTE WARNING : the memory region being unmapped "
"starting at address 0x"
<< reinterpret_cast<uint64_t>(address)
<< "is not fully MTE protected.\n";
VIXL_WARNING(sstream.str().c_str());
}
return count;
}
template <typename T>
void SetGranuleTag(T address,
int tag,
size_t length = kMTETagGranuleInBytes) {
for (size_t offset = 0; offset < length; offset += kMTETagGranuleInBytes) {
meta_data_.SetMTETag((uintptr_t)(address) + offset, tag);
}
}
template <typename T>
int GetGranuleTag(T address) {
return meta_data_.GetMTETag(address);
}
// Generate a random address tag, and any tags specified in the input are
// excluded from the selection.
uint64_t GenerateRandomTag(uint16_t exclude = 0);
// Register a new BranchInterception object. If 'function' is branched to
// (e.g: "bl function") in the future; instead, if provided, 'callback' will
// be called otherwise a runtime call will be performed on 'function'.
//
// For example: this can be used to always perform runtime calls on
// non-AArch64 functions without using the macroassembler.
template <typename R, typename... P>
void RegisterBranchInterception(R (*function)(P...),
InterceptionCallback callback = nullptr) {
meta_data_.RegisterBranchInterception(*function, callback);
}
// Return the current output stream in use by the simulator.
FILE* GetOutputStream() const { return stream_; }
bool IsDebuggerEnabled() const { return debugger_enabled_; }
void SetDebuggerEnabled(bool enabled) { debugger_enabled_ = enabled; }
Debugger* GetDebugger() const {
#ifndef PANDA_BUILD
return debugger_.get();
#else
return debugger_;
#endif
}
protected:
const char* clr_normal;
const char* clr_flag_name;
@@ -2907,13 +3265,45 @@ class Simulator : public DecoderVisitor {
AddrMode addr_mode);
void NEONLoadStoreSingleStructHelper(const Instruction* instr,
AddrMode addr_mode);
template <uint32_t mops_type>
void MOPSPHelper(const Instruction* instr) {
VIXL_ASSERT(instr->IsConsistentMOPSTriplet<mops_type>());
uint64_t AddressUntag(uint64_t address) { return address & ~kAddressTagMask; }
int d = instr->GetRd();
int n = instr->GetRn();
int s = instr->GetRs();
template <typename T>
T* AddressUntag(T* address) {
uintptr_t address_raw = reinterpret_cast<uintptr_t>(address);
return reinterpret_cast<T*>(AddressUntag(address_raw));
// Aliased registers and xzr are disallowed for Xd and Xn.
if ((d == n) || (d == s) || (n == s) || (d == 31) || (n == 31)) {
VisitUnallocated(instr);
}
// Additionally, Xs may not be xzr for cpy.
if ((mops_type == "cpy"_h) && (s == 31)) {
VisitUnallocated(instr);
}
// Bits 31 and 30 must be zero.
if (instr->ExtractBits(31, 30) != 0) {
VisitUnallocated(instr);
}
// Saturate copy count.
uint64_t xn = ReadXRegister(n);
int saturation_bits = (mops_type == "cpy"_h) ? 55 : 63;
if ((xn >> saturation_bits) != 0) {
xn = (UINT64_C(1) << saturation_bits) - 1;
if (mops_type == "setg"_h) {
// Align saturated value to granule.
xn &= ~UINT64_C(kMTETagGranuleInBytes - 1);
}
WriteXRegister(n, xn);
}
ReadNzcv().SetN(0);
ReadNzcv().SetZ(0);
ReadNzcv().SetC(1); // Indicates "option B" implementation.
ReadNzcv().SetV(0);
}
int64_t ShiftOperand(unsigned reg_size,
@@ -4747,7 +5137,7 @@ class Simulator : public DecoderVisitor {
const Instruction* pc_;
// Pointer to the last simulated instruction, used for checking the validity
// of the current instruction with movprfx.
// of the current instruction with the previous instruction, such as movprfx.
Instruction const* last_instr_;
// Branch type register, used for branch target identification.
@@ -4883,6 +5273,20 @@ class Simulator : public DecoderVisitor {
// A configurable size of SVE vector registers.
unsigned vector_length_;
// Representation of memory attributes such as MTE tagging and BTI page
// protection in addition to branch interceptions.
MetaDataDepot meta_data_;
// True if the debugger is enabled and might get entered.
bool debugger_enabled_;
// Debugger for the simulator.
#ifndef PANDA_BUILD
std::unique_ptr<Debugger> debugger_;
#else
Debugger* debugger_{nullptr};
#endif
};
#if defined(VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT) && __cplusplus < 201402L
@@ -4893,6 +5297,17 @@ struct Simulator::emulated_make_index_sequence_helper<0, I...>
: Simulator::emulated_index_sequence<I...> {};
#endif
template <typename R, typename... P>
void MetaDataDepot::BranchInterception<R, P...>::operator()(
Simulator* simulator) const {
if (callback_ == nullptr) {
Simulator::RuntimeCallStructHelper<R, P...>::
Wrapper(simulator, reinterpret_cast<uint64_t>(function_));
} else {
callback_(reinterpret_cast<uint64_t>(function_));
}
}
} // namespace aarch64
} // namespace vixl
@@ -56,6 +56,8 @@ enum DebugHltOpcode {
kDisableCPUFeaturesOpcode,
kSaveCPUFeaturesOpcode,
kRestoreCPUFeaturesOpcode,
kMTEActive,
kMTEInactive,
// Aliases.
kDebugHltFirstOpcode = kUnreachableOpcode,
kDebugHltLastOpcode = kLogOpcode
+6
View File
@@ -29,6 +29,12 @@
#include "code-buffer-vixl.h"
// Microsoft Visual C++ defines a `mvn` macro that conflicts with our own
// definition.
#if defined(_MSC_VER) && defined(mvn)
#undef mvn
#endif
namespace vixl {
class CodeBufferCheckScope;
+4 -3
View File
@@ -125,11 +125,12 @@ char* stpcpy (char *dst, const char *src) {
#endif
void CodeBuffer::EmitString(const char* string) {
VIXL_ASSERT(HasSpaceFor(strlen(string) + 1));
const auto len = strlen(string) + 1;
VIXL_ASSERT(HasSpaceFor(len));
char* dst = reinterpret_cast<char*>(cursor_);
dirty_ = true;
char* null_char = stpcpy(dst, string);
cursor_ = reinterpret_cast<byte*>(null_char) + 1;
memcpy(dst, string, len);
cursor_ = reinterpret_cast<byte*>(dst + len);
}
+3 -2
View File
@@ -145,8 +145,9 @@ class CodeBuffer {
void Emit(T value) {
VIXL_ASSERT(HasSpaceFor(sizeof(value)));
dirty_ = true;
memcpy(cursor_, &value, sizeof(value));
cursor_ += sizeof(value);
byte* c = cursor_;
memcpy(c, &value, sizeof(value));
cursor_ = c + sizeof(value);
}
void UpdateData(size_t offset, const void* data, size_t size);
+13 -6
View File
@@ -68,14 +68,19 @@ class CodeBufferCheckScope {
size_t size,
BufferSpacePolicy check_policy = kReserveBufferSpace,
SizePolicy size_policy = kMaximumSize)
: assembler_(NULL), initialised_(false) {
: CodeBufferCheckScope() {
Open(assembler, size, check_policy, size_policy);
}
// This constructor does not implicitly initialise the scope. Instead, the
// user is required to explicitly call the `Open` function before using the
// scope.
CodeBufferCheckScope() : assembler_(NULL), initialised_(false) {
CodeBufferCheckScope()
: assembler_(NULL),
assert_policy_(kMaximumSize),
limit_(0),
previous_allow_assembler_(false),
initialised_(false) {
// Nothing to do.
}
@@ -152,14 +157,15 @@ class EmissionCheckScope : public CodeBufferCheckScope {
// constructed.
EmissionCheckScope(MacroAssemblerInterface* masm,
size_t size,
SizePolicy size_policy = kMaximumSize) {
SizePolicy size_policy = kMaximumSize)
: EmissionCheckScope() {
Open(masm, size, size_policy);
}
// This constructor does not implicitly initialise the scope. Instead, the
// user is required to explicitly call the `Open` function before using the
// scope.
EmissionCheckScope() {}
EmissionCheckScope() : masm_(nullptr), pool_policy_(kBlockPools) {}
virtual ~EmissionCheckScope() { Close(); }
@@ -250,14 +256,15 @@ class ExactAssemblyScope : public EmissionCheckScope {
// constructed.
ExactAssemblyScope(MacroAssemblerInterface* masm,
size_t size,
SizePolicy size_policy = kExactSize) {
SizePolicy size_policy = kExactSize)
: ExactAssemblyScope() {
Open(masm, size, size_policy);
}
// This constructor does not implicitly initialise the scope. Instead, the
// user is required to explicitly call the `Open` function before using the
// scope.
ExactAssemblyScope() {}
ExactAssemblyScope() : previous_allow_macro_assembler_(false) {}
virtual ~ExactAssemblyScope() { Close(); }
+1
View File
@@ -25,6 +25,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "compiler-intrinsics-vixl.h"
#include "utils-vixl.h"
namespace vixl {
+3 -1
View File
@@ -29,6 +29,7 @@
#define VIXL_COMPILER_INTRINSICS_H
#include <limits.h>
#include "globals-vixl.h"
namespace vixl {
@@ -112,7 +113,8 @@ inline int CountLeadingSignBits(V value, int width = (sizeof(V) * 8)) {
VIXL_ASSERT(IsPowerOf2(width) && (width <= 64));
#if COMPILER_HAS_BUILTIN_CLRSB
VIXL_ASSERT((LLONG_MIN <= value) && (value <= LLONG_MAX));
int ll_width = sizeof(long long) * kBitsPerByte; // NOLINT(runtime/int)
int ll_width =
sizeof(long long) * kBitsPerByte; // NOLINT(google-runtime-int)
int result = __builtin_clrsbll(value) - (ll_width - width);
// Check that the value fits in the specified width.
VIXL_ASSERT(result >= 0);
+2 -1
View File
@@ -24,9 +24,10 @@
// 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.
#include "cpu-features.h"
#include <ostream>
#include "cpu-features.h"
#include "globals-vixl.h"
#include "utils-vixl.h"
+19 -1
View File
@@ -166,6 +166,7 @@ namespace vixl {
/* Memory Tagging Extension. */ \
V(kMTEInstructions, "MTE (EL0 instructions)", NULL) \
V(kMTE, "MTE", NULL) \
V(kMTE3, "MTE (asymmetric)", "mte3") \
/* PAuth extensions. */ \
V(kPAuthEnhancedPAC, "PAuth EnhancedPAC", NULL) \
V(kPAuthEnhancedPAC2, "PAuth EnhancedPAC2", NULL) \
@@ -183,7 +184,24 @@ namespace vixl {
/* Enhanced Counter Virtualization */ \
V(kECV, "ECV", "ecv") \
/* Increased precision of Reciprocal Estimate and Square Root Estimate */ \
V(kRPRES, "RPRES", "rpres")
V(kRPRES, "RPRES", "rpres") \
/* Memory operation instructions, for memcpy, memset */ \
V(kMOPS, "Memory ops", NULL) \
/* Scalable Matrix Extension (SME) */ \
V(kSME, "SME", "sme") \
V(kSMEi16i64, "SME (i16i64)", "smei16i64") \
V(kSMEf64f64, "SME (f64f64)", "smef64f64") \
V(kSMEi8i32, "SME (i8i32)", "smei8i32") \
V(kSMEf16f32, "SME (f16f32)", "smef16f32") \
V(kSMEb16f32, "SME (b16f32)", "smeb16f32") \
V(kSMEf32f32, "SME (f32f32)", "smef32f32") \
V(kSMEfa64, "SME (fa64)", "smefa64") \
/* WFET and WFIT instruction support */ \
V(kWFXT, "WFXT", "wfxt") \
/* Extended BFloat16 instructions */ \
V(kEBF16, "EBF16", "ebf16") \
V(kSVE_EBF16, "EBF16 (SVE)", "sveebf16") \
V(kCSSC, "CSSC", "cssc")
// clang-format on
+4 -4
View File
@@ -27,8 +27,8 @@
#ifndef VIXL_GLOBALS_H
#define VIXL_GLOBALS_H
#if __cplusplus < 201402L
#error VIXL requires C++14
#if __cplusplus < 201703L
#error VIXL requires C++17
#endif
// Get standard C99 macros for integer types.
@@ -158,7 +158,7 @@ struct Unsigned<64> {
#endif
// This is not as powerful as template based assertions, but it is simple.
// It assumes that the descriptions are unique. If this starts being a problem,
// we can switch to a different implemention.
// we can switch to a different implementation.
#define VIXL_CONCAT(a, b) a##b
#if __cplusplus >= 201103L
#define VIXL_STATIC_ASSERT_LINE(line_unused, condition, message) \
@@ -207,7 +207,7 @@ inline void USE(const T1&, const T2&, const T3&, const T4&) {}
#if __has_warning("-Wimplicit-fallthrough") && __cplusplus >= 201103L
#define VIXL_FALLTHROUGH() [[clang::fallthrough]]
// Fallthrough annotation for GCC >= 7.
#elif __GNUC__ >= 7
#elif defined(__GNUC__) && __GNUC__ >= 7
#define VIXL_FALLTHROUGH() __attribute__((fallthrough))
#else
#define VIXL_FALLTHROUGH() \
+9 -5
View File
@@ -27,9 +27,8 @@
#ifndef VIXL_INVALSET_H_
#define VIXL_INVALSET_H_
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
#include "globals-vixl.h"
@@ -119,7 +118,7 @@ class InvalSet {
size_t size() const;
// Returns true if no elements are stored in the set.
// Note that this does not mean the the backing storage is empty: it can still
// Note that this does not mean the backing storage is empty: it can still
// contain invalid elements.
bool empty() const;
@@ -256,8 +255,13 @@ class InvalSet {
template <class S>
class InvalSetIterator : public std::iterator<std::forward_iterator_tag,
typename S::_ElementType> {
class InvalSetIterator {
using iterator_category = std::forward_iterator_tag;
using value_type = typename S::_ElementType;
using difference_type = std::ptrdiff_t;
using pointer = S*;
using reference = S&;
private:
// Redefine types to mirror the associated set types.
typedef typename S::_ElementType ElementType;
+3 -3
View File
@@ -27,10 +27,10 @@
#ifndef VIXL_POOL_MANAGER_IMPL_H_
#define VIXL_POOL_MANAGER_IMPL_H_
#include "pool-manager.h"
#include <algorithm>
#include "assembler-base-vixl.h"
#include "pool-manager.h"
namespace vixl {
@@ -523,6 +523,6 @@ int PoolManager<T>::GetPoolSizeForTest() const {
}
return size;
}
}
} // namespace vixl
#endif // VIXL_POOL_MANAGER_IMPL_H_
+3 -4
View File
@@ -27,11 +27,10 @@
#ifndef VIXL_POOL_MANAGER_H_
#define VIXL_POOL_MANAGER_H_
#include <stdint.h>
#include <cstddef>
#include <limits>
#include <map>
#include <stdint.h>
#include <vector>
#include "globals-vixl.h"
@@ -372,8 +371,8 @@ class ForwardReference {
// Specify the possible locations where the object could be stored. AArch32's
// PC offset, and T32's PC alignment calculations should be applied by the
// Assembler, not here. The PoolManager deals only with simple locationes.
// Including min_object_adddress_ is necessary to handle AArch32 some
// Assembler, not here. The PoolManager deals only with simple locations.
// Including min_object_address_ is necessary to handle AArch32 some
// instructions which have a minimum offset of 0, but also have the implicit
// PC offset.
// Note that this structure cannot handle sparse ranges, such as A32's ADR,
+3 -3
View File
@@ -24,10 +24,10 @@
// 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.
#include <cstdio>
#include "utils-vixl.h"
#include <cstdio>
namespace vixl {
// The default NaN values (for FPCR.DN=1).
@@ -391,7 +391,7 @@ float FPToFloat(double value,
}
VIXL_UNREACHABLE();
return value;
return static_cast<float>(value);
}
// TODO: We should consider implementing a full FPToDouble(Float16)
+38 -9
View File
@@ -30,9 +30,9 @@
#include <cmath>
#include <cstring>
#include <limits>
#include <optional>
#include <type_traits>
#include <vector>
#include <optional>
#include "compiler-intrinsics-vixl.h"
#include "globals-vixl.h"
@@ -51,6 +51,7 @@
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#endif
@@ -72,6 +73,9 @@ using Map = ark::ArenaMap<K, V>;
template <typename K, typename V>
using UnorderedMap = ark::ArenaUnorderedMap<K, V>;
template <typename K>
using UnorderedSet = ark::ArenaUnorderedSet<K>;
using String = ark::ArenaString;
template <typename T>
@@ -86,6 +90,9 @@ using Map = std::map<K, V>;
template <typename K, typename V>
using UnorderedMap = std::unordered_map<K, V>;
template <typename K>
using UnorderedSet = std::unordered_set<K>;
using String = std::string;
template <typename T>
@@ -422,17 +429,37 @@ VIXL_DEPRECATED("RawbitsToDouble",
return RawbitsToDouble(bits);
}
// Some compilers dislike negating unsigned integers,
// so we provide an equivalent.
template <typename T>
T UnsignedNegate(T value) {
VIXL_STATIC_ASSERT(std::is_unsigned<T>::value);
return ~value + 1;
}
// An absolute operation for signed integers that is defined for results outside
// the representable range. Specifically, Abs(MIN_INT) is MIN_INT.
template <typename T>
T Abs(T val) {
// TODO: this static assertion is for signed integer inputs, as that's the
// only type tested. However, the code should work for all numeric inputs.
// Remove the assertion and this comment when more tests are available.
VIXL_STATIC_ASSERT(std::is_signed<T>::value && std::is_integral<T>::value);
return ((val >= -std::numeric_limits<T>::max()) && (val < 0)) ? -val : val;
}
// Convert unsigned to signed numbers in a well-defined way (using two's
// complement representations).
inline int64_t RawbitsToInt64(uint64_t bits) {
return (bits >= UINT64_C(0x8000000000000000))
? (-static_cast<int64_t>(-bits - 1) - 1)
? (-static_cast<int64_t>(UnsignedNegate(bits) - 1) - 1)
: static_cast<int64_t>(bits);
}
inline int32_t RawbitsToInt32(uint32_t bits) {
return (bits >= UINT64_C(0x80000000)) ? (-static_cast<int32_t>(-bits - 1) - 1)
: static_cast<int32_t>(bits);
return (bits >= UINT64_C(0x80000000))
? (-static_cast<int32_t>(UnsignedNegate(bits) - 1) - 1)
: static_cast<int32_t>(bits);
}
namespace internal {
@@ -458,7 +485,7 @@ class SimFloat16 : public Float16 {
bool operator>(SimFloat16 rhs) const;
bool operator==(SimFloat16 rhs) const;
bool operator!=(SimFloat16 rhs) const;
// This is necessary for conversions peformed in (macro asm) Fmov.
// This is necessary for conversions performed in (macro asm) Fmov.
bool operator==(double rhs) const;
operator double() const;
};
@@ -615,7 +642,9 @@ inline float FusedMultiplyAdd(float op1, float op2, float a) {
}
inline uint64_t LowestSetBit(uint64_t value) { return value & -value; }
inline uint64_t LowestSetBit(uint64_t value) {
return value & UnsignedNegate(value);
}
template <typename T>
@@ -978,7 +1007,7 @@ class Uint32 {
}
int32_t GetSigned() const { return data_; }
Uint32 operator~() const { return Uint32(~data_); }
Uint32 operator-() const { return Uint32(-data_); }
Uint32 operator-() const { return Uint32(UnsignedNegate(data_)); }
bool operator==(Uint32 value) const { return data_ == value.data_; }
bool operator!=(Uint32 value) const { return data_ != value.data_; }
bool operator>(Uint32 value) const { return data_ > value.data_; }
@@ -1046,7 +1075,7 @@ class Uint64 {
Uint32 GetHigh32() const { return Uint32(data_ >> 32); }
Uint32 GetLow32() const { return Uint32(data_ & 0xffffffff); }
Uint64 operator~() const { return Uint64(~data_); }
Uint64 operator-() const { return Uint64(-data_); }
Uint64 operator-() const { return Uint64(UnsignedNegate(data_)); }
bool operator==(Uint64 value) const { return data_ == value.data_; }
bool operator!=(Uint64 value) const { return data_ != value.data_; }
Uint64 operator+(Uint64 value) const { return Uint64(data_ + value.data_); }
@@ -1352,7 +1381,7 @@ T FPRound(int64_t sign,
// For subnormal outputs, the shift must be adjusted by the exponent. The +1
// is necessary because the exponent of a subnormal value (encoded as 0) is
// the same as the exponent of the smallest normal value (encoded as 1).
shift += -exponent + 1;
shift += static_cast<int>(-exponent + 1);
// Handle inputs that would produce a zero output.
//
@@ -97,7 +97,7 @@
"type": "assembler",
"test-cases": [
{
"name": "Unconditionnal",
"name": "Unconditional",
"operands": [
"cond", "rd", "rn", "shift", "rs"
],
@@ -192,7 +192,7 @@
"type": "assembler",
"test-cases": [
{
"name": "Unconditionnal",
"name": "Unconditional",
"operands": [
"cond", "rd", "rn", "rm"
],
+3 -3
View File
@@ -1100,7 +1100,7 @@
"identifier": "OffsetLowerThan4096",
"type": "int32_t",
// These variants are a random sample of 500 integers out of all integers
// from 1 to 4094 (included). We've added 0 and 4095 explicitely.
// from 1 to 4094 (included). We've added 0 and 4095 explicitly.
"variants": [
"0",
"4095",
@@ -1700,7 +1700,7 @@
],
"default": "NoFlag"
},
// TODO: Consider having a seperate list for inputs for which we are only
// TODO: Consider having a separate list for inputs for which we are only
// interested in recording the value after the instruction has executed.
// This applies to `Q` and `GE`.
{
@@ -1781,7 +1781,7 @@
"identifier": "RegisterOffsetLowerThan4096",
"type": "Register",
// These values are a random sample of 500 integers out of all integers
// from 1 to 4094 (included). We've added 0 and 4095 explicitely.
// from 1 to 4094 (included). We've added 0 and 4095 explicitly.
"values": [
"0",
"4095",
@@ -49,7 +49,7 @@ namespace aarch32 {
${instruction_list_declaration}
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -49,7 +49,7 @@ namespace aarch32 {
${instruction_list_declaration}
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -53,7 +53,7 @@ namespace aarch32 {
${instruction_list_declaration}
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -113,7 +113,7 @@ namespace aarch32 {
${instruction_list_declaration}
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` and
// `Inputs` have various layouts across generated tests so they absolutely
+5 -5
View File
@@ -1490,7 +1490,7 @@ void EmitLdrdLiteralTest(MacroAssembler* masm, TestMacroAssembler* test) {
VIXL_CHECK(masm->GetCursorOffset() == end);
}
// Check that the pool has not been emited along the way.
// Check that the pool has not been emitted along the way.
CHECK_POOL_SIZE(8);
// This extra instruction should trigger an emit of the pool.
__ Nop();
@@ -3653,7 +3653,7 @@ static void NearBranchAndLiteralFuzzHelper(InstructionSet isa,
// below). The cases are split in 4 groups:
//
// - 0..3: Generate various amount of nops.
// - 4..7: Generate various load intstructions with literals.
// - 4..7: Generate various load instructions with literals.
// - 8..14: Generate various branch instructions.
// - 15..19: Generate various amount of nops.
//
@@ -4849,7 +4849,7 @@ TEST_T32(branch_fuzz_example) {
// Generate a "B" and a "Cbz" which have the same checkpoint. Without proper
// management (i.e. if the veneers were only generated at the shared
// checkpoint), one one of the branches would be out of range.
// checkpoint), one of the branches would be out of range.
TEST_T32(veneer_simultaneous) {
SETUP();
@@ -5109,7 +5109,7 @@ TEST_T32(veneer_and_literal4) {
__ Ldr(r11, literal);
// The range for ldr is 4095, the range for cbz is 127. Generate nops
// to have the ldr becomming out of range just before the cbz.
// to have the ldr becoming out of range just before the cbz.
const int NUM_NOPS = 2044;
const int NUM_RANGE = 58;
@@ -5184,7 +5184,7 @@ TEST_T32(veneer_and_literal5) {
__ add(r1, r1, 3);
}
__ Bind(&labels[test_num]);
// Emit the literal pool if it has not beeen emitted (it's the case for
// Emit the literal pool if it has not been emitted (it's the case for
// the lower values of test_num).
__ EmitLiteralPool(PoolManager<int32_t>::kBranchRequired);
}
@@ -63,7 +63,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -63,7 +63,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -54,7 +54,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -54,7 +54,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -56,7 +56,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -56,7 +56,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -60,7 +60,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -56,7 +56,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -56,7 +56,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -56,7 +56,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -56,7 +56,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -60,7 +60,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -55,7 +55,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -66,7 +66,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.
@@ -52,7 +52,7 @@ namespace aarch32 {
// The following definitions are defined again in each generated test, therefore
// we need to place them in an anomymous namespace. It expresses that they are
// we need to place them in an anonymous namespace. It expresses that they are
// local to this file only, and the compiler is not allowed to share these types
// across test files during template instantiation. Specifically, `Operands` has
// various layouts across generated tests so it absolutely cannot be shared.

Some files were not shown because too many files have changed in this diff Show More