From f77f792cc4ed16a595f32df3c66ff5690bac7af1 Mon Sep 17 00:00:00 2001 From: kobalicekp Date: Wed, 5 Mar 2014 23:27:28 +0100 Subject: [PATCH] X86Assembler - Minor fixes related to illegal instruction/illegal addressing error handling. X86Compiler - Always create SArg for every stack-based function argument X86Compiler - Possible to allocate a register that has to be used to convert variable to function argument. X86Compiler - ContextID generation moved to context_p.h. X86Compiler - Support for one variable being used by multiple function-call arguments. X86Defs - Removed support for 'long double' (buggy, never used). X86Func - Register arguments have to be converted from Fp32/Fp64 to XmmSs/XmmSd, respectively. --- src/app/test/testx86.cpp | 143 ++++++-- src/asmjit/base/compiler.h | 51 ++- src/asmjit/base/context_p.h | 15 + src/asmjit/base/defs.h | 23 +- src/asmjit/x86/x86assembler.cpp | 13 +- src/asmjit/x86/x86compiler.h | 221 ++++++----- src/asmjit/x86/x86context.cpp | 628 +++++++++++++++++++++----------- src/asmjit/x86/x86context_p.h | 1 + src/asmjit/x86/x86defs.cpp | 51 ++- src/asmjit/x86/x86defs.h | 20 +- src/asmjit/x86/x86func.cpp | 28 +- src/asmjit/x86/x86func.h | 7 - tools/autoexp.dat | 8 +- 13 files changed, 761 insertions(+), 448 deletions(-) diff --git a/src/app/test/testx86.cpp b/src/app/test/testx86.cpp index 529ea35..5f74312 100644 --- a/src/app/test/testx86.cpp +++ b/src/app/test/testx86.cpp @@ -1584,6 +1584,64 @@ struct X86Test_CallManyArgs : public X86Test { } }; +// ============================================================================ +// [X86Test_CallDuplicateArgs] +// ============================================================================ + +struct X86Test_CallDuplicateArgs : public X86Test { + X86Test_CallDuplicateArgs() : X86Test("[Call] Duplicate Args") {} + + static void add(PodVector& tests) { + tests.append(new X86Test_CallDuplicateArgs()); + } + + static int calledFunc(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { + return (a * b * c * d * e) + (f * g * h * i * j); + } + + virtual void compile(Compiler& c) { + c.addFunc(kFuncConvHost, FuncBuilder0()); + + // Prepare. + GpVar fn(c, kVarTypeIntPtr, "fn"); + GpVar a(c, kVarTypeInt32, "a"); + + c.mov(fn, imm_ptr((void*)calledFunc)); + c.mov(a, 3); + + // Call function. + X86X64CallNode* call = c.call(fn, kFuncConvHost, + FuncBuilder10()); + call->setArg(0, a); + call->setArg(1, a); + call->setArg(2, a); + call->setArg(3, a); + call->setArg(4, a); + call->setArg(5, a); + call->setArg(6, a); + call->setArg(7, a); + call->setArg(8, a); + call->setArg(9, a); + call->setRet(0, a); + + c.ret(a); + c.endFunc(); + } + + virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) { + typedef int (*Func)(void); + Func func = asmjit_cast(_func); + + int resultRet = func(); + int expectRet = calledFunc(3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + + result.setFormat("ret=%d", resultRet); + expect.setFormat("ret=%d", expectRet); + + return resultRet == expectRet; + } +}; + // ============================================================================ // [X86Test_CallImmArgs] // ============================================================================ @@ -1638,14 +1696,14 @@ struct X86Test_CallImmArgs : public X86Test { }; // ============================================================================ -// [X86Test_CallFloatRet] +// [X86Test_CallFloatAsXmmRet] // ============================================================================ -struct X86Test_CallFloatRet : public X86Test { - X86Test_CallFloatRet() : X86Test("[Call] Float Ret") {} +struct X86Test_CallFloatAsXmmRet : public X86Test { + X86Test_CallFloatAsXmmRet() : X86Test("[Call] Float As Xmm Ret") {} static void add(PodVector& tests) { - tests.append(new X86Test_CallFloatRet()); + tests.append(new X86Test_CallFloatAsXmmRet()); } static float calledFunc(float a, float b) { @@ -1655,6 +1713,13 @@ struct X86Test_CallFloatRet : public X86Test { virtual void compile(Compiler& c) { c.addFunc(kFuncConvHost, FuncBuilder2()); + XmmVar a(c, kVarTypeXmmSs, "a"); + XmmVar b(c, kVarTypeXmmSs, "b"); + XmmVar ret(c, kVarTypeXmmSs, "ret"); + + c.setArg(0, a); + c.setArg(1, b); + // Prepare. GpVar fn(c); c.mov(fn, imm_ptr((void*)calledFunc)); @@ -1663,12 +1728,8 @@ struct X86Test_CallFloatRet : public X86Test { X86X64CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder2()); - XmmVar a(c, kVarTypeXmmSd, "a"); - XmmVar b(c, kVarTypeXmmSd, "b"); - XmmVar ret(c, kVarTypeXmmSd, "ret"); - call->setArg(0, a); - call->setArg(0, b); + call->setArg(1, b); call->setRet(0, ret); c.ret(ret); @@ -1690,14 +1751,14 @@ struct X86Test_CallFloatRet : public X86Test { }; // ============================================================================ -// [X86Test_CallDoubleRet] +// [X86Test_CallDoubleAsXmmRet] // ============================================================================ -struct X86Test_CallDoubleRet : public X86Test { - X86Test_CallDoubleRet() : X86Test("[Call] Float Ret") {} +struct X86Test_CallDoubleAsXmmRet : public X86Test { + X86Test_CallDoubleAsXmmRet() : X86Test("[Call] Double As Xmm Ret") {} static void add(PodVector& tests) { - tests.append(new X86Test_CallDoubleRet()); + tests.append(new X86Test_CallDoubleAsXmmRet()); } static double calledFunc(double a, double b) { @@ -1707,20 +1768,21 @@ struct X86Test_CallDoubleRet : public X86Test { virtual void compile(Compiler& c) { c.addFunc(kFuncConvHost, FuncBuilder2()); - // Prepare. - GpVar fn(c); - c.mov(fn, imm_ptr((void*)calledFunc)); - - // Call function. - X86X64CallNode* call = c.call(fn, kFuncConvHost, - FuncBuilder2()); - XmmVar a(c, kVarTypeXmmSd, "a"); XmmVar b(c, kVarTypeXmmSd, "b"); XmmVar ret(c, kVarTypeXmmSd, "ret"); + c.setArg(0, a); + c.setArg(1, b); + + GpVar fn(c); + c.mov(fn, imm_ptr((void*)calledFunc)); + + X86X64CallNode* call = c.call(fn, kFuncConvHost, + FuncBuilder2()); + call->setArg(0, a); - call->setArg(0, b); + call->setArg(1, b); call->setRet(0, ret); c.ret(ret); @@ -2058,8 +2120,10 @@ X86TestSuite::X86TestSuite() : ADD_TEST(X86Test_CallBase); ADD_TEST(X86Test_CallFast); ADD_TEST(X86Test_CallManyArgs); + ADD_TEST(X86Test_CallDuplicateArgs); ADD_TEST(X86Test_CallImmArgs); - ADD_TEST(X86Test_CallDoubleRet); + ADD_TEST(X86Test_CallFloatAsXmmRet); + ADD_TEST(X86Test_CallDoubleAsXmmRet); ADD_TEST(X86Test_CallConditional); ADD_TEST(X86Test_CallMultiple); ADD_TEST(X86Test_CallRecursive); @@ -2084,14 +2148,24 @@ int X86TestSuite::run() { FILE* file = stdout; + FileLogger fileLogger(file); + fileLogger.setOption(kLoggerOptionBinaryForm, true); + + StringLogger stringLogger; + stringLogger.setOption(kLoggerOptionBinaryForm, true); + for (i = 0; i < count; i++) { JitRuntime runtime; - - StringLogger logger; - logger.setOption(kLoggerOptionBinaryForm, true); - Compiler compiler(&runtime); - compiler.setLogger(&logger); + + if (alwaysPrintLog) { + fprintf(file, "\n"); + compiler.setLogger(&fileLogger); + } + else { + stringLogger.clearString(); + compiler.setLogger(&stringLogger); + } X86Test* test = tests[i]; test->compile(compiler); @@ -2099,7 +2173,6 @@ int X86TestSuite::run() { void* func = compiler.make(); if (alwaysPrintLog) { - fprintf(file, "\n%s", logger.getString()); fflush(file); } @@ -2111,8 +2184,10 @@ int X86TestSuite::run() { fprintf(file, "[Success] %s.\n", test->getName()); } else { - if (!alwaysPrintLog) - fprintf(file, "\n%s", logger.getString()); + if (!alwaysPrintLog) { + fprintf(file, "\n%s", stringLogger.getString()); + } + fprintf(file, "-------------------------------------------------------------------------------\n"); fprintf(file, "[Failure] %s.\n", test->getName()); fprintf(file, "-------------------------------------------------------------------------------\n"); @@ -2124,8 +2199,10 @@ int X86TestSuite::run() { runtime.release(func); } else { - if (!alwaysPrintLog) - fprintf(file, "%s\n", logger.getString()); + if (!alwaysPrintLog) { + fprintf(file, "%s\n", stringLogger.getString()); + } + fprintf(file, "-------------------------------------------------------------------------------\n"); fprintf(file, "[Failure] %s.\n", test->getName()); fprintf(file, "===============================================================================\n"); diff --git a/src/asmjit/base/compiler.h b/src/asmjit/base/compiler.h index f26964a..24b89df 100644 --- a/src/asmjit/base/compiler.h +++ b/src/asmjit/base/compiler.h @@ -81,15 +81,13 @@ ASMJIT_ENUM(kVarAttrFlags) { kVarAttrInCall = 0x00000100, //! @brief Variable is a function argument passed in register. kVarAttrInArg = 0x00000200, - //! @brief Variable is a function argument passed on the stack. - kVarAttrInStack = 0x00000400, + //! @brief Variable is a function return value passed in register. - kVarAttrOutRet = 0x00000800, - + kVarAttrOutRet = 0x00000400, //! @brief Variable should be unused at the end of the instruction/node. - kVarAttrUnuse = 0x00001000, + kVarAttrUnuse = 0x00000800, - kVarAttrInAll = kVarAttrInReg | kVarAttrInMem | kVarAttrInDecide | kVarAttrInCall | kVarAttrInArg | kVarAttrInStack, + kVarAttrInAll = kVarAttrInReg | kVarAttrInMem | kVarAttrInDecide | kVarAttrInCall | kVarAttrInArg, kVarAttrOutAll = kVarAttrOutReg | kVarAttrOutMem | kVarAttrOutDecide | kVarAttrOutRet, //! @brief Variable is already allocated on the input. @@ -544,9 +542,9 @@ struct VarAttr { _vd = vd; _flags = flags; _varCount = 0; - _argStackCount = 0; _inRegIndex = kInvalidReg; _outRegIndex = kInvalidReg; + _reserved = 0; _inRegs = inRegs; _allocableRegs = allocableRegs; } @@ -581,13 +579,6 @@ struct VarAttr { //! @brief Add how many times the variable is used by the instruction/node. ASMJIT_INLINE void addVarCount(uint32_t count = 1) { _varCount += static_cast(count); } - //! @brief Get how many times the variable is used by the function argument. - ASMJIT_INLINE uint32_t getArgStackCount() const { return _argStackCount; } - //! @brief Set how many times the variable is used by the function argument. - ASMJIT_INLINE void setArgStackCount(uint32_t count) { _argStackCount = static_cast(count); } - //! @brief Add how many times the variable is used by the function argument. - ASMJIT_INLINE void addArgStackCount(uint32_t count = 1) { _argStackCount += static_cast(count); } - //! @brief Get whether the variable has to be allocated in a specific input register. ASMJIT_INLINE uint32_t hasInRegIndex() const { return _inRegIndex != kInvalidReg; } //! @brief Get the input register index or @ref kInvalidReg. @@ -651,12 +642,6 @@ struct VarAttr { struct { //! @brief How many times the variable is used by the instruction/node. uint8_t _varCount; - //! @brief How many times the variable is used as a function argument on - //! the stack. - //! - //! This is important to know for function-call allocator. It doesn't - //! allocate by arguments, but by using VarAttr's. - uint8_t _argStackCount; //! @brief Input register index or @ref kInvalidReg if it's not given. //! //! Even if the input register index is not given (i.e. it may by any @@ -669,6 +654,8 @@ struct VarAttr { //! //! Typically @ref kInvalidReg if variable is only used on input. uint8_t _outRegIndex; + //! @internal + uint8_t _reserved; }; //! @internal @@ -1605,10 +1592,12 @@ struct SArgNode : public BaseNode { // -------------------------------------------------------------------------- //! @brief Create a new @ref SArgNode instance. - ASMJIT_INLINE SArgNode(BaseCompiler* compiler, VarData* vd, CallNode* call) : + ASMJIT_INLINE SArgNode(BaseCompiler* compiler, CallNode* call, VarData* sVd, VarData* cVd) : BaseNode(compiler, kNodeTypeSArg), - _vd(vd), - _call(call) {} + _call(call), + _sVd(sVd), + _cVd(cVd), + _args(0) {} //! @brief Destroy the @ref SArgNode instance. ASMJIT_INLINE ~SArgNode() {} @@ -1617,20 +1606,26 @@ struct SArgNode : public BaseNode { // [Accessors] // -------------------------------------------------------------------------- - //! @brief Get the associated variable. - ASMJIT_INLINE VarData* getVd() const { return _vd; } - //! @brief Get the associated function-call. ASMJIT_INLINE CallNode* getCall() const { return _call; } + //! @brief Get source variable. + ASMJIT_INLINE VarData* getSVd() const { return _sVd; } + //! @brief Get conversion variable. + ASMJIT_INLINE VarData* getCVd() const { return _cVd; } // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- - //! @brief Variable. - VarData* _vd; //! @brief Associated @ref CallNode. CallNode* _call; + //! @brief Source variable. + VarData* _sVd; + //! @brief Temporary variable used for conversion (or NULL). + VarData* _cVd; + + //! @brief Affected arguments bit-array. + uint32_t _args; }; // ============================================================================ diff --git a/src/asmjit/base/context_p.h b/src/asmjit/base/context_p.h index c82aa9a..3374cea 100644 --- a/src/asmjit/base/context_p.h +++ b/src/asmjit/base/context_p.h @@ -97,6 +97,21 @@ struct BaseContext { // [Mem] // -------------------------------------------------------------------------- + ASMJIT_INLINE Error _registerContextVar(VarData* vd) { + if (vd->hasContextId()) + return kErrorOk; + + uint32_t cid = static_cast(_contextVd.getLength()); + ASMJIT_PROPAGATE_ERROR(_contextVd.append(vd)); + + vd->setContextId(cid); + return kErrorOk; + } + + // -------------------------------------------------------------------------- + // [Mem] + // -------------------------------------------------------------------------- + MemCell* _newVarCell(VarData* vd); MemCell* _newStackCell(uint32_t size, uint32_t alignment); diff --git a/src/asmjit/base/defs.h b/src/asmjit/base/defs.h index c9070ff..60068e3 100644 --- a/src/asmjit/base/defs.h +++ b/src/asmjit/base/defs.h @@ -202,10 +202,6 @@ ASMJIT_ENUM(kVarType) { kVarTypeFp32 = 10, //! @brief Variable is 64-bit floating point (double precision). kVarTypeFp64 = 11, - //! @brief Variable is 80-bit or 128-bit floating point (extended precision). - //! - //! @note Experimental, better not to use. - kVarTypeFpEx = 12, //! @brief Invalid variable type. kVarTypeInvalid = 0xFF, @@ -213,7 +209,12 @@ ASMJIT_ENUM(kVarType) { //! @internal _kVarTypeIntStart = kVarTypeInt8, //! @internal - _kVarTypeIntEnd = kVarTypeUIntPtr + _kVarTypeIntEnd = kVarTypeUIntPtr, + + //! @internal + _kVarTypeFpStart = kVarTypeFp32, + //! @internal + _kVarTypeFpEnd = kVarTypeFp64 }; // ============================================================================ @@ -424,7 +425,9 @@ struct Operand { //! @internal //! //! @brief Initialize operand to @a other (used by constructors). - ASMJIT_INLINE void _init(const Operand& other) { ::memcpy(this, &other, sizeof(Operand)); } + ASMJIT_INLINE void _init(const Operand& other) { + ::memcpy(this, &other, sizeof(Operand)); + } ASMJIT_INLINE void _init_packed_op_sz_b0_b1_id(uint32_t op, uint32_t sz, uint32_t r0, uint32_t r1, uint32_t id) { // This hack is not for performance, but to decrease the size of the binary @@ -451,7 +454,9 @@ struct Operand { //! @internal //! //! @brief Initialize operand to @a other (used by assign operators). - ASMJIT_INLINE void _copy(const Operand& other) { ::memcpy(this, &other, sizeof(Operand)); } + ASMJIT_INLINE void _copy(const Operand& other) { + ::memcpy(this, &other, sizeof(Operand)); + } // -------------------------------------------------------------------------- // [Data] @@ -807,9 +812,7 @@ struct BaseVar : public Operand { ASMJIT_INLINE BaseVar& operator=(const BaseVar& other) { _copy(other); return *this; } - ASMJIT_INLINE bool operator==(const BaseVar& other) const - { return _packed[0] == other._packed[0]; } - + ASMJIT_INLINE bool operator==(const BaseVar& other) const { return _packed[0] == other._packed[0]; } ASMJIT_INLINE bool operator!=(const BaseVar& other) const { return !operator==(other); } }; diff --git a/src/asmjit/x86/x86assembler.cpp b/src/asmjit/x86/x86assembler.cpp index 6aac843..9233af6 100644 --- a/src/asmjit/x86/x86assembler.cpp +++ b/src/asmjit/x86/x86assembler.cpp @@ -3049,6 +3049,13 @@ _EmitAvxRvm: // [Illegal] // -------------------------------------------------------------------------- +_IllegalInst: + self->setError(kErrorAssemblerIllegalInst); +#if defined(ASMJIT_DEBUG) + assertIllegal = true; +#endif // ASMJIT_DEBUG + goto _EmitDone; + _IllegalAddr: self->setError(kErrorAssemblerIllegalAddr); #if defined(ASMJIT_DEBUG) @@ -3056,12 +3063,6 @@ _IllegalAddr: #endif // ASMJIT_DEBUG goto _EmitDone; -_IllegalInst: - self->setError(kErrorAssemblerIllegalInst); -#if defined(ASMJIT_DEBUG) - assertIllegal = true; -#endif // ASMJIT_DEBUG - goto _EmitDone; // -------------------------------------------------------------------------- // [Emit - X86] diff --git a/src/asmjit/x86/x86compiler.h b/src/asmjit/x86/x86compiler.h index 5cd2d64..45e9417 100644 --- a/src/asmjit/x86/x86compiler.h +++ b/src/asmjit/x86/x86compiler.h @@ -226,35 +226,38 @@ struct VarInst : public BaseVarInst { // -------------------------------------------------------------------------- //! @brief Get variable-attributes list as VarAttr data. - ASMJIT_INLINE VarAttr* getVaList() const - { return const_cast(_list); } + ASMJIT_INLINE VarAttr* getVaList() const { + return const_cast(_list); + } //! @brief Get variable-attributes list as VarAttr data (by class). - ASMJIT_INLINE VarAttr* getVaListByClass(uint32_t c) const - { return const_cast(_list) + _start.get(c); } + ASMJIT_INLINE VarAttr* getVaListByClass(uint32_t c) const { + return const_cast(_list) + _start.get(c); + } //! @brief Get position of variables (by class). - ASMJIT_INLINE uint32_t getVaStart(uint32_t c) const - { return _start.get(c); } + ASMJIT_INLINE uint32_t getVaStart(uint32_t c) const { + return _start.get(c); + } //! @brief Get count of variables (all). - ASMJIT_INLINE uint32_t getVaCount() const - { return _vaCount; } + ASMJIT_INLINE uint32_t getVaCount() const { + return _vaCount; + } //! @brief Get count of variables (by class). - ASMJIT_INLINE uint32_t getVaCountByClass(uint32_t c) const - { return _count.get(c); } + ASMJIT_INLINE uint32_t getVaCountByClass(uint32_t c) const { + return _count.get(c); + } //! @brief Get VarAttr at @a index. - ASMJIT_INLINE VarAttr* getVa(uint32_t index) const - { + ASMJIT_INLINE VarAttr* getVa(uint32_t index) const { ASMJIT_ASSERT(index < _vaCount); return getVaList() + index; } //! @brief Get VarAttr of @a c class at @a index. - ASMJIT_INLINE VarAttr* getVaByClass(uint32_t c, uint32_t index) const - { + ASMJIT_INLINE VarAttr* getVaByClass(uint32_t c, uint32_t index) const { ASMJIT_ASSERT(index < _count._regs[c]); return getVaListByClass(c) + index; } @@ -264,8 +267,7 @@ struct VarInst : public BaseVarInst { // -------------------------------------------------------------------------- //! @brief Find VarAttr. - ASMJIT_INLINE VarAttr* findVa(VarData* vd) const - { + ASMJIT_INLINE VarAttr* findVa(VarData* vd) const { VarAttr* list = getVaList(); uint32_t count = getVaCount(); @@ -277,8 +279,7 @@ struct VarInst : public BaseVarInst { } //! @brief Find VarAttr (by class). - ASMJIT_INLINE VarAttr* findVaByClass(uint32_t c, VarData* vd) const - { + ASMJIT_INLINE VarAttr* findVaByClass(uint32_t c, VarData* vd) const { VarAttr* list = getVaListByClass(c); uint32_t count = getVaCountByClass(c); @@ -385,11 +386,11 @@ struct VarState : BaseVarState { // [Accessors] // -------------------------------------------------------------------------- - ASMJIT_INLINE VarData** getList() - { return _list; } + ASMJIT_INLINE VarData** getList() { + return _list; + } - ASMJIT_INLINE VarData** getListByClass(uint32_t c) - { + ASMJIT_INLINE VarData** getListByClass(uint32_t c) { switch (c) { case kRegClassGp: return _listGp; case kRegClassMm: return _listMm; @@ -404,8 +405,7 @@ struct VarState : BaseVarState { // [Clear] // -------------------------------------------------------------------------- - ASMJIT_INLINE void reset(size_t numCells) - { + ASMJIT_INLINE void reset(size_t numCells) { ::memset(this, 0, kAllCount * sizeof(VarData* ) + 2 * sizeof(RegMask ) + numCells * sizeof(StateCell)); @@ -852,45 +852,44 @@ struct X86X64CallNode : public CallNode { //! //! X86/X64 variable types: //! -//! - @c kVarTypeInt8 - Signed 8-bit integer, mapped to Gpd register (eax, ebx, ...). -//! - @c kVarTypeUInt8 - Unsigned 8-bit integer, mapped to Gpd register (eax, ebx, ...). +//! - @c kVarTypeInt8 - Signed 8-bit integer, mapped to Gpd register (eax, ebx, ...). +//! - @c kVarTypeUInt8 - Unsigned 8-bit integer, mapped to Gpd register (eax, ebx, ...). //! -//! - @c kVarTypeInt16 - Signed 16-bit integer, mapped to Gpd register (eax, ebx, ...). -//! - @c kVarTypeUInt16 - Unsigned 16-bit integer, mapped to Gpd register (eax, ebx, ...). +//! - @c kVarTypeInt16 - Signed 16-bit integer, mapped to Gpd register (eax, ebx, ...). +//! - @c kVarTypeUInt16 - Unsigned 16-bit integer, mapped to Gpd register (eax, ebx, ...). //! -//! - @c kVarTypeInt32 - Signed 32-bit integer, mapped to Gpd register (eax, ebx, ...). -//! - @c kVarTypeUInt32 - Unsigned 32-bit integer, mapped to Gpd register (eax, ebx, ...). +//! - @c kVarTypeInt32 - Signed 32-bit integer, mapped to Gpd register (eax, ebx, ...). +//! - @c kVarTypeUInt32 - Unsigned 32-bit integer, mapped to Gpd register (eax, ebx, ...). //! -//! - @c kVarTypeInt64 - Signed 64-bit integer, mapped to Gpq register (rax, rbx, ...). -//! - @c kVarTypeUInt64 - Unsigned 64-bit integer, mapped to Gpq register (rax, rbx, ...). +//! - @c kVarTypeInt64 - Signed 64-bit integer, mapped to Gpq register (rax, rbx, ...). +//! - @c kVarTypeUInt64 - Unsigned 64-bit integer, mapped to Gpq register (rax, rbx, ...). //! -//! - @c kVarTypeIntPtr - intptr_t, mapped to Gpd/Gpq register; depends on target, not host! +//! - @c kVarTypeIntPtr - intptr_t, mapped to Gpd/Gpq register; depends on target, not host! //! - @c kVarTypeUIntPtr - uintptr_t, mapped to Gpd/Gpq register; depends on target, not host! //! -//! - @c kVarTypeFp32 - 32-bit floating point register (fp0, fp1, ...). -//! - @c kVarTypeFp64 - 64-bit floating point register (fp0, fp1, ...). -//! - @c kVarTypeFpEx - 80-bit floating point register (fp0, fp1, ...). +//! - @c kVarTypeFp32 - 32-bit floating point register (fp0, fp1, ...). +//! - @c kVarTypeFp64 - 64-bit floating point register (fp0, fp1, ...). //! -//! - @c kVarTypeMm - 64-bit Mm register (mm0, mm1, ...). +//! - @c kVarTypeMm - 64-bit Mm register (mm0, mm1, ...). //! -//! - @c kVarTypeXmm - 128-bit SSE register. -//! - @c kVarTypeXmmSs - 128-bit SSE register that contains a scalar 32-bit SP-FP value. -//! - @c kVarTypeXmmSd - 128-bit SSE register that contains a scalar 64-bit DP-FP value. -//! - @c kVarTypeXmmPs - 128-bit SSE register that contains 4 packed 32-bit SP-FP values. -//! - @c kVarTypeXmmPd - 128-bit SSE register that contains 2 packed 64-bit DP-FP values. +//! - @c kVarTypeXmm - 128-bit SSE register. +//! - @c kVarTypeXmmSs - 128-bit SSE register that contains a scalar 32-bit SP-FP value. +//! - @c kVarTypeXmmSd - 128-bit SSE register that contains a scalar 64-bit DP-FP value. +//! - @c kVarTypeXmmPs - 128-bit SSE register that contains 4 packed 32-bit SP-FP values. +//! - @c kVarTypeXmmPd - 128-bit SSE register that contains 2 packed 64-bit DP-FP values. //! -//! - @c kVarTypeYmm - 256-bit AVX register. -//! - @c kVarTypeYmmPs - 256-bit AVX register that contains 4 packed 32-bit SP-FP values. -//! - @c kVarTypeYmmPd - 256-bit AVX register that contains 2 packed 64-bit DP-FP values. +//! - @c kVarTypeYmm - 256-bit AVX register. +//! - @c kVarTypeYmmPs - 256-bit AVX register that contains 4 packed 32-bit SP-FP values. +//! - @c kVarTypeYmmPd - 256-bit AVX register that contains 2 packed 64-bit DP-FP values. //! //! Variable states: //! //! - @c kVarStateUnused - State that is assigned to newly created -//! variables or to not used variables (dereferenced to zero). -//! - @c kVarStateReg - State that means that variable is currently -//! allocated in register. -//! - @c kVarStateMem - State that means that variable is currently -//! only in memory location. +//! variables or to not used variables (dereferenced to zero). +//! - @c kVarStateReg - State that means that variable is currently +//! allocated in register. +//! - @c kVarStateMem - State that means that variable is currently +//! only in memory location. //! //! When you create new variable, initial state is always @c kVarStateUnused, //! allocating it to register or spilling to memory changes this state to @@ -1532,24 +1531,34 @@ struct X86X64Compiler : public BaseCompiler { // ------------------------------------------------------------------------- //! @brief Force short form of jmp/jcc/other instruction. - ASMJIT_INLINE X86X64Compiler& short_() - { _options |= kInstOptionShortForm; return *this; } + ASMJIT_INLINE X86X64Compiler& short_() { + _options |= kInstOptionShortForm; + return *this; + } //! @brief Force long form of jmp/jcc/other instruction. - ASMJIT_INLINE X86X64Compiler& long_() - { _options |= kInstOptionLongForm; return *this; } + ASMJIT_INLINE X86X64Compiler& long_() { + _options |= kInstOptionLongForm; + return *this; + } //! @brief Condition is likely to be taken. - ASMJIT_INLINE X86X64Compiler& taken() - { _options |= kInstOptionTaken; return *this; } + ASMJIT_INLINE X86X64Compiler& taken() { + _options |= kInstOptionTaken; + return *this; + } //! @brief Condition is unlikely to be taken. - ASMJIT_INLINE X86X64Compiler& notTaken() - { _options |= kInstOptionNotTaken; return *this; } + ASMJIT_INLINE X86X64Compiler& notTaken() { + _options |= kInstOptionNotTaken; + return *this; + } //! @brief Lock prefix. - ASMJIT_INLINE X86X64Compiler& lock() - { _options |= kInstOptionLock; return *this; } + ASMJIT_INLINE X86X64Compiler& lock() { + _options |= kInstOptionLock; + return *this; + } // -------------------------------------------------------------------------- // [X86 Instructions] @@ -1638,22 +1647,26 @@ struct X86X64Compiler : public BaseCompiler { INST_2i(bts, kInstBts, Mem, Imm) //! @brief Call. - ASMJIT_INLINE X86X64CallNode* call(const GpVar& dst, uint32_t conv, const FuncPrototype& p) - { return addCall(dst, conv, p); } + ASMJIT_INLINE X86X64CallNode* call(const GpVar& dst, uint32_t conv, const FuncPrototype& p) { + return addCall(dst, conv, p); + } //! @overload - ASMJIT_INLINE X86X64CallNode* call(const Mem& dst, uint32_t conv, const FuncPrototype& p) - { return addCall(dst, conv, p); } + ASMJIT_INLINE X86X64CallNode* call(const Mem& dst, uint32_t conv, const FuncPrototype& p) { + return addCall(dst, conv, p); + } //! @overload - ASMJIT_INLINE X86X64CallNode* call(const Imm& dst, uint32_t conv, const FuncPrototype& p) - { return addCall(dst, conv, p); } + ASMJIT_INLINE X86X64CallNode* call(const Imm& dst, uint32_t conv, const FuncPrototype& p) { + return addCall(dst, conv, p); + } //! @overload ASMJIT_INLINE X86X64CallNode* call(void* dst, uint32_t conv, const FuncPrototype& p) { Imm imm((intptr_t)dst); return addCall(imm, conv, p); } //! @overload - ASMJIT_INLINE X86X64CallNode* call(const Label& label, uint32_t conv, const FuncPrototype& p) - { return addCall(label, conv, p); } + ASMJIT_INLINE X86X64CallNode* call(const Label& label, uint32_t conv, const FuncPrototype& p) { + return addCall(label, conv, p); + } //! @brief Clear carry flag INST_0x(clc, kInstClc) @@ -4015,24 +4028,34 @@ struct Compiler : public X86X64Compiler { // ------------------------------------------------------------------------- //! @overload - ASMJIT_INLINE Compiler& short_() - { _options |= kInstOptionShortForm; return *this; } + ASMJIT_INLINE Compiler& short_() { + _options |= kInstOptionShortForm; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& long_() - { _options |= kInstOptionLongForm; return *this; } + ASMJIT_INLINE Compiler& long_() { + _options |= kInstOptionLongForm; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& taken() - { _options |= kInstOptionTaken; return *this; } + ASMJIT_INLINE Compiler& taken() { + _options |= kInstOptionTaken; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& notTaken() - { _options |= kInstOptionNotTaken; return *this; } + ASMJIT_INLINE Compiler& notTaken() { + _options |= kInstOptionNotTaken; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& lock() - { _options |= kInstOptionLock; return *this; } + ASMJIT_INLINE Compiler& lock() { + _options |= kInstOptionLock; + return *this; + } // -------------------------------------------------------------------------- // [X86-Only Instructions] @@ -4086,28 +4109,40 @@ struct Compiler : public X86X64Compiler { // ------------------------------------------------------------------------- //! @overload - ASMJIT_INLINE Compiler& short_() - { _options |= kInstOptionShortForm; return *this; } + ASMJIT_INLINE Compiler& short_() { + _options |= kInstOptionShortForm; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& long_() - { _options |= kInstOptionLongForm; return *this; } + ASMJIT_INLINE Compiler& long_() { + _options |= kInstOptionLongForm; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& taken() - { _options |= kInstOptionTaken; return *this; } + ASMJIT_INLINE Compiler& taken() { + _options |= kInstOptionTaken; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& notTaken() - { _options |= kInstOptionNotTaken; return *this; } + ASMJIT_INLINE Compiler& notTaken() { + _options |= kInstOptionNotTaken; + return *this; + } //! @overload - ASMJIT_INLINE Compiler& lock() - { _options |= kInstOptionLock; return *this; } + ASMJIT_INLINE Compiler& lock() { + _options |= kInstOptionLock; + return *this; + } //! @brief Force rex prefix. - ASMJIT_INLINE Compiler& rex() - { _options |= kInstOptionRex; return *this; } + ASMJIT_INLINE Compiler& rex() { + _options |= kInstOptionRex; + return *this; + } // -------------------------------------------------------------------------- // [X64-Only Instructions] @@ -4122,8 +4157,10 @@ struct Compiler : public X86X64Compiler { ASMJIT_INLINE InstNode* cmpxchg16b( const GpVar& cmp_edx, const GpVar& cmp_eax, const GpVar& cmp_ecx, const GpVar& cmp_ebx, - const Mem& dst) - { return emit(kInstCmpxchg16b, cmp_edx, cmp_eax, cmp_ecx, cmp_ebx, dst); } + const Mem& dst) { + + return emit(kInstCmpxchg16b, cmp_edx, cmp_eax, cmp_ecx, cmp_ebx, dst); + } //! @brief Move dword to qword with sign-extension. INST_2x(movsxd, kInstMovsxd, GpVar, GpVar) diff --git a/src/asmjit/x86/x86context.cpp b/src/asmjit/x86/x86context.cpp index 87dcc3a..866a26d 100644 --- a/src/asmjit/x86/x86context.cpp +++ b/src/asmjit/x86/x86context.cpp @@ -416,7 +416,6 @@ void X86X64Context::emitLoad(VarData* vd, uint32_t regIndex, const char* reason) case kVarTypeFp32: case kVarTypeFp64: - case kVarTypeFpEx: // TODO: [COMPILER] FPU. break; @@ -498,7 +497,6 @@ void X86X64Context::emitSave(VarData* vd, uint32_t regIndex, const char* reason) case kVarTypeFp32: case kVarTypeFp64: - case kVarTypeFpEx: // TODO: [COMPILER] FPU. break; @@ -572,7 +570,6 @@ void X86X64Context::emitMove(VarData* vd, uint32_t toRegIndex, uint32_t fromRegI case kVarTypeFp32: case kVarTypeFp64: - case kVarTypeFpEx: // TODO: [COMPILER] FPU. break; @@ -582,7 +579,7 @@ void X86X64Context::emitMove(VarData* vd, uint32_t toRegIndex, uint32_t fromRegI break; case kVarTypeXmm: - node = compiler->emit(kInstMovdqa, xmm(toRegIndex), xmm(fromRegIndex)); + node = compiler->emit(kInstMovaps, xmm(toRegIndex), xmm(fromRegIndex)); if (comment) goto _Comment; break; @@ -597,12 +594,8 @@ void X86X64Context::emitMove(VarData* vd, uint32_t toRegIndex, uint32_t fromRegI break; case kVarTypeXmmPs: - node = compiler->emit(kInstMovaps, xmm(toRegIndex), xmm(fromRegIndex)); - if (comment) goto _Comment; - break; - case kVarTypeXmmPd: - node = compiler->emit(kInstMovapd, xmm(toRegIndex), xmm(fromRegIndex)); + node = compiler->emit(kInstMovaps, xmm(toRegIndex), xmm(fromRegIndex)); if (comment) goto _Comment; break; } @@ -678,7 +671,65 @@ void X86X64Context::emitPopSequence(uint32_t regs) { } // ============================================================================ -// [asmjit::x86x64::X86X64Context - EmitMoveArgOnStack / EmitMoveImmOnStack] +// [asmjit::x86x64::X86X64Context - EmitConvertVarToVar] +// ============================================================================ + +void X86X64Context::emitConvertVarToVar(uint32_t dstType, uint32_t dstIndex, uint32_t srcType, uint32_t srcIndex) { + X86X64Compiler* compiler = getCompiler(); + + switch (dstType) { + case kVarTypeInt8: + case kVarTypeUInt8: + case kVarTypeInt16: + case kVarTypeUInt16: + case kVarTypeInt32: + case kVarTypeUInt32: + case kVarTypeInt64: + case kVarTypeUInt64: + break; + + case kVarTypeXmmPs: + if (srcType == kVarTypeXmmPd || srcType == kVarTypeYmmPd) { + compiler->emit(kInstCvtpd2ps, xmm(dstIndex), xmm(srcIndex)); + return; + } + // ... Fall through ... + + case kVarTypeXmmSs: + if (srcType == kVarTypeXmmSd || srcType == kVarTypeXmmPd || srcType == kVarTypeYmmPd) { + compiler->emit(kInstCvtsd2ss, xmm(dstIndex), xmm(srcIndex)); + break; + } + + if (IntUtil::inInterval(srcType, _kVarTypeIntStart, _kVarTypeIntEnd)) { + // TODO: + ASMJIT_ASSERT(!"Reached"); + } + break; + + case kVarTypeXmmPd: + if (srcType == kVarTypeXmmPs || srcType == kVarTypeYmmPs) { + compiler->emit(kInstCvtps2pd, xmm(dstIndex), xmm(srcIndex)); + return; + } + // ... Fall through ... + + case kVarTypeXmmSd: + if (srcType == kVarTypeXmmSs || srcType == kVarTypeXmmPs || srcType == kVarTypeYmmPs) { + compiler->emit(kInstCvtss2sd, xmm(dstIndex), xmm(srcIndex)); + return; + } + + if (IntUtil::inInterval(srcType, _kVarTypeIntStart, _kVarTypeIntEnd)) { + // TODO: + ASMJIT_ASSERT(!"Reached"); + } + break; + } +} + +// ============================================================================ +// [asmjit::x86x64::X86X64Context - EmitMoveVarOnStack / EmitMoveImmOnStack] // ============================================================================ void X86X64Context::emitMoveVarOnStack( @@ -730,7 +781,7 @@ void X86X64Context::emitMoveVarOnStack( // Move DWORD (Mm). if (IntUtil::inInterval(srcType, kVarTypeMm, kVarTypeMm)) goto _MovMmD; - + // Move DWORD (Xmm). if (IntUtil::inInterval(srcType, kVarTypeXmm, kVarTypeXmmPd)) goto _MovXmmD; @@ -851,18 +902,37 @@ void X86X64Context::emitMoveVarOnStack( goto _MovXmmQ; break; + case kVarTypeFp32: + case kVarTypeXmmSs: + // Move FLOAT. + if (srcType == kVarTypeXmmSs || srcType == kVarTypeXmmPs || srcType == kVarTypeXmm) + goto _MovXmmD; + + ASMJIT_ASSERT(!"Reached"); + break; + + case kVarTypeFp64: + case kVarTypeXmmSd: + // Move DOUBLE. + if (srcType == kVarTypeXmmSd || srcType == kVarTypeXmmPd || srcType == kVarTypeXmm) + goto _MovXmmQ; + + ASMJIT_ASSERT(!"Reached"); + break; + case kVarTypeXmm: + // TODO: [COMPILER]. + ASMJIT_ASSERT(!"Reached"); + break; + case kVarTypeXmmPs: + // TODO: [COMPILER]. + ASMJIT_ASSERT(!"Reached"); + break; + case kVarTypeXmmPd: // TODO: [COMPILER]. - break; - - case kVarTypeXmmSs: - // TODO: [COMPILER]. - break; - - case kVarTypeXmmSd: - // TODO: [COMPILER]. + ASMJIT_ASSERT(!"Reached"); break; } return; @@ -941,14 +1011,14 @@ _MovXmmD: m0.setSize(4); r0.setSize(16); r0.setCode(kRegTypeXmm, srcIndex); - compiler->emit(kInstMovd, m0, r0); + compiler->emit(kInstMovss, m0, r0); return; _MovXmmQ: m0.setSize(8); r0.setSize(16); r0.setCode(kRegTypeXmm, srcIndex); - compiler->emit(kInstMovq, m0, r0); + compiler->emit(kInstMovlps, m0, r0); } void X86X64Context::emitMoveImmOnStack(uint32_t dstType, const Mem* dst, const Imm* src) { @@ -1010,11 +1080,6 @@ _Move64: case kVarTypeFp64: goto _Move64; - case kVarTypeFpEx: - // Not supported. - ASMJIT_ASSERT(!"Reached"); - break; - case kVarTypeMm: goto _Move64; @@ -1108,7 +1173,6 @@ _Move32: case kVarTypeFp32: case kVarTypeFp64: - case kVarTypeFpEx: // TODO: [COMPILER] EmitMoveImmToReg. break; @@ -1403,14 +1467,6 @@ void X86X64Context::switchState(BaseVarState* src_) { X86X64Context_switchStateVars(this, src); X86X64Context_switchStateVars(this, src); - // TODO: Review: This is from the older version of asmjit and it shouldn't - // be needed to copy these masks, because switchStateVars() should have - // done it already. - // - // Copy occupied mask. - // cur->_occupied = src->_occupied; - // cur->_modified = src->_modified; - // Calculate changed state. VarData** vdArray = _contextVd.getData(); uint32_t vdCount = static_cast(_contextVd.getLength()); @@ -1439,7 +1495,6 @@ void X86X64Context::intersectStates(BaseVarState* a_, BaseVarState* b_) { VarState* bState = static_cast(b_); // TODO: [COMPILER] Intersect states. - ASMJIT_CONTEXT_CHECK_STATE } @@ -1464,7 +1519,7 @@ static ASMJIT_INLINE BaseNode* X86X64Context_getOppositeJccFlow(JumpNode* jNode) } // ============================================================================ -// [asmjit::x86x64::X86X64Context - Prepare - SingleVarInst] +// [asmjit::x86x64::X86X64Context - SingleVarInst] // ============================================================================ //! @internal @@ -1497,7 +1552,7 @@ static void X86X64Context_prepareSingleVarInst(uint32_t code, VarAttr* va) { } // ============================================================================ -// [asmjit::x86x64::X86X64Context - Prepare] +// [asmjit::x86x64::X86X64Context - Helpers] // ============================================================================ //! @internal @@ -1550,42 +1605,214 @@ static ASMJIT_INLINE RegMask X86X64Context_getUsedArgs(X86X64Context* self, X86X } // ============================================================================ -// [Helpers] +// [asmjit::x86x64::X86X64Context - SArg Insertion] // ============================================================================ -static ASMJIT_INLINE SArgNode* X86X64Context_insertSArgNode( - X86X64Context* self, - X86X64Compiler* compiler, - X86X64CallNode* call, - VarData* vd, const uint32_t* gaRegs) { +struct SArgData { + VarData* sVd; + VarData* cVd; + SArgNode* sArg; + uint32_t aType; +}; - uint32_t vType = vd->getType(); - const VarInfo& vInfo = _varInfo[vType]; - uint32_t c = vInfo.getClass(); +#define SARG(_Dst_, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20) \ + (S0 << 0) | (S1 << 1) | (S2 << 2) | (S3 << 3) | \ + (S4 << 4) | (S5 << 5) | (S6 << 6) | (S7 << 7) | \ + (S8 << 8) | (S9 << 9) | (S10 << 10) | (S11 << 11) | \ + (S12 << 12) | (S13 << 13) | (S14 << 14) | (S15 << 15) | \ + (S16 << 16) | (S17 << 17) | (S18 << 18) | (S19 << 19) | \ + (S20 << 20) +#define A 0 /* Auto-convert (doesn't need conversion step). */ +static const uint32_t X86X64Context_sArgConvTable[kVarTypeCount] = { + // dst <- | i8| u8|i16|u16|i32|u32|i64|u64| iP| uP|f32|f64|mmx|xmm|xSs|xPs|xSd|xPd|ymm|yPs|yPd| + //--------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + SARG(i8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(u8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(i16 , A , A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(u16 , A , A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(i32 , A , A , A , A , 0 , 0 , 0 , 0 , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(u32 , A , A , A , A , 0 , 0 , 0 , 0 , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(i64 , A , A , A , A , A , A , 0 , 0 , A , A , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(u64 , A , A , A , A , A , A , 0 , 0 , A , A , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(iPtr , A , A , A , A , A , A , A , A , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(uPtr , A , A , A , A , A , A , A , A , 0 , 0 , A , A , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), + SARG(f32 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , A , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ), + SARG(f64 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , A , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 ), + SARG(mmx , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), + SARG(xmm , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), + SARG(xSs , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ), + SARG(xPs , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ), + SARG(xSd , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 ), + SARG(xPd , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 ), + SARG(ymm , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), + SARG(yPs , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 ), + SARG(yPd , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 ) +}; +#undef A +#undef SARG - SArgNode* sArg = compiler->newNode(vd, call); - if (sArg == NULL) - return NULL; - - VarInst* vi = self->newVarInst(1); - if (vi == NULL) - return NULL; - - vi->_vaCount = 1; - vi->_count.reset(); - vi->_count.add(c); - vi->_start.reset(); - vi->_inRegs.reset(); - vi->_outRegs.reset(); - vi->_clobberedRegs.reset(); - vi->_list[0].setup(vd, kVarAttrInReg, 0, gaRegs[c]); - - sArg->setVarInst(vi); - - compiler->addNodeBefore(sArg, call); - return sArg; +static ASMJIT_INLINE bool X86X64Context_mustConvertSArg(X86X64Context* self, uint32_t aType, uint32_t sType) { + return (X86X64Context_sArgConvTable[aType] & (1 << sType)) != 0; } +static ASMJIT_INLINE uint32_t X86X64Context_typeOfConvertedSArg(X86X64Context* self, uint32_t aType, uint32_t sType) { + ASMJIT_ASSERT(X86X64Context_mustConvertSArg(self, aType, sType)); + + if (IntUtil::inInterval(aType, _kVarTypeIntStart, _kVarTypeIntEnd)) + return aType; + + if (aType == kVarTypeFp32) + return kVarTypeXmmSs; + + if (aType == kVarTypeFp64) + return kVarTypeXmmSd; + + if (IntUtil::inInterval(aType, _kVarTypeXmmStart, _kVarTypeXmmEnd)) + return aType; + + if (IntUtil::inInterval(aType, _kVarTypeYmmStart, _kVarTypeYmmEnd)) + return aType; + + ASMJIT_ASSERT(!"Reached"); + return aType; +} + +static ASMJIT_INLINE Error X86X64Context_insertSArgNode( + X86X64Context* self, X86X64CallNode* call, + VarData* sVd, const uint32_t* gaRegs, + const FuncInOut& arg, uint32_t argIndex, + SArgData* sArgList, uint32_t& sArgCount) { + + X86X64Compiler* compiler = self->getCompiler(); + uint32_t i; + + uint32_t aType = arg.getVarType(); + uint32_t sType = sVd->getType(); + + // First locate or create sArgBase. + for (i = 0; i < sArgCount; i++) { + if (sArgList[i].sVd == sVd && sArgList[i].cVd == NULL) + break; + } + + SArgData* sArgData = &sArgList[i]; + + if (i == sArgCount) { + sArgData->sVd = sVd; + sArgData->cVd = NULL; + sArgData->sArg = NULL; + sArgData->aType = 0xFF; + sArgCount++; + } + + const VarInfo& sInfo = _varInfo[sType]; + uint32_t sClass = sInfo.getClass(); + + if (X86X64Context_mustConvertSArg(self, aType, sType)) { + uint32_t cType = X86X64Context_typeOfConvertedSArg(self, aType, sType); + + const VarInfo& cInfo = _varInfo[cType]; + uint32_t cClass = cInfo.getClass(); + + while (++i < sArgCount) { + sArgData = &sArgList[i]; + if (sArgData->sVd != sVd) + break; + + if (sArgData->cVd->getType() != cType || sArgData->aType != aType) + continue; + + sArgData->sArg->_args |= IntUtil::mask(argIndex); + return kErrorOk; + } + + VarData* cVd = compiler->_newVd(cType, cInfo.getSize(), cInfo.getClass(), NULL); + if (cVd == NULL) + return kErrorNoHeapMemory; + + SArgNode* sArg = compiler->newNode(call, sVd, cVd); + if (sArg == NULL) + return kErrorNoHeapMemory; + + VarInst* vi = self->newVarInst(2); + if (vi == NULL) + return kErrorNoHeapMemory; + + ASMJIT_PROPAGATE_ERROR(self->_registerContextVar(cVd)); + ASMJIT_PROPAGATE_ERROR(self->_registerContextVar(sVd)); + + vi->_vaCount = 2; + vi->_count.reset(); + vi->_count.add(sClass); + vi->_count.add(cClass); + + vi->_start.reset(); + vi->_inRegs.reset(); + vi->_outRegs.reset(); + vi->_clobberedRegs.reset(); + + if (sClass <= cClass) { + vi->_list[0].setup(sVd, kVarAttrInReg , 0, gaRegs[sClass]); + vi->_list[1].setup(cVd, kVarAttrOutReg, 0, gaRegs[cClass]); + vi->_start.set(cClass, sClass != cClass); + } + else { + vi->_list[0].setup(cVd, kVarAttrOutReg, 0, gaRegs[cClass]); + vi->_list[1].setup(sVd, kVarAttrInReg , 0, gaRegs[sClass]); + vi->_start.set(sClass, 1); + } + + sArg->setVarInst(vi); + sArg->_args |= IntUtil::mask(argIndex); + + compiler->addNodeBefore(sArg, call); + ::memmove(sArgData + 1, sArgData, (sArgCount - i) * sizeof(SArgData)); + + sArgData->sVd = sVd; + sArgData->cVd = cVd; + sArgData->sArg = sArg; + sArgData->aType = aType; + + sArgCount++; + return kErrorOk; + } + else { + SArgNode* sArg = sArgData->sArg; + ASMJIT_PROPAGATE_ERROR(self->_registerContextVar(sVd)); + + if (sArg == NULL) { + sArg = compiler->newNode(call, sVd, (VarData*)NULL); + if (sArg == NULL) + return kErrorNoHeapMemory; + + VarInst* vi = self->newVarInst(1); + if (vi == NULL) + return kErrorNoHeapMemory; + + vi->_vaCount = 1; + vi->_count.reset(); + vi->_count.add(sClass); + vi->_start.reset(); + vi->_inRegs.reset(); + vi->_outRegs.reset(); + vi->_clobberedRegs.reset(); + vi->_list[0].setup(sVd, kVarAttrInReg, 0, gaRegs[sClass]); + + sArg->setVarInst(vi); + sArgData->sArg = sArg; + + compiler->addNodeBefore(sArg, call); + } + + sArg->_args |= IntUtil::mask(argIndex); + return kErrorOk; + } +} + +// ============================================================================ +// [asmjit::x86x64::X86X64Context - Fetch] +// ============================================================================ + //! @internal //! //! @brief Prepare the given function @a func. @@ -1607,6 +1834,8 @@ Error X86X64Context::fetch() { uint32_t flowId = 0; VarAttr vaTmpList[80]; + SArgData sArgList[80]; + PodList::Link* jLink = NULL; // Function flags. @@ -1696,15 +1925,6 @@ Error X86X64Context::fetch() { _Node_->setVarInst(vi); \ } while (0) -#define VI_UPDATE_CID(_Vd_) \ - do { \ - if (!_Vd_->hasContextId()) { \ - _Vd_->setContextId(static_cast(_contextVd.getLength())); \ - if (_contextVd.append(_Vd_) != kErrorOk) \ - goto _NoMemory; \ - } \ - } while (0) - #define VI_ADD_VAR(_Vd_, _Va_, _Flags_, _NewAllocable_) \ do { \ ASMJIT_ASSERT(_Vd_->_va == NULL); \ @@ -1714,7 +1934,8 @@ Error X86X64Context::fetch() { _Va_->addVarCount(1); \ _Vd_->setVa(_Va_); \ \ - VI_UPDATE_CID(_Vd_); \ + if (_registerContextVar(_Vd_) != kErrorOk) \ + goto _NoMemory; \ regCount.add(_Vd_->getClass()); \ } while (0) @@ -1727,7 +1948,8 @@ Error X86X64Context::fetch() { _Va_->setup(_Vd_, 0, 0, _NewAllocable_); \ _Vd_->setVa(_Va_); \ \ - VI_UPDATE_CID(_Vd_); \ + if (_registerContextVar(_Vd_) != kErrorOk) \ + goto _NoMemory; \ regCount.add(_Vd_->getClass()); \ } \ \ @@ -2140,18 +2362,28 @@ _NextGroup: return compiler->setError(kErrorCompilerOverlappedArgs); VI_ADD_VAR(vd, va, 0, 0); - if (x86VarTypeToClass(arg.getVarType()) == vd->getClass()) { - if (arg.hasRegIndex()) { + uint32_t aType = arg.getVarType(); + uint32_t vType = vd->getType(); + + if (arg.hasRegIndex()) { + if (x86VarTypeToClass(aType) == vd->getClass()) { va->addFlags(kVarAttrOutReg); va->setOutRegIndex(arg.getRegIndex()); } else { - va->addFlags(kVarAttrOutMem); + va->addFlags(kVarAttrOutConv); } } else { - // TODO: [COMPILER] Function Argument Conversion. - va->addFlags(kVarAttrOutDecide | kVarAttrOutConv); + if ((x86VarTypeToClass(aType) == vd->getClass()) || + (vType == kVarTypeXmmSs && aType == kVarTypeFp32) || + (vType == kVarTypeXmmSd && aType == kVarTypeFp64)) { + va->addFlags(kVarAttrOutMem); + } + else { + // TODO: [COMPILER] Not implemented. + ASMJIT_ASSERT(!"Implemented"); + } } } VI_END(node_); @@ -2218,6 +2450,7 @@ _NextGroup: uint32_t i; uint32_t argCount = decl->getArgCount(); + uint32_t sArgCount = 0; uint32_t gpAllocableMask = gaRegs[kRegClassGp] & ~node->_usedArgs.get(kRegClassGp); VarData* vd; @@ -2270,10 +2503,11 @@ _NextGroup: continue; vd = compiler->getVdById(op->getId()); - VI_MERGE_VAR(vd, va, 0, 0); - const FuncInOut& arg = decl->getArg(i); + if (arg.hasRegIndex()) { + VI_MERGE_VAR(vd, va, 0, 0); + uint32_t argType = arg.getVarType(); uint32_t argClass = x86VarTypeToClass(argType); @@ -2285,9 +2519,15 @@ _NextGroup: va->addFlags(kVarAttrInConv | kVarAttrInArg); } } + // If this is a stack-based argument we insert SArgNode instead of + // using VarAttr. It improves the code, because the argument can be + // moved onto stack as soon as it is ready and the register used by + // the variable can be reused for something else. It is also much + // easier to handle argument conversions, because there will be at + // most only one node per conversion. else { - va->addArgStackCount(); - va->addFlags(kVarAttrInStack | kVarAttrInArg); + if (X86X64Context_insertSArgNode(this, node, vd, gaRegs, arg, i, sArgList, sArgCount) != kErrorOk) + goto _NoMemory; } } @@ -2321,20 +2561,6 @@ _NextGroup: clobberedRegs.set(kRegClassMm, IntUtil::bits(kRegCountMm ) & (~decl->getPreserved(kRegClassMm))); clobberedRegs.set(kRegClassXy, IntUtil::bits(_baseRegsCount) & (~decl->getPreserved(kRegClassXy))); - // Split all variables allocated in stack-only (i.e. if the variable is - // only passed in stack; it doesn't matter how many times) and create - // extra nodes having only stack moves. It improves x86 code, because - // arguments can be moved on stack right after they are ready. - for (i = 0; i < vaCount; i++) { - VarAttr* va = &vaTmpList[i]; - - if ((va->getFlags() & kVarAttrInAll) == (kVarAttrInArg | kVarAttrInStack)) { - if (!X86X64Context_insertSArgNode(this, compiler, node, va->getVd(), gaRegs)) - goto _NoMemory; - va->delFlags(kVarAttrInAll); - } - } - VI_END(node_); break; } @@ -2698,7 +2924,6 @@ ASMJIT_INLINE void X86X64BaseAlloc::unuseBefore() { kVarAttrInOutReg | kVarAttrInMem | kVarAttrInArg | - kVarAttrInStack | kVarAttrInCall | kVarAttrInConv ; @@ -2845,21 +3070,38 @@ ASMJIT_INLINE Error X86X64VarAlloc::run(BaseNode* node_) { } else if (node_->getType() == kNodeTypeSArg) { SArgNode* node = static_cast(node_); - VarData* vd = node->getVd(); X86X64CallNode* call = static_cast(node->getCall()); X86X64FuncDecl* decl = call->getDecl(); - uint32_t argCount = decl->getArgCount(); - for (uint32_t i = 0; i < argCount; i++) { - Operand& op = call->getArg(i); - FuncInOut& arg = decl->getArg(i); + uint32_t argIndex = 0; + uint32_t argMask = node->_args; - if (!op.isVar() || op.getId() != vd->getId()) - continue; + VarData* sVd = node->getSVd(); + VarData* cVd = node->getCVd(); - Mem dst = ptr(_context->_zsp, -static_cast(_context->getRegSize()) + arg.getStackOffset()); - _context->emitMoveVarOnStack(arg.getVarType(), &dst, vd->getType(), vd->getRegIndex()); + // Convert first. + ASMJIT_ASSERT(sVd->getRegIndex() != kInvalidReg); + + if (cVd != NULL) { + ASMJIT_ASSERT(cVd->getRegIndex() != kInvalidReg); + _context->emitConvertVarToVar( + cVd->getType(), cVd->getRegIndex(), + sVd->getType(), sVd->getRegIndex()); + sVd = cVd; + } + + while (argMask != 0) { + if (argMask & 0x1) { + FuncInOut& arg = decl->getArg(argIndex); + ASMJIT_ASSERT(arg.hasStackOffset()); + + Mem dst = ptr(_context->_zsp, -static_cast(_context->getRegSize()) + arg.getStackOffset()); + _context->emitMoveVarOnStack(arg.getVarType(), &dst, sVd->getType(), sVd->getRegIndex()); + } + + argIndex++; + argMask >>= 1; } } @@ -3378,12 +3620,18 @@ protected: ASMJIT_INLINE void alloc(); // -------------------------------------------------------------------------- - // [AllocVars/Imms] + // [AllocImmsOnStack] // -------------------------------------------------------------------------- - ASMJIT_INLINE void allocVarsOnStack(); ASMJIT_INLINE void allocImmsOnStack(); + // -------------------------------------------------------------------------- + // [Duplicate] + // -------------------------------------------------------------------------- + + template + ASMJIT_INLINE void duplicate(); + // -------------------------------------------------------------------------- // [GuessAlloc / GuessSpill] // -------------------------------------------------------------------------- @@ -3414,15 +3662,6 @@ protected: ASMJIT_INLINE void ret(); - // -------------------------------------------------------------------------- - // [Utils] - // -------------------------------------------------------------------------- - - ASMJIT_INLINE void stackArgDone(uint32_t argMask) { - ASMJIT_ASSERT(_stackArgsMask & argMask); - _stackArgsMask ^= argMask; - } - // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- @@ -3431,12 +3670,6 @@ protected: RegMask _willAlloc; //! @brief Will spill these registers. RegMask _willSpill; - - //! @brief Pending stack-arguments mask. - uint32_t _stackArgsMask; - - //! @brief Argument index to VarAttr mapping. - VarAttr* _argToVa[kFuncArgCountLoHi]; }; // ============================================================================ @@ -3452,9 +3685,6 @@ ASMJIT_INLINE Error X86X64CallAlloc::run(X86X64CallNode* node) { // Initialize the allocator; prepare basics and connect Vd->Va. init(node, vi); - // Move whatever can be moved on the stack. - allocVarsOnStack(); - // Plan register allocation. Planner is only able to assign one register per // variable. If any variable is used multiple times it will be handled later. plan(); @@ -3471,9 +3701,6 @@ ASMJIT_INLINE Error X86X64CallAlloc::run(X86X64CallNode* node) { alloc(); alloc(); - // Move the remaining variables on the stack. - allocVarsOnStack(); - // Unuse clobbered registers that are not used to pass function arguments and // save variables used to pass function arguments that will be reused later on. save(); @@ -3483,8 +3710,10 @@ ASMJIT_INLINE Error X86X64CallAlloc::run(X86X64CallNode* node) { // Allocate immediates in registers and on the stack. allocImmsOnStack(); - // Duplicate/Convert. - // TODO: + // Duplicate. + duplicate(); + duplicate(); + duplicate(); // Translate call operand. ASMJIT_PROPAGATE_ERROR(X86X64Context_translateOperands(_context, &node->_target, 1)); @@ -3522,35 +3751,6 @@ ASMJIT_INLINE void X86X64CallAlloc::init(X86X64CallNode* node, VarInst* vi) { // Create mask of all registers that will be used to pass function arguments. _willAlloc = node->_usedArgs; _willSpill.reset(); - - // Initialize argToVa[] array and pending stack-args mask/count. - X86X64FuncDecl* decl = node->getDecl(); - uint32_t i, mask; - - Operand* argList = node->_args; - uint32_t argCount = decl->getArgCount(); - - _stackArgsMask = 0; - ::memset(_argToVa, 0, kFuncArgCountLoHi * sizeof(VarAttr*)); - - for (i = 0, mask = 1; i < argCount; i++, mask <<= 1) { - Operand* op = &argList[i]; - - if (!op->isVar()) - continue; - - VarData* vd = _compiler->getVdById(op->getId()); - VarAttr* va = vd->getVa(); - _argToVa[i] = va; - - const FuncInOut& arg = decl->getArg(i); - if (!arg.hasStackOffset()) - continue; - - if ((va->getFlags() & kVarAttrInAll) == 0) - continue; - _stackArgsMask |= mask; - } } ASMJIT_INLINE void X86X64CallAlloc::cleanup() { @@ -3792,44 +3992,9 @@ ASMJIT_INLINE void X86X64CallAlloc::alloc() { } // ============================================================================ -// [asmjit::x86x64::X86X64CallAlloc - AllocVars/Imms] +// [asmjit::x86x64::X86X64CallAlloc - AllocImmsOnStack] // ============================================================================ -ASMJIT_INLINE void X86X64CallAlloc::allocVarsOnStack() { - if (_stackArgsMask == 0) - return; - - X86X64CallNode* node = getNode(); - X86X64FuncDecl* decl = node->getDecl(); - - uint32_t i; - uint32_t mask; - - uint32_t argCount = decl->getArgCount(); - Operand* argList = node->_args; - - for (i = 0, mask = 1; i < argCount; i++, mask <<= 1) { - if ((_stackArgsMask & mask) == 0) - continue; - - VarAttr* va = _argToVa[i]; - ASMJIT_ASSERT(va != NULL); - ASMJIT_ASSERT(va->getArgStackCount() != 0); - - VarData* vd = va->getVd(); - uint32_t regIndex = vd->getRegIndex(); - - if (regIndex == kInvalidReg) - continue; - - const FuncInOut& arg = decl->getArg(i); - Mem dst = ptr(_context->_zsp, -static_cast(_context->getRegSize()) + arg.getStackOffset()); - - _context->emitMoveVarOnStack(arg.getVarType(), &dst, vd->getType(), regIndex); - stackArgDone(mask); - } -} - ASMJIT_INLINE void X86X64CallAlloc::allocImmsOnStack() { X86X64CallNode* node = getNode(); X86X64FuncDecl* decl = node->getDecl(); @@ -3838,11 +4003,12 @@ ASMJIT_INLINE void X86X64CallAlloc::allocImmsOnStack() { Operand* argList = node->_args; for (uint32_t i = 0; i < argCount; i++) { - VarAttr* va = _argToVa[i]; - if (va != NULL) + Operand& op = argList[i]; + + if (!op.isImm()) continue; - const Imm& imm = static_cast(node->getArg(i)); + const Imm& imm = static_cast(op); const FuncInOut& arg = decl->getArg(i); if (arg.hasStackOffset()) { @@ -3855,6 +4021,42 @@ ASMJIT_INLINE void X86X64CallAlloc::allocImmsOnStack() { } } +// ============================================================================ +// [asmjit::x86x64::X86X64CallAlloc - Duplicate] +// ============================================================================ + +template +ASMJIT_INLINE void X86X64CallAlloc::duplicate() { + VarAttr* list = getVaListByClass(C); + uint32_t count = getVaCountByClass(C); + + for (uint32_t i = 0; i < count; i++) { + VarAttr* va = &list[i]; + if (!va->hasFlag(kVarAttrInReg)) + continue; + + uint32_t inRegs = va->getInRegs(); + if (!inRegs) + continue; + + VarData* vd = va->getVd(); + uint32_t regIndex = vd->getRegIndex(); + + ASMJIT_ASSERT(regIndex != kInvalidReg); + + inRegs &= ~IntUtil::mask(regIndex); + if (!inRegs) + continue; + + for (uint32_t dupIndex = 0; inRegs != 0; dupIndex++, inRegs >>= 1) { + if (inRegs & 0x1) { + _context->emitMove(vd, dupIndex, regIndex, "Duplicate"); + _context->_clobberedRegs.add(C, IntUtil::mask(dupIndex)); + } + } + } +} + // ============================================================================ // [asmjit::x86x64::X86X64CallAlloc - GuessAlloc / GuessSpill] // ============================================================================ @@ -4100,7 +4302,7 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) { uint32_t requiredStackAlignment = IntUtil::iMax(self->_memMaxAlign, self->getRegSize()); if (requiredStackAlignment < 16) { - // Require 16-byte alignment 8-byte vars are used. + // Require 16-byte alignment if 8-byte vars are used. if (self->_mem8ByteVarsUsed) requiredStackAlignment = 16; else if (func->_saveRestoreRegs.get(kRegClassMm) || func->_saveRestoreRegs.get(kRegClassXy)) @@ -4148,7 +4350,7 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) { fRegMask = tRegMask; // Try to remove preserved registers from the mask. - tRegMask = fRegMask & decl->getPreserved(kRegClassGp); + tRegMask = fRegMask & ~decl->getPreserved(kRegClassGp); if (tRegMask != 0) fRegMask = tRegMask; @@ -4218,9 +4420,9 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) { func->_alignStackSize = 0; } else { - // If function is aligned, the RETURN address is stored to the aligned + // If function is aligned, the RETURN address is stored in the aligned // [ZSP - PtrSize] which makes current ZSP unaligned. - int32_t v = regSize; + int32_t v = static_cast(regSize); // If we have to store function frame pointer we have to count it as well, // because it is the first thing pushed on the stack. @@ -4443,7 +4645,7 @@ static Error X86X64Context_translatePrologEpilog(X86X64Context* self, X86X64Func } // -------------------------------------------------------------------------- - // [Copy-Args] + // [Move-Args] // -------------------------------------------------------------------------- if (func->hasFuncFlag(kFuncFlagMoveArgs)) { @@ -4858,10 +5060,9 @@ _NextGroup: VarAttr* va = vi->findVa(vd); ASMJIT_ASSERT(va != NULL); - if (vd->getFlags() & kVarAttrUnuse) + if (va->getFlags() & kVarAttrUnuse) continue; - // Special means that the argument is passed in register. uint32_t regIndex = va->getOutRegIndex(); if (regIndex != kInvalidReg && (va->getFlags() & kVarAttrOutConv) == 0) { switch (vd->getClass()) { @@ -4872,6 +5073,7 @@ _NextGroup: } else if (va->hasFlag(kVarAttrOutConv)) { // TODO: [COMPILER] Function Argument Conversion. + ASMJIT_ASSERT(!"Reached"); } else { vd->_isMemArg = true; @@ -5051,7 +5253,7 @@ static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64As case kInstMul: case kInstIdiv: case kInstDiv: - // We assume "Mul/Div dst_hi (implicit), dst_lo (implicit), src (explicit)". + // Assume "Mul/Div dst_hi (implicit), dst_lo (implicit), src (explicit)". ASMJIT_ASSERT(opCount == 3); o0 = &opList[2]; break; diff --git a/src/asmjit/x86/x86context_p.h b/src/asmjit/x86/x86context_p.h index e44d2fd..6433db2 100644 --- a/src/asmjit/x86/x86context_p.h +++ b/src/asmjit/x86/x86context_p.h @@ -98,6 +98,7 @@ struct X86X64Context : public BaseContext { void emitPushSequence(uint32_t regs); void emitPopSequence(uint32_t regs); + void emitConvertVarToVar(uint32_t dstType, uint32_t dstIndex, uint32_t srcType, uint32_t srcIndex); void emitMoveVarOnStack(uint32_t dstType, const Mem* dst, uint32_t srcType, uint32_t srcIndex); void emitMoveImmOnStack(uint32_t dstType, const Mem* dst, const Imm* src); diff --git a/src/asmjit/x86/x86defs.cpp b/src/asmjit/x86/x86defs.cpp index 2fe46e4..6ebf270 100644 --- a/src/asmjit/x86/x86defs.cpp +++ b/src/asmjit/x86/x86defs.cpp @@ -3038,16 +3038,15 @@ const VarInfo _varInfo[] = { /* 09: kVarTypeUIntPtr */ { 0 , 0 , C(Gp), 0 , "" }, // Remapped. /* 10: kVarTypeFp32 */ { kRegTypeFp , 4 , C(Fp), D(Sp) , "fp" }, /* 11: kVarTypeFp64 */ { kRegTypeFp , 8 , C(Fp), D(Dp) , "fp" }, - /* 12: kVarTypeFpEx */ { kRegTypeFp , 16, C(Fp), D(Sp) , "fp" }, - /* 13: kVarTypeMm */ { kRegTypeMm , 8 , C(Mm), 0 , "mm" }, - /* 14: kVarTypeXmm */ { kRegTypeXmm , 16, C(Xy), 0 , "xmm" }, - /* 15: kVarTypeXmmSs */ { kRegTypeXmm , 4 , C(Xy), D(Sp) , "xmm" }, + /* 12: kVarTypeMm */ { kRegTypeMm , 8 , C(Mm), 0 , "mm" }, + /* 13: kVarTypeXmm */ { kRegTypeXmm , 16, C(Xy), 0 , "xmm" }, + /* 14: kVarTypeXmmSs */ { kRegTypeXmm , 4 , C(Xy), D(Sp) , "xmm" }, + /* 15: kVarTypeXmmPs */ { kRegTypeXmm , 16, C(Xy), D(Sp) | D(Packed), "xmm" }, /* 16: kVarTypeXmmSd */ { kRegTypeXmm , 8 , C(Xy), D(Dp) , "xmm" }, - /* 17: kVarTypeXmmPs */ { kRegTypeXmm , 16, C(Xy), D(Sp) | D(Packed), "xmm" }, - /* 18: kVarTypeXmmPd */ { kRegTypeXmm , 16, C(Xy), D(Dp) | D(Packed), "xmm" }, - /* 19: kVarTypeYmm */ { kRegTypeYmm , 32, C(Xy), 0 , "ymm" }, - /* 20: kVarTypeYmmPs */ { kRegTypeYmm , 32, C(Xy), D(Sp) | D(Packed), "ymm" }, - /* 21: kVarTypeYmmPd */ { kRegTypeYmm , 32, C(Xy), D(Dp) | D(Packed), "ymm" } + /* 17: kVarTypeXmmPd */ { kRegTypeXmm , 16, C(Xy), D(Dp) | D(Packed), "xmm" }, + /* 18: kVarTypeYmm */ { kRegTypeYmm , 32, C(Xy), 0 , "ymm" }, + /* 19: kVarTypeYmmPs */ { kRegTypeYmm , 32, C(Xy), D(Sp) | D(Packed), "ymm" }, + /* 20: kVarTypeYmmPd */ { kRegTypeYmm , 32, C(Xy), D(Dp) | D(Packed), "ymm" } }; #undef D @@ -3196,16 +3195,15 @@ const uint8_t _varMapping[kVarTypeCount] = { /* 09: kVarTypeUIntPtr */ kVarTypeUInt32, // Remapped. /* 10: kVarTypeFp32 */ kVarTypeFp32, /* 11: kVarTypeFp64 */ kVarTypeFp64, - /* 12: kVarTypeFpEx */ kVarTypeFpEx, - /* 13: kVarTypeMm */ kVarTypeMm, - /* 14: kVarTypeXmm */ kVarTypeXmm, - /* 15: kVarTypeXmmSs */ kVarTypeXmmSs, + /* 12: kVarTypeMm */ kVarTypeMm, + /* 13: kVarTypeXmm */ kVarTypeXmm, + /* 14: kVarTypeXmmSs */ kVarTypeXmmSs, + /* 15: kVarTypeXmmPs */ kVarTypeXmmPs, /* 16: kVarTypeXmmSd */ kVarTypeXmmSd, - /* 17: kVarTypeXmmPs */ kVarTypeXmmPs, - /* 18: kVarTypeXmmPd */ kVarTypeXmmPd, - /* 19: kVarTypeYmm */ kVarTypeYmm, - /* 20: kVarTypeYmmPs */ kVarTypeYmmPs, - /* 21: kVarTypeYmmPd */ kVarTypeYmmPd + /* 17: kVarTypeXmmPd */ kVarTypeXmmPd, + /* 18: kVarTypeYmm */ kVarTypeYmm, + /* 19: kVarTypeYmmPs */ kVarTypeYmmPs, + /* 20: kVarTypeYmmPd */ kVarTypeYmmPd }; const GpReg zax(kRegTypeGpd, kRegIndexAx, 4); @@ -3243,16 +3241,15 @@ const uint8_t _varMapping[kVarTypeCount] = { /* 09: kVarTypeUIntPtr */ kVarTypeUInt64, // Remapped. /* 10: kVarTypeFp32 */ kVarTypeFp32, /* 11: kVarTypeFp64 */ kVarTypeFp64, - /* 12: kVarTypeFpEx */ kVarTypeFpEx, - /* 13: kVarTypeMm */ kVarTypeMm, - /* 14: kVarTypeXmm */ kVarTypeXmm, - /* 15: kVarTypeXmmSs */ kVarTypeXmmSs, + /* 12: kVarTypeMm */ kVarTypeMm, + /* 13: kVarTypeXmm */ kVarTypeXmm, + /* 14: kVarTypeXmmSs */ kVarTypeXmmSs, + /* 15: kVarTypeXmmPs */ kVarTypeXmmPs, /* 16: kVarTypeXmmSd */ kVarTypeXmmSd, - /* 17: kVarTypeXmmPs */ kVarTypeXmmPs, - /* 18: kVarTypeXmmPd */ kVarTypeXmmPd, - /* 19: kVarTypeYmm */ kVarTypeYmm, - /* 20: kVarTypeYmmPs */ kVarTypeYmmPs, - /* 21: kVarTypeYmmPd */ kVarTypeYmmPd + /* 17: kVarTypeXmmPd */ kVarTypeXmmPd, + /* 18: kVarTypeYmm */ kVarTypeYmm, + /* 19: kVarTypeYmmPs */ kVarTypeYmmPs, + /* 20: kVarTypeYmmPd */ kVarTypeYmmPd }; const GpReg spl(kRegTypeGpbLo, kRegIndexSp, 1); diff --git a/src/asmjit/x86/x86defs.h b/src/asmjit/x86/x86defs.h index 0ac4a76..704b412 100644 --- a/src/asmjit/x86/x86defs.h +++ b/src/asmjit/x86/x86defs.h @@ -1869,28 +1869,28 @@ ASMJIT_ENUM(kCond) { //! @brief X86 variable type. ASMJIT_ENUM(kVarType) { //! @brief Variable is Mm (MMX). - kVarTypeMm = 13, + kVarTypeMm = 12, //! @brief Variable is Xmm (SSE/SSE2). - kVarTypeXmm = 14, + kVarTypeXmm, //! @brief Variable is SSE scalar SP-FP number. - kVarTypeXmmSs = 15, + kVarTypeXmmSs, //! @brief Variable is SSE packed SP-FP number (4 floats). - kVarTypeXmmPs = 16, + kVarTypeXmmPs, //! @brief Variable is SSE2 scalar DP-FP number. - kVarTypeXmmSd = 17, + kVarTypeXmmSd, //! @brief Variable is SSE2 packed DP-FP number (2 doubles). - kVarTypeXmmPd = 18, + kVarTypeXmmPd, //! @brief Variable is Ymm (AVX). - kVarTypeYmm = 19, + kVarTypeYmm, //! @brief Variable is AVX packed SP-FP number (8 floats). - kVarTypeYmmPs = 20, + kVarTypeYmmPs, //! @brief Variable is AVX packed DP-FP number (4 doubles). - kVarTypeYmmPd = 21, + kVarTypeYmmPd, //! @brief Count of variable types. - kVarTypeCount = 22, + kVarTypeCount, //! @internal _kVarTypeMmStart = kVarTypeMm, diff --git a/src/asmjit/x86/x86func.cpp b/src/asmjit/x86/x86func.cpp index 6d9620b..48f64c0 100644 --- a/src/asmjit/x86/x86func.cpp +++ b/src/asmjit/x86/x86func.cpp @@ -25,17 +25,15 @@ namespace asmjit { namespace x86x64 { // ============================================================================ -// [asmjit::X86X64FuncDecl - FindArgByReg] +// [asmjit::X86X64FuncDecl - Helpers] // ============================================================================ -uint32_t X86X64FuncDecl::findArgByReg(uint32_t rClass, uint32_t rIndex) const { - for (uint32_t i = 0; i < _argCount; i++) { - const FuncInOut& arg = getArg(i); - if (arg.getRegIndex() == rIndex && x86VarTypeToClass(arg.getVarType()) == rClass) - return i; - } - - return kInvalidValue; +static ASMJIT_INLINE uint32_t x86FpVarTypeToXmmType(uint32_t vType) { + if (vType == kVarTypeFp32) + return kVarTypeXmmSs; + if (vType == kVarTypeFp64) + return kVarTypeXmmSd; + return vType; } // ============================================================================ @@ -152,7 +150,7 @@ static uint32_t X86X64FuncDecl_initConv(X86X64FuncDecl* self, uint32_t arch, uin self->_passedOrderGp[2] = R(R8); self->_passedOrderGp[3] = R(R9); - self->_passed.set(kRegClassXy, IntUtil::mask(0, 1, 2, 3)); + self->_passed.set(kRegClassXy, IntUtil::mask(R(Xmm0), R(Xmm1), R(Xmm2), R(Xmm3))); self->_passedOrderXmm[0] = R(Xmm0); self->_passedOrderXmm[1] = R(Xmm1); self->_passedOrderXmm[2] = R(Xmm2); @@ -298,12 +296,6 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch, } break; - case kVarTypeFpEx: - self->_retCount = 1; - self->_retList[0]._varType = static_cast(ret); - self->_retList[0]._regIndex = kRegIndexFp0; - break; - case kVarTypeXmm: case kVarTypeXmmSs: case kVarTypeXmmSd: @@ -366,7 +358,7 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch, #if defined(ASMJIT_BUILD_X64) if (arch == kArchX64) { if (conv == kFuncConvX64W) { - int32_t argMax = argCount < 4 ? argCount : 4; + int32_t argMax = IntUtil::iMin(argCount, 4); // Register arguments (Gp/Xmm), always left-to-right. for (i = 0; i != argMax; i++) { @@ -378,6 +370,7 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch, self->_used.add(kRegClassGp, IntUtil::mask(arg.getRegIndex())); } else if (x86VarIsFloat(varType)) { + arg._varType = static_cast(x86FpVarTypeToXmmType(varType)); arg._regIndex = self->_passedOrderXmm[i]; self->_used.add(kRegClassXy, IntUtil::mask(arg.getRegIndex())); } @@ -423,6 +416,7 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch, uint32_t varType = varMapping[arg.getVarType()]; if (x86VarIsFloat(varType)) { + arg._varType = static_cast(x86FpVarTypeToXmmType(varType)); arg._regIndex = self->_passedOrderXmm[xmmPos++]; self->_used.add(kRegClassXy, IntUtil::mask(arg.getRegIndex())); } diff --git a/src/asmjit/x86/x86func.h b/src/asmjit/x86/x86func.h index a6c9420..c6a37e1 100644 --- a/src/asmjit/x86/x86func.h +++ b/src/asmjit/x86/x86func.h @@ -446,13 +446,6 @@ struct X86X64FuncDecl : public FuncDecl { //! prototype of the function doesn't affect the mask returned. ASMJIT_INLINE const uint8_t* getPassedOrderXmm() const { return _passedOrderXmm; } - // -------------------------------------------------------------------------- - // [FindArgByReg] - // -------------------------------------------------------------------------- - - //! @brief Find argument ID by register class and index. - ASMJIT_API uint32_t findArgByReg(uint32_t rClass, uint32_t rIndex) const; - // -------------------------------------------------------------------------- // [SetPrototype] // -------------------------------------------------------------------------- diff --git a/tools/autoexp.dat b/tools/autoexp.dat index 4d2de36..02aa1fd 100644 --- a/tools/autoexp.dat +++ b/tools/autoexp.dat @@ -30,9 +30,8 @@ @define asmjit::kVarAttrInOutConv (0x000000C0) @define asmjit::kVarAttrInCall (0x00000100) @define asmjit::kVarAttrInArg (0x00000200) -@define asmjit::kVarAttrInStack (0x00000400) -@define asmjit::kVarAttrOutRet (0x00000800) -@define asmjit::kVarAttrUnuse (0x00001000) +@define asmjit::kVarAttrOutRet (0x00000400) +@define asmjit::kVarAttrUnuse (0x00000800) @ @define asmjit::kVarTypeInt8 (0x0) @define asmjit::kVarTypeUInt8 (0x1) @@ -727,7 +726,7 @@ asmjit::BaseVarAttr|asmjit::x86x64::VarAttr { #else ("INVALID"), " ", - #if (($e._flags & (asmjit::kVarAttrInReg | asmjit::kVarAttrInMem | asmjit::kVarAttrInDecide | asmjit::kVarAttrInConv | asmjit::kVarAttrInCall | asmjit::kVarAttrInArg | asmjit::kVarAttrInStack)) != 0) ( + #if (($e._flags & (asmjit::kVarAttrInReg | asmjit::kVarAttrInMem | asmjit::kVarAttrInDecide | asmjit::kVarAttrInConv | asmjit::kVarAttrInCall | asmjit::kVarAttrInArg)) != 0) ( #( "in[", #if (($e._flags & asmjit::kVarAttrInReg) != 0) ("reg "), @@ -736,7 +735,6 @@ asmjit::BaseVarAttr|asmjit::x86x64::VarAttr { #if (($e._flags & asmjit::kVarAttrInConv) != 0) ("conv "), #if (($e._flags & asmjit::kVarAttrInCall) != 0) ("call "), #if (($e._flags & asmjit::kVarAttrInArg) != 0) ("arg "), - #if (($e._flags & asmjit::kVarAttrInStack) != 0) ("stack "), "] " ) ),