mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-16 20:17:05 +03:00
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:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
@@ -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 "),
|
||||
"] "
|
||||
)
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user