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.
This commit is contained in:
kobalicekp
2014-03-05 23:27:28 +01:00
parent 17c690c5e2
commit f77f792cc4
13 changed files with 761 additions and 448 deletions

View File

@@ -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<X86Test*>& 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<int>());
// 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<int, int, int, int, int, int, int, int, int, int, int>());
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>(_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<X86Test*>& 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<float, float, float>());
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<float, float, float>());
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<X86Test*>& 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<double, double, double>());
// Prepare.
GpVar fn(c);
c.mov(fn, imm_ptr((void*)calledFunc));
// Call function.
X86X64CallNode* call = c.call(fn, kFuncConvHost,
FuncBuilder2<double, double, double>());
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<double, double, double>());
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");

View File

@@ -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<uint8_t>(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<uint8_t>(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<uint8_t>(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;
};
// ============================================================================

View File

@@ -97,6 +97,21 @@ struct BaseContext {
// [Mem]
// --------------------------------------------------------------------------
ASMJIT_INLINE Error _registerContextVar(VarData* vd) {
if (vd->hasContextId())
return kErrorOk;
uint32_t cid = static_cast<uint32_t>(_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);

View File

@@ -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); }
};

View File

@@ -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]

View File

@@ -226,35 +226,38 @@ struct VarInst : public BaseVarInst {
// --------------------------------------------------------------------------
//! @brief Get variable-attributes list as VarAttr data.
ASMJIT_INLINE VarAttr* getVaList() const
{ return const_cast<VarAttr*>(_list); }
ASMJIT_INLINE VarAttr* getVaList() const {
return const_cast<VarAttr*>(_list);
}
//! @brief Get variable-attributes list as VarAttr data (by class).
ASMJIT_INLINE VarAttr* getVaListByClass(uint32_t c) const
{ return const_cast<VarAttr*>(_list) + _start.get(c); }
ASMJIT_INLINE VarAttr* getVaListByClass(uint32_t c) const {
return const_cast<VarAttr*>(_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)

View File

@@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(srcType, kVarTypeMm, kVarTypeMm))
goto _MovMmD;
// Move DWORD (Xmm).
if (IntUtil::inInterval<uint32_t>(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<kRegClassMm>(this, src);
X86X64Context_switchStateVars<kRegClassXy>(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<uint32_t>(_contextVd.getLength());
@@ -1439,7 +1495,6 @@ void X86X64Context::intersectStates(BaseVarState* a_, BaseVarState* b_) {
VarState* bState = static_cast<VarState*>(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<SArgNode>(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<uint32_t>(aType, _kVarTypeIntStart, _kVarTypeIntEnd))
return aType;
if (aType == kVarTypeFp32)
return kVarTypeXmmSs;
if (aType == kVarTypeFp64)
return kVarTypeXmmSd;
if (IntUtil::inInterval<uint32_t>(aType, _kVarTypeXmmStart, _kVarTypeXmmEnd))
return aType;
if (IntUtil::inInterval<uint32_t>(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<SArgNode>(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<SArgNode>(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<BaseNode*>::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<uint32_t>(_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<SArgNode*>(node_);
VarData* vd = node->getVd();
X86X64CallNode* call = static_cast<X86X64CallNode*>(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<int>(_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<int>(_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<int C>
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<kRegClassGp>();
@@ -3471,9 +3701,6 @@ ASMJIT_INLINE Error X86X64CallAlloc::run(X86X64CallNode* node) {
alloc<kRegClassMm>();
alloc<kRegClassXy>();
// 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<kRegClassGp>();
@@ -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<kRegClassGp>();
duplicate<kRegClassMm>();
duplicate<kRegClassXy>();
// 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<int>(_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<const Imm&>(node->getArg(i));
const Imm& imm = static_cast<const Imm&>(op);
const FuncInOut& arg = decl->getArg(i);
if (arg.hasStackOffset()) {
@@ -3855,6 +4021,42 @@ ASMJIT_INLINE void X86X64CallAlloc::allocImmsOnStack() {
}
}
// ============================================================================
// [asmjit::x86x64::X86X64CallAlloc - Duplicate]
// ============================================================================
template<int C>
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<int32_t>(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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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<uint8_t>(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<int32_t>(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<uint8_t>(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<uint8_t>(x86FpVarTypeToXmmType(varType));
arg._regIndex = self->_passedOrderXmm[xmmPos++];
self->_used.add(kRegClassXy, IntUtil::mask(arg.getRegIndex()));
}

View File

@@ -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]
// --------------------------------------------------------------------------

View File

@@ -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 "),
"] "
)
),