CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/FakeEmitter.h
Views: 1401
// Copyright (C) 2003 Dolphin Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official SVN repository and contact information can be found at15// http://code.google.com/p/dolphin-emu/1617// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!1819#ifndef _DOLPHIN_FAKE_CODEGEN_20#define _DOLPHIN_FAKE_CODEGEN_2122#include <stdint.h>2324#include "Common/CommonTypes.h"25#include "Common/CodeBlock.h"2627// VCVT flags28#define TO_FLOAT 029#define TO_INT 1 << 030#define IS_SIGNED 1 << 131#define ROUND_TO_ZERO 1 << 23233namespace FakeGen34{35enum FakeReg36{37// GPRs38R0 = 0, R1, R2, R3, R4, R5,39R6, R7, R8, R9, R10, R11,4041// SPRs42// R13 - R15 are SP, LR, and PC.43// Almost always referred to by name instead of register number44R12 = 12, R13 = 13, R14 = 14, R15 = 15,45R_IP = 12, R_SP = 13, R_LR = 14, R_PC = 15,464748// VFP single precision registers49S0, S1, S2, S3, S4, S5, S6,50S7, S8, S9, S10, S11, S12, S13,51S14, S15, S16, S17, S18, S19, S20,52S21, S22, S23, S24, S25, S26, S27,53S28, S29, S30, S31,5455// VFP Double Precision registers56D0, D1, D2, D3, D4, D5, D6, D7,57D8, D9, D10, D11, D12, D13, D14, D15,58D16, D17, D18, D19, D20, D21, D22, D23,59D24, D25, D26, D27, D28, D29, D30, D31,6061// ASIMD Quad-Word registers62Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,63Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,6465// for NEON VLD/VST instructions66REG_UPDATE = R13,67INVALID_REG = 0xFFFFFFFF68};6970enum CCFlags71{72CC_EQ = 0, // Equal73CC_NEQ, // Not equal74CC_CS, // Carry Set75CC_CC, // Carry Clear76CC_MI, // Minus (Negative)77CC_PL, // Plus78CC_VS, // Overflow79CC_VC, // No Overflow80CC_HI, // Unsigned higher81CC_LS, // Unsigned lower or same82CC_GE, // Signed greater than or equal83CC_LT, // Signed less than84CC_GT, // Signed greater than85CC_LE, // Signed less than or equal86CC_AL, // Always (unconditional) 1487CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same88CC_LO = CC_CC, // Alias of CC_CC Unsigned lower89};90const u32 NO_COND = 0xE0000000;9192enum ShiftType93{94ST_LSL = 0,95ST_ASL = 0,96ST_LSR = 1,97ST_ASR = 2,98ST_ROR = 3,99ST_RRX = 4100};101enum IntegerSize102{103I_I8 = 0,104I_I16,105I_I32,106I_I64107};108109enum110{111NUMGPRs = 13,112};113114class FakeXEmitter;115116enum OpType117{118TYPE_IMM = 0,119TYPE_REG,120TYPE_IMMSREG,121TYPE_RSR,122TYPE_MEM123};124125// This is no longer a proper operand2 class. Need to split up.126class Operand2127{128friend class FakeXEmitter;129protected:130u32 Value;131132private:133OpType Type;134135// IMM types136u8 Rotation; // Only for u8 values137138// Register types139u8 IndexOrShift;140ShiftType Shift;141public:142OpType GetType()143{144return Type;145}146Operand2() {}147Operand2(u32 imm, OpType type = TYPE_IMM) : IndexOrShift(), Shift()148{149Type = type;150Value = imm;151Rotation = 0;152}153154Operand2(FakeReg Reg) : IndexOrShift(), Shift()155{156Type = TYPE_REG;157Value = Reg;158Rotation = 0;159}160Operand2(u8 imm, u8 rotation) : IndexOrShift(), Shift()161{162Type = TYPE_IMM;163Value = imm;164Rotation = rotation;165}166Operand2(FakeReg base, ShiftType type, FakeReg shift) : Rotation(0) // RSR167{168Type = TYPE_RSR;169_assert_msg_(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");170IndexOrShift = shift;171Shift = type;172Value = base;173}174175Operand2(FakeReg base, ShiftType type, u8 shift) : Rotation(0) // For IMM shifted register176{177if(shift == 32) shift = 0;178switch (type)179{180case ST_LSL:181_assert_msg_(shift < 32, "Invalid Operand2: LSL %u", shift);182break;183case ST_LSR:184_assert_msg_(shift <= 32, "Invalid Operand2: LSR %u", shift);185if (!shift)186type = ST_LSL;187if (shift == 32)188shift = 0;189break;190case ST_ASR:191_assert_msg_(shift < 32, "Invalid Operand2: ASR %u", shift);192if (!shift)193type = ST_LSL;194if (shift == 32)195shift = 0;196break;197case ST_ROR:198_assert_msg_(shift < 32, "Invalid Operand2: ROR %u", shift);199if (!shift)200type = ST_LSL;201break;202case ST_RRX:203_assert_msg_(shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");204type = ST_ROR;205break;206}207IndexOrShift = shift;208Shift = type;209Value = base;210Type = TYPE_IMMSREG;211}212u32 GetData()213{214switch(Type)215{216case TYPE_IMM:217return Imm12Mod(); // This'll need to be changed later218case TYPE_REG:219return Rm();220case TYPE_IMMSREG:221return IMMSR();222case TYPE_RSR:223return RSR();224default:225_assert_msg_(false, "GetData with Invalid Type");226return 0;227}228}229u32 IMMSR() // IMM shifted register230{231_assert_msg_(Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");232return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);233}234u32 RSR() // Register shifted register235{236_assert_msg_(Type == TYPE_RSR, "RSR must be RSR Of Course");237return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;238}239u32 Rm()240{241_assert_msg_(Type == TYPE_REG, "Rm must be with Reg");242return Value;243}244245u32 Imm5()246{247_assert_msg_(Type == TYPE_IMM, "Imm5 not IMM value");248return ((Value & 0x0000001F) << 7);249}250u32 Imm8()251{252_assert_msg_(Type == TYPE_IMM, "Imm8Rot not IMM value");253return Value & 0xFF;254}255u32 Imm8Rot() // IMM8 with Rotation256{257_assert_msg_(Type == TYPE_IMM, "Imm8Rot not IMM value");258_assert_msg_((Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);259return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);260}261u32 Imm12()262{263_assert_msg_(Type == TYPE_IMM, "Imm12 not IMM");264return (Value & 0x00000FFF);265}266267u32 Imm12Mod()268{269// This is an IMM12 with the top four bits being rotation and the270// bottom eight being an IMM. This is for instructions that need to271// expand a 8bit IMM to a 32bit value and gives you some rotation as272// well.273// Each rotation rotates to the right by 2 bits274_assert_msg_(Type == TYPE_IMM, "Imm12Mod not IMM");275return ((Rotation & 0xF) << 8) | (Value & 0xFF);276}277u32 Imm16()278{279_assert_msg_(Type == TYPE_IMM, "Imm16 not IMM");280return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);281}282u32 Imm16Low()283{284return Imm16();285}286u32 Imm16High() // Returns high 16bits287{288_assert_msg_(Type == TYPE_IMM, "Imm16 not IMM");289return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);290}291u32 Imm24()292{293_assert_msg_(Type == TYPE_IMM, "Imm16 not IMM");294return (Value & 0x0FFFFFFF);295}296};297298// Use these when you don't know if an imm can be represented as an operand2.299// This lets you generate both an optimal and a fallback solution by checking300// the return value, which will be false if these fail to find a Operand2 that301// represents your 32-bit imm value.302bool TryMakeOperand2(u32 imm, Operand2 &op2);303bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);304bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);305306// Use this only when you know imm can be made into an Operand2.307Operand2 AssumeMakeOperand2(u32 imm);308309inline Operand2 R(FakeReg Reg) { return Operand2(Reg, TYPE_REG); }310inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }311inline Operand2 Mem(void *ptr) { return Operand2((u32)(uintptr_t)ptr, TYPE_IMM); }312//usage: struct {int e;} s; STRUCT_OFFSET(s,e)313#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))314315316struct FixupBranch317{318u8 *ptr;319u32 condition; // Remembers our codition at the time320int type; //0 = B 1 = BL321};322323typedef const u8* JumpTarget;324325// XXX: Stop polluting the global namespace326const u32 I_8 = (1 << 0);327const u32 I_16 = (1 << 1);328const u32 I_32 = (1 << 2);329const u32 I_64 = (1 << 3);330const u32 I_SIGNED = (1 << 4);331const u32 I_UNSIGNED = (1 << 5);332const u32 F_32 = (1 << 6);333const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL334335u32 EncodeVd(FakeReg Vd);336u32 EncodeVn(FakeReg Vn);337u32 EncodeVm(FakeReg Vm);338339u32 encodedSize(u32 value);340341// Subtracts the base from the register to give us the real one342FakeReg SubBase(FakeReg Reg);343344// See A.7.1 in the Fakev7-A345// VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed346FakeReg DScalar(FakeReg dreg, int subScalar);347FakeReg QScalar(FakeReg qreg, int subScalar);348349enum NEONAlignment {350ALIGN_NONE = 0,351ALIGN_64 = 1,352ALIGN_128 = 2,353ALIGN_256 = 3354};355356357class NEONXEmitter;358359class FakeXEmitter360{361friend struct OpArg; // for Write8 etc362private:363u8 *code, *startcode;364u8 *lastCacheFlushEnd;365u32 condition;366367protected:368inline void Write32(u32 value) {*(u32*)code = value; code+=4;}369370public:371FakeXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {372condition = CC_AL << 28;373}374FakeXEmitter(u8 *code_ptr) {375code = code_ptr;376lastCacheFlushEnd = code_ptr;377startcode = code_ptr;378condition = CC_AL << 28;379}380virtual ~FakeXEmitter() {}381382void SetCodePointer(u8 *ptr, u8 *writePtr) {}383const u8 *GetCodePointer() const { return nullptr; }384385void SetCodePtr(u8 *ptr) {}386void ReserveCodeSpace(u32 bytes) {}387const u8 *AlignCode16() { return nullptr; }388const u8 *AlignCodePage() { return nullptr; }389const u8 *GetCodePtr() const { return nullptr; }390void FlushIcache() {}391void FlushIcacheSection(u8 *start, u8 *end) {}392u8 *GetWritableCodePtr() { return nullptr; }393394CCFlags GetCC() { return CCFlags(condition >> 28); }395void SetCC(CCFlags cond = CC_AL) {}396397// Special purpose instructions398399// Do nothing400void NOP(int count = 1) {} //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)401402#ifdef CALL403#undef CALL404#endif405406void QuickCallFunction(FakeReg scratchreg, const void *func);407template <typename T> void QuickCallFunction(FakeReg scratchreg, T func) {408QuickCallFunction(scratchreg, (const void *)func);409}410}; // class FakeXEmitter411412413// Everything that needs to generate machine code should inherit from this.414// You get memory management for free, plus, you can use all the MOV etc functions without415// having to prefix them with gen-> or something similar.416class FakeXCodeBlock : public CodeBlock<FakeXEmitter> {417public:418void PoisonMemory(int offset) override {419}420};421422} // namespace423424#endif // _DOLPHIN_FAKE_CODEGEN_425426427