Import VIXL, an ARMv8 assembler/disassembler/simulator

This diff is intended primarily as a medium for everyone to look at and
discuss the code I'm planning to use as our ARMv8 in-memory assembler
and simulator. This is what I was about to spend weeks and weeks writing
myself, but thankfully ARM has done all that for us!

To get an idea of what it looks like to use VIXL, look at
test-assembler-a64.cc, at lines that begin with "__". Superficially, it
looks very similar to clients of X64Assembler. Things like x0, w1, etc.
are registers. "Operand" is a struct that encapsulates some of the extra
stuff tacked on to ARMv8 instructions -- e.g. when comparing against an
immediate, you can include a left-shift amount for the immediate, and it
will look like "Operand(x1, LSL, 1)" or similar.

The simulator is similarly easy to use. You set initial register values,
give it an instruction pointer, and say go. It runs until it hits a ret
instruction that takes it out of the top level, and then you can read
register values out of it. It can access memory just like native code
can.

VIXL includes its own abstraction for registers, and it's structurally
quite similar to our PhysReg. (It's defined in assembler-a64.h.) One of
the most nontrivial parts of this effort will be to figure out how to
unify these two abstractions.

The instruction coverage is internally consistent (i.e. the simulator
and disassembler can deal with any instruction the assembler can output)
and is almost certainly enough for our needs. Even if it's not, the code
is pretty clean, and it won't be hard to add whatever we need.

The big thing I'm not yet sure about is the implementation of nonlocal
jumps. The usage examples that come with VIXL (but I'm not including
here; see the original github) use jumps, but only within the small
snippets they emit. There's nothing that resembles our jumps between a
and astubs. This might be something we have to hack in, but it shouldn't
be too hard. The one potentially tricky part will be to support jump
smashing. If we have to encode a jump as multiple instructions, we won't
be able to smash it atomically. The only viable alternative I can think
of is to have a "jump target table" on the side, emit an indirect jump
in code, and smash the table entries instead of the code.

The open-source distribution of VIXL is built with scons, but it was
near-trivial to get it building with our internal system. To build the
library, I just had to change the include paths. To build the tests, I
deleted the custom test driver that came with VIXL and converted the
test files themselves to use gtest. This was mostly a matter of tweaking
the macros to use gtest asserts.

I also fixed lint errors (NULL -> nullptr, include ordering, static at
namespace scope, ...)

About licensing. The code is under a 3-clause BSD license, and the
license header is preserved in all the files I pulled in.

Pulled from https://github.com/armvixl/vixl at ad96eda894.
Esse commit está contido em:
Owen Yamauchi
2013-07-17 08:51:55 -07:00
commit de Sara Golemon
commit 5978586214
25 arquivos alterados com 24167 adições e 0 exclusões
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+148
Ver Arquivo
@@ -0,0 +1,148 @@
// Copyright 2013, ARM Limited
// 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 "hphp/util/vixl/a64/cpu-a64.h"
#include "hphp/util/vixl/utils.h"
namespace vixl {
// Initialise to smallest possible cache size.
unsigned CPU::dcache_line_size_ = 1;
unsigned CPU::icache_line_size_ = 1;
// Currently computes I and D cache line size.
void CPU::SetUp() {
uint32_t cache_type_register = GetCacheType();
// The cache type register holds information about the caches, including I
// D caches line size.
static const int kDCacheLineSizeShift = 16;
static const int kICacheLineSizeShift = 0;
static const uint32_t kDCacheLineSizeMask = 0xf << kDCacheLineSizeShift;
static const uint32_t kICacheLineSizeMask = 0xf << kICacheLineSizeShift;
// The cache type register holds the size of the I and D caches as a power of
// two.
uint32_t dcache_line_size_power_of_two =
(cache_type_register & kDCacheLineSizeMask) >> kDCacheLineSizeShift;
uint32_t icache_line_size_power_of_two =
(cache_type_register & kICacheLineSizeMask) >> kICacheLineSizeShift;
dcache_line_size_ = 1 << dcache_line_size_power_of_two;
icache_line_size_ = 1 << icache_line_size_power_of_two;
}
uint32_t CPU::GetCacheType() {
#ifdef USE_SIMULATOR
// This will lead to a cache with 1 byte long lines, which is fine since the
// simulator will not need this information.
return 0;
#else
uint32_t cache_type_register;
// Copy the content of the cache type register to a core register.
__asm__ __volatile__ ("mrs %[ctr], ctr_el0" // NOLINT
: [ctr] "=r" (cache_type_register));
return cache_type_register;
#endif
}
void CPU::EnsureIAndDCacheCoherency(void *address, size_t length) {
#ifdef USE_SIMULATOR
USE(address);
USE(length);
// TODO: consider adding cache simulation to ensure every address run has been
// synchronised.
#else
// The code below assumes user space cache operations are allowed.
uintptr_t start = reinterpret_cast<uintptr_t>(address);
// Sizes will be used to generate a mask big enough to cover a pointer.
uintptr_t dsize = static_cast<uintptr_t>(dcache_line_size_);
uintptr_t isize = static_cast<uintptr_t>(icache_line_size_);
// Cache line sizes are always a power of 2.
ASSERT(CountSetBits(dsize, 64) == 1);
ASSERT(CountSetBits(isize, 64) == 1);
uintptr_t dstart = start & ~(dsize - 1);
uintptr_t istart = start & ~(isize - 1);
uintptr_t end = start + length;
__asm__ __volatile__ ( // NOLINT
// Clean every line of the D cache containing the target data.
"0: \n\t"
// dc : Data Cache maintenance
// c : Clean
// va : by (Virtual) Address
// u : to the point of Unification
// The point of unification for a processor is the point by which the
// instruction and data caches are guaranteed to see the same copy of a
// memory location. See ARM DDI 0406B page B2-12 for more information.
"dc cvau, %[dline] \n\t"
"add %[dline], %[dline], %[dsize] \n\t"
"cmp %[dline], %[end] \n\t"
"b.lt 0b \n\t"
// Barrier to make sure the effect of the code above is visible to the rest
// of the world.
// dsb : Data Synchronisation Barrier
// ish : Inner SHareable domain
// The point of unification for an Inner Shareable shareability domain is
// the point by which the instruction and data caches of all the processors
// in that Inner Shareable shareability domain are guaranteed to see the
// same copy of a memory location. See ARM DDI 0406B page B2-12 for more
// information.
"dsb ish \n\t"
// Invalidate every line of the I cache containing the target data.
"1: \n\t"
// ic : instruction cache maintenance
// i : invalidate
// va : by address
// u : to the point of unification
"ic ivau, %[iline] \n\t"
"add %[iline], %[iline], %[isize] \n\t"
"cmp %[iline], %[end] \n\t"
"b.lt 1b \n\t"
// Barrier to make sure the effect of the code above is visible to the rest
// of the world.
"dsb ish \n\t"
// Barrier to ensure any prefetching which happened before this code is
// discarded.
// isb : Instruction Synchronisation Barrier
"isb \n\t"
: [dline] "+r" (dstart),
[iline] "+r" (istart)
: [dsize] "r" (dsize),
[isize] "r" (isize),
[end] "r" (end)
// This code does not write to memory but without the dependency gcc might
// move this code before the code is generated.
: "cc", "memory"
); // NOLINT
#endif
}
} // namespace vixl
+56
Ver Arquivo
@@ -0,0 +1,56 @@
// Copyright 2013, ARM Limited
// 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_CPU_A64_H
#define VIXL_CPU_A64_H
#include "hphp/util/vixl/globals.h"
namespace vixl {
class CPU {
public:
// Initialise CPU support.
static void SetUp();
// Ensures the data at a given address and with a given size is the same for
// the I and D caches. I and D caches are not automatically coherent on ARM
// so this operation is required before any dynamically generated code can
// safely run.
static void EnsureIAndDCacheCoherency(void *address, size_t length);
private:
// Return the content of the cache type register.
static uint32_t GetCacheType();
// I and D cache line size in bytes.
static unsigned icache_line_size_;
static unsigned dcache_line_size_;
};
} // namespace vixl
#endif // VIXL_CPU_A64_H
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+188
Ver Arquivo
@@ -0,0 +1,188 @@
// Copyright 2013, ARM Limited
// 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_A64_DEBUGGER_A64_H_
#define VIXL_A64_DEBUGGER_A64_H_
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <vector>
#include "hphp/util/vixl/globals.h"
#include "hphp/util/vixl/utils.h"
#include "hphp/util/vixl/a64/constants-a64.h"
#include "hphp/util/vixl/a64/simulator-a64.h"
namespace vixl {
// Debug instructions.
//
// VIXL's macro-assembler and debugger support a few pseudo instructions to
// make debugging easier. These pseudo instructions do not exist on real
// hardware.
//
// Each debug pseudo instruction is represented by a HLT instruction. The HLT
// immediate field is used to identify the type of debug pseudo isntruction.
// Each pseudo instruction use a custom encoding for additional arguments, as
// described below.
// Unreachable
//
// Instruction which should never be executed. This is used as a guard in parts
// of the code that should not be reachable, such as in data encoded inline in
// the instructions.
const Instr kUnreachableOpcode = 0xdeb0;
// Trace
// - parameter: TraceParameter stored as a uint32_t
// - command: TraceCommand stored as a uint32_t
//
// Allow for trace management in the generated code. See the corresponding
// enums for more information on permitted actions.
const Instr kTraceOpcode = 0xdeb2;
const unsigned kTraceParamsOffset = 1 * kInstructionSize;
const unsigned kTraceCommandOffset = 2 * kInstructionSize;
const unsigned kTraceLength = 3 * kInstructionSize;
// Log
// - parameter: TraceParameter stored as a uint32_t
//
// Output the requested information.
const Instr kLogOpcode = 0xdeb3;
const unsigned kLogParamsOffset = 1 * kInstructionSize;
const unsigned kLogLength = 2 * kInstructionSize;
// Trace commands.
enum TraceCommand {
TRACE_ENABLE = 1,
TRACE_DISABLE = 2
};
// Trace parameters.
enum TraceParameters {
LOG_DISASM = 1 << 0, // Log disassembly.
LOG_REGS = 1 << 1, // Log general purpose registers.
LOG_FP_REGS = 1 << 2, // Log floating-point registers.
LOG_FLAGS = 1 << 3, // Log the status flags.
LOG_STATE = LOG_REGS | LOG_FP_REGS | LOG_FLAGS,
LOG_ALL = LOG_DISASM | LOG_REGS | LOG_FP_REGS | LOG_FLAGS
};
// Debugger parameters
enum DebugParameters {
DBG_ACTIVE = 1 << 0, // The debugger is active.
DBG_BREAK = 1 << 1 // The debugger is at a breakpoint.
};
// Forward declarations.
class DebugCommand;
class Token;
class FormatToken;
class Debugger : public Simulator {
public:
explicit Debugger(Decoder* decoder, FILE* stream = stdout);
virtual void Run();
void VisitException(Instruction* instr);
inline int log_parameters() {
// The simulator can control disassembly, so make sure that the Debugger's
// log parameters agree with it.
if (disasm_trace()) {
log_parameters_ |= LOG_DISASM;
}
return log_parameters_;
}
inline void set_log_parameters(int parameters) {
set_disasm_trace((parameters & LOG_DISASM) != 0);
log_parameters_ = parameters;
update_pending_request();
}
inline int debug_parameters() { return debug_parameters_; }
inline void set_debug_parameters(int parameters) {
debug_parameters_ = parameters;
update_pending_request();
}
// Numbers of instructions to execute before the debugger shell is given
// back control.
inline int steps() { return steps_; }
inline void set_steps(int value) {
ASSERT(value > 1);
steps_ = value;
}
inline bool IsDebuggerRunning() {
return (debug_parameters_ & DBG_ACTIVE) != 0;
}
inline bool pending_request() { return pending_request_; }
inline void update_pending_request() {
const int kLoggingMask = LOG_FLAGS | LOG_REGS | LOG_FP_REGS;
const bool logging = (log_parameters_ & kLoggingMask) != 0;
const bool debugging = IsDebuggerRunning();
pending_request_ = logging || debugging;
}
void PrintInstructions(void* address, int64_t count = 1);
void PrintMemory(const uint8_t* address,
int64_t count,
const FormatToken* format);
private:
void LogFlags();
void LogRegisters();
void LogFPRegisters();
void LogProcessorState();
char* ReadCommandLine(const char* prompt, char* buffer, int length);
void RunDebuggerShell();
void DoBreakpoint(Instruction* instr);
void DoUnreachable(Instruction* instr);
void DoTrace(Instruction* instr);
void DoLog(Instruction* instr);
int log_parameters_;
int debug_parameters_;
bool pending_request_;
int steps_;
DebugCommand* last_command_;
PrintDisassembler* disasm_;
Decoder* printer_;
// Length of the biggest command line accepted by the debugger shell.
static const int kMaxDebugShellLine = 256;
};
} // namespace vixl
#endif // VIXL_A64_DEBUGGER_A64_H_
+524
Ver Arquivo
@@ -0,0 +1,524 @@
// Copyright 2013, ARM Limited
// 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 "hphp/util/vixl/a64/decoder-a64.h"
#include "hphp/util/vixl/globals.h"
#include "hphp/util/vixl/utils.h"
namespace vixl {
// Top-level instruction decode function.
void Decoder::Decode(Instruction *instr) {
switch (instr->Bits(27, 24)) {
// 1: Add/sub immediate.
// A: Logical shifted register.
// Add/sub with carry.
// Conditional compare register.
// Conditional compare immediate.
// Conditional select.
// Data processing 1 source.
// Data processing 2 source.
// B: Add/sub shifted register.
// Add/sub extended register.
// Data processing 3 source.
case 0x1:
case 0xA:
case 0xB: DecodeDataProcessing(instr); break;
// 2: Logical immediate.
// Move wide immediate.
case 0x2: DecodeLogical(instr); break;
// 3: Bitfield.
// Extract.
case 0x3: DecodeBitfieldExtract(instr); break;
// 0: PC relative addressing.
// 4: Unconditional branch immediate.
// Exception generation.
// Compare and branch immediate.
// 5: Compare and branch immediate.
// Conditional branch.
// System.
// 6,7: Unconditional branch.
// Test and branch immediate.
case 0x0:
case 0x4:
case 0x5:
case 0x6:
case 0x7: DecodeBranchSystemException(instr); break;
// 8,9: Load/store register pair post-index.
// Load register literal.
// Load/store register unscaled immediate.
// Load/store register immediate post-index.
// Load/store register immediate pre-index.
// Load/store register offset.
// Load/store exclusive.
// C,D: Load/store register pair offset.
// Load/store register pair pre-index.
// Load/store register unsigned immediate.
case 0x8:
case 0x9:
case 0xC:
case 0xD: DecodeLoadStore(instr); break;
// E: FP fixed point conversion.
// FP integer conversion.
// FP data processing 1 source.
// FP compare.
// FP immediate.
// FP data processing 2 source.
// FP conditional compare.
// FP conditional select.
// F: FP data processing 3 source.
case 0xE:
case 0xF: DecodeFP(instr); break;
}
}
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
visitors_.remove(new_visitor);
visitors_.push_front(new_visitor);
}
void Decoder::PrependVisitor(DecoderVisitor* new_visitor) {
visitors_.remove(new_visitor);
visitors_.push_back(new_visitor);
}
void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor) {
visitors_.remove(new_visitor);
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
if (*it == registered_visitor) {
visitors_.insert(it, new_visitor);
return;
}
}
// We reached the end of the list. The last element must be
// registered_visitor.
ASSERT(*it == registered_visitor);
visitors_.insert(it, new_visitor);
}
void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor) {
visitors_.remove(new_visitor);
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
if (*it == registered_visitor) {
it++;
visitors_.insert(it, new_visitor);
return;
}
}
// We reached the end of the list. The last element must be
// registered_visitor.
ASSERT(*it == registered_visitor);
visitors_.push_back(new_visitor);
}
void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
visitors_.remove(visitor);
}
void Decoder::DecodeBranchSystemException(Instruction *instr) {
ASSERT((instr->Bits(27, 24) == 0x0) ||
(instr->Bits(27, 24) == 0x4) ||
(instr->Bits(27, 24) == 0x5) ||
(instr->Bits(27, 24) == 0x6) ||
(instr->Bits(27, 24) == 0x7) );
if (instr->Bit(26) == 0) {
VisitPCRelAddressing(instr);
} else {
switch (instr->Bits(31, 29)) {
case 0:
case 4: {
VisitUnconditionalBranch(instr);
break;
}
case 1:
case 5: {
if (instr->Bit(25) == 0) {
VisitCompareBranch(instr);
} else {
VisitTestBranch(instr);
}
break;
}
case 2: {
UNALLOC(instr, SpacedBits(2, 24, 4) == 0x1);
UNALLOC(instr, Bit(24) == 0x1);
VisitConditionalBranch(instr);
break;
}
case 6: {
if (instr->Bit(25) == 0) {
if (instr->Bit(24) == 0) {
UNALLOC(instr, Bits(4, 2) != 0);
UNALLOC(instr, Mask(0x00E0001D) == 0x00200001);
UNALLOC(instr, Mask(0x00E0001E) == 0x00200002);
UNALLOC(instr, Mask(0x00E0001D) == 0x00400001);
UNALLOC(instr, Mask(0x00E0001E) == 0x00400002);
UNALLOC(instr, Mask(0x00E0001C) == 0x00600000);
UNALLOC(instr, Mask(0x00E0001C) == 0x00800000);
UNALLOC(instr, Mask(0x00E0001F) == 0x00A00000);
UNALLOC(instr, Mask(0x00C0001C) == 0x00C00000);
VisitException(instr);
} else {
UNALLOC(instr, Mask(0x0038E000) == 0x00000000);
UNALLOC(instr, Mask(0x0039E000) == 0x00002000);
UNALLOC(instr, Mask(0x003AE000) == 0x00002000);
UNALLOC(instr, Mask(0x003CE000) == 0x00042000);
UNALLOC(instr, Mask(0x003FFFC0) == 0x000320C0);
UNALLOC(instr, Mask(0x003FF100) == 0x00032100);
UNALLOC(instr, Mask(0x003FF200) == 0x00032200);
UNALLOC(instr, Mask(0x003FF400) == 0x00032400);
UNALLOC(instr, Mask(0x003FF800) == 0x00032800);
UNALLOC(instr, Mask(0x003FF0E0) == 0x00033000);
UNALLOC(instr, Mask(0x003FF0E0) == 0x003FF020);
UNALLOC(instr, Mask(0x003FF0E0) == 0x003FF060);
UNALLOC(instr, Mask(0x003FF0E0) == 0x003FF0E0);
UNALLOC(instr, Mask(0x0038F000) == 0x00005000);
UNALLOC(instr, Mask(0x0038E000) == 0x00006000);
UNALLOC(instr, SpacedBits(4, 21, 20, 19, 15) == 0x1);
UNALLOC(instr, Bits(21, 19) == 0x4);
VisitSystem(instr);
}
} else {
UNALLOC(instr, Bits(20, 16) != 0x1F);
UNALLOC(instr, Bits(15, 10) != 0);
UNALLOC(instr, Bits(4, 0) != 0);
UNALLOC(instr, Bits(24, 21) == 0x3);
UNALLOC(instr, Bits(24, 22) == 0x3);
UNALLOC(instr, Bit(24) == 0x1);
VisitUnconditionalBranchToRegister(instr);
}
break;
}
default: VisitUnknown(instr);
}
}
}
void Decoder::DecodeLoadStore(Instruction *instr) {
ASSERT((instr->Bits(27, 24) == 0x8) ||
(instr->Bits(27, 24) == 0x9) ||
(instr->Bits(27, 24) == 0xC) ||
(instr->Bits(27, 24) == 0xD) );
if (instr->Bit(24) == 0) {
if (instr->Bit(28) == 0) {
if (instr->Bit(29) == 0) {
if (instr->Bit(26) == 0) {
// TODO: VisitLoadStoreExclusive.
UNIMPLEMENTED();
} else {
// TODO: VisitLoadStoreAdvSIMD.
UNIMPLEMENTED();
}
} else {
UNALLOC(instr, Bits(31, 30) == 0x3);
UNALLOC(instr, SpacedBits(4, 26, 31, 30, 22) == 0x2);
if (instr->Bit(23) == 0) {
UNALLOC(instr, SpacedBits(4, 26, 31, 30, 22) == 0x3);
VisitLoadStorePairNonTemporal(instr);
} else {
VisitLoadStorePairPostIndex(instr);
}
}
} else {
if (instr->Bit(29) == 0) {
UNALLOC(instr, SpacedBits(3, 26, 31, 30) == 0x7);
VisitLoadLiteral(instr);
} else {
UNALLOC(instr, SpacedBits(4, 26, 23, 22, 31) == 0x7);
UNALLOC(instr, SpacedBits(3, 26, 23, 30) == 0x7);
UNALLOC(instr, SpacedBits(3, 26, 23, 31) == 0x7);
if (instr->Bit(21) == 0) {
switch (instr->Bits(11, 10)) {
case 0: {
VisitLoadStoreUnscaledOffset(instr);
break;
}
case 1: {
UNALLOC(instr, SpacedBits(5, 26, 23, 22, 31, 30) == 0xB);
VisitLoadStorePostIndex(instr);
break;
}
case 3: {
UNALLOC(instr, SpacedBits(5, 26, 23, 22, 31, 30) == 0xB);
VisitLoadStorePreIndex(instr);
break;
}
default: VisitUnknown(instr);
}
} else {
UNALLOC(instr, Bit(14) == 0);
VisitLoadStoreRegisterOffset(instr);
}
}
}
} else {
if (instr->Bit(28) == 0) {
UNALLOC(instr, SpacedBits(4, 26, 31, 30, 22) == 0x2);
UNALLOC(instr, Bits(31, 30) == 0x3);
if (instr->Bit(23) == 0) {
VisitLoadStorePairOffset(instr);
} else {
VisitLoadStorePairPreIndex(instr);
}
} else {
UNALLOC(instr, SpacedBits(4, 26, 23, 22, 31) == 0x7);
UNALLOC(instr, SpacedBits(3, 26, 23, 30) == 0x7);
UNALLOC(instr, SpacedBits(3, 26, 23, 31) == 0x7);
VisitLoadStoreUnsignedOffset(instr);
}
}
}
void Decoder::DecodeLogical(Instruction *instr) {
ASSERT(instr->Bits(27, 24) == 0x2);
UNALLOC(instr, SpacedBits(2, 31, 22) == 0x1);
if (instr->Bit(23) == 0) {
VisitLogicalImmediate(instr);
} else {
UNALLOC(instr, Bits(30, 29) == 0x1);
VisitMoveWideImmediate(instr);
}
}
void Decoder::DecodeBitfieldExtract(Instruction *instr) {
ASSERT(instr->Bits(27, 24) == 0x3);
UNALLOC(instr, SpacedBits(2, 31, 22) == 0x2);
UNALLOC(instr, SpacedBits(2, 31, 22) == 0x1);
UNALLOC(instr, SpacedBits(2, 31, 15) == 0x1);
if (instr->Bit(23) == 0) {
UNALLOC(instr, SpacedBits(2, 31, 21) == 0x1);
UNALLOC(instr, Bits(30, 29) == 0x3);
VisitBitfield(instr);
} else {
UNALLOC(instr, SpacedBits(3, 30, 29, 21) == 0x1);
UNALLOC(instr, Bits(30, 29) != 0);
VisitExtract(instr);
}
}
void Decoder::DecodeDataProcessing(Instruction *instr) {
ASSERT((instr->Bits(27, 24) == 0x1) ||
(instr->Bits(27, 24) == 0xA) ||
(instr->Bits(27, 24) == 0xB) );
if (instr->Bit(27) == 0) {
UNALLOC(instr, Bit(23) == 0x1);
VisitAddSubImmediate(instr);
} else if (instr->Bit(24) == 0) {
if (instr->Bit(28) == 0) {
UNALLOC(instr, SpacedBits(2, 31, 15) == 0x1);
VisitLogicalShifted(instr);
} else {
switch (instr->Bits(23, 21)) {
case 0: {
UNALLOC(instr, Bits(15, 10) != 0);
VisitAddSubWithCarry(instr);
break;
}
case 2: {
UNALLOC(instr, SpacedBits(2, 10, 4) != 0);
UNALLOC(instr, Bit(29) == 0x0);
if (instr->Bit(11) == 0) {
VisitConditionalCompareRegister(instr);
} else {
VisitConditionalCompareImmediate(instr);
}
break;
}
case 4: {
UNALLOC(instr, SpacedBits(2, 11, 29) != 0);
VisitConditionalSelect(instr);
break;
}
case 6: {
UNALLOC(instr, Bit(29) == 1);
UNALLOC(instr, Bits(15, 14) != 0);
if (instr->Bit(30) == 0) {
UNALLOC(instr, Bits(15, 11) == 0);
UNALLOC(instr, Bits(15, 12) == 0x1);
UNALLOC(instr, Bits(15, 12) == 0x3);
VisitDataProcessing2Source(instr);
} else {
UNALLOC(instr, Bit(13) == 1);
UNALLOC(instr, Bits(20, 16) != 0);
UNALLOC(instr, Mask(0xA01FFC00) == 0x00000C00);
UNALLOC(instr, Mask(0x201FF800) == 0x00001800);
VisitDataProcessing1Source(instr);
}
break;
}
default: VisitUnknown(instr);
}
}
} else {
if (instr->Bit(28) == 0) {
if (instr->Bit(21) == 0) {
UNALLOC(instr, Bits(23, 22) == 0x3);
UNALLOC(instr, SpacedBits(2, 31, 15) == 0x1);
VisitAddSubShifted(instr);
} else {
UNALLOC(instr, SpacedBits(2, 23, 22) != 0);
UNALLOC(instr, SpacedBits(2, 12, 10) == 0x3);
UNALLOC(instr, Bits(12, 11) == 0x3);
VisitAddSubExtended(instr);
}
} else {
UNALLOC(instr, Mask(0xE0E08000) == 0x00200000);
UNALLOC(instr, Mask(0xE0E08000) == 0x00208000);
UNALLOC(instr, Mask(0xE0E08000) == 0x00400000);
UNALLOC(instr, Mask(0x60E08000) == 0x00408000);
UNALLOC(instr, SpacedBits(5, 30, 29, 23, 22, 21) == 0x3);
UNALLOC(instr, SpacedBits(5, 30, 29, 23, 22, 21) == 0x4);
UNALLOC(instr, Mask(0xE0E08000) == 0x00A00000);
UNALLOC(instr, Mask(0xE0E08000) == 0x00A08000);
UNALLOC(instr, Mask(0xE0E08000) == 0x00C00000);
UNALLOC(instr, Mask(0x60E08000) == 0x00C08000);
UNALLOC(instr, SpacedBits(5, 30, 29, 23, 22, 21) == 0x7);
UNALLOC(instr, Bits(30, 29) == 0x1);
UNALLOC(instr, Bit(30) == 0x1);
VisitDataProcessing3Source(instr);
}
}
}
void Decoder::DecodeFP(Instruction *instr) {
ASSERT((instr->Bits(27, 24) == 0xE) ||
(instr->Bits(27, 24) == 0xF) );
UNALLOC(instr, Bit(29) == 0x1);
if (instr->Bit(24) == 0) {
if (instr->Bit(21) == 0) {
UNALLOC(instr, Bit(23) == 1);
UNALLOC(instr, SpacedBits(2, 31, 15) == 0);
UNALLOC(instr, SpacedBits(3, 18, 17, 19) == 0);
UNALLOC(instr, SpacedBits(3, 18, 17, 20) == 0);
UNALLOC(instr, SpacedBits(3, 18, 17, 19) == 0x3);
UNALLOC(instr, SpacedBits(3, 18, 17, 20) == 0x3);
UNALLOC(instr, Bit(18) == 1);
VisitFPFixedPointConvert(instr);
} else {
if (instr->Bits(15, 10) == 0) {
UNALLOC(instr, SpacedBits(3, 18, 17, 19) == 0x3);
UNALLOC(instr, SpacedBits(3, 18, 17, 20) == 0x3);
UNALLOC(instr, SpacedBits(3, 18, 17, 19) == 0x5);
UNALLOC(instr, SpacedBits(3, 18, 17, 20) == 0x5);
UNALLOC(instr, Mask(0xA0C60000) == 0x80060000);
UNALLOC(instr, Mask(0xA0CE0000) == 0x000E0000);
UNALLOC(instr, Mask(0xA0D60000) == 0x00160000);
UNALLOC(instr, Mask(0xA0C60000) == 0x00460000);
UNALLOC(instr, Mask(0xA0CE0000) == 0x804E0000);
UNALLOC(instr, Mask(0xA0D60000) == 0x80560000);
UNALLOC(instr, SpacedBits(4, 23, 22, 18, 29) == 0x8);
UNALLOC(instr, SpacedBits(5, 23, 22, 18, 17, 29) == 0x14);
UNALLOC(instr, Mask(0xA0C60000) == 0x00860000);
UNALLOC(instr, Mask(0xA0CE0000) == 0x80860000);
UNALLOC(instr, Mask(0xA0D60000) == 0x80960000);
UNALLOC(instr, Bits(23, 22) == 0x3);
VisitFPIntegerConvert(instr);
} else if (instr->Bits(14, 10) == 16) {
UNALLOC(instr, SpacedBits(3, 31, 19, 20) != 0);
UNALLOC(instr, Mask(0xA0DF8000) == 0x00020000);
UNALLOC(instr, Mask(0xA0DF8000) == 0x00030000);
UNALLOC(instr, Mask(0xA0DF8000) == 0x00068000);
UNALLOC(instr, Mask(0xA0DF8000) == 0x00428000);
UNALLOC(instr, Mask(0xA0DF8000) == 0x00430000);
UNALLOC(instr, Mask(0xA0DF8000) == 0x00468000);
UNALLOC(instr, Mask(0xA0D80000) == 0x00800000);
UNALLOC(instr, Mask(0xA0DE0000) == 0x00C00000);
UNALLOC(instr, Mask(0xA0DF0000) == 0x00C30000);
UNALLOC(instr, Mask(0xA0DC0000) == 0x00C40000);
VisitFPDataProcessing1Source(instr);
} else if (instr->Bits(13, 10) == 8) {
UNALLOC(instr, SpacedBits(2, 31, 23) != 0);
UNALLOC(instr, Bits(2, 0) != 0);
UNALLOC(instr, Bits(15, 14) != 0);
VisitFPCompare(instr);
} else if (instr->Bits(12, 10) == 4) {
UNALLOC(instr, Bits(9, 5) != 0);
UNALLOC(instr, SpacedBits(2, 31, 23) != 0);
VisitFPImmediate(instr);
} else {
UNALLOC(instr, SpacedBits(2, 31, 23) != 0);
switch (instr->Bits(11, 10)) {
case 1: {
VisitFPConditionalCompare(instr);
break;
}
case 2: {
UNALLOC(instr, SpacedBits(2, 15, 12) == 0x3);
UNALLOC(instr, SpacedBits(2, 15, 13) == 0x3);
UNALLOC(instr, Bits(15, 14) == 0x3);
VisitFPDataProcessing2Source(instr);
break;
}
case 3: {
VisitFPConditionalSelect(instr);
break;
}
default: VisitUnknown(instr);
}
}
}
} else {
UNALLOC(instr, Bit(31) == 0x1);
UNALLOC(instr, Bit(23) == 0x1);
VisitFPDataProcessing3Source(instr);
}
}
#define DEFINE_VISITOR_CALLERS(A) \
void Decoder::Visit##A(Instruction *instr) { \
ASSERT(instr->Mask(A##FMask) == A##Fixed); \
std::list<DecoderVisitor*>::iterator it; \
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
(*it)->Visit##A(instr); \
} \
}
VISITOR_LIST(DEFINE_VISITOR_CALLERS)
#undef DEFINE_VISITOR_CALLERS
} // namespace vixl
+188
Ver Arquivo
@@ -0,0 +1,188 @@
// Copyright 2013, ARM Limited
// 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_A64_DECODER_A64_H_
#define VIXL_A64_DECODER_A64_H_
#include <list>
#include "hphp/util/vixl/globals.h"
#include "hphp/util/vixl/a64/instructions-a64.h"
#ifdef DEBUG
#define UNALLOC(I, P) \
if (I->P) { \
printf("Instruction 0x%08" PRIx32 " uses an unallocated encoding.\n", \
I->InstructionBits()); \
} \
ASSERT(!(I->P));
#else
#define UNALLOC(I, P) ((void) 0)
#endif
// List macro containing all visitors needed by the decoder class.
#define VISITOR_LIST(V) \
V(PCRelAddressing) \
V(AddSubImmediate) \
V(LogicalImmediate) \
V(MoveWideImmediate) \
V(Bitfield) \
V(Extract) \
V(UnconditionalBranch) \
V(UnconditionalBranchToRegister) \
V(CompareBranch) \
V(TestBranch) \
V(ConditionalBranch) \
V(System) \
V(Exception) \
V(LoadStorePairPostIndex) \
V(LoadStorePairOffset) \
V(LoadStorePairPreIndex) \
V(LoadStorePairNonTemporal) \
V(LoadLiteral) \
V(LoadStoreUnscaledOffset) \
V(LoadStorePostIndex) \
V(LoadStorePreIndex) \
V(LoadStoreRegisterOffset) \
V(LoadStoreUnsignedOffset) \
V(LogicalShifted) \
V(AddSubShifted) \
V(AddSubExtended) \
V(AddSubWithCarry) \
V(ConditionalCompareRegister) \
V(ConditionalCompareImmediate) \
V(ConditionalSelect) \
V(DataProcessing1Source) \
V(DataProcessing2Source) \
V(DataProcessing3Source) \
V(FPCompare) \
V(FPConditionalCompare) \
V(FPConditionalSelect) \
V(FPImmediate) \
V(FPDataProcessing1Source) \
V(FPDataProcessing2Source) \
V(FPDataProcessing3Source) \
V(FPIntegerConvert) \
V(FPFixedPointConvert) \
V(Unknown)
namespace vixl {
// The Visitor interface. Disassembler and simulator (and other tools)
// must provide implementations for all of these functions.
class DecoderVisitor {
public:
#define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
VISITOR_LIST(DECLARE)
#undef DECLARE
virtual ~DecoderVisitor() {}
private:
// Visitors are registered in a list.
std::list<DecoderVisitor*> visitors_;
friend class Decoder;
};
class Decoder: public DecoderVisitor {
public:
Decoder() {}
// Top-level instruction decoder function. Decodes an instruction and calls
// the visitor functions registered with the Decoder class.
void Decode(Instruction *instr);
// Register a new visitor class with the decoder.
// Decode() will call the corresponding visitor method from all registered
// visitor classes when decoding reaches the leaf node of the instruction
// decode tree.
// Visitors are called in the order.
// A visitor can only be registered once.
// Registering an already registered visitor will update its position.
//
// d.AppendVisitor(V1);
// d.AppendVisitor(V2);
// d.PrependVisitor(V2); // Move V2 at the start of the list.
// d.InsertVisitorBefore(V3, V2);
// d.AppendVisitor(V4);
// d.AppendVisitor(V4); // No effect.
//
// d.Decode(i);
//
// will call in order visitor methods in V3, V2, V1, V4.
void AppendVisitor(DecoderVisitor* visitor);
void PrependVisitor(DecoderVisitor* visitor);
void InsertVisitorBefore(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor);
void InsertVisitorAfter(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor);
// Remove a previously registered visitor class from the list of visitors
// stored by the decoder.
void RemoveVisitor(DecoderVisitor *visitor);
#define DECLARE(A) void Visit##A(Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
private:
// Decode the branch, system command, and exception generation parts of
// the instruction tree, and call the corresponding visitors.
// On entry, instruction bits 27:24 = {0x0, 0x4, 0x5, 0x6, 0x7}.
void DecodeBranchSystemException(Instruction *instr);
// Decode the load and store parts of the instruction tree, and call
// the corresponding visitors.
// On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
void DecodeLoadStore(Instruction *instr);
// Decode the logical immediate and move wide immediate parts of the
// instruction tree, and call the corresponding visitors.
// On entry, instruction bits 27:24 = 0x2.
void DecodeLogical(Instruction *instr);
// Decode the bitfield and extraction parts of the instruction tree,
// and call the corresponding visitors.
// On entry, instruction bits 27:24 = 0x3.
void DecodeBitfieldExtract(Instruction *instr);
// Decode the data processing parts of the instruction tree, and call the
// corresponding visitors.
// On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
void DecodeDataProcessing(Instruction *instr);
// Decode the floating point parts of the instruction tree, and call the
// corresponding visitors.
// On entry, instruction bits 27:24 = {0xE, 0xF}.
void DecodeFP(Instruction *instr);
};
} // namespace vixl
#endif // VIXL_A64_DECODER_A64_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+109
Ver Arquivo
@@ -0,0 +1,109 @@
// Copyright 2013, ARM Limited
// 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_A64_DISASM_A64_H
#define VIXL_A64_DISASM_A64_H
#include "hphp/util/vixl/globals.h"
#include "hphp/util/vixl/utils.h"
#include "instructions-a64.h"
#include "decoder-a64.h"
namespace vixl {
class Disassembler: public DecoderVisitor {
public:
Disassembler();
Disassembler(char* text_buffer, int buffer_size);
virtual ~Disassembler();
char* GetOutput();
// Declare all Visitor functions.
#define DECLARE(A) void Visit##A(Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
protected:
virtual void ProcessOutput(Instruction* instr);
private:
void Format(Instruction* instr, const char* mnemonic, const char* format);
void Substitute(Instruction* instr, const char* string);
int SubstituteField(Instruction* instr, const char* format);
int SubstituteRegisterField(Instruction* instr, const char* format);
int SubstituteImmediateField(Instruction* instr, const char* format);
int SubstituteLiteralField(Instruction* instr, const char* format);
int SubstituteBitfieldImmediateField(Instruction* instr, const char* format);
int SubstituteShiftField(Instruction* instr, const char* format);
int SubstituteExtendField(Instruction* instr, const char* format);
int SubstituteConditionField(Instruction* instr, const char* format);
int SubstitutePCRelAddressField(Instruction* instr, const char* format);
int SubstituteBranchTargetField(Instruction* instr, const char* format);
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
int SubstitutePrefetchField(Instruction* instr, const char* format);
inline bool RdIsZROrSP(Instruction* instr) const {
return (instr->Rd() == kZeroRegCode);
}
inline bool RnIsZROrSP(Instruction* instr) const {
return (instr->Rn() == kZeroRegCode);
}
inline bool RmIsZROrSP(Instruction* instr) const {
return (instr->Rm() == kZeroRegCode);
}
inline bool RaIsZROrSP(Instruction* instr) const {
return (instr->Ra() == kZeroRegCode);
}
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
void ResetOutput();
void AppendToOutput(const char* string, ...);
char* buffer_;
uint32_t buffer_pos_;
uint32_t buffer_size_;
bool own_buffer_;
};
class PrintDisassembler: public Disassembler {
public:
explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
~PrintDisassembler() { }
protected:
virtual void ProcessOutput(Instruction* instr);
private:
FILE *stream_;
};
} // namespace vixl
#endif // VIXL_A64_DISASM_A64_H
+242
Ver Arquivo
@@ -0,0 +1,242 @@
// Copyright 2013, ARM Limited
// 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 "hphp/util/vixl/a64/instructions-a64.h"
#include "hphp/util/vixl/a64/assembler-a64.h"
namespace vixl {
#ifdef DEBUG
uint32_t Instruction::SpacedBits(int num_bits, ...) const {
va_list bit_list;
va_start(bit_list, num_bits);
int32_t result = 0;
for (int i = 0; i < num_bits; i++) {
result = (result << 1) | Bit(va_arg(bit_list, int));
}
va_end(bit_list);
return result;
}
#endif
static uint64_t RotateRight(uint64_t value,
unsigned int rotate,
unsigned int width) {
ASSERT(width <= 64);
rotate &= 63;
return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
(value >> rotate);
}
static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
uint64_t value,
unsigned width) {
ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
(width == 32));
ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
uint64_t result = value & ((1UL << width) - 1UL);
for (unsigned i = width; i < reg_size; i *= 2) {
result |= (result << i);
}
return result;
}
uint64_t Instruction::ImmLogical() {
unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize;
int64_t n = BitN();
int64_t imm_s = ImmSetBits();
int64_t imm_r = ImmRotate();
// An integer is constructed from the n, imm_s and imm_r bits according to
// the following table:
//
// N imms immr size S R
// 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
// 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
// 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
// 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
// 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
// 0 11110s xxxxxr 2 UInt(s) UInt(r)
// (s bits must not be all set)
//
// A pattern is constructed of size bits, where the least significant S+1
// bits are set. The pattern is rotated right by R, and repeated across a
// 32 or 64-bit value, depending on destination register width.
//
if (n == 1) {
ASSERT(imm_s != 0x3F);
uint64_t bits = (1UL << (imm_s + 1)) - 1;
return RotateRight(bits, imm_r, 64);
} else {
ASSERT((imm_s >> 1) != 0x1F);
for (int width = 0x20; width >= 0x2; width >>= 1) {
if ((imm_s & width) == 0) {
int mask = width - 1;
ASSERT((imm_s & mask) != mask);
uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
return RepeatBitsAcrossReg(reg_size,
RotateRight(bits, imm_r & mask, width),
width);
}
}
}
UNREACHABLE();
return 0;
}
float Instruction::ImmFP32() {
// ImmFP: abcdefgh (8 bits)
// Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
// where B is b ^ 1
uint32_t bits = ImmFP();
uint32_t bit7 = (bits >> 7) & 0x1;
uint32_t bit6 = (bits >> 6) & 0x1;
uint32_t bit5_to_0 = bits & 0x3f;
uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19);
return rawbits_to_float(result);
}
double Instruction::ImmFP64() {
// ImmFP: abcdefgh (8 bits)
// Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
// 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
// where B is b ^ 1
uint32_t bits = ImmFP();
uint64_t bit7 = (bits >> 7) & 0x1;
uint64_t bit6 = (bits >> 6) & 0x1;
uint64_t bit5_to_0 = bits & 0x3f;
uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48);
return rawbits_to_double(result);
}
LSDataSize CalcLSPairDataSize(LoadStorePairOp op) {
switch (op) {
case STP_x:
case LDP_x:
case STP_d:
case LDP_d: return LSDoubleWord;
default: return LSWord;
}
}
Instruction* Instruction::ImmPCOffsetTarget() {
ptrdiff_t offset;
if (IsPCRelAddressing()) {
// PC-relative addressing. Only ADR is supported.
offset = ImmPCRel();
} else {
// All PC-relative branches.
ASSERT(BranchType() != UnknownBranchType);
// Relative branch offsets are instruction-size-aligned.
offset = ImmBranch() << kInstructionSizeLog2;
}
return this + offset;
}
inline int Instruction::ImmBranch() const {
switch (BranchType()) {
case CondBranchType: return ImmCondBranch();
case UncondBranchType: return ImmUncondBranch();
case CompareBranchType: return ImmCmpBranch();
case TestBranchType: return ImmTestBranch();
default: UNREACHABLE();
}
return 0;
}
void Instruction::SetImmPCOffsetTarget(Instruction* target) {
if (IsPCRelAddressing()) {
SetPCRelImmTarget(target);
} else {
SetBranchImmTarget(target);
}
}
void Instruction::SetPCRelImmTarget(Instruction* target) {
// ADRP is not supported, so 'this' must point to an ADR instruction.
ASSERT(Mask(PCRelAddressingMask) == ADR);
Instr imm = Assembler::ImmPCRelAddress(target - this);
SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
}
void Instruction::SetBranchImmTarget(Instruction* target) {
ASSERT(((target - this) & 3) == 0);
Instr branch_imm = 0;
uint32_t imm_mask = 0;
int offset = (target - this) >> kInstructionSizeLog2;
switch (BranchType()) {
case CondBranchType: {
branch_imm = Assembler::ImmCondBranch(offset);
imm_mask = ImmCondBranch_mask;
break;
}
case UncondBranchType: {
branch_imm = Assembler::ImmUncondBranch(offset);
imm_mask = ImmUncondBranch_mask;
break;
}
case CompareBranchType: {
branch_imm = Assembler::ImmCmpBranch(offset);
imm_mask = ImmCmpBranch_mask;
break;
}
case TestBranchType: {
branch_imm = Assembler::ImmTestBranch(offset);
imm_mask = ImmTestBranch_mask;
break;
}
default: UNREACHABLE();
}
SetInstructionBits(Mask(~imm_mask) | branch_imm);
}
void Instruction::SetImmLLiteral(Instruction* source) {
ASSERT(((source - this) & 3) == 0);
int offset = (source - this) >> kLiteralEntrySizeLog2;
Instr imm = Assembler::ImmLLiteral(offset);
Instr mask = ImmLLiteral_mask;
SetInstructionBits(Mask(~mask) | imm);
}
} // namespace vixl
+330
Ver Arquivo
@@ -0,0 +1,330 @@
// Copyright 2013, ARM Limited
// 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_A64_INSTRUCTIONS_A64_H_
#define VIXL_A64_INSTRUCTIONS_A64_H_
#include "hphp/util/vixl/globals.h"
#include "hphp/util/vixl/utils.h"
#include "hphp/util/vixl/a64/constants-a64.h"
namespace vixl {
// ISA constants. --------------------------------------------------------------
typedef uint32_t Instr;
const unsigned kInstructionSize = 4;
const unsigned kInstructionSizeLog2 = 2;
const unsigned kLiteralEntrySize = 4;
const unsigned kLiteralEntrySizeLog2 = 2;
const unsigned kMaxLoadLiteralRange = 1 * MBytes;
const unsigned kWRegSize = 32;
const unsigned kWRegSizeLog2 = 5;
const unsigned kWRegSizeInBytes = kWRegSize / 8;
const unsigned kXRegSize = 64;
const unsigned kXRegSizeLog2 = 6;
const unsigned kXRegSizeInBytes = kXRegSize / 8;
const unsigned kSRegSize = 32;
const unsigned kSRegSizeLog2 = 5;
const unsigned kSRegSizeInBytes = kSRegSize / 8;
const unsigned kDRegSize = 64;
const unsigned kDRegSizeLog2 = 6;
const unsigned kDRegSizeInBytes = kDRegSize / 8;
const int64_t kWRegMask = 0x00000000ffffffffL;
const int64_t kXRegMask = 0xffffffffffffffffL;
const int64_t kSRegMask = 0x00000000ffffffffL;
const int64_t kDRegMask = 0xffffffffffffffffL;
const int64_t kXSignMask = 0x1L << 63;
const int64_t kWSignMask = 0x1L << 31;
const int64_t kByteMask = 0xffL;
const int64_t kHalfWordMask = 0xffffL;
const int64_t kWordMask = 0xffffffffL;
const uint64_t kXMaxUInt = 0xffffffffffffffffUL;
const uint64_t kWMaxUInt = 0xffffffffUL;
const int64_t kXMaxInt = 0x7fffffffffffffffL;
const int64_t kXMinInt = 0x8000000000000000L;
const int32_t kWMaxInt = 0x7fffffff;
const int32_t kWMinInt = 0x80000000;
const unsigned kLinkRegCode = 30;
const unsigned kZeroRegCode = 31;
const unsigned kSPRegInternalCode = 63;
const unsigned kRegCodeMask = 0x1f;
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
const double kFP64PositiveInfinity = rawbits_to_double(0x7ff0000000000000UL);
const double kFP64NegativeInfinity = rawbits_to_double(0xfff0000000000000UL);
// This value is a signalling NaN as both a double and as a float (taking the
// least-significant word).
const double kFP64SignallingNaN = rawbits_to_double(0x7ff000007f800001);
// A similar value, but as a quiet NaN.
const double kFP64QuietNaN = rawbits_to_double(0x7ff800007fc00001);
enum LSDataSize {
LSByte = 0,
LSHalfword = 1,
LSWord = 2,
LSDoubleWord = 3
};
LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
enum ImmBranchType {
UnknownBranchType = 0,
CondBranchType = 1,
UncondBranchType = 2,
CompareBranchType = 3,
TestBranchType = 4
};
enum AddrMode {
Offset,
PreIndex,
PostIndex
};
enum FPRounding {
FPTieEven,
FPPositiveInfinity,
FPNegativeInfinity,
FPZero,
FPTieAway
};
enum Reg31Mode {
Reg31IsStackPointer,
Reg31IsZeroRegister
};
// Instructions. ---------------------------------------------------------------
class Instruction {
public:
inline Instr InstructionBits() const {
return *(reinterpret_cast<const Instr*>(this));
}
inline void SetInstructionBits(Instr new_instr) {
*(reinterpret_cast<Instr*>(this)) = new_instr;
}
inline int Bit(int pos) const {
return (InstructionBits() >> pos) & 1;
}
inline uint32_t Bits(int msb, int lsb) const {
return unsigned_bitextract_32(msb, lsb, InstructionBits());
}
inline int32_t SignedBits(int msb, int lsb) const {
int32_t bits = *(reinterpret_cast<const int32_t*>(this));
return signed_bitextract_32(msb, lsb, bits);
}
#ifdef DEBUG
uint32_t SpacedBits(int num_bits, ...) const;
#endif
inline Instr Mask(uint32_t mask) const {
return InstructionBits() & mask;
}
#define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
inline int64_t Name() const { return Func(HighBit, LowBit); }
FIELDS_LIST(DEFINE_GETTER)
#undef DEFINE_GETTER
// ImmPCRel is a compound field (not present in FIELDS_LIST), formed from
// ImmPCRelLo and ImmPCRelHi.
int ImmPCRel() const {
int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
int const width = ImmPCRelLo_width + ImmPCRelHi_width;
return signed_bitextract_32(width-1, 0, offset);
}
uint64_t ImmLogical();
float ImmFP32();
double ImmFP64();
inline LSDataSize SizeLSPair() const {
return CalcLSPairDataSize(
static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
}
// Helpers.
inline bool IsCondBranchImm() const {
return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
}
inline bool IsUncondBranchImm() const {
return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
}
inline bool IsCompareBranch() const {
return Mask(CompareBranchFMask) == CompareBranchFixed;
}
inline bool IsTestBranch() const {
return Mask(TestBranchFMask) == TestBranchFixed;
}
inline bool IsPCRelAddressing() const {
return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
}
inline bool IsLogicalImmediate() const {
return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
}
inline bool IsAddSubImmediate() const {
return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
}
inline bool IsAddSubExtended() const {
return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
}
inline bool IsLoadOrStore() const {
return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
}
// Indicate whether Rd can be the stack pointer or the zero register. This
// does not check that the instruction actually has an Rd field.
inline Reg31Mode RdMode() const {
// The following instructions use sp or wsp as Rd:
// Add/sub (immediate) when not setting the flags.
// Add/sub (extended) when not setting the flags.
// Logical (immediate) when not setting the flags.
// Otherwise, r31 is the zero register.
if (IsAddSubImmediate() || IsAddSubExtended()) {
if (Mask(AddSubSetFlagsBit)) {
return Reg31IsZeroRegister;
} else {
return Reg31IsStackPointer;
}
}
if (IsLogicalImmediate()) {
// Of the logical (immediate) instructions, only ANDS (and its aliases)
// can set the flags. The others can all write into sp.
// Note that some logical operations are not available to
// immediate-operand instructions, so we have to combine two masks here.
if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
return Reg31IsZeroRegister;
} else {
return Reg31IsStackPointer;
}
}
return Reg31IsZeroRegister;
}
// Indicate whether Rn can be the stack pointer or the zero register. This
// does not check that the instruction actually has an Rn field.
inline Reg31Mode RnMode() const {
// The following instructions use sp or wsp as Rn:
// All loads and stores.
// Add/sub (immediate).
// Add/sub (extended).
// Otherwise, r31 is the zero register.
if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
return Reg31IsStackPointer;
}
return Reg31IsZeroRegister;
}
inline ImmBranchType BranchType() const {
if (IsCondBranchImm()) {
return CondBranchType;
} else if (IsUncondBranchImm()) {
return UncondBranchType;
} else if (IsCompareBranch()) {
return CompareBranchType;
} else if (IsTestBranch()) {
return TestBranchType;
} else {
return UnknownBranchType;
}
}
// Find the target of this instruction. 'this' may be a branch or a
// PC-relative addressing instruction.
Instruction* ImmPCOffsetTarget();
// Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
// a PC-relative addressing instruction.
void SetImmPCOffsetTarget(Instruction* target);
// Patch a literal load instruction to load from 'source'.
void SetImmLLiteral(Instruction* source);
inline uint8_t* LiteralAddress() {
int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
return reinterpret_cast<uint8_t*>(this) + offset;
}
inline uint32_t Literal32() {
uint32_t literal;
memcpy(&literal, LiteralAddress(), sizeof(literal));
return literal;
}
inline uint64_t Literal64() {
uint64_t literal;
memcpy(&literal, LiteralAddress(), sizeof(literal));
return literal;
}
inline float LiteralFP32() {
return rawbits_to_float(Literal32());
}
inline double LiteralFP64() {
return rawbits_to_double(Literal64());
}
inline Instruction* NextInstruction() {
return this + kInstructionSize;
}
inline Instruction* InstructionAtOffset(int64_t offset) {
ASSERT(IsWordAligned(this + offset));
return this + offset;
}
template<typename T> static inline Instruction* Cast(T src) {
return reinterpret_cast<Instruction*>(src);
}
private:
inline int ImmBranch() const;
void SetPCRelImmTarget(Instruction* target);
void SetBranchImmTarget(Instruction* target);
};
} // namespace vixl
#endif // VIXL_A64_INSTRUCTIONS_A64_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+476
Ver Arquivo
@@ -0,0 +1,476 @@
// Copyright 2013, ARM Limited
// 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_A64_SIMULATOR_A64_H_
#define VIXL_A64_SIMULATOR_A64_H_
#include "hphp/util/vixl/globals.h"
#include "hphp/util/vixl/utils.h"
#include "hphp/util/vixl/a64/instructions-a64.h"
#include "hphp/util/vixl/a64/assembler-a64.h"
#include "hphp/util/vixl/a64/disasm-a64.h"
namespace vixl {
enum ReverseByteMode {
Reverse16 = 0,
Reverse32 = 1,
Reverse64 = 2
};
// Printf. See debugger-a64.h for more information on pseudo instructions.
// - type: CPURegister::RegisterType stored as a uint32_t.
//
// Simulate a call to printf.
//
// Floating-point and integer arguments are passed in separate sets of
// registers in AAPCS64 (even for varargs functions), so it is not possible to
// determine the type of location of each argument without some information
// about the values that were passed in. This information could be retrieved
// from the printf format string, but the format string is not trivial to
// parse so we encode the relevant information with the HLT instruction under
// the type argument. Therefore the interface is:
// x0: The format string
// x1-x7: Optional arguments, if type == CPURegister::kRegister
// d0-d7: Optional arguments, if type == CPURegister::kFPRegister
const Instr kPrintfOpcode = 0xdeb1;
const unsigned kPrintfTypeOffset = 1 * kInstructionSize;
const unsigned kPrintfLength = 2 * kInstructionSize;
class Simulator : public DecoderVisitor {
public:
explicit Simulator(Decoder* decoder, FILE* stream = stdout);
~Simulator();
void ResetState();
// TODO: We assume little endianness, and the way in which the members of this
// union overlay. Add tests to ensure this, or fix accessors to no longer
// require this assumption.
union SimRegister {
int64_t x;
int32_t w;
};
union SimFPRegister {
double d;
float s;
};
// Run the simulator.
virtual void Run();
void RunFrom(Instruction* first);
// Simulation helpers.
inline Instruction* pc() { return pc_; }
inline void set_pc(Instruction* new_pc) {
pc_ = new_pc;
pc_modified_ = true;
}
inline void increment_pc() {
if (!pc_modified_) {
pc_ = pc_->NextInstruction();
}
pc_modified_ = false;
}
inline void ExecuteInstruction() {
// The program counter should always be aligned.
ASSERT(IsWordAligned(pc_));
decoder_->Decode(pc_);
increment_pc();
}
// Declare all Visitor functions.
#define DECLARE(A) void Visit##A(Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
// Register accessors.
inline int32_t wreg(unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
ASSERT(code < kNumberOfRegisters);
if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
return 0;
}
return registers_[code].w;
}
inline int64_t xreg(unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
ASSERT(code < kNumberOfRegisters);
if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
return 0;
}
return registers_[code].x;
}
inline int64_t reg(unsigned size,
unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
switch (size) {
case kWRegSize: return wreg(code, r31mode) & kWRegMask;
case kXRegSize: return xreg(code, r31mode);
default:
UNREACHABLE();
return 0;
}
}
inline void set_wreg(unsigned code, int32_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
ASSERT(code < kNumberOfRegisters);
if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
return;
}
registers_[code].x = 0; // First clear the register top bits.
registers_[code].w = value;
}
inline void set_xreg(unsigned code, int64_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
ASSERT(code < kNumberOfRegisters);
if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
return;
}
registers_[code].x = value;
}
inline void set_reg(unsigned size, unsigned code, int64_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
switch (size) {
case kWRegSize:
return set_wreg(code, static_cast<int32_t>(value & 0xffffffff),
r31mode);
case kXRegSize:
return set_xreg(code, value, r31mode);
default:
UNREACHABLE();
break;
}
}
#define REG_ACCESSORS(N) \
inline int32_t w##N() { return wreg(N); } \
inline int64_t x##N() { return xreg(N); } \
inline void set_w##N(int32_t val) { set_wreg(N, val); } \
inline void set_x##N(int64_t val) { set_xreg(N, val); }
REGISTER_CODE_LIST(REG_ACCESSORS)
#undef REG_ACCESSORS
// Aliases.
#define REG_ALIAS_ACCESSORS(N, wname, xname) \
inline int32_t wname() { return wreg(N); } \
inline int64_t xname() { return xreg(N); } \
inline void set_##wname(int32_t val) { set_wreg(N, val); } \
inline void set_##xname(int64_t val) { set_xreg(N, val); }
REG_ALIAS_ACCESSORS(30, wlr, lr);
#undef REG_ALIAS_ACCESSORS
// The stack is a special case in aarch64.
inline int32_t wsp() { return wreg(31, Reg31IsStackPointer); }
inline int64_t sp() { return xreg(31, Reg31IsStackPointer); }
inline void set_wsp(int32_t val) {
set_wreg(31, val, Reg31IsStackPointer);
}
inline void set_sp(int64_t val) {
set_xreg(31, val, Reg31IsStackPointer);
}
// FPRegister accessors.
inline float sreg(unsigned code) const {
ASSERT(code < kNumberOfFPRegisters);
return fpregisters_[code].s;
}
inline uint32_t sreg_bits(unsigned code) const {
return float_to_rawbits(sreg(code));
}
inline double dreg(unsigned code) const {
ASSERT(code < kNumberOfFPRegisters);
return fpregisters_[code].d;
}
inline uint64_t dreg_bits(unsigned code) const {
return double_to_rawbits(dreg(code));
}
inline double fpreg(unsigned size, unsigned code) const {
switch (size) {
case kSRegSize: return sreg(code);
case kDRegSize: return dreg(code);
default: {
UNREACHABLE();
return 0.0;
}
}
}
inline void set_sreg(unsigned code, float val) {
ASSERT(code < kNumberOfFPRegisters);
// Ensure that the upper word is set to 0.
set_dreg_bits(code, 0);
fpregisters_[code].s = val;
}
inline void set_sreg_bits(unsigned code, uint32_t rawbits) {
ASSERT(code < kNumberOfFPRegisters);
// Ensure that the upper word is set to 0.
set_dreg_bits(code, 0);
set_sreg(code, rawbits_to_float(rawbits));
}
inline void set_dreg(unsigned code, double val) {
ASSERT(code < kNumberOfFPRegisters);
fpregisters_[code].d = val;
}
inline void set_dreg_bits(unsigned code, uint64_t rawbits) {
ASSERT(code < kNumberOfFPRegisters);
set_dreg(code, rawbits_to_double(rawbits));
}
inline void set_fpreg(unsigned size, unsigned code, double value) {
switch (size) {
case kSRegSize:
return set_sreg(code, value);
case kDRegSize:
return set_dreg(code, value);
default:
UNREACHABLE();
break;
}
}
#define FPREG_ACCESSORS(N) \
inline float s##N() { return sreg(N); } \
inline double d##N() { return dreg(N); } \
inline void set_s##N(float val) { set_sreg(N, val); } \
inline void set_d##N(double val) { set_dreg(N, val); }
REGISTER_CODE_LIST(FPREG_ACCESSORS)
#undef FPREG_ACCESSORS
bool N() { return (psr_ & NFlag) != 0; }
bool Z() { return (psr_ & ZFlag) != 0; }
bool C() { return (psr_ & CFlag) != 0; }
bool V() { return (psr_ & VFlag) != 0; }
uint32_t nzcv() { return psr_ & (NFlag | ZFlag | CFlag | VFlag); }
// Debug helpers
void PrintFlags(bool print_all = false);
void PrintRegisters(bool print_all_regs = false);
void PrintFPRegisters(bool print_all_regs = false);
void PrintProcessorState();
static const char* WRegNameForCode(unsigned code,
Reg31Mode mode = Reg31IsZeroRegister);
static const char* XRegNameForCode(unsigned code,
Reg31Mode mode = Reg31IsZeroRegister);
static const char* SRegNameForCode(unsigned code);
static const char* DRegNameForCode(unsigned code);
static const char* VRegNameForCode(unsigned code);
inline bool coloured_trace() { return coloured_trace_; }
inline void set_coloured_trace(bool value) { coloured_trace_ = value; }
inline bool disasm_trace() { return disasm_trace_; }
inline void set_disasm_trace(bool value) {
if (value != disasm_trace_) {
if (value) {
decoder_->InsertVisitorBefore(print_disasm_, this);
} else {
decoder_->RemoveVisitor(print_disasm_);
}
disasm_trace_ = value;
}
}
protected:
// Simulation helpers ------------------------------------
bool ConditionPassed(Condition cond) {
switch (cond) {
case eq:
return Z();
case ne:
return !Z();
case hs:
return C();
case lo:
return !C();
case mi:
return N();
case pl:
return !N();
case vs:
return V();
case vc:
return !V();
case hi:
return C() && !Z();
case ls:
return !(C() && !Z());
case ge:
return N() == V();
case lt:
return N() != V();
case gt:
return !Z() && (N() == V());
case le:
return !(!Z() && (N() == V()));
case al:
return true;
default:
UNREACHABLE();
return false;
}
}
bool ConditionFailed(Condition cond) {
return !ConditionPassed(cond);
}
void AddSubHelper(Instruction* instr, int64_t op2);
int64_t AddWithCarry(unsigned reg_size,
bool set_flags,
int64_t src1,
int64_t src2,
int64_t carry_in = 0);
void LogicalHelper(Instruction* instr, int64_t op2);
void ConditionalCompareHelper(Instruction* instr, int64_t op2);
void LoadStoreHelper(Instruction* instr,
int64_t offset,
AddrMode addrmode);
void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
uint8_t* AddressModeHelper(unsigned addr_reg,
int64_t offset,
AddrMode addrmode);
uint64_t MemoryRead(const uint8_t* address, unsigned num_bytes);
uint8_t MemoryRead8(uint8_t* address);
uint16_t MemoryRead16(uint8_t* address);
uint32_t MemoryRead32(uint8_t* address);
float MemoryReadFP32(uint8_t* address);
uint64_t MemoryRead64(uint8_t* address);
double MemoryReadFP64(uint8_t* address);
void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes);
void MemoryWrite32(uint8_t* address, uint32_t value);
void MemoryWriteFP32(uint8_t* address, float value);
void MemoryWrite64(uint8_t* address, uint64_t value);
void MemoryWriteFP64(uint8_t* address, double value);
int64_t ShiftOperand(unsigned reg_size,
int64_t value,
Shift shift_type,
unsigned amount);
int64_t Rotate(unsigned reg_width,
int64_t value,
Shift shift_type,
unsigned amount);
int64_t ExtendValue(unsigned reg_width,
int64_t value,
Extend extend_type,
unsigned left_shift = 0);
uint64_t ReverseBits(uint64_t value, unsigned num_bits);
uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
void FPCompare(double val0, double val1);
double FPRoundInt(double value, FPRounding round_mode);
int32_t FPToInt32(double value, FPRounding rmode);
int64_t FPToInt64(double value, FPRounding rmode);
uint32_t FPToUInt32(double value, FPRounding rmode);
uint64_t FPToUInt64(double value, FPRounding rmode);
double FPMax(double a, double b);
double FPMin(double a, double b);
// Pseudo Printf instruction
void DoPrintf(Instruction* instr);
// Processor state ---------------------------------------
// Output stream.
FILE* stream_;
PrintDisassembler* print_disasm_;
// General purpose registers. Register 31 is the stack pointer.
SimRegister registers_[kNumberOfRegisters];
// Floating point registers
SimFPRegister fpregisters_[kNumberOfFPRegisters];
// Program Status Register.
// bits[31, 27]: Condition flags N, Z, C, and V.
// (Negative, Zero, Carry, Overflow)
uint32_t psr_;
// Condition flags.
void SetFlags(uint32_t new_flags);
static inline uint32_t CalcNFlag(int64_t result, unsigned reg_size) {
return ((result >> (reg_size - 1)) & 1) * NFlag;
}
static inline uint32_t CalcZFlag(int64_t result) {
return (result == 0) ? static_cast<uint32_t>(ZFlag) : 0;
}
static const uint32_t kConditionFlagsMask = 0xf0000000;
// Stack
byte* stack_;
static const int stack_protection_size_ = 256;
// 2 KB stack.
static const int stack_size_ = 2 * 1024 + 2 * stack_protection_size_;
byte* stack_limit_;
Decoder* decoder_;
// Indicates if the pc has been modified by the instruction and should not be
// automatically incremented.
bool pc_modified_;
Instruction* pc_;
static const char* xreg_names[];
static const char* wreg_names[];
static const char* sreg_names[];
static const char* dreg_names[];
static const char* vreg_names[];
static const Instruction* kEndOfSimAddress;
private:
bool coloured_trace_;
// Indicates whether the disassembly trace is active.
bool disasm_trace_;
};
} // namespace vixl
#endif // VIXL_A64_SIMULATOR_A64_H_
+66
Ver Arquivo
@@ -0,0 +1,66 @@
// Copyright 2013, ARM Limited
// 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_GLOBALS_H
#define VIXL_GLOBALS_H
// Get the standard printf format macros for C99 stdint types.
//#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include "platform.h"
typedef uint8_t byte;
const int KBytes = 1024;
const int MBytes = 1024 * KBytes;
const int GBytes = 1024 * MBytes;
#define ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
#ifdef DEBUG
#define ASSERT(condition) assert(condition)
#define CHECK(condition) ASSERT(condition)
#define UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); ABORT()
#define UNREACHABLE() printf("UNREACHABLE\t"); ABORT()
#else
#define ASSERT(condition) ((void) 0)
#define CHECK(condition) assert(condition)
#define UNIMPLEMENTED() ((void) 0)
#define UNREACHABLE() ((void) 0)
#endif
template <typename T> inline void USE(T) {}
#define ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); ABORT()
#endif // VIXL_GLOBALS_H
+43
Ver Arquivo
@@ -0,0 +1,43 @@
// Copyright 2013, ARM Limited
// 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 PLATFORM_H
#define PLATFORM_H
// Define platform specific functionalities.
namespace vixl {
#ifdef USE_SIMULATOR
// Currently we assume running the simulator implies running on x86 hardware.
inline void HostBreakpoint() { asm("int3"); }
#else
inline void HostBreakpoint() {
// TODO: Implement HostBreakpoint on a64.
}
#endif
} // namespace vixl
#endif
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+423
Ver Arquivo
@@ -0,0 +1,423 @@
// Copyright 2013, ARM Limited
// 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 "test-utils-a64.h"
#include <math.h> // Needed for isnan().
#include "hphp/util/vixl/a64/macro-assembler-a64.h"
#include "hphp/util/vixl/a64/simulator-a64.h"
#include "hphp/util/vixl/a64/disasm-a64.h"
#include "hphp/util/vixl/a64/cpu-a64.h"
#define __ masm->
namespace vixl {
bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result) {
if (result != expected) {
printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n",
expected, result);
}
return expected == result;
}
bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result) {
if (result != expected) {
printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
expected, result);
}
return expected == result;
}
bool EqualFP32(float expected, const RegisterDump*, float result) {
if (result != expected) {
printf("Expected %.20f\t Found %.20f\n", expected, result);
}
return expected == result;
}
bool EqualFP64(double expected, const RegisterDump*, double result) {
if (result != expected) {
printf("Expected %.20f\t Found %.20f\n", expected, result);
}
return expected == result;
}
bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) {
ASSERT(reg.Is32Bits());
// Retrieve the corresponding X register so we can check that the upper part
// was properly cleared.
int64_t result_x = core->xreg(reg.code());
if ((result_x & 0xffffffff00000000L) != 0) {
printf("Expected 0x%08" PRIx32 "\t Found 0x%016" PRIx64 "\n",
expected, result_x);
return false;
}
uint32_t result_w = core->wreg(reg.code());
return Equal32(expected, core, result_w);
}
bool Equal64(uint64_t expected,
const RegisterDump* core,
const Register& reg) {
ASSERT(reg.Is64Bits());
uint64_t result = core->xreg(reg.code());
return Equal64(expected, core, result);
}
bool EqualFP32(float expected,
const RegisterDump* core,
const FPRegister& fpreg) {
ASSERT(fpreg.Is32Bits());
// Retrieve the corresponding D register so we can check that the upper part
// was properly cleared.
uint64_t result_64 = core->dreg_bits(fpreg.code());
if ((result_64 & 0xffffffff00000000L) != 0) {
printf("Expected 0x%08" PRIx32 " (%f)\t Found 0x%016" PRIx64 "\n",
float_to_rawbits(expected), expected, result_64);
return false;
}
if (expected == 0.0) {
return Equal32(float_to_rawbits(expected), core,
core->sreg_bits(fpreg.code()));
} else if (isnan(expected)) {
return isnan(core->sreg(fpreg.code()));
} else {
float result = core->sreg(fpreg.code());
return EqualFP32(expected, core, result);
}
}
bool EqualFP64(double expected,
const RegisterDump* core,
const FPRegister& fpreg) {
ASSERT(fpreg.Is64Bits());
if (expected == 0.0) {
return Equal64(double_to_rawbits(expected), core,
core->dreg_bits(fpreg.code()));
} else if (isnan(expected)) {
return isnan(core->dreg(fpreg.code()));
} else {
double result = core->dreg(fpreg.code());
return EqualFP64(expected, core, result);
}
}
bool Equal64(const Register& reg0,
const RegisterDump* core,
const Register& reg1) {
ASSERT(reg0.Is64Bits() && reg1.Is64Bits());
int64_t expected = core->xreg(reg0.code());
int64_t result = core->xreg(reg1.code());
return Equal64(expected, core, result);
}
static char FlagN(uint32_t flags) {
return (flags & NFlag) ? 'N' : 'n';
}
static char FlagZ(uint32_t flags) {
return (flags & ZFlag) ? 'Z' : 'z';
}
static char FlagC(uint32_t flags) {
return (flags & CFlag) ? 'C' : 'c';
}
static char FlagV(uint32_t flags) {
return (flags & VFlag) ? 'V' : 'v';
}
bool EqualNzcv(uint32_t expected, uint32_t result) {
ASSERT((expected & ~NZCVFlag) == 0);
ASSERT((result & ~NZCVFlag) == 0);
if (result != expected) {
printf("Expected: %c%c%c%c\t Found: %c%c%c%c\n",
FlagN(expected), FlagZ(expected), FlagC(expected), FlagV(expected),
FlagN(result), FlagZ(result), FlagC(result), FlagV(result));
}
return result == expected;
}
bool EqualRegisters(const RegisterDump* a, const RegisterDump* b) {
for (unsigned i = 0; i < kNumberOfRegisters; i++) {
if (a->xreg(i) != b->xreg(i)) {
printf("x%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
i, a->xreg(i), b->xreg(i));
return false;
}
}
for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
uint64_t a_bits = a->dreg_bits(i);
uint64_t b_bits = b->dreg_bits(i);
if (a_bits != b_bits) {
printf("d%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
i, a_bits, b_bits);
return false;
}
}
return true;
}
RegList PopulateRegisterArray(Register* w, Register* x, Register* r,
int reg_size, int reg_count, RegList allowed) {
RegList list = 0;
int i = 0;
for (unsigned n = 0; (n < kNumberOfRegisters) && (i < reg_count); n++) {
if (((1UL << n) & allowed) != 0) {
// Only assign allowed registers.
if (r) {
r[i] = Register(n, reg_size);
}
if (x) {
x[i] = Register(n, kXRegSize);
}
if (w) {
w[i] = Register(n, kWRegSize);
}
list |= (1UL << n);
i++;
}
}
// Check that we got enough registers.
ASSERT(CountSetBits(list, kNumberOfRegisters) == reg_count);
return list;
}
RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v,
int reg_size, int reg_count, RegList allowed) {
RegList list = 0;
int i = 0;
for (unsigned n = 0; (n < kNumberOfFPRegisters) && (i < reg_count); n++) {
if (((1UL << n) & allowed) != 0) {
// Only assigned allowed registers.
if (v) {
v[i] = FPRegister(n, reg_size);
}
if (d) {
d[i] = FPRegister(n, kDRegSize);
}
if (s) {
s[i] = FPRegister(n, kSRegSize);
}
list |= (1UL << n);
i++;
}
}
// Check that we got enough registers.
ASSERT(CountSetBits(list, kNumberOfFPRegisters) == reg_count);
return list;
}
void Clobber(MacroAssembler* masm, RegList reg_list, uint64_t const value) {
Register first = NoReg;
for (unsigned i = 0; i < kNumberOfRegisters; i++) {
if (reg_list & (1UL << i)) {
Register xn(i, kXRegSize);
// We should never write into sp here.
ASSERT(!xn.Is(sp));
if (!xn.IsZero()) {
if (!first.IsValid()) {
// This is the first register we've hit, so construct the literal.
__ Mov(xn, value);
first = xn;
} else {
// We've already loaded the literal, so re-use the value already
// loaded into the first register we hit.
__ Mov(xn, first);
}
}
}
}
}
void ClobberFP(MacroAssembler* masm, RegList reg_list, double const value) {
FPRegister first = NoFPReg;
for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
if (reg_list & (1UL << i)) {
FPRegister dn(i, kDRegSize);
if (!first.IsValid()) {
// This is the first register we've hit, so construct the literal.
__ Fmov(dn, value);
first = dn;
} else {
// We've already loaded the literal, so re-use the value already loaded
// into the first register we hit.
__ Fmov(dn, first);
}
}
}
}
void Clobber(MacroAssembler* masm, CPURegList reg_list) {
if (reg_list.type() == CPURegister::kRegister) {
// This will always clobber X registers.
Clobber(masm, reg_list.list());
} else if (reg_list.type() == CPURegister::kFPRegister) {
// This will always clobber D registers.
ClobberFP(masm, reg_list.list());
} else {
UNREACHABLE();
}
}
void RegisterDump::Dump(MacroAssembler* masm) {
ASSERT(__ StackPointer().Is(sp));
// Ensure that we don't unintentionally clobber any registers.
Register old_tmp0 = __ Tmp0();
Register old_tmp1 = __ Tmp1();
FPRegister old_fptmp0 = __ FPTmp0();
__ SetScratchRegisters(NoReg, NoReg);
__ SetFPScratchRegister(NoFPReg);
// Preserve some temporary registers.
Register dump_base = x0;
Register dump = x1;
Register tmp = x2;
Register dump_base_w = dump_base.W();
Register dump_w = dump.W();
Register tmp_w = tmp.W();
// Offsets into the dump_ structure.
const int x_offset = offsetof(dump_t, x_);
const int w_offset = offsetof(dump_t, w_);
const int d_offset = offsetof(dump_t, d_);
const int s_offset = offsetof(dump_t, s_);
const int sp_offset = offsetof(dump_t, sp_);
const int wsp_offset = offsetof(dump_t, wsp_);
const int flags_offset = offsetof(dump_t, flags_);
__ Push(xzr, dump_base, dump, tmp);
// Load the address where we will dump the state.
__ Mov(dump_base, reinterpret_cast<uint64_t>(&dump_));
// Dump the stack pointer (sp and wsp).
// The stack pointer cannot be stored directly; it needs to be moved into
// another register first. Also, we pushed four X registers, so we need to
// compensate here.
__ Add(tmp, sp, 4 * kXRegSizeInBytes);
__ Str(tmp, MemOperand(dump_base, sp_offset));
__ Add(tmp_w, wsp, 4 * kXRegSizeInBytes);
__ Str(tmp_w, MemOperand(dump_base, wsp_offset));
// Dump X registers.
__ Add(dump, dump_base, x_offset);
for (unsigned i = 0; i < kNumberOfRegisters; i += 2) {
__ Stp(Register::XRegFromCode(i), Register::XRegFromCode(i + 1),
MemOperand(dump, i * kXRegSizeInBytes));
}
// Dump W registers.
__ Add(dump, dump_base, w_offset);
for (unsigned i = 0; i < kNumberOfRegisters; i += 2) {
__ Stp(Register::WRegFromCode(i), Register::WRegFromCode(i + 1),
MemOperand(dump, i * kWRegSizeInBytes));
}
// Dump D registers.
__ Add(dump, dump_base, d_offset);
for (unsigned i = 0; i < kNumberOfFPRegisters; i += 2) {
__ Stp(FPRegister::DRegFromCode(i), FPRegister::DRegFromCode(i + 1),
MemOperand(dump, i * kDRegSizeInBytes));
}
// Dump S registers.
__ Add(dump, dump_base, s_offset);
for (unsigned i = 0; i < kNumberOfFPRegisters; i += 2) {
__ Stp(FPRegister::SRegFromCode(i), FPRegister::SRegFromCode(i + 1),
MemOperand(dump, i * kSRegSizeInBytes));
}
// Dump the flags.
__ Mrs(tmp, NZCV);
__ Str(tmp, MemOperand(dump_base, flags_offset));
// To dump the values that were in tmp amd dump, we need a new scratch
// register. We can use any of the already dumped registers since we can
// easily restore them.
Register dump2_base = x10;
Register dump2 = x11;
ASSERT(!AreAliased(dump_base, dump, tmp, dump2_base, dump2));
// Don't lose the dump_ address.
__ Mov(dump2_base, dump_base);
__ Pop(tmp, dump, dump_base, xzr);
__ Add(dump2, dump2_base, w_offset);
__ Str(dump_base_w, MemOperand(dump2, dump_base.code() * kWRegSizeInBytes));
__ Str(dump_w, MemOperand(dump2, dump.code() * kWRegSizeInBytes));
__ Str(tmp_w, MemOperand(dump2, tmp.code() * kWRegSizeInBytes));
__ Add(dump2, dump2_base, x_offset);
__ Str(dump_base, MemOperand(dump2, dump_base.code() * kXRegSizeInBytes));
__ Str(dump, MemOperand(dump2, dump.code() * kXRegSizeInBytes));
__ Str(tmp, MemOperand(dump2, tmp.code() * kXRegSizeInBytes));
// Finally, restore dump2_base and dump2.
__ Ldr(dump2_base, MemOperand(dump2, dump2_base.code() * kXRegSizeInBytes));
__ Ldr(dump2, MemOperand(dump2, dump2.code() * kXRegSizeInBytes));
// Restore the MacroAssembler's scratch registers.
__ SetScratchRegisters(old_tmp0, old_tmp1);
__ SetFPScratchRegister(old_fptmp0);
completed_ = true;
}
} // namespace vixl
+230
Ver Arquivo
@@ -0,0 +1,230 @@
// Copyright 2013, ARM Limited
// 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_A64_TEST_UTILS_A64_H_
#define VIXL_A64_TEST_UTILS_A64_H_
#include "hphp/util/vixl/a64/macro-assembler-a64.h"
#include "hphp/util/vixl/a64/simulator-a64.h"
#include "hphp/util/vixl/a64/disasm-a64.h"
#include "hphp/util/vixl/a64/cpu-a64.h"
namespace vixl {
// RegisterDump: Object allowing integer, floating point and flags registers
// to be saved to itself for future reference.
class RegisterDump {
public:
RegisterDump() : completed_(false) {
ASSERT(sizeof(dump_.d_[0]) == kDRegSizeInBytes);
ASSERT(sizeof(dump_.s_[0]) == kSRegSizeInBytes);
ASSERT(sizeof(dump_.d_[0]) == kXRegSizeInBytes);
ASSERT(sizeof(dump_.s_[0]) == kWRegSizeInBytes);
ASSERT(sizeof(dump_.x_[0]) == kXRegSizeInBytes);
ASSERT(sizeof(dump_.w_[0]) == kWRegSizeInBytes);
}
// The Dump method generates code to store a snapshot of the register values.
// It needs to be able to use the stack temporarily, and requires that the
// current stack pointer is sp, and is properly aligned.
//
// The dumping code is generated though the given MacroAssembler. No registers
// are corrupted in the process, but the stack is used briefly. The flags will
// be corrupted during this call.
void Dump(MacroAssembler* assm);
// Register accessors.
inline int32_t wreg(unsigned code) const {
if (code == kSPRegInternalCode) {
return wspreg();
}
ASSERT(RegAliasesMatch(code));
return dump_.w_[code];
}
inline int64_t xreg(unsigned code) const {
if (code == kSPRegInternalCode) {
return spreg();
}
ASSERT(RegAliasesMatch(code));
return dump_.x_[code];
}
// FPRegister accessors.
inline uint32_t sreg_bits(unsigned code) const {
ASSERT(FPRegAliasesMatch(code));
return dump_.s_[code];
}
inline float sreg(unsigned code) const {
return rawbits_to_float(sreg_bits(code));
}
inline uint64_t dreg_bits(unsigned code) const {
ASSERT(FPRegAliasesMatch(code));
return dump_.d_[code];
}
inline double dreg(unsigned code) const {
return rawbits_to_double(dreg_bits(code));
}
// Stack pointer accessors.
inline int64_t spreg() const {
ASSERT(SPRegAliasesMatch());
return dump_.sp_;
}
inline int64_t wspreg() const {
ASSERT(SPRegAliasesMatch());
return dump_.wsp_;
}
// Flags accessors.
inline uint64_t flags_nzcv() const {
ASSERT(IsComplete());
ASSERT((dump_.flags_ & ~Flags_mask) == 0);
return dump_.flags_ & Flags_mask;
}
inline bool IsComplete() const {
return completed_;
}
private:
// Indicate whether the dump operation has been completed.
bool completed_;
// Check that the lower 32 bits of x<code> exactly match the 32 bits of
// w<code>. A failure of this test most likely represents a failure in the
// ::Dump method, or a failure in the simulator.
bool RegAliasesMatch(unsigned code) const {
ASSERT(IsComplete());
ASSERT(code < kNumberOfRegisters);
return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]);
}
// As RegAliasesMatch, but for the stack pointer.
bool SPRegAliasesMatch() const {
ASSERT(IsComplete());
return ((dump_.sp_ & kWRegMask) == dump_.wsp_);
}
// As RegAliasesMatch, but for floating-point registers.
bool FPRegAliasesMatch(unsigned code) const {
ASSERT(IsComplete());
ASSERT(code < kNumberOfFPRegisters);
return (dump_.d_[code] & kSRegMask) == dump_.s_[code];
}
// Store all the dumped elements in a simple struct so the implementation can
// use offsetof to quickly find the correct field.
struct dump_t {
// Core registers.
uint64_t x_[kNumberOfRegisters];
uint32_t w_[kNumberOfRegisters];
// Floating-point registers, as raw bits.
uint64_t d_[kNumberOfFPRegisters];
uint32_t s_[kNumberOfFPRegisters];
// The stack pointer.
uint64_t sp_;
uint64_t wsp_;
// NZCV flags, stored in bits 28 to 31.
// bit[31] : Negative
// bit[30] : Zero
// bit[29] : Carry
// bit[28] : oVerflow
uint64_t flags_;
} dump_;
};
// Some of these methods don't use the RegisterDump argument, but they have to
// accept them so that they can overload those that take register arguments.
bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result);
bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result);
bool EqualFP32(float expected, const RegisterDump*, float result);
bool EqualFP64(double expected, const RegisterDump*, double result);
bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg);
bool Equal64(uint64_t expected, const RegisterDump* core, const Register& reg);
bool EqualFP32(float expected, const RegisterDump* core,
const FPRegister& fpreg);
bool EqualFP64(double expected, const RegisterDump* core,
const FPRegister& fpreg);
bool Equal64(const Register& reg0, const RegisterDump* core,
const Register& reg1);
bool EqualNzcv(uint32_t expected, uint32_t result);
bool EqualRegisters(const RegisterDump* a, const RegisterDump* b);
// Populate the w, x and r arrays with registers from the 'allowed' mask. The
// r array will be populated with <reg_size>-sized registers,
//
// This allows for tests which use large, parameterized blocks of registers
// (such as the push and pop tests), but where certain registers must be
// avoided as they are used for other purposes.
//
// Any of w, x, or r can be nullptr if they are not required.
//
// The return value is a RegList indicating which registers were allocated.
RegList PopulateRegisterArray(Register* w, Register* x, Register* r,
int reg_size, int reg_count, RegList allowed);
// As PopulateRegisterArray, but for floating-point registers.
RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v,
int reg_size, int reg_count, RegList allowed);
// Ovewrite the contents of the specified registers. This enables tests to
// check that register contents are written in cases where it's likely that the
// correct outcome could already be stored in the register.
//
// This always overwrites X-sized registers. If tests are operating on W
// registers, a subsequent write into an aliased W register should clear the
// top word anyway, so clobbering the full X registers should make tests more
// rigorous.
void Clobber(MacroAssembler* masm, RegList reg_list,
uint64_t const value = 0xfedcba9876543210UL);
// As Clobber, but for FP registers.
void ClobberFP(MacroAssembler* masm, RegList reg_list,
double const value = kFP64SignallingNaN);
// As Clobber, but for a CPURegList with either FP or integer registers. When
// using this method, the clobber value is always the default for the basic
// Clobber or ClobberFP functions.
void Clobber(MacroAssembler* masm, CPURegList reg_list);
} // namespace vixl
#endif // VIXL_A64_TEST_UTILS_A64_H_
+120
Ver Arquivo
@@ -0,0 +1,120 @@
// Copyright 2013, ARM Limited
// 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 "hphp/util/vixl/utils.h"
#include <stdio.h>
namespace vixl {
uint32_t float_to_rawbits(float value) {
uint32_t bits = 0;
memcpy(&bits, &value, 4);
return bits;
}
uint64_t double_to_rawbits(double value) {
uint64_t bits = 0;
memcpy(&bits, &value, 8);
return bits;
}
float rawbits_to_float(uint32_t bits) {
float value = 0.0;
memcpy(&value, &bits, 4);
return value;
}
double rawbits_to_double(uint64_t bits) {
double value = 0.0;
memcpy(&value, &bits, 8);
return value;
}
int CountLeadingZeros(uint64_t value, int width) {
ASSERT((width == 32) || (width == 64));
int count = 0;
uint64_t bit_test = 1UL << (width - 1);
while ((count < width) && ((bit_test & value) == 0)) {
count++;
bit_test >>= 1;
}
return count;
}
int CountLeadingSignBits(int64_t value, int width) {
ASSERT((width == 32) || (width == 64));
if (value >= 0) {
return CountLeadingZeros(value, width) - 1;
} else {
return CountLeadingZeros(~value, width) - 1;
}
}
int CountTrailingZeros(uint64_t value, int width) {
ASSERT((width == 32) || (width == 64));
int count = 0;
while ((count < width) && (((value >> count) & 1) == 0)) {
count++;
}
return count;
}
int CountSetBits(uint64_t value, int width) {
// TODO: Other widths could be added here, as the implementation already
// supports them.
ASSERT((width == 32) || (width == 64));
// Mask out unused bits to ensure that they are not counted.
value &= (0xffffffffffffffffUL >> (64-width));
// Add up the set bits.
// The algorithm works by adding pairs of bit fields together iteratively,
// where the size of each bit field doubles each time.
// An example for an 8-bit value:
// Bits: h g f e d c b a
// \ | \ | \ | \ |
// value = h+g f+e d+c b+a
// \ | \ |
// value = h+g+f+e d+c+b+a
// \ |
// value = h+g+f+e+d+c+b+a
value = ((value >> 1) & 0x5555555555555555) + (value & 0x5555555555555555);
value = ((value >> 2) & 0x3333333333333333) + (value & 0x3333333333333333);
value = ((value >> 4) & 0x0f0f0f0f0f0f0f0f) + (value & 0x0f0f0f0f0f0f0f0f);
value = ((value >> 8) & 0x00ff00ff00ff00ff) + (value & 0x00ff00ff00ff00ff);
value = ((value >> 16) & 0x0000ffff0000ffff) + (value & 0x0000ffff0000ffff);
value = ((value >> 32) & 0x00000000ffffffff) + (value & 0x00000000ffffffff);
return value;
}
} // namespace vixl
+126
Ver Arquivo
@@ -0,0 +1,126 @@
// Copyright 2013, ARM Limited
// 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_UTILS_H
#define VIXL_UTILS_H
#include <string.h>
#include "hphp/util/vixl/globals.h"
namespace vixl {
// Check number width.
inline bool is_intn(unsigned n, int64_t x) {
ASSERT((0 < n) && (n < 64));
int64_t limit = 1L << (n - 1);
return (-limit <= x) && (x < limit);
}
inline bool is_uintn(unsigned n, int64_t x) {
ASSERT((0 < n) && (n < 64));
return !(x >> n);
}
inline unsigned truncate_to_intn(unsigned n, int64_t x) {
ASSERT((0 < n) && (n < 64));
return (x & ((1L << n) - 1));
}
#define INT_1_TO_63_LIST(V) \
V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \
V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \
V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \
V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32) \
V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \
V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \
V(57) V(58) V(59) V(60) V(61) V(62) V(63)
#define DECLARE_IS_INT_N(N) \
inline bool is_int##N(int64_t x) { return is_intn(N, x); }
#define DECLARE_IS_UINT_N(N) \
inline bool is_uint##N(int64_t x) { return is_uintn(N, x); }
#define DECLARE_TRUNCATE_TO_INT_N(N) \
inline int truncate_to_int##N(int x) { return truncate_to_intn(N, x); }
INT_1_TO_63_LIST(DECLARE_IS_INT_N)
INT_1_TO_63_LIST(DECLARE_IS_UINT_N)
INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N)
#undef DECLARE_IS_INT_N
#undef DECLARE_IS_UINT_N
#undef DECLARE_TRUNCATE_TO_INT_N
// Bit field extraction.
inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) {
return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
}
inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) {
return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
}
inline int32_t signed_bitextract_32(int msb, int lsb, int32_t x) {
return (x << (31 - msb)) >> (lsb + 31 - msb);
}
inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) {
return (x << (63 - msb)) >> (lsb + 63 - msb);
}
// floating point representation
uint32_t float_to_rawbits(float value);
uint64_t double_to_rawbits(double value);
float rawbits_to_float(uint32_t bits);
double rawbits_to_double(uint64_t bits);
// Bits counting.
int CountLeadingZeros(uint64_t value, int width);
int CountLeadingSignBits(int64_t value, int width);
int CountTrailingZeros(uint64_t value, int width);
int CountSetBits(uint64_t value, int width);
// Pointer alignment
// TODO: rename/refactor to make it specific to instructions.
template<typename T>
bool IsWordAligned(T pointer) {
ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
}
// Increment a pointer until it has the specified alignment.
template<class T>
T AlignUp(T pointer, size_t alignment) {
ASSERT(sizeof(pointer) == sizeof(uintptr_t));
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
size_t align_step = (alignment - pointer_raw) % alignment;
ASSERT((pointer_raw + align_step) % alignment == 0);
return reinterpret_cast<T>(pointer_raw + align_step);
}
} // namespace vixl
#endif // VIXL_UTILS_H