dep: Add vixl (AArch32/64 assembler)
This commit is contained in:
322
dep/vixl/include/vixl/code-generation-scopes-vixl.h
Normal file
322
dep/vixl/include/vixl/code-generation-scopes-vixl.h
Normal file
@@ -0,0 +1,322 @@
|
||||
// Copyright 2016, VIXL authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#ifndef VIXL_CODE_GENERATION_SCOPES_H_
|
||||
#define VIXL_CODE_GENERATION_SCOPES_H_
|
||||
|
||||
|
||||
#include "assembler-base-vixl.h"
|
||||
#include "macro-assembler-interface.h"
|
||||
|
||||
|
||||
namespace vixl {
|
||||
|
||||
// This scope will:
|
||||
// - Allow code emission from the specified `Assembler`.
|
||||
// - Optionally reserve space in the `CodeBuffer` (if it is managed by VIXL).
|
||||
// - Optionally, on destruction, check the size of the generated code.
|
||||
// (The size can be either exact or a maximum size.)
|
||||
class CodeBufferCheckScope {
|
||||
public:
|
||||
// Tell whether or not the scope needs to ensure the associated CodeBuffer
|
||||
// has enough space for the requested size.
|
||||
enum BufferSpacePolicy {
|
||||
kReserveBufferSpace,
|
||||
kDontReserveBufferSpace,
|
||||
|
||||
// Deprecated, but kept for backward compatibility.
|
||||
kCheck = kReserveBufferSpace,
|
||||
kNoCheck = kDontReserveBufferSpace
|
||||
};
|
||||
|
||||
// Tell whether or not the scope should assert the amount of code emitted
|
||||
// within the scope is consistent with the requested amount.
|
||||
enum SizePolicy {
|
||||
kNoAssert, // Do not check the size of the code emitted.
|
||||
kExactSize, // The code emitted must be exactly size bytes.
|
||||
kMaximumSize // The code emitted must be at most size bytes.
|
||||
};
|
||||
|
||||
// This constructor implicitly calls `Open` to initialise the scope
|
||||
// (`assembler` must not be `NULL`), so it is ready to use immediately after
|
||||
// it has been constructed.
|
||||
CodeBufferCheckScope(internal::AssemblerBase* assembler,
|
||||
size_t size,
|
||||
BufferSpacePolicy check_policy = kReserveBufferSpace,
|
||||
SizePolicy size_policy = kMaximumSize)
|
||||
: assembler_(NULL), initialised_(false) {
|
||||
Open(assembler, size, check_policy, size_policy);
|
||||
}
|
||||
|
||||
// This constructor does not implicitly initialise the scope. Instead, the
|
||||
// user is required to explicitly call the `Open` function before using the
|
||||
// scope.
|
||||
CodeBufferCheckScope() : assembler_(NULL), initialised_(false) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
virtual ~CodeBufferCheckScope() { Close(); }
|
||||
|
||||
// This function performs the actual initialisation work.
|
||||
void Open(internal::AssemblerBase* assembler,
|
||||
size_t size,
|
||||
BufferSpacePolicy check_policy = kReserveBufferSpace,
|
||||
SizePolicy size_policy = kMaximumSize) {
|
||||
VIXL_ASSERT(!initialised_);
|
||||
VIXL_ASSERT(assembler != NULL);
|
||||
assembler_ = assembler;
|
||||
if (check_policy == kReserveBufferSpace) {
|
||||
assembler->GetBuffer()->EnsureSpaceFor(size);
|
||||
}
|
||||
#ifdef VIXL_DEBUG
|
||||
limit_ = assembler_->GetSizeOfCodeGenerated() + size;
|
||||
assert_policy_ = size_policy;
|
||||
previous_allow_assembler_ = assembler_->AllowAssembler();
|
||||
assembler_->SetAllowAssembler(true);
|
||||
#else
|
||||
USE(size_policy);
|
||||
#endif
|
||||
initialised_ = true;
|
||||
}
|
||||
|
||||
// This function performs the cleaning-up work. It must succeed even if the
|
||||
// scope has not been opened. It is safe to call multiple times.
|
||||
void Close() {
|
||||
#ifdef VIXL_DEBUG
|
||||
if (!initialised_) {
|
||||
return;
|
||||
}
|
||||
assembler_->SetAllowAssembler(previous_allow_assembler_);
|
||||
switch (assert_policy_) {
|
||||
case kNoAssert:
|
||||
break;
|
||||
case kExactSize:
|
||||
VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() == limit_);
|
||||
break;
|
||||
case kMaximumSize:
|
||||
VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() <= limit_);
|
||||
break;
|
||||
default:
|
||||
VIXL_UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
initialised_ = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
internal::AssemblerBase* assembler_;
|
||||
SizePolicy assert_policy_;
|
||||
size_t limit_;
|
||||
bool previous_allow_assembler_;
|
||||
bool initialised_;
|
||||
};
|
||||
|
||||
|
||||
// This scope will:
|
||||
// - Do the same as `CodeBufferCheckSCope`, but:
|
||||
// - If managed by VIXL, always reserve space in the `CodeBuffer`.
|
||||
// - Always check the size (exact or maximum) of the generated code on
|
||||
// destruction.
|
||||
// - Emit pools if the specified size would push them out of range.
|
||||
// - Block pools emission for the duration of the scope.
|
||||
// This scope allows the `Assembler` and `MacroAssembler` to be freely and
|
||||
// safely mixed for its duration.
|
||||
class EmissionCheckScope : public CodeBufferCheckScope {
|
||||
public:
|
||||
// This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
|
||||
// initialise the scope, so it is ready to use immediately after it has been
|
||||
// constructed.
|
||||
EmissionCheckScope(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy = kMaximumSize) {
|
||||
Open(masm, size, size_policy);
|
||||
}
|
||||
|
||||
// This constructor does not implicitly initialise the scope. Instead, the
|
||||
// user is required to explicitly call the `Open` function before using the
|
||||
// scope.
|
||||
EmissionCheckScope() {}
|
||||
|
||||
virtual ~EmissionCheckScope() { Close(); }
|
||||
|
||||
enum PoolPolicy {
|
||||
// Do not forbid pool emission inside the scope. Pools will not be emitted
|
||||
// on `Open` either.
|
||||
kIgnorePools,
|
||||
// Force pools to be generated on `Open` if necessary and block their
|
||||
// emission inside the scope.
|
||||
kBlockPools,
|
||||
// Deprecated, but kept for backward compatibility.
|
||||
kCheckPools = kBlockPools
|
||||
};
|
||||
|
||||
void Open(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy = kMaximumSize) {
|
||||
Open(masm, size, size_policy, kBlockPools);
|
||||
}
|
||||
|
||||
void Close() {
|
||||
if (!initialised_) {
|
||||
return;
|
||||
}
|
||||
if (masm_ == NULL) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
// Perform the opposite of `Open`, which is:
|
||||
// - Check the code generation limit was not exceeded.
|
||||
// - Release the pools.
|
||||
CodeBufferCheckScope::Close();
|
||||
if (pool_policy_ == kBlockPools) {
|
||||
masm_->ReleasePools();
|
||||
}
|
||||
VIXL_ASSERT(!initialised_);
|
||||
}
|
||||
|
||||
protected:
|
||||
void Open(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy,
|
||||
PoolPolicy pool_policy) {
|
||||
if (masm == NULL) {
|
||||
// Nothing to do.
|
||||
// We may reach this point in a context of conditional code generation.
|
||||
// See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example.
|
||||
return;
|
||||
}
|
||||
masm_ = masm;
|
||||
pool_policy_ = pool_policy;
|
||||
if (pool_policy_ == kBlockPools) {
|
||||
// To avoid duplicating the work to check that enough space is available
|
||||
// in the buffer, do not use the more generic `EnsureEmitFor()`. It is
|
||||
// done below when opening `CodeBufferCheckScope`.
|
||||
masm->EnsureEmitPoolsFor(size);
|
||||
masm->BlockPools();
|
||||
}
|
||||
// The buffer should be checked *after* we emit the pools.
|
||||
CodeBufferCheckScope::Open(masm->AsAssemblerBase(),
|
||||
size,
|
||||
kReserveBufferSpace,
|
||||
size_policy);
|
||||
VIXL_ASSERT(initialised_);
|
||||
}
|
||||
|
||||
// This constructor should only be used from code that is *currently
|
||||
// generating* the pools, to avoid an infinite loop.
|
||||
EmissionCheckScope(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy,
|
||||
PoolPolicy pool_policy) {
|
||||
Open(masm, size, size_policy, pool_policy);
|
||||
}
|
||||
|
||||
MacroAssemblerInterface* masm_;
|
||||
PoolPolicy pool_policy_;
|
||||
};
|
||||
|
||||
// Use this scope when you need a one-to-one mapping between methods and
|
||||
// instructions. This scope will:
|
||||
// - Do the same as `EmissionCheckScope`.
|
||||
// - Block access to the MacroAssemblerInterface (using run-time assertions).
|
||||
class ExactAssemblyScope : public EmissionCheckScope {
|
||||
public:
|
||||
// This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
|
||||
// initialise the scope, so it is ready to use immediately after it has been
|
||||
// constructed.
|
||||
ExactAssemblyScope(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy = kExactSize) {
|
||||
Open(masm, size, size_policy);
|
||||
}
|
||||
|
||||
// This constructor does not implicitly initialise the scope. Instead, the
|
||||
// user is required to explicitly call the `Open` function before using the
|
||||
// scope.
|
||||
ExactAssemblyScope() {}
|
||||
|
||||
virtual ~ExactAssemblyScope() { Close(); }
|
||||
|
||||
void Open(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy = kExactSize) {
|
||||
Open(masm, size, size_policy, kBlockPools);
|
||||
}
|
||||
|
||||
void Close() {
|
||||
if (!initialised_) {
|
||||
return;
|
||||
}
|
||||
if (masm_ == NULL) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
#ifdef VIXL_DEBUG
|
||||
masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_);
|
||||
#else
|
||||
USE(previous_allow_macro_assembler_);
|
||||
#endif
|
||||
EmissionCheckScope::Close();
|
||||
}
|
||||
|
||||
protected:
|
||||
// This protected constructor allows overriding the pool policy. It is
|
||||
// available to allow this scope to be used in code that handles generation
|
||||
// of pools.
|
||||
ExactAssemblyScope(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy assert_policy,
|
||||
PoolPolicy pool_policy) {
|
||||
Open(masm, size, assert_policy, pool_policy);
|
||||
}
|
||||
|
||||
void Open(MacroAssemblerInterface* masm,
|
||||
size_t size,
|
||||
SizePolicy size_policy,
|
||||
PoolPolicy pool_policy) {
|
||||
VIXL_ASSERT(size_policy != kNoAssert);
|
||||
if (masm == NULL) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
// Rely on EmissionCheckScope::Open to initialise `masm_` and
|
||||
// `pool_policy_`.
|
||||
EmissionCheckScope::Open(masm, size, size_policy, pool_policy);
|
||||
#ifdef VIXL_DEBUG
|
||||
previous_allow_macro_assembler_ = masm->AllowMacroInstructions();
|
||||
masm->SetAllowMacroInstructions(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
bool previous_allow_macro_assembler_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
#endif // VIXL_CODE_GENERATION_SCOPES_H_
|
||||
Reference in New Issue
Block a user