dynarmic/sample/quantize.cpp
Merry f6fdb5f55a Squashed 'externals/xbyak/' changes from 88f2f771f..a1ac3750f
a1ac3750f Merge branch 'dev'
5f4ba971f v6.68
cac2c175f update doc
1b08a8248 add test of prefetchiti
bef70d9b1 add prefetchit{0,1}
f66785876 add detection of prefetchiti
124617ac9 Merge branch 'dev'
1bce8be17 Merge commit 'fbb18f6' into dev
bebfe64a3 [test] X32 is optional and remove CFLAGS
d8c332cef Merge branch 'Tachi107-small-changes' into dev
fbb18f69d ci: use containers
8a974696c test: simplify makefile
1efe9fe7c Merge branch 'dev'
bb70083e6 v6.67
436e452d7 update doc
47ff6ef42 I get an error after all on GitHub action
445c0dcec add test of CMPccXADD
c9347907d add CMPccXADD
dc792cc56 add detection of cmpccxadd
62be84cc8 fix detection of boost
b5ac7b0f0 Merge branch 'dev'
05dd400e0 recover a removed line
94eff6246 v6.66
ec3fadeba update doc
00bfaaa7f add test of rao-int
0f2f1aaa6 support rio-int
6c047f480 detect rao-int
f07c5c255 fix args of EmptyAllocator::alloc in test
04d3eb5f5 stop if a test script causes an error
1c1d2366f disable boost sample
cfb1127c3 tweak
5fcbeb7c4 [sample] change the way of detection of boost
bafc1ee60 CXX uses g++ as default value
d8cabc6cb remove warning of blace
bc73a0816 remove -fno-operator-names option
6989aea94 use CXX instead of g++
a7c5a1bd7 use English
1bfbd8c4d Fix incorrect format strings
0ecef5c28 Merge branch 'dev'
7556c20ba update doc
a15709271 v6.65
3b83aab3e add detect_x32 to TARGET
8c64bbbc3 use gcc instead of dpkg for portability
5e9a9b96f test_avx512.sh runs on x32
8ae01b0c2 disable some tests on x32
83b3da217 x32 does not check large disp
693ab8c9d sizeof(void*) = 4 on x32, so disable the test
348e3e548 Merge branch 'dev'
11b9c4dc0 v6.64
459636196 add T_M_K flag to vpmov*
1d3722928 add include path
5e27eddae move CrearError from LabelManager::reset() to CodeGenerator::reset()
f8ea5c28d Merge branch 'dev'
20b2b1eae v6.63
3706869f8 desc. of setDefaultEncoding
d6f2d7577 add test of setDefaultEncoding
3b0a19c41 vpmadd52{h,l}uq for avx-ifma
95752ebd7 add tAVX_IFMA
cd36e31ea [sample] show AMX_FP16/AVX_VNNI_INT8/AVX_NE_CONVERT
e5858af27 add setDefaultEncoding
2f7fb0220 modify gen.cpp for AVX-NE-CONVERT/AVX-VNNI-INT8/AMX-FP16
1c5cb7efa add AVX-NE-CONVERT instructions
564fe9acd add AVX-VNNI-INT8 instructions
cd14d07b1 add AMX-FP16 instruction
7811f593c Merge pull request #161 from scribam/patch-1
2218f6c08 Update changelog.md
7bccdbbb4 Merge pull request #160 from herumi/dev
5fcf87596 compile nasm-2.15 instead of apt install
e31961ea8 v6.62
ff4f9e65c update doc
9c8fb81db disable wrong detection of gcc -Warray-bounds
6b7519659 add serialize
e16582696 Merge branch 'JonLiu1993-vcpkg-installition' into dev
edbb410fb Add vcpkg installation instructions
055d31242 Merge branch 'dev'
21ab98441 Merge branch 'akodanka-enable_CIV' into dev
ed4d598e3 Changes to compile xbyak project for openvino
b652430c4 mingw uses __cpuidex
48457bfa0 Merge branch 'dev'
29cb524d1 v6.61.2
1a9a0b0e1 avoid including algorithm header in xbyak_util.h
6fadefd04 Merge branch 'dev'
fc1c18a9d update doc
f7cae7f11 v6.61.1
6f5ec5cf3 Merge branch 'doyaGu-master' into dev
4554d6bb9 Fix error related to XBYAK_NOEXCEPT

git-subtree-dir: externals/xbyak
git-subtree-split: a1ac3750f9a639b5a6c6d6c7da4259b8d6790989
2022-12-30 23:05:02 +00:00

226 lines
4.7 KiB
C++

/*
@author herumi
JPEG quantize sample
This program generates a quantization routine by using fast division algorithm in run-time.
time(sec)
quality 1(high) 10 50 100(low)
VC2005 8.0 8.0 8.0 8.0
Xbyak 1.6 0.8 0.5 0.5
; generated code at q = 1
push esi
push edi
mov edi,dword ptr [esp+0Ch]
mov esi,dword ptr [esp+10h]
mov eax,dword ptr [esi]
shr eax,4
mov dword ptr [edi],eax
mov eax,dword ptr [esi+4]
mov edx,0BA2E8BA3h
mul eax,edx
shr edx,3
...
; generated code at q = 100
push esi
push edi
mov edi,dword ptr [esp+0Ch]
mov esi,dword ptr [esp+10h]
mov eax,dword ptr [esi]
mov dword ptr [edi],eax
mov eax,dword ptr [esi+4]
mov dword ptr [edi+4],eax
mov eax,dword ptr [esi+8]
mov dword ptr [edi+8],eax
mov eax,dword ptr [esi+0Ch]
...
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996) // scanf
#endif
const int N = 64;
class Quantize : public Xbyak::CodeGenerator {
static int ilog2(int x)
{
int shift = 0;
while ((1 << shift) <= x) shift++;
return shift - 1;
}
public:
/*
input : esi
output : eax = [esi+offset] / dividend
destroy : edx
*/
void udiv(uint32_t dividend, int offset)
{
mov(eax, ptr[esi + offset]);
/* dividend = odd x 2^exponent */
int exponent = 0, odd = dividend;
while ((odd & 1) == 0) {
odd >>= 1; exponent++;
}
if (odd == 1) { // trivial case
if (exponent) {
shr(eax, exponent);
}
return;
}
uint64_t mLow, mHigh;
int len = ilog2(odd) + 1;
{
uint64_t roundUp = uint64_t(1) << (32 + len);
uint64_t k = roundUp / (0xFFFFFFFFL - (0xFFFFFFFFL % odd));
mLow = roundUp / odd;
mHigh = (roundUp + k) / odd;
}
while (((mLow >> 1) < (mHigh >> 1)) && (len > 0)) {
mLow >>= 1; mHigh >>= 1; len--;
}
uint64_t m; int a;
if ((mHigh >> 32) == 0) {
m = mHigh; a = 0;
} else {
len = ilog2(odd);
uint64_t roundDown = uint64_t(1) << (32 + len);
mLow = roundDown / odd;
int r = (int)(roundDown % odd);
m = (r <= (odd >> 1)) ? mLow : mLow + 1;
a = 1;
}
while ((m & 1) == 0) {
m >>= 1; len--;
}
len += exponent;
mov(edx, int(m));
mul(edx);
if (a) {
add(eax, int(m));
adc(edx, 0);
}
if (len) {
shr(edx, len);
}
mov(eax, edx);
}
/*
quantize(uint32_t dest[64], const uint32_t src[64]);
*/
Quantize(const uint32_t qTbl[64])
{
push(esi);
push(edi);
const int P_ = 4 * 2;
mov(edi, ptr [esp+P_+4]); // dest
mov(esi, ptr [esp+P_+8]); // src
for (int i = 0; i < N; i++) {
udiv(qTbl[i], i * 4);
mov(ptr[edi+i*4], eax);
}
pop(edi);
pop(esi);
ret();
}
};
void quantize(uint32_t dest[64], const uint32_t src[64], const uint32_t qTbl[64])
{
for (int i = 0; i < N; i++) {
dest[i] = src[i] / qTbl[i];
}
}
#ifdef XBYAK64
int main()
{
puts("not implemented for 64bit");
return 1;
}
#else
int main(int argc, char *argv[])
{
int q;
if (argc > 1) {
q = atoi(argv[1]);
} else {
printf("input quantize=");
if (scanf("%d", &q) != 1) {
fprintf(stderr, "bad number\n");
return 1;
}
}
printf("q=%d\n", q);
uint32_t qTbl[] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
for (int i = 0; i < N; i++) {
qTbl[i] /= q;
if (qTbl[i] == 0) qTbl[i] = 1;
}
try {
uint32_t src[N];
uint32_t dest[N];
uint32_t dest2[N];
for (int i = 0; i < N; i++) {
src[i] = rand() % 2048;
}
Quantize jit(qTbl);
//printf("jit size=%d, ptr=%p\n", jit.getSize(), jit.getCode());
void (*quantize2)(uint32_t*, const uint32_t*, const uint32_t *) = jit.getCode<void (*)(uint32_t*, const uint32_t*, const uint32_t *)>();
quantize(dest, src, qTbl);
quantize2(dest2, src, qTbl);
for (int i = 0; i < N; i++) {
if (dest[i] != dest2[i]) {
printf("err[%d] %u %u\n", i, dest[i], dest2[i]);
}
}
const int count = 10000000;
int begin;
begin = clock();
for (int i = 0; i < count; i++) {
quantize(dest, src, qTbl);
}
printf("time=%.1fsec\n", (clock() - begin) / double(CLOCKS_PER_SEC));
begin = clock();
for (int i = 0; i < count; i++) {
quantize2(dest, src, qTbl);
}
printf("time=%.1fsec\n", (clock() - begin) / double(CLOCKS_PER_SEC));
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
} catch (...) {
printf("unknown error\n");
}
}
#endif