2016-07-01 14:01:06 +01:00
|
|
|
/* This file is part of the dynarmic project.
|
|
|
|
* Copyright (c) 2016 MerryMage
|
|
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
|
|
* General Public License version 2 or any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2016-08-17 15:53:36 +01:00
|
|
|
#include <initializer_list>
|
|
|
|
|
2018-01-04 21:12:02 +00:00
|
|
|
#include <dynarmic/A32/coprocessor_util.h>
|
2016-12-31 11:17:47 +00:00
|
|
|
|
2016-08-17 15:53:36 +01:00
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "frontend/ir/basic_block.h"
|
2016-09-05 11:54:09 +01:00
|
|
|
#include "frontend/ir/location_descriptor.h"
|
2016-08-17 15:53:36 +01:00
|
|
|
#include "frontend/ir/terminal.h"
|
|
|
|
#include "frontend/ir/value.h"
|
|
|
|
|
|
|
|
// ARM JIT Microinstruction Intermediate Representation
|
|
|
|
//
|
|
|
|
// This intermediate representation is an SSA IR. It is designed primarily for analysis,
|
|
|
|
// though it can be lowered into a reduced form for interpretation. Each IR node (Value)
|
|
|
|
// is a microinstruction of an idealised ARM CPU. The choice of microinstructions is made
|
|
|
|
// not based on any existing microarchitecture but on ease of implementation.
|
2016-07-01 14:01:06 +01:00
|
|
|
|
|
|
|
namespace Dynarmic {
|
2016-08-25 17:36:42 +01:00
|
|
|
namespace IR {
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2016-09-03 21:48:03 +01:00
|
|
|
enum class Opcode;
|
|
|
|
|
2018-01-05 21:47:23 +00:00
|
|
|
template <typename T>
|
|
|
|
struct ResultAndCarry {
|
|
|
|
T result;
|
|
|
|
U1 carry;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct ResultAndOverflow {
|
|
|
|
T result;
|
|
|
|
U1 overflow;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct ResultAndCarryAndOverflow {
|
|
|
|
T result;
|
|
|
|
U1 carry;
|
|
|
|
U1 overflow;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct ResultAndGE {
|
|
|
|
T result;
|
|
|
|
U32 ge;
|
|
|
|
};
|
|
|
|
|
2016-08-12 18:17:31 +01:00
|
|
|
/**
|
|
|
|
* Convenience class to construct a basic block of the intermediate representation.
|
|
|
|
* `block` is the resulting block.
|
|
|
|
* The user of this class updates `current_location` as appropriate.
|
|
|
|
*/
|
2018-01-01 15:47:56 +00:00
|
|
|
class IREmitter {
|
2016-07-01 14:01:06 +01:00
|
|
|
public:
|
2018-01-12 19:34:25 +00:00
|
|
|
explicit IREmitter(Block& block) : block(block) {}
|
2016-07-04 14:37:50 +01:00
|
|
|
|
2018-01-12 19:34:25 +00:00
|
|
|
Block& block;
|
2016-07-01 14:01:06 +01:00
|
|
|
|
|
|
|
void Unimplemented();
|
|
|
|
|
2018-01-05 21:47:23 +00:00
|
|
|
U1 Imm1(bool value);
|
|
|
|
U8 Imm8(u8 value);
|
|
|
|
U32 Imm32(u32 value);
|
|
|
|
U64 Imm64(u64 value);
|
2016-08-25 17:36:42 +01:00
|
|
|
|
2018-01-01 16:19:43 +00:00
|
|
|
void PushRSB(const LocationDescriptor& return_location);
|
|
|
|
|
2018-01-05 21:47:23 +00:00
|
|
|
U64 Pack2x32To1x64(const U32& lo, const U32& hi);
|
|
|
|
U32 LeastSignificantWord(const U64& value);
|
|
|
|
ResultAndCarry<U32> MostSignificantWord(const U64& value);
|
2018-01-07 11:31:20 +00:00
|
|
|
U16 LeastSignificantHalf(U32U64 value);
|
|
|
|
U8 LeastSignificantByte(U32U64 value);
|
2018-01-05 21:47:23 +00:00
|
|
|
U1 MostSignificantBit(const U32& value);
|
|
|
|
U1 IsZero(const U32& value);
|
2018-01-07 16:33:02 +00:00
|
|
|
U1 IsZero(const U64& value);
|
|
|
|
U1 IsZero(const U32U64& value);
|
|
|
|
U1 TestBit(const U32U64& value, const U8& bit);
|
2018-01-05 21:47:23 +00:00
|
|
|
|
2018-01-07 11:31:20 +00:00
|
|
|
// This pseudo-instruction may only be added to instructions that support it.
|
|
|
|
NZCV NZCVFrom(const Value& value);
|
|
|
|
|
2018-01-05 21:47:23 +00:00
|
|
|
ResultAndCarry<U32> LogicalShiftLeft(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
|
|
|
ResultAndCarry<U32> LogicalShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
|
|
|
ResultAndCarry<U32> ArithmeticShiftRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
|
|
|
ResultAndCarry<U32> RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in);
|
2018-01-07 00:11:57 +00:00
|
|
|
U64 LogicalShiftRight(const U64& value_in, const U8& shift_amount);
|
|
|
|
U32U64 LogicalShiftLeft(const U32U64& value_in, const U8& shift_amount);
|
|
|
|
U32U64 LogicalShiftRight(const U32U64& value_in, const U8& shift_amount);
|
|
|
|
U32U64 ArithmeticShiftRight(const U32U64& value_in, const U8& shift_amount);
|
|
|
|
U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount);
|
2018-01-05 21:47:23 +00:00
|
|
|
ResultAndCarry<U32> RotateRightExtended(const U32& value_in, const U1& carry_in);
|
2018-01-07 11:31:20 +00:00
|
|
|
ResultAndCarryAndOverflow<U32> AddWithCarry(const U32& a, const U32& b, const U1& carry_in);
|
|
|
|
ResultAndCarryAndOverflow<U32> SubWithCarry(const U32& a, const U32& b, const U1& carry_in);
|
|
|
|
U32U64 AddWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
|
|
|
|
U32U64 SubWithCarry(const U32U64& a, const U32U64& b, const U1& carry_in);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 Add(const U32& a, const U32& b);
|
2018-01-07 00:11:57 +00:00
|
|
|
U64 Add(const U64& a, const U64& b);
|
|
|
|
U32U64 Add(const U32U64& a, const U32U64& b);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 Sub(const U32& a, const U32& b);
|
2018-01-07 00:11:57 +00:00
|
|
|
U64 Sub(const U64& a, const U64& b);
|
2018-01-07 11:31:20 +00:00
|
|
|
U32U64 Sub(const U32U64& a, const U32U64& b);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 Mul(const U32& a, const U32& b);
|
2018-01-07 00:11:57 +00:00
|
|
|
U64 Mul(const U64& a, const U64& b);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 And(const U32& a, const U32& b);
|
2018-01-07 12:52:12 +00:00
|
|
|
U32U64 And(const U32U64& a, const U32U64& b);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 Eor(const U32& a, const U32& b);
|
2018-01-07 12:52:12 +00:00
|
|
|
U32U64 Eor(const U32U64& a, const U32U64& b);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 Or(const U32& a, const U32& b);
|
2018-01-07 12:52:12 +00:00
|
|
|
U32U64 Or(const U32U64& a, const U32U64& b);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 Not(const U32& a);
|
2018-01-07 12:52:12 +00:00
|
|
|
U32U64 Not(const U32U64& a);
|
2018-01-07 11:31:20 +00:00
|
|
|
U32 SignExtendToWord(const UAny& a);
|
|
|
|
U64 SignExtendToLong(const UAny& a);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 SignExtendByteToWord(const U8& a);
|
2018-01-07 11:31:20 +00:00
|
|
|
U32 SignExtendHalfToWord(const U16& a);
|
|
|
|
U64 SignExtendWordToLong(const U32& a);
|
|
|
|
U32 ZeroExtendToWord(const UAny& a);
|
|
|
|
U64 ZeroExtendToLong(const UAny& a);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 ZeroExtendByteToWord(const U8& a);
|
2018-01-07 11:31:20 +00:00
|
|
|
U32 ZeroExtendHalfToWord(const U16& a);
|
|
|
|
U64 ZeroExtendWordToLong(const U32& a);
|
2018-01-07 16:33:02 +00:00
|
|
|
U32 IndeterminateExtendToWord(const UAny& a);
|
|
|
|
U64 IndeterminateExtendToLong(const UAny& a);
|
2018-01-05 21:47:23 +00:00
|
|
|
U32 ByteReverseWord(const U32& a);
|
|
|
|
U16 ByteReverseHalf(const U16& a);
|
|
|
|
U64 ByteReverseDual(const U64& a);
|
|
|
|
U32 CountLeadingZeros(const U32& a);
|
|
|
|
|
|
|
|
ResultAndOverflow<U32> SignedSaturatedAdd(const U32& a, const U32& b);
|
|
|
|
ResultAndOverflow<U32> SignedSaturatedSub(const U32& a, const U32& b);
|
|
|
|
ResultAndOverflow<U32> UnsignedSaturation(const U32& a, size_t bit_size_to_saturate_to);
|
|
|
|
ResultAndOverflow<U32> SignedSaturation(const U32& a, size_t bit_size_to_saturate_to);
|
|
|
|
|
|
|
|
ResultAndGE<U32> PackedAddU8(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedAddS8(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedAddU16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedAddS16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedSubU8(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedSubS8(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedSubU16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedSubS16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedAddSubU16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedAddSubS16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedSubAddU16(const U32& a, const U32& b);
|
|
|
|
ResultAndGE<U32> PackedSubAddS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingAddU8(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingAddS8(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingSubU8(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingSubS8(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingAddU16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingAddS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingSubU16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingSubS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingAddSubU16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingAddSubS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingSubAddU16(const U32& a, const U32& b);
|
|
|
|
U32 PackedHalvingSubAddS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedAddU8(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedAddS8(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedSubU8(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedSubS8(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedAddU16(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedAddS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedSubU16(const U32& a, const U32& b);
|
|
|
|
U32 PackedSaturatedSubS16(const U32& a, const U32& b);
|
|
|
|
U32 PackedAbsDiffSumS8(const U32& a, const U32& b);
|
|
|
|
U32 PackedSelect(const U32& ge, const U32& a, const U32& b);
|
|
|
|
|
|
|
|
F32 TransferToFP32(const U32& a);
|
|
|
|
F64 TransferToFP64(const U64& a);
|
|
|
|
U32 TransferFromFP32(const F32& a);
|
|
|
|
U64 TransferFromFP64(const F64& a);
|
|
|
|
F32 FPAbs32(const F32& a);
|
|
|
|
F64 FPAbs64(const F64& a);
|
|
|
|
F32 FPAdd32(const F32& a, const F32& b, bool fpscr_controlled);
|
|
|
|
F64 FPAdd64(const F64& a, const F64& b, bool fpscr_controlled);
|
|
|
|
void FPCompare32(const F32& a, const F32& b, bool exc_on_qnan, bool fpscr_controlled);
|
|
|
|
void FPCompare64(const F64& a, const F64& b, bool exc_on_qnan, bool fpscr_controlled);
|
|
|
|
F32 FPDiv32(const F32& a, const F32& b, bool fpscr_controlled);
|
|
|
|
F64 FPDiv64(const F64& a, const F64& b, bool fpscr_controlled);
|
|
|
|
F32 FPMul32(const F32& a, const F32& b, bool fpscr_controlled);
|
|
|
|
F64 FPMul64(const F64& a, const F64& b, bool fpscr_controlled);
|
|
|
|
F32 FPNeg32(const F32& a);
|
|
|
|
F64 FPNeg64(const F64& a);
|
|
|
|
F32 FPSqrt32(const F32& a);
|
|
|
|
F64 FPSqrt64(const F64& a);
|
|
|
|
F32 FPSub32(const F32& a, const F32& b, bool fpscr_controlled);
|
|
|
|
F64 FPSub64(const F64& a, const F64& b, bool fpscr_controlled);
|
|
|
|
F32 FPDoubleToSingle(const F64& a, bool fpscr_controlled);
|
|
|
|
F64 FPSingleToDouble(const F32& a, bool fpscr_controlled);
|
|
|
|
F32 FPSingleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
|
|
|
F32 FPSingleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
|
|
|
F32 FPDoubleToS32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
|
|
|
F32 FPDoubleToU32(const F32& a, bool round_towards_zero, bool fpscr_controlled);
|
|
|
|
F32 FPS32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
|
|
|
F32 FPU32ToSingle(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
|
|
|
F64 FPS32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
|
|
|
F64 FPU32ToDouble(const F32& a, bool round_to_nearest, bool fpscr_controlled);
|
2016-08-06 17:21:29 +01:00
|
|
|
|
2016-08-05 14:07:27 +01:00
|
|
|
void Breakpoint();
|
|
|
|
|
2016-08-25 17:36:42 +01:00
|
|
|
void SetTerm(const Terminal& terminal);
|
2016-07-07 10:53:09 +01:00
|
|
|
|
2018-01-01 15:47:56 +00:00
|
|
|
protected:
|
2018-01-05 21:47:23 +00:00
|
|
|
template<typename T = Value, typename ...Args>
|
|
|
|
T Inst(Opcode op, Args ...args) {
|
|
|
|
block.AppendNewInst(op, {Value(args)...});
|
|
|
|
return T(Value(&block.back()));
|
|
|
|
}
|
2016-07-01 14:01:06 +01:00
|
|
|
};
|
|
|
|
|
2016-08-25 17:36:42 +01:00
|
|
|
} // namespace IR
|
2016-07-01 14:01:06 +01:00
|
|
|
} // namespace Dynarmic
|