forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
2
Kha/Kinc/Sources/kinc/libs/.clang-format
Normal file
2
Kha/Kinc/Sources/kinc/libs/.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: false
|
706
Kha/Kinc/Sources/kinc/libs/lz4x.h
Normal file
706
Kha/Kinc/Sources/kinc/libs/lz4x.h
Normal file
@ -0,0 +1,706 @@
|
||||
/*
|
||||
|
||||
LZ4X - An optimized LZ4 compressor
|
||||
|
||||
Written and placed in the public domain by Ilya Muravyov
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#define _CRT_DISABLE_PERFCRIT_LOCKS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define NO_UTIME
|
||||
|
||||
#ifndef NO_UTIME
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# include <sys/utime.h>
|
||||
# else
|
||||
# include <utime.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# define _ftelli64 ftello64
|
||||
#endif
|
||||
|
||||
typedef unsigned char U8;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
|
||||
//FILE* g_in;
|
||||
//FILE* g_out;
|
||||
|
||||
#define LZ4_MAGIC 0x184C2102
|
||||
#define BLOCK_SIZE (8<<20) // 8 MB
|
||||
#define PADDING_LITERALS 5
|
||||
|
||||
#define WINDOW_BITS 16
|
||||
#define WINDOW_SIZE (1<<WINDOW_BITS)
|
||||
#define WINDOW_MASK (WINDOW_SIZE-1)
|
||||
|
||||
#define MIN_MATCH 4
|
||||
|
||||
#define EXCESS (16+(BLOCK_SIZE/255))
|
||||
|
||||
static U8 g_buf[BLOCK_SIZE+BLOCK_SIZE+EXCESS];
|
||||
|
||||
#define MIN(a, b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a, b) (((a)>(b))?(a):(b))
|
||||
|
||||
#define LOAD_16(p) (*(const U16*)(&g_buf[p]))
|
||||
#define LOAD_32(p) (*(const U32*)(&g_buf[p]))
|
||||
#define STORE_16(p, x) (*(U16*)(&g_buf[p])=(x))
|
||||
#define COPY_32(d, s) (*(U32*)(&g_buf[d])=LOAD_32(s))
|
||||
|
||||
#define HASH_BITS 18
|
||||
#define HASH_SIZE (1<<HASH_BITS)
|
||||
#define NIL (-1)
|
||||
|
||||
#define HASH_32(p) ((LOAD_32(p)*0x9E3779B9)>>(32-HASH_BITS))
|
||||
|
||||
static inline void wild_copy(int d, int s, int n)
|
||||
{
|
||||
COPY_32(d, s);
|
||||
COPY_32(d+4, s+4);
|
||||
|
||||
for (int i=8; i<n; i+=8)
|
||||
{
|
||||
COPY_32(d+i, s+i);
|
||||
COPY_32(d+4+i, s+4+i);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void compress(const int max_chain)
|
||||
{
|
||||
static int head[HASH_SIZE];
|
||||
static int tail[WINDOW_SIZE];
|
||||
|
||||
int n;
|
||||
while ((n=fread(g_buf, 1, BLOCK_SIZE, g_in))>0)
|
||||
{
|
||||
for (int i=0; i<HASH_SIZE; ++i)
|
||||
head[i]=NIL;
|
||||
|
||||
int op=BLOCK_SIZE;
|
||||
int pp=0;
|
||||
|
||||
int p=0;
|
||||
while (p<n)
|
||||
{
|
||||
int best_len=0;
|
||||
int dist=0;
|
||||
|
||||
const int max_match=(n-PADDING_LITERALS)-p;
|
||||
if (max_match>=MAX(12-PADDING_LITERALS, MIN_MATCH))
|
||||
{
|
||||
const int limit=MAX(p-WINDOW_SIZE, NIL);
|
||||
int chain_len=max_chain;
|
||||
|
||||
int s=head[HASH_32(p)];
|
||||
while (s>limit)
|
||||
{
|
||||
if (g_buf[s+best_len]==g_buf[p+best_len] && LOAD_32(s)==LOAD_32(p))
|
||||
{
|
||||
int len=MIN_MATCH;
|
||||
while (len<max_match && g_buf[s+len]==g_buf[p+len])
|
||||
++len;
|
||||
|
||||
if (len>best_len)
|
||||
{
|
||||
best_len=len;
|
||||
dist=p-s;
|
||||
|
||||
if (len==max_match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (--chain_len==0)
|
||||
break;
|
||||
|
||||
s=tail[s&WINDOW_MASK];
|
||||
}
|
||||
}
|
||||
|
||||
if (best_len>=MIN_MATCH)
|
||||
{
|
||||
int len=best_len-MIN_MATCH;
|
||||
const int nib=MIN(len, 15);
|
||||
|
||||
if (pp!=p)
|
||||
{
|
||||
const int run=p-pp;
|
||||
if (run>=15)
|
||||
{
|
||||
g_buf[op++]=(15<<4)+nib;
|
||||
|
||||
int j=run-15;
|
||||
for (; j>=255; j-=255)
|
||||
g_buf[op++]=255;
|
||||
g_buf[op++]=j;
|
||||
}
|
||||
else
|
||||
g_buf[op++]=(run<<4)+nib;
|
||||
|
||||
wild_copy(op, pp, run);
|
||||
op+=run;
|
||||
}
|
||||
else
|
||||
g_buf[op++]=nib;
|
||||
|
||||
STORE_16(op, dist);
|
||||
op+=2;
|
||||
|
||||
if (len>=15)
|
||||
{
|
||||
len-=15;
|
||||
for (; len>=255; len-=255)
|
||||
g_buf[op++]=255;
|
||||
g_buf[op++]=len;
|
||||
}
|
||||
|
||||
pp=p+best_len;
|
||||
|
||||
while (p<pp)
|
||||
{
|
||||
const U32 h=HASH_32(p);
|
||||
tail[p&WINDOW_MASK]=head[h];
|
||||
head[h]=p++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const U32 h=HASH_32(p);
|
||||
tail[p&WINDOW_MASK]=head[h];
|
||||
head[h]=p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pp!=p)
|
||||
{
|
||||
const int run=p-pp;
|
||||
if (run>=15)
|
||||
{
|
||||
g_buf[op++]=15<<4;
|
||||
|
||||
int j=run-15;
|
||||
for (; j>=255; j-=255)
|
||||
g_buf[op++]=255;
|
||||
g_buf[op++]=j;
|
||||
}
|
||||
else
|
||||
g_buf[op++]=run<<4;
|
||||
|
||||
wild_copy(op, pp, run);
|
||||
op+=run;
|
||||
}
|
||||
|
||||
const int comp_len=op-BLOCK_SIZE;
|
||||
fwrite(&comp_len, 1, sizeof(comp_len), g_out);
|
||||
fwrite(&g_buf[BLOCK_SIZE], 1, comp_len, g_out);
|
||||
|
||||
fprintf(stderr, "%lld -> %lld\r", _ftelli64(g_in), _ftelli64(g_out));
|
||||
}
|
||||
}
|
||||
|
||||
void compress_optimal()
|
||||
{
|
||||
static int head[HASH_SIZE];
|
||||
static int nodes[WINDOW_SIZE][2];
|
||||
static struct
|
||||
{
|
||||
int cum;
|
||||
|
||||
int len;
|
||||
int dist;
|
||||
} path[BLOCK_SIZE+1];
|
||||
|
||||
int n;
|
||||
while ((n=fread(g_buf, 1, BLOCK_SIZE, g_in))>0)
|
||||
{
|
||||
// Pass 1: Find all matches
|
||||
|
||||
for (int i=0; i<HASH_SIZE; ++i)
|
||||
head[i]=NIL;
|
||||
|
||||
for (int p=0; p<n; ++p)
|
||||
{
|
||||
int best_len=0;
|
||||
int dist=0;
|
||||
|
||||
const int max_match=(n-PADDING_LITERALS)-p;
|
||||
if (max_match>=MAX(12-PADDING_LITERALS, MIN_MATCH))
|
||||
{
|
||||
const int limit=MAX(p-WINDOW_SIZE, NIL);
|
||||
|
||||
int* left=&nodes[p&WINDOW_MASK][1];
|
||||
int* right=&nodes[p&WINDOW_MASK][0];
|
||||
|
||||
int left_len=0;
|
||||
int right_len=0;
|
||||
|
||||
const U32 h=HASH_32(p);
|
||||
int s=head[h];
|
||||
head[h]=p;
|
||||
|
||||
while (s>limit)
|
||||
{
|
||||
int len=MIN(left_len, right_len);
|
||||
|
||||
if (g_buf[s+len]==g_buf[p+len])
|
||||
{
|
||||
while (++len<max_match && g_buf[s+len]==g_buf[p+len]);
|
||||
|
||||
if (len>best_len)
|
||||
{
|
||||
best_len=len;
|
||||
dist=p-s;
|
||||
|
||||
if (len==max_match || len>=(1<<16))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_buf[s+len]<g_buf[p+len])
|
||||
{
|
||||
*right=s;
|
||||
right=&nodes[s&WINDOW_MASK][1];
|
||||
s=*right;
|
||||
right_len=len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*left=s;
|
||||
left=&nodes[s&WINDOW_MASK][0];
|
||||
s=*left;
|
||||
left_len=len;
|
||||
}
|
||||
}
|
||||
|
||||
*left=NIL;
|
||||
*right=NIL;
|
||||
}
|
||||
|
||||
path[p].len=best_len;
|
||||
path[p].dist=dist;
|
||||
}
|
||||
|
||||
// Pass 2: Build the shortest path
|
||||
|
||||
path[n].cum=0;
|
||||
|
||||
int count=15;
|
||||
|
||||
for (int p=n-1; p>0; --p)
|
||||
{
|
||||
int c0=path[p+1].cum+1;
|
||||
|
||||
if (--count==0)
|
||||
{
|
||||
count=255;
|
||||
++c0;
|
||||
}
|
||||
|
||||
int len=path[p].len;
|
||||
if (len>=MIN_MATCH)
|
||||
{
|
||||
int c1=1<<30;
|
||||
|
||||
const int j=MAX(len-255, MIN_MATCH);
|
||||
for (int i=len; i>=j; --i)
|
||||
{
|
||||
int tmp=path[p+i].cum+3;
|
||||
|
||||
if (i>=(15+MIN_MATCH))
|
||||
tmp+=1+((i-(15+MIN_MATCH))/255);
|
||||
|
||||
if (tmp<c1)
|
||||
{
|
||||
c1=tmp;
|
||||
len=i;
|
||||
}
|
||||
}
|
||||
|
||||
if (c1<=c0)
|
||||
{
|
||||
path[p].cum=c1;
|
||||
path[p].len=len;
|
||||
|
||||
count=15;
|
||||
}
|
||||
else
|
||||
{
|
||||
path[p].cum=c0;
|
||||
path[p].len=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
path[p].cum=c0;
|
||||
}
|
||||
|
||||
// Pass 3: Output the codes
|
||||
|
||||
int op=BLOCK_SIZE;
|
||||
int pp=0;
|
||||
|
||||
int p=0;
|
||||
while (p<n)
|
||||
{
|
||||
if (path[p].len>=MIN_MATCH)
|
||||
{
|
||||
int len=path[p].len-MIN_MATCH;
|
||||
const int nib=MIN(len, 15);
|
||||
|
||||
if (pp!=p)
|
||||
{
|
||||
const int run=p-pp;
|
||||
if (run>=15)
|
||||
{
|
||||
g_buf[op++]=(15<<4)+nib;
|
||||
|
||||
int j=run-15;
|
||||
for (; j>=255; j-=255)
|
||||
g_buf[op++]=255;
|
||||
g_buf[op++]=j;
|
||||
}
|
||||
else
|
||||
g_buf[op++]=(run<<4)+nib;
|
||||
|
||||
wild_copy(op, pp, run);
|
||||
op+=run;
|
||||
}
|
||||
else
|
||||
g_buf[op++]=nib;
|
||||
|
||||
STORE_16(op, path[p].dist);
|
||||
op+=2;
|
||||
|
||||
if (len>=15)
|
||||
{
|
||||
len-=15;
|
||||
for (; len>=255; len-=255)
|
||||
g_buf[op++]=255;
|
||||
g_buf[op++]=len;
|
||||
}
|
||||
|
||||
p+=path[p].len;
|
||||
|
||||
pp=p;
|
||||
}
|
||||
else
|
||||
++p;
|
||||
}
|
||||
|
||||
if (pp!=p)
|
||||
{
|
||||
const int run=p-pp;
|
||||
if (run>=15)
|
||||
{
|
||||
g_buf[op++]=15<<4;
|
||||
|
||||
int j=run-15;
|
||||
for (; j>=255; j-=255)
|
||||
g_buf[op++]=255;
|
||||
g_buf[op++]=j;
|
||||
}
|
||||
else
|
||||
g_buf[op++]=run<<4;
|
||||
|
||||
wild_copy(op, pp, run);
|
||||
op+=run;
|
||||
}
|
||||
|
||||
const int comp_len=op-BLOCK_SIZE;
|
||||
fwrite(&comp_len, 1, sizeof(comp_len), g_out);
|
||||
fwrite(&g_buf[BLOCK_SIZE], 1, comp_len, g_out);
|
||||
|
||||
fprintf(stderr, "%lld -> %lld\r", _ftelli64(g_in), _ftelli64(g_out));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t kread(void* dst, size_t size, const char* src, size_t* offset, size_t compressedSize) {
|
||||
size_t realSize = MIN(size, compressedSize - *offset);
|
||||
memcpy(dst, &src[*offset], realSize);
|
||||
*offset += realSize;
|
||||
return realSize;
|
||||
}
|
||||
|
||||
static size_t kwrite(void* src, size_t size, char* dst, size_t* offset, int maxOutputSize) {
|
||||
size_t realSize = MIN(size, maxOutputSize - *offset);
|
||||
memcpy(&dst[*offset], src, size);
|
||||
*offset += realSize;
|
||||
return realSize;
|
||||
}
|
||||
|
||||
//int decompress()
|
||||
#ifdef KINC_LZ4X
|
||||
#include <kinc/error.h>
|
||||
|
||||
int LZ4_decompress_safe(const char *source, char *buf, int compressedSize, int maxOutputSize)
|
||||
{
|
||||
size_t read_offset = 0;
|
||||
size_t write_offset = 0;
|
||||
int comp_len;
|
||||
while (kread(&comp_len, sizeof(comp_len), source, &read_offset, compressedSize)>0)
|
||||
{
|
||||
if (comp_len<2 || comp_len>(BLOCK_SIZE+EXCESS)
|
||||
|| kread(&g_buf[BLOCK_SIZE], comp_len, source, &read_offset, compressedSize)!=comp_len)
|
||||
return -1;
|
||||
|
||||
int p=0;
|
||||
|
||||
int ip=BLOCK_SIZE;
|
||||
const int ip_end=ip+comp_len;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const int token=g_buf[ip++];
|
||||
if (token>=16)
|
||||
{
|
||||
int run=token>>4;
|
||||
if (run==15)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const int c=g_buf[ip++];
|
||||
run+=c;
|
||||
if (c!=255)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((p+run)>BLOCK_SIZE)
|
||||
return -1;
|
||||
|
||||
wild_copy(p, ip, run);
|
||||
p+=run;
|
||||
ip+=run;
|
||||
if (ip>=ip_end)
|
||||
break;
|
||||
}
|
||||
|
||||
int s=p-LOAD_16(ip);
|
||||
ip+=2;
|
||||
if (s<0)
|
||||
return -1;
|
||||
|
||||
int len=(token&15)+MIN_MATCH;
|
||||
if (len==(15+MIN_MATCH))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const int c=g_buf[ip++];
|
||||
len+=c;
|
||||
if (c!=255)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((p+len)>BLOCK_SIZE)
|
||||
return -1;
|
||||
|
||||
if ((p-s)>=4)
|
||||
{
|
||||
wild_copy(p, s, len);
|
||||
p+=len;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len--!=0)
|
||||
g_buf[p++]=g_buf[s++];
|
||||
}
|
||||
}
|
||||
|
||||
if (kwrite(g_buf, p, buf, &write_offset, maxOutputSize)!=p)
|
||||
{
|
||||
kinc_error_message("Fwrite() failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const clock_t start=clock();
|
||||
|
||||
int level=4;
|
||||
bool do_decomp=false;
|
||||
bool overwrite=false;
|
||||
|
||||
while (argc>1 && *argv[1]=='-')
|
||||
{
|
||||
for (int i=1; argv[1][i]!='\0'; ++i)
|
||||
{
|
||||
switch (argv[1][i])
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
level=argv[1][i]-'0';
|
||||
break;
|
||||
case 'd':
|
||||
do_decomp=true;
|
||||
break;
|
||||
case 'f':
|
||||
overwrite=true;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option: -%c\n", argv[1][i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (argc<2)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"LZ4X - An optimized LZ4 compressor, v1.60\n"
|
||||
"Written and placed in the public domain by Ilya Muravyov\n"
|
||||
"\n"
|
||||
"Usage: LZ4X [options] infile [outfile]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -1 Compress faster\n"
|
||||
" -9 Compress better\n"
|
||||
" -d Decompress\n"
|
||||
" -f Force overwrite of output file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_in=fopen(argv[1], "rb");
|
||||
if (!g_in)
|
||||
{
|
||||
perror(argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char out_name[FILENAME_MAX];
|
||||
if (argc<3)
|
||||
{
|
||||
strcpy(out_name, argv[1]);
|
||||
if (do_decomp)
|
||||
{
|
||||
const int p=strlen(out_name)-4;
|
||||
if (p>0 && strcmp(&out_name[p], ".lz4")==0)
|
||||
out_name[p]='\0';
|
||||
else
|
||||
strcat(out_name, ".out");
|
||||
}
|
||||
else
|
||||
strcat(out_name, ".lz4");
|
||||
}
|
||||
else
|
||||
strcpy(out_name, argv[2]);
|
||||
|
||||
if (!overwrite)
|
||||
{
|
||||
FILE* f=fopen(out_name, "rb");
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
|
||||
fprintf(stderr, "%s already exists. Overwrite (y/n)? ", out_name);
|
||||
fflush(stderr);
|
||||
|
||||
if (getchar()!='y')
|
||||
{
|
||||
fprintf(stderr, "Not overwritten\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (do_decomp)
|
||||
{
|
||||
int magic;
|
||||
fread(&magic, 1, sizeof(magic), g_in);
|
||||
if (magic!=LZ4_MAGIC)
|
||||
{
|
||||
fprintf(stderr, "%s: Not in Legacy format\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_out=fopen(out_name, "wb");
|
||||
if (!g_out)
|
||||
{
|
||||
perror(out_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Decompressing %s:\n", argv[1]);
|
||||
|
||||
if (decompress()!=0)
|
||||
{
|
||||
fprintf(stderr, "%s: Corrupt input\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_out=fopen(out_name, "wb");
|
||||
if (!g_out)
|
||||
{
|
||||
perror(out_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const int magic=LZ4_MAGIC;
|
||||
fwrite(&magic, 1, sizeof(magic), g_out);
|
||||
|
||||
fprintf(stderr, "Compressing %s:\n", argv[1]);
|
||||
|
||||
if (level==9)
|
||||
compress_optimal();
|
||||
else
|
||||
compress((level<8)?1<<level:WINDOW_SIZE);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%lld -> %lld in %1.3f sec\n", _ftelli64(g_in),
|
||||
_ftelli64(g_out), double(clock()-start)/CLOCKS_PER_SEC);
|
||||
|
||||
fclose(g_in);
|
||||
fclose(g_out);
|
||||
|
||||
#ifndef NO_UTIME
|
||||
struct _stati64 sb;
|
||||
if (_stati64(argv[1], &sb)!=0)
|
||||
{
|
||||
perror("Stat() failed");
|
||||
exit(1);
|
||||
}
|
||||
struct utimbuf ub;
|
||||
ub.actime=sb.st_atime;
|
||||
ub.modtime=sb.st_mtime;
|
||||
if (utime(out_name, &ub)!=0)
|
||||
{
|
||||
perror("Utime() failed");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
301
Kha/Kinc/Sources/kinc/libs/neon_mathfun.h
Normal file
301
Kha/Kinc/Sources/kinc/libs/neon_mathfun.h
Normal file
@ -0,0 +1,301 @@
|
||||
/* NEON implementation of sin, cos, exp and log
|
||||
|
||||
Inspired by Intel Approximate Math library, and based on the
|
||||
corresponding algorithms of the cephes math library
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2011 Julien Pommier
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
(this is the zlib license)
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
typedef float32x4_t v4sf; // vector of 4 float
|
||||
typedef uint32x4_t v4su; // vector of 4 uint32
|
||||
typedef int32x4_t v4si; // vector of 4 uint32
|
||||
|
||||
#define c_inv_mant_mask ~0x7f800000u
|
||||
#define c_cephes_SQRTHF 0.707106781186547524
|
||||
#define c_cephes_log_p0 7.0376836292E-2
|
||||
#define c_cephes_log_p1 - 1.1514610310E-1
|
||||
#define c_cephes_log_p2 1.1676998740E-1
|
||||
#define c_cephes_log_p3 - 1.2420140846E-1
|
||||
#define c_cephes_log_p4 + 1.4249322787E-1
|
||||
#define c_cephes_log_p5 - 1.6668057665E-1
|
||||
#define c_cephes_log_p6 + 2.0000714765E-1
|
||||
#define c_cephes_log_p7 - 2.4999993993E-1
|
||||
#define c_cephes_log_p8 + 3.3333331174E-1
|
||||
#define c_cephes_log_q1 -2.12194440e-4
|
||||
#define c_cephes_log_q2 0.693359375
|
||||
|
||||
/* natural logarithm computed for 4 simultaneous float
|
||||
return NaN for x <= 0
|
||||
*/
|
||||
v4sf log_ps(v4sf x) {
|
||||
v4sf one = vdupq_n_f32(1);
|
||||
|
||||
x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */
|
||||
v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0));
|
||||
|
||||
v4si ux = vreinterpretq_s32_f32(x);
|
||||
|
||||
v4si emm0 = vshrq_n_s32(ux, 23);
|
||||
|
||||
/* keep only the fractional part */
|
||||
ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask));
|
||||
ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f)));
|
||||
x = vreinterpretq_f32_s32(ux);
|
||||
|
||||
emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f));
|
||||
v4sf e = vcvtq_f32_s32(emm0);
|
||||
|
||||
e = vaddq_f32(e, one);
|
||||
|
||||
/* part2:
|
||||
if( x < SQRTHF ) {
|
||||
e -= 1;
|
||||
x = x + x - 1.0;
|
||||
} else { x = x - 1.0; }
|
||||
*/
|
||||
v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF));
|
||||
v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask));
|
||||
x = vsubq_f32(x, one);
|
||||
e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask)));
|
||||
x = vaddq_f32(x, tmp);
|
||||
|
||||
v4sf z = vmulq_f32(x,x);
|
||||
|
||||
v4sf y = vdupq_n_f32(c_cephes_log_p0);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8));
|
||||
y = vmulq_f32(y, x);
|
||||
|
||||
y = vmulq_f32(y, z);
|
||||
|
||||
|
||||
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1));
|
||||
y = vaddq_f32(y, tmp);
|
||||
|
||||
|
||||
tmp = vmulq_f32(z, vdupq_n_f32(0.5f));
|
||||
y = vsubq_f32(y, tmp);
|
||||
|
||||
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2));
|
||||
x = vaddq_f32(x, y);
|
||||
x = vaddq_f32(x, tmp);
|
||||
x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN
|
||||
return x;
|
||||
}
|
||||
|
||||
#define c_exp_hi 88.3762626647949f
|
||||
#define c_exp_lo -88.3762626647949f
|
||||
|
||||
#define c_cephes_LOG2EF 1.44269504088896341
|
||||
#define c_cephes_exp_C1 0.693359375
|
||||
#define c_cephes_exp_C2 -2.12194440e-4
|
||||
|
||||
#define c_cephes_exp_p0 1.9875691500E-4
|
||||
#define c_cephes_exp_p1 1.3981999507E-3
|
||||
#define c_cephes_exp_p2 8.3334519073E-3
|
||||
#define c_cephes_exp_p3 4.1665795894E-2
|
||||
#define c_cephes_exp_p4 1.6666665459E-1
|
||||
#define c_cephes_exp_p5 5.0000001201E-1
|
||||
|
||||
/* exp() computed for 4 float at once */
|
||||
v4sf exp_ps(v4sf x) {
|
||||
v4sf tmp, fx;
|
||||
|
||||
v4sf one = vdupq_n_f32(1);
|
||||
x = vminq_f32(x, vdupq_n_f32(c_exp_hi));
|
||||
x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo));
|
||||
|
||||
/* express exp(x) as exp(g + n*log(2)) */
|
||||
fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF));
|
||||
|
||||
/* perform a floorf */
|
||||
tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx));
|
||||
|
||||
/* if greater, substract 1 */
|
||||
v4su mask = vcgtq_f32(tmp, fx);
|
||||
mask = vandq_u32(mask, vreinterpretq_u32_f32(one));
|
||||
|
||||
|
||||
fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask));
|
||||
|
||||
tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1));
|
||||
v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2));
|
||||
x = vsubq_f32(x, tmp);
|
||||
x = vsubq_f32(x, z);
|
||||
|
||||
static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 };
|
||||
v4sf y = vld1q_dup_f32(cephes_exp_p+0);
|
||||
v4sf c1 = vld1q_dup_f32(cephes_exp_p+1);
|
||||
v4sf c2 = vld1q_dup_f32(cephes_exp_p+2);
|
||||
v4sf c3 = vld1q_dup_f32(cephes_exp_p+3);
|
||||
v4sf c4 = vld1q_dup_f32(cephes_exp_p+4);
|
||||
v4sf c5 = vld1q_dup_f32(cephes_exp_p+5);
|
||||
|
||||
y = vmulq_f32(y, x);
|
||||
z = vmulq_f32(x,x);
|
||||
y = vaddq_f32(y, c1);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c2);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c3);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c4);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c5);
|
||||
|
||||
y = vmulq_f32(y, z);
|
||||
y = vaddq_f32(y, x);
|
||||
y = vaddq_f32(y, one);
|
||||
|
||||
/* build 2^n */
|
||||
int32x4_t mm;
|
||||
mm = vcvtq_s32_f32(fx);
|
||||
mm = vaddq_s32(mm, vdupq_n_s32(0x7f));
|
||||
mm = vshlq_n_s32(mm, 23);
|
||||
v4sf pow2n = vreinterpretq_f32_s32(mm);
|
||||
|
||||
y = vmulq_f32(y, pow2n);
|
||||
return y;
|
||||
}
|
||||
|
||||
#define c_minus_cephes_DP1 -0.78515625
|
||||
#define c_minus_cephes_DP2 -2.4187564849853515625e-4
|
||||
#define c_minus_cephes_DP3 -3.77489497744594108e-8
|
||||
#define c_sincof_p0 -1.9515295891E-4
|
||||
#define c_sincof_p1 8.3321608736E-3
|
||||
#define c_sincof_p2 -1.6666654611E-1
|
||||
#define c_coscof_p0 2.443315711809948E-005
|
||||
#define c_coscof_p1 -1.388731625493765E-003
|
||||
#define c_coscof_p2 4.166664568298827E-002
|
||||
#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI
|
||||
|
||||
/* evaluation of 4 sines & cosines at once.
|
||||
|
||||
The code is the exact rewriting of the cephes sinf function.
|
||||
Precision is excellent as long as x < 8192 (I did not bother to
|
||||
take into account the special handling they have for greater values
|
||||
-- it does not return garbage for arguments over 8192, though, but
|
||||
the extra precision is missing).
|
||||
|
||||
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
|
||||
surprising but correct result.
|
||||
|
||||
Note also that when you compute sin(x), cos(x) is available at
|
||||
almost no extra price so both sin_ps and cos_ps make use of
|
||||
sincos_ps..
|
||||
*/
|
||||
void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x
|
||||
v4sf xmm1, xmm2, xmm3, y;
|
||||
|
||||
v4su emm2;
|
||||
|
||||
v4su sign_mask_sin, sign_mask_cos;
|
||||
sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0));
|
||||
x = vabsq_f32(x);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = vmulq_f32(x, vdupq_n_f32(c_cephes_FOPI));
|
||||
|
||||
/* store the integer part of y in mm0 */
|
||||
emm2 = vcvtq_u32_f32(y);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = vaddq_u32(emm2, vdupq_n_u32(1));
|
||||
emm2 = vandq_u32(emm2, vdupq_n_u32(~1));
|
||||
y = vcvtq_f32_u32(emm2);
|
||||
|
||||
/* get the polynom selection mask
|
||||
there is one polynom for 0 <= x <= Pi/4
|
||||
and another one for Pi/4<x<=Pi/2
|
||||
|
||||
Both branches will be computed.
|
||||
*/
|
||||
v4su poly_mask = vtstq_u32(emm2, vdupq_n_u32(2));
|
||||
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = vmulq_n_f32(y, c_minus_cephes_DP1);
|
||||
xmm2 = vmulq_n_f32(y, c_minus_cephes_DP2);
|
||||
xmm3 = vmulq_n_f32(y, c_minus_cephes_DP3);
|
||||
x = vaddq_f32(x, xmm1);
|
||||
x = vaddq_f32(x, xmm2);
|
||||
x = vaddq_f32(x, xmm3);
|
||||
|
||||
sign_mask_sin = veorq_u32(sign_mask_sin, vtstq_u32(emm2, vdupq_n_u32(4)));
|
||||
sign_mask_cos = vtstq_u32(vsubq_u32(emm2, vdupq_n_u32(2)), vdupq_n_u32(4));
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) in y1,
|
||||
and the second polynom (Pi/4 <= x <= 0) in y2 */
|
||||
v4sf z = vmulq_f32(x,x);
|
||||
v4sf y1, y2;
|
||||
|
||||
y1 = vmulq_n_f32(z, c_coscof_p0);
|
||||
y2 = vmulq_n_f32(z, c_sincof_p0);
|
||||
y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p1));
|
||||
y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p1));
|
||||
y1 = vmulq_f32(y1, z);
|
||||
y2 = vmulq_f32(y2, z);
|
||||
y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p2));
|
||||
y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p2));
|
||||
y1 = vmulq_f32(y1, z);
|
||||
y2 = vmulq_f32(y2, z);
|
||||
y1 = vmulq_f32(y1, z);
|
||||
y2 = vmulq_f32(y2, x);
|
||||
y1 = vsubq_f32(y1, vmulq_f32(z, vdupq_n_f32(0.5f)));
|
||||
y2 = vaddq_f32(y2, x);
|
||||
y1 = vaddq_f32(y1, vdupq_n_f32(1));
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
v4sf ys = vbslq_f32(poly_mask, y1, y2);
|
||||
v4sf yc = vbslq_f32(poly_mask, y2, y1);
|
||||
*ysin = vbslq_f32(sign_mask_sin, vnegq_f32(ys), ys);
|
||||
*ycos = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc));
|
||||
}
|
||||
|
||||
v4sf sin_ps(v4sf x) {
|
||||
v4sf ysin, ycos;
|
||||
sincos_ps(x, &ysin, &ycos);
|
||||
return ysin;
|
||||
}
|
||||
|
||||
v4sf cos_ps(v4sf x) {
|
||||
v4sf ysin, ycos;
|
||||
sincos_ps(x, &ysin, &ycos);
|
||||
return ycos;
|
||||
}
|
||||
|
||||
|
711
Kha/Kinc/Sources/kinc/libs/sse_mathfun.h
Normal file
711
Kha/Kinc/Sources/kinc/libs/sse_mathfun.h
Normal file
@ -0,0 +1,711 @@
|
||||
/* SIMD (SSE1+MMX or SSE2) implementation of sin, cos, exp and log
|
||||
|
||||
Inspired by Intel Approximate Math library, and based on the
|
||||
corresponding algorithms of the cephes math library
|
||||
|
||||
The default is to use the SSE1 version. If you define USE_SSE2 the
|
||||
the SSE2 intrinsics will be used in place of the MMX intrinsics. Do
|
||||
not expect any significant performance improvement with SSE2.
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2007 Julien Pommier
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
(this is the zlib license)
|
||||
*/
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
/* yes I know, the top of this file is quite ugly */
|
||||
|
||||
#ifdef _MSC_VER /* visual c++ */
|
||||
# define ALIGN16_BEG __declspec(align(16))
|
||||
# define ALIGN16_END
|
||||
#else /* gcc or icc */
|
||||
# define ALIGN16_BEG
|
||||
# define ALIGN16_END __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
/* __m128 is ugly to write */
|
||||
typedef __m128 v4sf; // vector of 4 float (sse1)
|
||||
|
||||
#ifdef USE_SSE2
|
||||
# include <emmintrin.h>
|
||||
typedef __m128i v4si; // vector of 4 int (sse2)
|
||||
#else
|
||||
typedef __m64 v2si; // vector of 2 int (mmx)
|
||||
#endif
|
||||
|
||||
/* declare some SSE constants -- why can't I figure a better way to do that? */
|
||||
#define _PS_CONST(Name, Val) \
|
||||
static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
|
||||
#define _PI32_CONST(Name, Val) \
|
||||
static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
|
||||
#define _PS_CONST_TYPE(Name, Type, Val) \
|
||||
static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
|
||||
|
||||
_PS_CONST(1 , 1.0f);
|
||||
_PS_CONST(0p5, 0.5f);
|
||||
/* the smallest non denormalized float number */
|
||||
_PS_CONST_TYPE(min_norm_pos, int, 0x00800000);
|
||||
_PS_CONST_TYPE(mant_mask, int, 0x7f800000);
|
||||
_PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000);
|
||||
|
||||
_PS_CONST_TYPE(sign_mask, int, (int)0x80000000);
|
||||
_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000);
|
||||
|
||||
_PI32_CONST(1, 1);
|
||||
_PI32_CONST(inv1, ~1);
|
||||
_PI32_CONST(2, 2);
|
||||
_PI32_CONST(4, 4);
|
||||
_PI32_CONST(0x7f, 0x7f);
|
||||
|
||||
_PS_CONST(cephes_SQRTHF, 0.707106781186547524);
|
||||
_PS_CONST(cephes_log_p0, 7.0376836292E-2);
|
||||
_PS_CONST(cephes_log_p1, - 1.1514610310E-1);
|
||||
_PS_CONST(cephes_log_p2, 1.1676998740E-1);
|
||||
_PS_CONST(cephes_log_p3, - 1.2420140846E-1);
|
||||
_PS_CONST(cephes_log_p4, + 1.4249322787E-1);
|
||||
_PS_CONST(cephes_log_p5, - 1.6668057665E-1);
|
||||
_PS_CONST(cephes_log_p6, + 2.0000714765E-1);
|
||||
_PS_CONST(cephes_log_p7, - 2.4999993993E-1);
|
||||
_PS_CONST(cephes_log_p8, + 3.3333331174E-1);
|
||||
_PS_CONST(cephes_log_q1, -2.12194440e-4);
|
||||
_PS_CONST(cephes_log_q2, 0.693359375);
|
||||
|
||||
#ifndef USE_SSE2
|
||||
typedef union xmm_mm_union {
|
||||
__m128 xmm;
|
||||
__m64 mm[2];
|
||||
} xmm_mm_union;
|
||||
|
||||
#define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \
|
||||
xmm_mm_union u; u.xmm = xmm_; \
|
||||
mm0_ = u.mm[0]; \
|
||||
mm1_ = u.mm[1]; \
|
||||
}
|
||||
|
||||
#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \
|
||||
xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \
|
||||
}
|
||||
|
||||
#endif // USE_SSE2
|
||||
|
||||
/* natural logarithm computed for 4 simultaneous float
|
||||
return NaN for x <= 0
|
||||
*/
|
||||
v4sf log_ps(v4sf x) {
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0;
|
||||
#else
|
||||
v2si mm0, mm1;
|
||||
#endif
|
||||
v4sf one = *(v4sf*)_ps_1;
|
||||
|
||||
v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps());
|
||||
|
||||
x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */
|
||||
|
||||
#ifndef USE_SSE2
|
||||
/* part 1: x = frexpf(x, &e); */
|
||||
COPY_XMM_TO_MM(x, mm0, mm1);
|
||||
mm0 = _mm_srli_pi32(mm0, 23);
|
||||
mm1 = _mm_srli_pi32(mm1, 23);
|
||||
#else
|
||||
emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23);
|
||||
#endif
|
||||
/* keep only the fractional part */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask);
|
||||
x = _mm_or_ps(x, *(v4sf*)_ps_0p5);
|
||||
|
||||
#ifndef USE_SSE2
|
||||
/* now e=mm0:mm1 contain the really base-2 exponent */
|
||||
mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f);
|
||||
mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f);
|
||||
v4sf e = _mm_cvtpi32x2_ps(mm0, mm1);
|
||||
_mm_empty(); /* bye bye mmx */
|
||||
#else
|
||||
emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f);
|
||||
v4sf e = _mm_cvtepi32_ps(emm0);
|
||||
#endif
|
||||
|
||||
e = _mm_add_ps(e, one);
|
||||
|
||||
/* part2:
|
||||
if( x < SQRTHF ) {
|
||||
e -= 1;
|
||||
x = x + x - 1.0;
|
||||
} else { x = x - 1.0; }
|
||||
*/
|
||||
v4sf mask = _mm_cmplt_ps(x, *(v4sf*)_ps_cephes_SQRTHF);
|
||||
v4sf tmp = _mm_and_ps(x, mask);
|
||||
x = _mm_sub_ps(x, one);
|
||||
e = _mm_sub_ps(e, _mm_and_ps(one, mask));
|
||||
x = _mm_add_ps(x, tmp);
|
||||
|
||||
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
|
||||
v4sf y = *(v4sf*)_ps_cephes_log_p0;
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p1);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p2);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p3);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p4);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p5);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p6);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p7);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p8);
|
||||
y = _mm_mul_ps(y, x);
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
|
||||
|
||||
tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q1);
|
||||
y = _mm_add_ps(y, tmp);
|
||||
|
||||
|
||||
tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
|
||||
tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q2);
|
||||
x = _mm_add_ps(x, y);
|
||||
x = _mm_add_ps(x, tmp);
|
||||
x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN
|
||||
return x;
|
||||
}
|
||||
|
||||
_PS_CONST(exp_hi, 88.3762626647949f);
|
||||
_PS_CONST(exp_lo, -88.3762626647949f);
|
||||
|
||||
_PS_CONST(cephes_LOG2EF, 1.44269504088896341);
|
||||
_PS_CONST(cephes_exp_C1, 0.693359375);
|
||||
_PS_CONST(cephes_exp_C2, -2.12194440e-4);
|
||||
|
||||
_PS_CONST(cephes_exp_p0, 1.9875691500E-4);
|
||||
_PS_CONST(cephes_exp_p1, 1.3981999507E-3);
|
||||
_PS_CONST(cephes_exp_p2, 8.3334519073E-3);
|
||||
_PS_CONST(cephes_exp_p3, 4.1665795894E-2);
|
||||
_PS_CONST(cephes_exp_p4, 1.6666665459E-1);
|
||||
_PS_CONST(cephes_exp_p5, 5.0000001201E-1);
|
||||
|
||||
v4sf exp_ps(v4sf x) {
|
||||
v4sf tmp = _mm_setzero_ps(), fx;
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0;
|
||||
#else
|
||||
v2si mm0, mm1;
|
||||
#endif
|
||||
v4sf one = *(v4sf*)_ps_1;
|
||||
|
||||
x = _mm_min_ps(x, *(v4sf*)_ps_exp_hi);
|
||||
x = _mm_max_ps(x, *(v4sf*)_ps_exp_lo);
|
||||
|
||||
/* express exp(x) as exp(g + n*log(2)) */
|
||||
fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF);
|
||||
fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5);
|
||||
|
||||
/* how to perform a floorf with SSE: just below */
|
||||
#ifndef USE_SSE2
|
||||
/* step 1 : cast to int */
|
||||
tmp = _mm_movehl_ps(tmp, fx);
|
||||
mm0 = _mm_cvttps_pi32(fx);
|
||||
mm1 = _mm_cvttps_pi32(tmp);
|
||||
/* step 2 : cast back to float */
|
||||
tmp = _mm_cvtpi32x2_ps(mm0, mm1);
|
||||
#else
|
||||
emm0 = _mm_cvttps_epi32(fx);
|
||||
tmp = _mm_cvtepi32_ps(emm0);
|
||||
#endif
|
||||
/* if greater, substract 1 */
|
||||
v4sf mask = _mm_cmpgt_ps(tmp, fx);
|
||||
mask = _mm_and_ps(mask, one);
|
||||
fx = _mm_sub_ps(tmp, mask);
|
||||
|
||||
tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1);
|
||||
v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2);
|
||||
x = _mm_sub_ps(x, tmp);
|
||||
x = _mm_sub_ps(x, z);
|
||||
|
||||
z = _mm_mul_ps(x,x);
|
||||
|
||||
v4sf y = *(v4sf*)_ps_cephes_exp_p0;
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p1);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p2);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p3);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p4);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p5);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, x);
|
||||
y = _mm_add_ps(y, one);
|
||||
|
||||
/* build 2^n */
|
||||
#ifndef USE_SSE2
|
||||
z = _mm_movehl_ps(z, fx);
|
||||
mm0 = _mm_cvttps_pi32(fx);
|
||||
mm1 = _mm_cvttps_pi32(z);
|
||||
mm0 = _mm_add_pi32(mm0, *(v2si*)_pi32_0x7f);
|
||||
mm1 = _mm_add_pi32(mm1, *(v2si*)_pi32_0x7f);
|
||||
mm0 = _mm_slli_pi32(mm0, 23);
|
||||
mm1 = _mm_slli_pi32(mm1, 23);
|
||||
|
||||
v4sf pow2n;
|
||||
COPY_MM_TO_XMM(mm0, mm1, pow2n);
|
||||
_mm_empty();
|
||||
#else
|
||||
emm0 = _mm_cvttps_epi32(fx);
|
||||
emm0 = _mm_add_epi32(emm0, *(v4si*)_pi32_0x7f);
|
||||
emm0 = _mm_slli_epi32(emm0, 23);
|
||||
v4sf pow2n = _mm_castsi128_ps(emm0);
|
||||
#endif
|
||||
y = _mm_mul_ps(y, pow2n);
|
||||
return y;
|
||||
}
|
||||
|
||||
_PS_CONST(minus_cephes_DP1, -0.78515625);
|
||||
_PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4);
|
||||
_PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8);
|
||||
_PS_CONST(sincof_p0, -1.9515295891E-4);
|
||||
_PS_CONST(sincof_p1, 8.3321608736E-3);
|
||||
_PS_CONST(sincof_p2, -1.6666654611E-1);
|
||||
_PS_CONST(coscof_p0, 2.443315711809948E-005);
|
||||
_PS_CONST(coscof_p1, -1.388731625493765E-003);
|
||||
_PS_CONST(coscof_p2, 4.166664568298827E-002);
|
||||
_PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI
|
||||
|
||||
|
||||
/* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so
|
||||
it runs also on old athlons XPs and the pentium III of your grand
|
||||
mother.
|
||||
|
||||
The code is the exact rewriting of the cephes sinf function.
|
||||
Precision is excellent as long as x < 8192 (I did not bother to
|
||||
take into account the special handling they have for greater values
|
||||
-- it does not return garbage for arguments over 8192, though, but
|
||||
the extra precision is missing).
|
||||
|
||||
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
|
||||
surprising but correct result.
|
||||
|
||||
Performance is also surprisingly good, 1.33 times faster than the
|
||||
macos vsinf SSE2 function, and 1.5 times faster than the
|
||||
__vrs4_sinf of amd's ACML (which is only available in 64 bits). Not
|
||||
too bad for an SSE1 function (with no special tuning) !
|
||||
However the latter libraries probably have a much better handling of NaN,
|
||||
Inf, denormalized and other special arguments..
|
||||
|
||||
On my core 1 duo, the execution of this function takes approximately 95 cycles.
|
||||
|
||||
From what I have observed on the experiments with Intel AMath lib, switching to an
|
||||
SSE2 version would improve the perf by only 10%.
|
||||
|
||||
Since it is based on SSE intrinsics, it has to be compiled at -O2 to
|
||||
deliver full speed.
|
||||
*/
|
||||
v4sf sin_ps(v4sf x) { // any x
|
||||
v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y;
|
||||
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0, emm2;
|
||||
#else
|
||||
v2si mm0, mm1, mm2, mm3;
|
||||
#endif
|
||||
sign_bit = x;
|
||||
/* take the absolute value */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
|
||||
/* extract the sign bit (upper one) */
|
||||
sign_bit = _mm_and_ps(sign_bit, *(v4sf*)_ps_sign_mask);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
/* store the integer part of y in mm0 */
|
||||
emm2 = _mm_cvttps_epi32(y);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
|
||||
y = _mm_cvtepi32_ps(emm2);
|
||||
|
||||
/* get the swap sign flag */
|
||||
emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4);
|
||||
emm0 = _mm_slli_epi32(emm0, 29);
|
||||
/* get the polynom selection mask
|
||||
there is one polynom for 0 <= x <= Pi/4
|
||||
and another one for Pi/4<x<=Pi/2
|
||||
|
||||
Both branches will be computed.
|
||||
*/
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
|
||||
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
|
||||
|
||||
v4sf swap_sign_bit = _mm_castsi128_ps(emm0);
|
||||
v4sf poly_mask = _mm_castsi128_ps(emm2);
|
||||
sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
|
||||
|
||||
#else
|
||||
/* store the integer part of y in mm0:mm1 */
|
||||
xmm2 = _mm_movehl_ps(xmm2, y);
|
||||
mm2 = _mm_cvttps_pi32(y);
|
||||
mm3 = _mm_cvttps_pi32(xmm2);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
|
||||
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
|
||||
y = _mm_cvtpi32x2_ps(mm2, mm3);
|
||||
/* get the swap sign flag */
|
||||
mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4);
|
||||
mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4);
|
||||
mm0 = _mm_slli_pi32(mm0, 29);
|
||||
mm1 = _mm_slli_pi32(mm1, 29);
|
||||
/* get the polynom selection mask */
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
|
||||
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
|
||||
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
|
||||
v4sf swap_sign_bit, poly_mask;
|
||||
COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit);
|
||||
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
|
||||
sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
|
||||
_mm_empty(); /* good-bye mmx */
|
||||
#endif
|
||||
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
|
||||
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
|
||||
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
|
||||
xmm1 = _mm_mul_ps(y, xmm1);
|
||||
xmm2 = _mm_mul_ps(y, xmm2);
|
||||
xmm3 = _mm_mul_ps(y, xmm3);
|
||||
x = _mm_add_ps(x, xmm1);
|
||||
x = _mm_add_ps(x, xmm2);
|
||||
x = _mm_add_ps(x, xmm3);
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
||||
y = *(v4sf*)_ps_coscof_p0;
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_mul_ps(y, z);
|
||||
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_1);
|
||||
|
||||
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
||||
|
||||
v4sf y2 = *(v4sf*)_ps_sincof_p0;
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_mul_ps(y2, x);
|
||||
y2 = _mm_add_ps(y2, x);
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
xmm3 = poly_mask;
|
||||
y2 = _mm_and_ps(xmm3, y2); //, xmm3);
|
||||
y = _mm_andnot_ps(xmm3, y);
|
||||
y = _mm_add_ps(y,y2);
|
||||
/* update the sign */
|
||||
y = _mm_xor_ps(y, sign_bit);
|
||||
return y;
|
||||
}
|
||||
|
||||
/* almost the same as sin_ps */
|
||||
v4sf cos_ps(v4sf x) { // any x
|
||||
v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, y;
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0, emm2;
|
||||
#else
|
||||
v2si mm0, mm1, mm2, mm3;
|
||||
#endif
|
||||
/* take the absolute value */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
/* store the integer part of y in mm0 */
|
||||
emm2 = _mm_cvttps_epi32(y);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
|
||||
y = _mm_cvtepi32_ps(emm2);
|
||||
|
||||
emm2 = _mm_sub_epi32(emm2, *(v4si*)_pi32_2);
|
||||
|
||||
/* get the swap sign flag */
|
||||
emm0 = _mm_andnot_si128(emm2, *(v4si*)_pi32_4);
|
||||
emm0 = _mm_slli_epi32(emm0, 29);
|
||||
/* get the polynom selection mask */
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
|
||||
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
|
||||
|
||||
v4sf sign_bit = _mm_castsi128_ps(emm0);
|
||||
v4sf poly_mask = _mm_castsi128_ps(emm2);
|
||||
#else
|
||||
/* store the integer part of y in mm0:mm1 */
|
||||
xmm2 = _mm_movehl_ps(xmm2, y);
|
||||
mm2 = _mm_cvttps_pi32(y);
|
||||
mm3 = _mm_cvttps_pi32(xmm2);
|
||||
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
|
||||
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
|
||||
|
||||
y = _mm_cvtpi32x2_ps(mm2, mm3);
|
||||
|
||||
|
||||
mm2 = _mm_sub_pi32(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_sub_pi32(mm3, *(v2si*)_pi32_2);
|
||||
|
||||
/* get the swap sign flag in mm0:mm1 and the
|
||||
polynom selection mask in mm2:mm3 */
|
||||
|
||||
mm0 = _mm_andnot_si64(mm2, *(v2si*)_pi32_4);
|
||||
mm1 = _mm_andnot_si64(mm3, *(v2si*)_pi32_4);
|
||||
mm0 = _mm_slli_pi32(mm0, 29);
|
||||
mm1 = _mm_slli_pi32(mm1, 29);
|
||||
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
|
||||
|
||||
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
|
||||
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
|
||||
|
||||
v4sf sign_bit, poly_mask;
|
||||
COPY_MM_TO_XMM(mm0, mm1, sign_bit);
|
||||
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
|
||||
_mm_empty(); /* good-bye mmx */
|
||||
#endif
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
|
||||
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
|
||||
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
|
||||
xmm1 = _mm_mul_ps(y, xmm1);
|
||||
xmm2 = _mm_mul_ps(y, xmm2);
|
||||
xmm3 = _mm_mul_ps(y, xmm3);
|
||||
x = _mm_add_ps(x, xmm1);
|
||||
x = _mm_add_ps(x, xmm2);
|
||||
x = _mm_add_ps(x, xmm3);
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
||||
y = *(v4sf*)_ps_coscof_p0;
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_mul_ps(y, z);
|
||||
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_1);
|
||||
|
||||
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
||||
|
||||
v4sf y2 = *(v4sf*)_ps_sincof_p0;
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_mul_ps(y2, x);
|
||||
y2 = _mm_add_ps(y2, x);
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
xmm3 = poly_mask;
|
||||
y2 = _mm_and_ps(xmm3, y2); //, xmm3);
|
||||
y = _mm_andnot_ps(xmm3, y);
|
||||
y = _mm_add_ps(y,y2);
|
||||
/* update the sign */
|
||||
y = _mm_xor_ps(y, sign_bit);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* since sin_ps and cos_ps are almost identical, sincos_ps could replace both of them..
|
||||
it is almost as fast, and gives you a free cosine with your sine */
|
||||
void sincos_ps(v4sf x, v4sf *s, v4sf *c) {
|
||||
v4sf xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y;
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0, emm2, emm4;
|
||||
#else
|
||||
v2si mm0, mm1, mm2, mm3, mm4, mm5;
|
||||
#endif
|
||||
sign_bit_sin = x;
|
||||
/* take the absolute value */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
|
||||
/* extract the sign bit (upper one) */
|
||||
sign_bit_sin = _mm_and_ps(sign_bit_sin, *(v4sf*)_ps_sign_mask);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
/* store the integer part of y in emm2 */
|
||||
emm2 = _mm_cvttps_epi32(y);
|
||||
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
|
||||
y = _mm_cvtepi32_ps(emm2);
|
||||
|
||||
emm4 = emm2;
|
||||
|
||||
/* get the swap sign flag for the sine */
|
||||
emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4);
|
||||
emm0 = _mm_slli_epi32(emm0, 29);
|
||||
v4sf swap_sign_bit_sin = _mm_castsi128_ps(emm0);
|
||||
|
||||
/* get the polynom selection mask for the sine*/
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
|
||||
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
|
||||
v4sf poly_mask = _mm_castsi128_ps(emm2);
|
||||
#else
|
||||
/* store the integer part of y in mm2:mm3 */
|
||||
xmm3 = _mm_movehl_ps(xmm3, y);
|
||||
mm2 = _mm_cvttps_pi32(y);
|
||||
mm3 = _mm_cvttps_pi32(xmm3);
|
||||
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
|
||||
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
|
||||
|
||||
y = _mm_cvtpi32x2_ps(mm2, mm3);
|
||||
|
||||
mm4 = mm2;
|
||||
mm5 = mm3;
|
||||
|
||||
/* get the swap sign flag for the sine */
|
||||
mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4);
|
||||
mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4);
|
||||
mm0 = _mm_slli_pi32(mm0, 29);
|
||||
mm1 = _mm_slli_pi32(mm1, 29);
|
||||
v4sf swap_sign_bit_sin;
|
||||
COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit_sin);
|
||||
|
||||
/* get the polynom selection mask for the sine */
|
||||
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
|
||||
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
|
||||
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
|
||||
v4sf poly_mask;
|
||||
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
|
||||
#endif
|
||||
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
|
||||
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
|
||||
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
|
||||
xmm1 = _mm_mul_ps(y, xmm1);
|
||||
xmm2 = _mm_mul_ps(y, xmm2);
|
||||
xmm3 = _mm_mul_ps(y, xmm3);
|
||||
x = _mm_add_ps(x, xmm1);
|
||||
x = _mm_add_ps(x, xmm2);
|
||||
x = _mm_add_ps(x, xmm3);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
emm4 = _mm_sub_epi32(emm4, *(v4si*)_pi32_2);
|
||||
emm4 = _mm_andnot_si128(emm4, *(v4si*)_pi32_4);
|
||||
emm4 = _mm_slli_epi32(emm4, 29);
|
||||
v4sf sign_bit_cos = _mm_castsi128_ps(emm4);
|
||||
#else
|
||||
/* get the sign flag for the cosine */
|
||||
mm4 = _mm_sub_pi32(mm4, *(v2si*)_pi32_2);
|
||||
mm5 = _mm_sub_pi32(mm5, *(v2si*)_pi32_2);
|
||||
mm4 = _mm_andnot_si64(mm4, *(v2si*)_pi32_4);
|
||||
mm5 = _mm_andnot_si64(mm5, *(v2si*)_pi32_4);
|
||||
mm4 = _mm_slli_pi32(mm4, 29);
|
||||
mm5 = _mm_slli_pi32(mm5, 29);
|
||||
v4sf sign_bit_cos;
|
||||
COPY_MM_TO_XMM(mm4, mm5, sign_bit_cos);
|
||||
_mm_empty(); /* good-bye mmx */
|
||||
#endif
|
||||
|
||||
sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin);
|
||||
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
y = *(v4sf*)_ps_coscof_p0;
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_mul_ps(y, z);
|
||||
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_1);
|
||||
|
||||
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
||||
|
||||
v4sf y2 = *(v4sf*)_ps_sincof_p0;
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_mul_ps(y2, x);
|
||||
y2 = _mm_add_ps(y2, x);
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
xmm3 = poly_mask;
|
||||
v4sf ysin2 = _mm_and_ps(xmm3, y2);
|
||||
v4sf ysin1 = _mm_andnot_ps(xmm3, y);
|
||||
y2 = _mm_sub_ps(y2,ysin2);
|
||||
y = _mm_sub_ps(y, ysin1);
|
||||
|
||||
xmm1 = _mm_add_ps(ysin1,ysin2);
|
||||
xmm2 = _mm_add_ps(y,y2);
|
||||
|
||||
/* update the sign */
|
||||
*s = _mm_xor_ps(xmm1, sign_bit_sin);
|
||||
*c = _mm_xor_ps(xmm2, sign_bit_cos);
|
||||
}
|
||||
|
7552
Kha/Kinc/Sources/kinc/libs/stb_image.h
Normal file
7552
Kha/Kinc/Sources/kinc/libs/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
1906
Kha/Kinc/Sources/kinc/libs/stb_sprintf.h
Normal file
1906
Kha/Kinc/Sources/kinc/libs/stb_sprintf.h
Normal file
File diff suppressed because it is too large
Load Diff
5520
Kha/Kinc/Sources/kinc/libs/stb_vorbis.c
Normal file
5520
Kha/Kinc/Sources/kinc/libs/stb_vorbis.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user