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/ABI.cpp
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 or later versions.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#include "ppsspp_config.h"18#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)1920#include "x64Emitter.h"21#include "ABI.h"2223using namespace Gen;2425// Shared code between Win64 and Unix642627// Sets up a __cdecl function.28void XEmitter::ABI_EmitPrologue(int maxCallParams)29{30#if PPSSPP_ARCH(X86)31// Don't really need to do anything32#elif PPSSPP_ARCH(AMD64)33#if _WIN3234int stacksize = ((maxCallParams + 1) & ~1) * 8 + 8;35// Set up a stack frame so that we can call functions36// TODO: use maxCallParams37SUB(64, R(RSP), Imm8(stacksize));38#endif39#else40#error Arch not supported41#endif42}4344void XEmitter::ABI_EmitEpilogue(int maxCallParams)45{46#if PPSSPP_ARCH(X86)47RET();48#elif PPSSPP_ARCH(AMD64)49#ifdef _WIN3250int stacksize = ((maxCallParams+1)&~1)*8 + 8;51ADD(64, R(RSP), Imm8(stacksize));52#endif53RET();54#else55#error Arch not supported565758#endif59}6061#if PPSSPP_ARCH(X86) // All326263// Shared code between Win32 and Unix3264void XEmitter::ABI_CallFunction(const void *func) {65ABI_AlignStack(0);66CALL(func);67ABI_RestoreStack(0);68}6970void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) {71ABI_AlignStack(1 * 2);72PUSH(16, Imm16(param1));73CALL(func);74ABI_RestoreStack(1 * 2);75}7677void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) {78ABI_AlignStack(1 * 2 + 1 * 4);79PUSH(16, Imm16(param2));80PUSH(32, Imm32(param1));81CALL(func);82ABI_RestoreStack(1 * 2 + 1 * 4);83}8485void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) {86ABI_AlignStack(1 * 4);87PUSH(32, Imm32(param1));88CALL(func);89ABI_RestoreStack(1 * 4);90}9192void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) {93ABI_AlignStack(2 * 4);94PUSH(32, Imm32(param2));95PUSH(32, Imm32(param1));96CALL(func);97ABI_RestoreStack(2 * 4);98}99100void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) {101ABI_AlignStack(3 * 4);102PUSH(32, Imm32(param3));103PUSH(32, Imm32(param2));104PUSH(32, Imm32(param1));105CALL(func);106ABI_RestoreStack(3 * 4);107}108109void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) {110ABI_AlignStack(3 * 4);111PUSH(32, ImmPtr(param3));112PUSH(32, Imm32(param2));113PUSH(32, Imm32(param1));114CALL(func);115ABI_RestoreStack(3 * 4);116}117118void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2,u32 param3, void *param4) {119ABI_AlignStack(4 * 4);120PUSH(32, ImmPtr(param4));121PUSH(32, Imm32(param3));122PUSH(32, Imm32(param2));123PUSH(32, Imm32(param1));124CALL(func);125ABI_RestoreStack(4 * 4);126}127128void XEmitter::ABI_CallFunctionP(const void *func, void *param1) {129ABI_AlignStack(1 * 4);130PUSH(32, ImmPtr(param1));131CALL(func);132ABI_RestoreStack(1 * 4);133}134135void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) {136ABI_AlignStack(2 * 4);137PUSH(32, arg2);138PUSH(32, ImmPtr(param1));139CALL(func);140ABI_RestoreStack(2 * 4);141}142143void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) {144ABI_AlignStack(3 * 4);145PUSH(32, arg3);146PUSH(32, arg2);147PUSH(32, ImmPtr(param1));148CALL(func);149ABI_RestoreStack(3 * 4);150}151152void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) {153ABI_AlignStack(3 * 4);154PUSH(32, Imm32(param3));155PUSH(32, ImmPtr(param2));156PUSH(32, ImmPtr(param1));157CALL(func);158ABI_RestoreStack(3 * 4);159}160161// Pass a register as a parameter.162void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) {163ABI_AlignStack(1 * 4);164PUSH(32, R(reg1));165CALL(func);166ABI_RestoreStack(1 * 4);167}168169// Pass two registers as parameters.170void XEmitter::ABI_CallFunctionRR(const void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)171{172ABI_AlignStack(2 * 4);173PUSH(32, R(reg2));174PUSH(32, R(reg1));175CALL(func);176ABI_RestoreStack(2 * 4);177}178179void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2)180{181ABI_AlignStack(2 * 4);182PUSH(32, Imm32(param2));183PUSH(32, arg1);184CALL(func);185ABI_RestoreStack(2 * 4);186}187188void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3)189{190ABI_AlignStack(3 * 4);191PUSH(32, Imm32(param3));192PUSH(32, Imm32(param2));193PUSH(32, arg1);194CALL(func);195ABI_RestoreStack(3 * 4);196}197198void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1)199{200ABI_AlignStack(1 * 4);201PUSH(32, arg1);202CALL(func);203ABI_RestoreStack(1 * 4);204}205206void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2)207{208ABI_AlignStack(2 * 4);209PUSH(32, arg2);210PUSH(32, arg1);211CALL(func);212ABI_RestoreStack(2 * 4);213}214215void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {216// Note: 4 * 4 = 16 bytes, so alignment is preserved.217PUSH(EBP);218PUSH(EBX);219PUSH(ESI);220PUSH(EDI);221}222223void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {224POP(EDI);225POP(ESI);226POP(EBX);227POP(EBP);228}229230unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {231frameSize += 4; // reserve space for return address232unsigned int alignedSize =233#ifdef __GNUC__234(frameSize + 15) & -16;235#else236(frameSize + 3) & -4;237#endif238return alignedSize;239}240241242void XEmitter::ABI_AlignStack(unsigned int frameSize) {243// Mac OS X requires the stack to be 16-byte aligned before every call.244// Linux requires the stack to be 16-byte aligned before calls that put SSE245// vectors on the stack, but since we do not keep track of which calls do that,246// it is effectively every call as well.247// Windows binaries compiled with MSVC do not have such a restriction*, but I248// expect that GCC on Windows acts the same as GCC on Linux in this respect.249// It would be nice if someone could verify this.250// *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.251unsigned int fillSize =252ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);253if (fillSize != 0) {254SUB(32, R(ESP), Imm8(fillSize));255}256}257258void XEmitter::ABI_RestoreStack(unsigned int frameSize) {259unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);260alignedSize -= 4; // return address is POPped at end of call261if (alignedSize != 0) {262ADD(32, R(ESP), Imm8(alignedSize));263}264}265266#else //64bit267268// Common functions269void XEmitter::ABI_CallFunction(const void *func) {270u64 distance = u64(func) - (u64(code) + 5);271if (distance >= 0x0000000080000000ULL272&& distance < 0xFFFFFFFF80000000ULL) {273// Far call274MOV(64, R(RAX), ImmPtr(func));275CALLptr(R(RAX));276} else {277CALL(func);278}279}280281void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) {282MOV(32, R(ABI_PARAM1), Imm32((u32)param1));283u64 distance = u64(func) - (u64(code) + 5);284if (distance >= 0x0000000080000000ULL285&& distance < 0xFFFFFFFF80000000ULL) {286// Far call287MOV(64, R(RAX), ImmPtr(func));288CALLptr(R(RAX));289} else {290CALL(func);291}292}293294void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) {295MOV(32, R(ABI_PARAM1), Imm32(param1));296MOV(32, R(ABI_PARAM2), Imm32((u32)param2));297u64 distance = u64(func) - (u64(code) + 5);298if (distance >= 0x0000000080000000ULL299&& distance < 0xFFFFFFFF80000000ULL) {300// Far call301MOV(64, R(RAX), ImmPtr(func));302CALLptr(R(RAX));303} else {304CALL(func);305}306}307308void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) {309MOV(32, R(ABI_PARAM1), Imm32(param1));310u64 distance = u64(func) - (u64(code) + 5);311if (distance >= 0x0000000080000000ULL312&& distance < 0xFFFFFFFF80000000ULL) {313// Far call314MOV(64, R(RAX), ImmPtr(func));315CALLptr(R(RAX));316} else {317CALL(func);318}319}320321void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) {322MOV(32, R(ABI_PARAM1), Imm32(param1));323MOV(32, R(ABI_PARAM2), Imm32(param2));324u64 distance = u64(func) - (u64(code) + 5);325if (distance >= 0x0000000080000000ULL326&& distance < 0xFFFFFFFF80000000ULL) {327// Far call328MOV(64, R(RAX), ImmPtr(func));329CALLptr(R(RAX));330} else {331CALL(func);332}333}334335void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) {336MOV(32, R(ABI_PARAM1), Imm32(param1));337MOV(32, R(ABI_PARAM2), Imm32(param2));338MOV(32, R(ABI_PARAM3), Imm32(param3));339u64 distance = u64(func) - (u64(code) + 5);340if (distance >= 0x0000000080000000ULL341&& distance < 0xFFFFFFFF80000000ULL) {342// Far call343MOV(64, R(RAX), ImmPtr(func));344CALLptr(R(RAX));345} else {346CALL(func);347}348}349350void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) {351MOV(32, R(ABI_PARAM1), Imm32(param1));352MOV(32, R(ABI_PARAM2), Imm32(param2));353MOV(64, R(ABI_PARAM3), ImmPtr(param3));354u64 distance = u64(func) - (u64(code) + 5);355if (distance >= 0x0000000080000000ULL356&& distance < 0xFFFFFFFF80000000ULL) {357// Far call358MOV(64, R(RAX), ImmPtr(func));359CALLptr(R(RAX));360} else {361CALL(func);362}363}364365void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u32 param3, void *param4) {366MOV(32, R(ABI_PARAM1), Imm32(param1));367MOV(32, R(ABI_PARAM2), Imm32(param2));368MOV(32, R(ABI_PARAM3), Imm32(param3));369MOV(64, R(ABI_PARAM4), ImmPtr(param4));370u64 distance = u64(func) - (u64(code) + 5);371if (distance >= 0x0000000080000000ULL372&& distance < 0xFFFFFFFF80000000ULL) {373// Far call374MOV(64, R(RAX), ImmPtr(func));375CALLptr(R(RAX));376} else {377CALL(func);378}379}380381void XEmitter::ABI_CallFunctionP(const void *func, void *param1) {382MOV(64, R(ABI_PARAM1), ImmPtr(param1));383u64 distance = u64(func) - (u64(code) + 5);384if (distance >= 0x0000000080000000ULL385&& distance < 0xFFFFFFFF80000000ULL) {386// Far call387MOV(64, R(RAX), ImmPtr(func));388CALLptr(R(RAX));389} else {390CALL(func);391}392}393394void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) {395MOV(64, R(ABI_PARAM1), ImmPtr(param1));396if (!arg2.IsSimpleReg(ABI_PARAM2))397MOV(32, R(ABI_PARAM2), arg2);398u64 distance = u64(func) - (u64(code) + 5);399if (distance >= 0x0000000080000000ULL400&& distance < 0xFFFFFFFF80000000ULL) {401// Far call402MOV(64, R(RAX), ImmPtr(func));403CALLptr(R(RAX));404} else {405CALL(func);406}407}408409void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) {410MOV(64, R(ABI_PARAM1), ImmPtr(param1));411if (!arg2.IsSimpleReg(ABI_PARAM2))412MOV(32, R(ABI_PARAM2), arg2);413if (!arg3.IsSimpleReg(ABI_PARAM3))414MOV(32, R(ABI_PARAM3), arg3);415u64 distance = u64(func) - (u64(code) + 5);416if (distance >= 0x0000000080000000ULL417&& distance < 0xFFFFFFFF80000000ULL) {418// Far call419MOV(64, R(RAX), ImmPtr(func));420CALLptr(R(RAX));421} else {422CALL(func);423}424}425426void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) {427MOV(64, R(ABI_PARAM1), ImmPtr(param1));428MOV(64, R(ABI_PARAM2), ImmPtr(param2));429MOV(32, R(ABI_PARAM3), Imm32(param3));430u64 distance = u64(func) - (u64(code) + 5);431if (distance >= 0x0000000080000000ULL432&& distance < 0xFFFFFFFF80000000ULL) {433// Far call434MOV(64, R(RAX), ImmPtr(func));435CALLptr(R(RAX));436} else {437CALL(func);438}439}440441// Pass a register as a parameter.442void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) {443if (reg1 != ABI_PARAM1)444MOV(32, R(ABI_PARAM1), R(reg1));445u64 distance = u64(func) - (u64(code) + 5);446if (distance >= 0x0000000080000000ULL447&& distance < 0xFFFFFFFF80000000ULL) {448// Far call449MOV(64, R(RAX), ImmPtr(func));450CALLptr(R(RAX));451} else {452CALL(func);453}454}455456// Pass two registers as parameters.457void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) {458if (reg2 != ABI_PARAM1) {459if (reg1 != ABI_PARAM1)460MOV(64, R(ABI_PARAM1), R(reg1));461if (reg2 != ABI_PARAM2)462MOV(64, R(ABI_PARAM2), R(reg2));463} else {464if (reg2 != ABI_PARAM2)465MOV(64, R(ABI_PARAM2), R(reg2));466if (reg1 != ABI_PARAM1)467MOV(64, R(ABI_PARAM1), R(reg1));468}469u64 distance = u64(func) - (u64(code) + 5);470if (distance >= 0x0000000080000000ULL471&& distance < 0xFFFFFFFF80000000ULL) {472// Far call473MOV(64, R(RAX), ImmPtr(func));474CALLptr(R(RAX));475} else {476CALL(func);477}478}479480void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2)481{482if (!arg1.IsSimpleReg(ABI_PARAM1))483MOV(32, R(ABI_PARAM1), arg1);484MOV(32, R(ABI_PARAM2), Imm32(param2));485u64 distance = u64(func) - (u64(code) + 5);486if (distance >= 0x0000000080000000ULL487&& distance < 0xFFFFFFFF80000000ULL) {488// Far call489MOV(64, R(RAX), ImmPtr(func));490CALLptr(R(RAX));491} else {492CALL(func);493}494}495496void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3)497{498if (!arg1.IsSimpleReg(ABI_PARAM1))499MOV(32, R(ABI_PARAM1), arg1);500MOV(32, R(ABI_PARAM2), Imm32(param2));501MOV(64, R(ABI_PARAM3), Imm64(param3));502u64 distance = u64(func) - (u64(code) + 5);503if (distance >= 0x0000000080000000ULL504&& distance < 0xFFFFFFFF80000000ULL) {505// Far call506MOV(64, R(RAX), ImmPtr(func));507CALLptr(R(RAX));508} else {509CALL(func);510}511}512513void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1)514{515if (!arg1.IsSimpleReg(ABI_PARAM1))516MOV(32, R(ABI_PARAM1), arg1);517u64 distance = u64(func) - (u64(code) + 5);518if (distance >= 0x0000000080000000ULL519&& distance < 0xFFFFFFFF80000000ULL) {520// Far call521MOV(64, R(RAX), ImmPtr(func));522CALLptr(R(RAX));523} else {524CALL(func);525}526}527528void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2)529{530if (!arg1.IsSimpleReg(ABI_PARAM1))531MOV(32, R(ABI_PARAM1), arg1);532if (!arg2.IsSimpleReg(ABI_PARAM2))533MOV(32, R(ABI_PARAM2), arg2);534u64 distance = u64(func) - (u64(code) + 5);535if (distance >= 0x0000000080000000ULL536&& distance < 0xFFFFFFFF80000000ULL) {537// Far call538MOV(64, R(RAX), ImmPtr(func));539CALLptr(R(RAX));540} else {541CALL(func);542}543}544545unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {546return frameSize;547}548549#ifdef _WIN32550551// The Windows x64 ABI requires XMM6 - XMM15 to be callee saved. 10 regs.552// But, not saving XMM4 and XMM5 breaks things in VS 2010, even though they are volatile regs.553// Let's just save all 16.554const int XMM_STACK_SPACE = 16 * 16;555556// Win64 Specific Code557void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {558//we only want to do this once559PUSH(RBX);560PUSH(RSI);561PUSH(RDI);562PUSH(RBP);563PUSH(R12);564PUSH(R13);565PUSH(R14);566PUSH(R15);567ABI_AlignStack(0);568569// Do this after aligning, because before it's offset by 8.570SUB(64, R(RSP), Imm32(XMM_STACK_SPACE));571for (int i = 0; i < 16; ++i)572MOVAPS(MDisp(RSP, i * 16), (X64Reg)(XMM0 + i));573}574575void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {576for (int i = 0; i < 16; ++i)577MOVAPS((X64Reg)(XMM0 + i), MDisp(RSP, i * 16));578ADD(64, R(RSP), Imm32(XMM_STACK_SPACE));579580ABI_RestoreStack(0);581POP(R15);582POP(R14);583POP(R13);584POP(R12);585POP(RBP);586POP(RDI);587POP(RSI);588POP(RBX);589}590591// Win64 Specific Code592void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {593PUSH(RCX);594PUSH(RDX);595PUSH(RSI);596PUSH(RDI);597PUSH(R8);598PUSH(R9);599PUSH(R10);600PUSH(R11);601// TODO: Callers preserve XMM4-5 (XMM0-3 are args.)602ABI_AlignStack(0);603}604605void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {606ABI_RestoreStack(0);607POP(R11);608POP(R10);609POP(R9);610POP(R8);611POP(RDI);612POP(RSI);613POP(RDX);614POP(RCX);615}616617void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {618SUB(64, R(RSP), Imm8(0x28));619}620621void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {622ADD(64, R(RSP), Imm8(0x28));623}624625#else626// Unix64 Specific Code627void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {628PUSH(RBX);629PUSH(RBP);630PUSH(R12);631PUSH(R13);632PUSH(R14);633PUSH(R15);634PUSH(R15); //just to align stack. duped push/pop doesn't hurt.635// TODO: XMM?636}637638void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {639POP(R15);640POP(R15);641POP(R14);642POP(R13);643POP(R12);644POP(RBP);645POP(RBX);646}647648void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {649PUSH(RCX);650PUSH(RDX);651PUSH(RSI);652PUSH(RDI);653PUSH(R8);654PUSH(R9);655PUSH(R10);656PUSH(R11);657PUSH(R11);658}659660void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {661POP(R11);662POP(R11);663POP(R10);664POP(R9);665POP(R8);666POP(RDI);667POP(RSI);668POP(RDX);669POP(RCX);670}671672void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {673SUB(64, R(RSP), Imm8(0x08));674}675676void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {677ADD(64, R(RSP), Imm8(0x08));678}679680#endif // WIN32681682#endif // 32bit683684#endif // PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)685686687