[Bug] Fixed sign and zero extension in Function API (x86)

The problem was that the sign/zero extension was not working with
TypeIds, but it was working with register IDs, when emitted. Thus,
even when TypeId was uint8, for example, the register could be
uint32, so the final instruction emitted was 'movzx eax, eax', for
example, which was wrong.
This commit is contained in:
kobalicek
2024-01-13 14:31:35 +01:00
parent c620b113ad
commit 118ae6ced1
9 changed files with 204 additions and 83 deletions

View File

@@ -216,14 +216,17 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
}
else {
WorkData& wd = workData[outGroup];
if (!wd.isAssigned(outId)) {
if (!wd.isAssigned(outId) || curId == outId) {
EmitMove:
ASMJIT_PROPAGATE(
emitArgMove(
BaseReg(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(),
BaseReg(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId()));
wd.reassign(varId, outId, curId);
// Only reassign if this is not a sign/zero extension that happens on the same in/out register.
if (curId != outId)
wd.reassign(varId, outId, curId);
cur.initReg(out.regType(), outId, out.typeId());
if (outId == out.regId())

View File

@@ -24,7 +24,7 @@ enum class Vendor : uint8_t {
//! Unknown or uninitialized platform vendor.
kUnknown = 0,
//! Maximum value of `PlatformVendor`.
//! Maximum value of `Vendor`.
kMaxValue = kUnknown,
//! Platform vendor detected at compile-time.
@@ -500,7 +500,7 @@ public:
return isFamilyAArch32(arch) || isFamilyAArch64(arch);
}
//! Tests whether the given architecture family is MISP or MIPS64.
//! Tests whether the given architecture family is MIPS or MIPS64.
static ASMJIT_INLINE_NODEBUG bool isFamilyMIPS(Arch arch) noexcept {
return isArchMIPS32(arch) || isArchMIPS64(arch);
}

View File

@@ -180,6 +180,11 @@ struct CallConv {
//! Natural stack alignment as defined by OS/ABI.
uint8_t _naturalStackAlignment;
//! \cond INTERNAL
//! Reserved for future use.
uint8_t _reserved[2];
//! \endcond
//! Calling convention flags.
CallConvFlags _flags;
@@ -220,7 +225,7 @@ struct CallConv {
//! as it prevents from using an uninitialized data (CallConv doesn't have a constructor that would initialize it,
//! it's just a struct).
ASMJIT_INLINE_NODEBUG void reset() noexcept {
memset(this, 0, sizeof(*this));
*this = CallConv{};
memset(_passedOrder.data(), 0xFF, sizeof(_passedOrder));
}

View File

@@ -102,9 +102,23 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
ASMJIT_ASSERT(dstWd != nullptr);
dstWd->assign(varId, srcId);
// The best case, register is allocated where it is expected to be.
if (dstId == srcId)
var.markDone();
// The best case, register is allocated where it is expected to be. However, we should
// not mark this as done if both registers are GP and sign or zero extension is required.
if (dstId == srcId) {
if (dstGroup != RegGroup::kGp) {
var.markDone();
}
else {
TypeId dt = dst.typeId();
TypeId st = src.typeId();
uint32_t dstSize = TypeUtils::sizeOf(dt);
uint32_t srcSize = TypeUtils::sizeOf(st);
if (dt == TypeId::kVoid || st == TypeId::kVoid || dstSize <= srcSize)
var.markDone();
}
}
}
else {
if (ASMJIT_UNLIKELY(srcGroup > RegGroup::kMaxVirt))

View File

@@ -202,9 +202,13 @@ static ASMJIT_INLINE_NODEBUG constexpr bool isInt64(TypeId typeId) noexcept { re
//! Tests whether a given type is a scalar 64-bit integer (unsigned).
static ASMJIT_INLINE_NODEBUG constexpr bool isUInt64(TypeId typeId) noexcept { return typeId == TypeId::kUInt64; }
//! Tests whether a given type is an 8-bit general purpose register representing either signed or unsigned 8-bit integer.
static ASMJIT_INLINE_NODEBUG constexpr bool isGp8(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt8, TypeId::kUInt8); }
//! Tests whether a given type is a 16-bit general purpose register representing either signed or unsigned 16-bit integer
static ASMJIT_INLINE_NODEBUG constexpr bool isGp16(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt16, TypeId::kUInt16); }
//! Tests whether a given type is a 32-bit general purpose register representing either signed or unsigned 32-bit integer
static ASMJIT_INLINE_NODEBUG constexpr bool isGp32(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt32, TypeId::kUInt32); }
//! Tests whether a given type is a 64-bit general purpose register representing either signed or unsigned 64-bit integer
static ASMJIT_INLINE_NODEBUG constexpr bool isGp64(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt64, TypeId::kUInt64); }
//! Tests whether a given type is a scalar floating point of any size.
@@ -216,21 +220,41 @@ static ASMJIT_INLINE_NODEBUG constexpr bool isFloat64(TypeId typeId) noexcept {
//! Tests whether a given type is a scalar 80-bit float.
static ASMJIT_INLINE_NODEBUG constexpr bool isFloat80(TypeId typeId) noexcept { return typeId == TypeId::kFloat80; }
//! Tests whether a given type is a mask register of any size.
static ASMJIT_INLINE_NODEBUG constexpr bool isMask(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kMaskStart, TypeId::_kMaskEnd); }
//! Tests whether a given type is an 8-bit mask register.
static ASMJIT_INLINE_NODEBUG constexpr bool isMask8(TypeId typeId) noexcept { return typeId == TypeId::kMask8; }
//! Tests whether a given type is an 16-bit mask register.
static ASMJIT_INLINE_NODEBUG constexpr bool isMask16(TypeId typeId) noexcept { return typeId == TypeId::kMask16; }
//! Tests whether a given type is an 32-bit mask register.
static ASMJIT_INLINE_NODEBUG constexpr bool isMask32(TypeId typeId) noexcept { return typeId == TypeId::kMask32; }
//! Tests whether a given type is an 64-bit mask register.
static ASMJIT_INLINE_NODEBUG constexpr bool isMask64(TypeId typeId) noexcept { return typeId == TypeId::kMask64; }
//! Tests whether a given type is an MMX register.
//!
//! \note MMX functionality is in general deprecated on X86 architecture. AsmJit provides it just for completeness.
static ASMJIT_INLINE_NODEBUG constexpr bool isMmx(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kMmxStart, TypeId::_kMmxEnd); }
//! Tests whether a given type is an MMX register, which only uses the low 32 bits of data (only specific cases).
//!
//! \note MMX functionality is in general deprecated on X86 architecture. AsmJit provides it just for completeness.
static ASMJIT_INLINE_NODEBUG constexpr bool isMmx32(TypeId typeId) noexcept { return typeId == TypeId::kMmx32; }
//! Tests whether a given type is an MMX register, which uses 64 bits of data (default).
//!
//! \note MMX functionality is in general deprecated on X86 architecture. AsmJit provides it just for completeness.
static ASMJIT_INLINE_NODEBUG constexpr bool isMmx64(TypeId typeId) noexcept { return typeId == TypeId::kMmx64; }
//! Tests whether a given type is a vector register of any size.
static ASMJIT_INLINE_NODEBUG constexpr bool isVec(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec32Start, TypeId::_kVec512End); }
//! Tests whether a given type is a 32-bit or 32-bit view of a vector register.
static ASMJIT_INLINE_NODEBUG constexpr bool isVec32(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec32Start, TypeId::_kVec32End); }
//! Tests whether a given type is a 64-bit or 64-bit view of a vector register.
static ASMJIT_INLINE_NODEBUG constexpr bool isVec64(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec64Start, TypeId::_kVec64End); }
//! Tests whether a given type is a 128-bit or 128-bit view of a vector register.
static ASMJIT_INLINE_NODEBUG constexpr bool isVec128(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec128Start, TypeId::_kVec128End); }
//! Tests whether a given type is a 256-bit or 256-bit view of a vector register.
static ASMJIT_INLINE_NODEBUG constexpr bool isVec256(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec256Start, TypeId::_kVec256End); }
//! Tests whether a given type is a 512-bit or 512-bit view of a vector register.
static ASMJIT_INLINE_NODEBUG constexpr bool isVec512(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec512Start, TypeId::_kVec512End); }
//! \cond

View File

@@ -22,6 +22,18 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
// x86::EmitHelper - Utilities
// ===========================
static constexpr OperandSignature regSizeToGpSignature[8 + 1] = {
OperandSignature{0},
OperandSignature{RegTraits<RegType::kX86_GpbLo>::kSignature},
OperandSignature{RegTraits<RegType::kX86_Gpw>::kSignature},
OperandSignature{0},
OperandSignature{RegTraits<RegType::kX86_Gpd>::kSignature},
OperandSignature{0},
OperandSignature{0},
OperandSignature{0},
OperandSignature{RegTraits<RegType::kX86_Gpq>::kSignature}
};
static inline uint32_t getXmmMovInst(const FuncFrame& frame) {
bool avx = frame.isAvxEnabled();
bool aligned = frame.hasAlignedVecSR();
@@ -182,41 +194,42 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitArgMove(
// Not a real loop, just 'break' is nicer than 'goto'.
for (;;) {
if (TypeUtils::isInt(dstTypeId)) {
// Sign extend.
if (TypeUtils::isInt(srcTypeId)) {
instId = Inst::kIdMovsx;
uint32_t castOp = makeCastOp(dstTypeId, srcTypeId);
// Sign extend by using 'movsx'.
if (castOp == makeCastOp(TypeId::kInt16, TypeId::kInt8 ) ||
castOp == makeCastOp(TypeId::kInt32, TypeId::kInt8 ) ||
castOp == makeCastOp(TypeId::kInt32, TypeId::kInt16) ||
castOp == makeCastOp(TypeId::kInt64, TypeId::kInt8 ) ||
castOp == makeCastOp(TypeId::kInt64, TypeId::kInt16))
break;
castOp == makeCastOp(TypeId::kInt32, TypeId::kInt16) ||
castOp == makeCastOp(TypeId::kInt64, TypeId::kInt16) ||
castOp == makeCastOp(TypeId::kInt64, TypeId::kInt32)) {
// Sign extend by using 'movsx' or 'movsxd'.
instId =
castOp == makeCastOp(TypeId::kInt64, TypeId::kInt32)
? Inst::kIdMovsxd
: Inst::kIdMovsx;
// Sign extend by using 'movsxd'.
instId = Inst::kIdMovsxd;
if (castOp == makeCastOp(TypeId::kInt64, TypeId::kInt32))
dst.setSignature(regSizeToGpSignature[dstSize]);
if (src.isReg())
src.setSignature(regSizeToGpSignature[srcSize]);
break;
}
}
// Zero extend.
if (TypeUtils::isInt(srcTypeId) || src_.isMem()) {
// Zero extend by using 'movzx' or 'mov'.
if (dstSize <= 4 && srcSize < 4) {
instId = Inst::kIdMovzx;
dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
}
else {
// We should have caught all possibilities where `srcSize` is less than 4, so we don't have to worry
// about 'movzx' anymore. Minimum size is enough to determine if we want 32-bit or 64-bit move.
instId = Inst::kIdMov;
srcSize = Support::min(srcSize, dstSize);
uint32_t movSize = Support::min(srcSize, dstSize);
if (movSize <= 4)
dstSize = 4;
dst.setSignature(srcSize == 4 ? Reg::signatureOfT<RegType::kX86_Gpd>()
: Reg::signatureOfT<RegType::kX86_Gpq>());
if (src.isReg())
src.setSignature(dst.signature());
}
// Zero extend by using 'movzx' or 'mov'.
instId = movSize < 4 ? Inst::kIdMovzx : Inst::kIdMov;
srcSize = Support::min(srcSize, movSize);
dst.setSignature(regSizeToGpSignature[dstSize]);
if (src.isReg())
src.setSignature(regSizeToGpSignature[srcSize]);
break;
}

View File

@@ -35,6 +35,7 @@ using namespace asmjit;
int TestApp::handleArgs(int argc, const char* const* argv) {
CmdLine cmd(argc, argv);
_arch = cmd.valueOf("--arch", "all");
_filter = cmd.valueOf("--filter", nullptr);
if (cmd.hasArg("--help")) _helpOnly = true;
if (cmd.hasArg("--verbose")) _verbose = true;
@@ -56,11 +57,12 @@ void TestApp::showInfo() {
asmjitArchAsString(Arch::kHost));
printf("Usage:\n");
printf(" --help Show usage only\n");
printf(" --arch=<ARCH> Select architecture to run ('all' by default)\n");
printf(" --verbose Verbose output\n");
printf(" --dump-asm Assembler output\n");
printf(" --dump-hex Hexadecimal output (relocated, only for host arch)\n");
printf(" --help Show usage only\n");
printf(" --arch=<NAME> Select architecture to run ('all' by default)\n");
printf(" --filter=<NAME> Use a filter to restrict which test is called\n");
printf(" --verbose Verbose output\n");
printf(" --dump-asm Assembler output\n");
printf(" --dump-hex Hexadecimal output (relocated, only for host arch)\n");
printf("\n");
}
@@ -82,6 +84,13 @@ public:
};
#endif // !ASMJIT_NO_LOGGING
bool TestApp::shouldRun(const TestCase* tc) {
if (!_filter)
return true;
return strstr(tc->name(), _filter) != nullptr;
}
int TestApp::run() {
#ifndef ASMJIT_NO_LOGGING
FormatOptions formatOptions;
@@ -120,6 +129,11 @@ int TestApp::run() {
double finalizeTime = 0;
for (std::unique_ptr<TestCase>& test : _tests) {
if (!shouldRun(test.get()))
continue;
_numTests++;
for (uint32_t pass = 0; pass < 2; pass++) {
bool runnable = false;
CodeHolder code;
@@ -306,7 +320,7 @@ int TestApp::run() {
printf(" [Output]\n");
printf(" Returned: %s\n", result.data());
printf(" Expected: %s\n", expect.data());
_nFailed++;
_numFailed++;
}
if (_dumpAsm)
@@ -321,7 +335,7 @@ int TestApp::run() {
printStringLoggerContent();
printf(" [Status]\n");
printf(" ERROR 0x%08X: %s\n", unsigned(err), errorHandler._message.data());
_nFailed++;
_numFailed++;
}
}
#endif // !ASMJIT_NO_JIT
@@ -330,7 +344,7 @@ int TestApp::run() {
if (err) {
printf(" [Status]\n");
printf(" ERROR 0x%08X: %s\n", unsigned(err), errorHandler._message.data());
_nFailed++;
_numFailed++;
}
else {
printf("%s[COMPILE OK]\n", statusSeparator);
@@ -352,12 +366,12 @@ int TestApp::run() {
printf(" FinalizeTime: %.2f ms\n", finalizeTime);
printf("\n");
if (_nFailed == 0)
printf("** SUCCESS: All %u tests passed **\n", unsigned(_tests.size()));
if (_numFailed == 0)
printf("** SUCCESS: All %u tests passed **\n", _numTests);
else
printf("** FAILURE: %u of %u tests failed **\n", _nFailed, unsigned(_tests.size()));
printf("** FAILURE: %u of %u tests failed **\n", _numFailed, _numTests);
return _nFailed == 0 ? 0 : 1;
return _numFailed == 0 ? 0 : 1;
}
int main(int argc, char* argv[]) {

View File

@@ -52,12 +52,14 @@ public:
std::vector<std::unique_ptr<TestCase>> _tests;
const char* _arch = nullptr;
const char* _filter = nullptr;
bool _helpOnly = false;
bool _verbose = false;
bool _dumpAsm = false;
bool _dumpHex = false;
unsigned _nFailed = 0;
unsigned _numTests = 0;
unsigned _numFailed = 0;
size_t _outputSize = 0;
TestApp() noexcept
@@ -73,6 +75,8 @@ public:
int handleArgs(int argc, const char* const* argv);
void showInfo();
bool shouldRun(const TestCase* tc);
int run();
};

View File

@@ -203,7 +203,7 @@ public:
result.assignFormat("ret={%u, %u}", resultRet >> 28, resultRet & 0x0FFFFFFFu);
expect.assignFormat("ret={%u, %u}", expectRet >> 28, expectRet & 0x0FFFFFFFu);
return resultRet == expectRet;
return result == expect;
}
uint32_t _argCount;
@@ -437,7 +437,7 @@ public:
result.assignFormat("ret={%d}", resultRet);
expect.assignFormat("ret={%d}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -912,7 +912,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -1192,7 +1192,7 @@ public:
result.assignFormat("result=%d", resultRet);
expect.assignFormat("result=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -1288,7 +1288,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -1373,7 +1373,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -1409,7 +1409,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -1860,7 +1860,7 @@ public:
result.assignFormat("ret={%g}", resultRet);
expect.assignFormat("ret={%g}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -1911,7 +1911,7 @@ public:
result.assignFormat("ret={%g}", resultRet);
expect.assignFormat("ret={%g}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2001,7 +2001,7 @@ public:
result.assignFormat("ret={%g}", resultRet);
expect.assignFormat("ret={%g}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2040,7 +2040,7 @@ public:
result.assignFormat("ret={%g}", resultRet);
expect.assignFormat("ret={%g}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2075,7 +2075,7 @@ public:
result.assignFormat("ret={%g}", resultRet);
expect.assignFormat("ret={%g}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2114,7 +2114,7 @@ public:
result.assignFormat("ret={%g}", resultRet);
expect.assignFormat("ret={%g}", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2181,7 +2181,7 @@ public:
result.assignInt(resultRet);
expect.assignInt(expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2406,6 +2406,47 @@ public:
}
};
// x86::Compiler - X86Test_FuncArgInt8
// ===================================
class X86Test_FuncArgInt8 : public X86TestCase {
public:
X86Test_FuncArgInt8() : X86TestCase("FuncArgInt8") {}
static void add(TestApp& app) {
app.add(new X86Test_FuncArgInt8());
}
virtual void compile(x86::Compiler& cc) {
x86::Gp v0 = cc.newUInt32("v0");
x86::Gp v1 = cc.newUInt32("v1");
FuncNode* funcNode = cc.addFunc(FuncSignature::build<unsigned, uint8_t, uint8_t, uint32_t>());
funcNode->setArg(0, v0);
funcNode->setArg(1, v1);
cc.add(v0, v1);
cc.ret(v0);
cc.endFunc();
}
virtual bool run(void* _func, String& result, String& expect) {
typedef uint32_t (*Func)(uint8_t, uint8_t, uint32_t);
Func func = ptr_as_func<Func>(_func);
uint32_t arg = uint32_t(uintptr_t(_func) & 0xFFFFFFFF);
unsigned resultRet = func(uint8_t(arg & 0xFF), uint8_t(arg & 0xFF), arg);
unsigned expectRet = (arg & 0xFF) * 2;
result.assignFormat("ret=%u", resultRet);
expect.assignFormat("ret=%u", expectRet);
return result == expect;
}
};
// x86::Compiler - X86Test_FuncCallBase1
// =====================================
@@ -2454,7 +2495,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
static int calledFunc(int a, int b, int c) { return (a + b) * c; }
@@ -2537,7 +2578,7 @@ public:
result.assignInt(resultRet);
expect.assignInt(expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2585,7 +2626,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
// STDCALL function that is called inside the generated one.
@@ -2635,7 +2676,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
// FASTCALL function that is called inside the generated one.
@@ -2906,7 +2947,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -2963,7 +3004,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3016,7 +3057,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3082,7 +3123,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3148,7 +3189,7 @@ public:
result.assignFormat("ret={%08X %08X %08X %08X %08X}", resultRet, inputs[0], inputs[1], inputs[2], inputs[3]);
expect.assignFormat("ret={%08X %08X %08X %08X %08X}", expectRet, outputs[0], outputs[1], outputs[2], outputs[3]);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3198,7 +3239,7 @@ public:
result.assignFormat("ret=%g", resultRet);
expect.assignFormat("ret=%g", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3247,7 +3288,7 @@ public:
result.assignFormat("ret=%g", resultRet);
expect.assignFormat("ret=%g", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3403,7 +3444,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3454,7 +3495,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3510,7 +3551,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
static int calledFunc(size_t n, ...) {
@@ -3578,7 +3619,7 @@ public:
result.assignFormat("ret=%f", resultRet);
expect.assignFormat("ret=%f", expectRet);
return resultRet == expectRet;
return result == expect;
}
static double calledFunc(size_t n, ...) {
@@ -3639,7 +3680,7 @@ public:
result.assignFormat("ret=%llu", (unsigned long long)resultRet);
expect.assignFormat("ret=%llu", (unsigned long long)expectRet);
return resultRet == expectRet;
return result == expect;
}
static double calledFunc(size_t n, ...) {
@@ -3701,7 +3742,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -3749,7 +3790,7 @@ public:
result.assignFormat("ret=%g", resultRet);
expect.assignFormat("ret=%g", expectRet);
return resultRet == expectRet;
return result == expect;
}
static double op(double a) { return a * a; }
@@ -3802,7 +3843,7 @@ public:
result.assignFormat("ret=%g", resultRet);
expect.assignFormat("ret=%g", expectRet);
return resultRet == expectRet;
return result == expect;
}
static double op(double a) { return a * a; }
@@ -3849,7 +3890,7 @@ public:
result.assignFormat("ret=%g", resultRet);
expect.assignFormat("ret=%g", expectRet);
return resultRet == expectRet;
return result == expect;
}
static double calledFunc() { return 3.14; }
@@ -3907,7 +3948,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
static void calledFunc() {}
@@ -3967,7 +4008,7 @@ public:
result.assignFormat("ret=%u", resultRet);
expect.assignFormat("ret=%u", expectRet);
return resultRet == expectRet;
return result == expect;
}
static uint32_t calledFunc(uint32_t x) { return x + 1; }
@@ -4129,7 +4170,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -4171,7 +4212,7 @@ public:
result.assignFormat("ret=%d", resultRet);
expect.assignFormat("ret=%d", expectRet);
return resultRet == expectRet;
return result == expect;
}
};
@@ -4377,7 +4418,7 @@ public:
result.assignFormat("ret={%d}", resultRet);
expect.assignFormat("ret={%d}", expectRet);
return resultRet == expectRet;
return result == expect;
}
static void ASMJIT_FASTCALL handler() { longjmp(globalJmpBuf, 1); }
@@ -4437,6 +4478,9 @@ void compiler_add_x86_tests(TestApp& app) {
app.addT<X86Test_AllocExtraBlock>();
app.addT<X86Test_AllocAlphaBlend>();
// Function arguments handling tests.
app.addT<X86Test_FuncArgInt8>();
// Function call tests.
app.addT<X86Test_FuncCallBase1>();
app.addT<X86Test_FuncCallBase2>();