Skip to content

Commit 5116cd8

Browse files
committed
Use logf and powf intrinsics
This handles edge cases like a `pow` base of 0 better than the `exp(log(x) * y)` identity did. Fixes #11
1 parent b4908cd commit 5116cd8

9 files changed

Lines changed: 187 additions & 211 deletions

File tree

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,27 @@ jobs:
9494
- name: Dump Meson logs
9595
if: failure()
9696
run: cat builddir/meson-logs/meson-log.txt builddir/compile_commands.json
97+
98+
test:
99+
strategy:
100+
fail-fast: false
101+
matrix:
102+
os: [ubuntu-24.04, macos-15]
103+
name: Test os=${{ matrix.os }}
104+
runs-on: ${{ matrix.os }}
105+
steps:
106+
- name: Checkout code
107+
uses: actions/checkout@v4.2.2
108+
109+
- name: Install Nix
110+
uses: cachix/install-nix-action@v31.6.1
111+
with:
112+
nix_path: nixpkgs=channel:nixos-unstable
113+
114+
- name: Set up Nix cache
115+
uses: cachix/cachix-action@v16
116+
with:
117+
name: vs-nix-overlay
118+
119+
- name: Run tests
120+
run: nix flake check -L

expr2/exprfilter.cpp

Lines changed: 21 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -432,12 +432,12 @@ class Compiler {
432432
bool mirror;
433433
bool cached;
434434
Context(
435-
const std::string &expr,
436-
const VSVideoInfo *vo,
437-
const VSVideoInfo *const *vi,
435+
const std::string &expr,
436+
const VSVideoInfo *vo,
437+
const VSVideoInfo *const *vi,
438438
const VSAPI *vsapi,
439-
int numInputs,
440-
int opt,
439+
int numInputs,
440+
int opt,
441441
int mirror
442442
):
443443
expr(expr), vo(vo), vi(vi), vsapi(vsapi), numInputs(numInputs), optMask(opt), mirror(!!mirror), cached(false) {
@@ -487,13 +487,10 @@ class Compiler {
487487
using ftype = rr::ModuleFunction<FloatV(FloatV)>;
488488
using ftype2 = rr::ModuleFunction<FloatV(FloatV, FloatV)>;
489489
std::unique_ptr<ftype> Exp;
490-
std::unique_ptr<ftype> Log;
491490
std::unique_ptr<ftype> Sin;
492491
std::unique_ptr<ftype> Cos;
493-
std::unique_ptr<ftype2> Pow;
494492
};
495493
rr::RValue<FloatV> Exp_(rr::RValue<FloatV>);
496-
rr::RValue<FloatV> Log_(rr::RValue<FloatV>);
497494
rr::RValue<FloatV> SinCos_(rr::RValue<FloatV>, bool issin);
498495
rr::RValue<FloatV> FP16To32(rr::RValue<UShortV>);
499496
rr::RValue<UShortV> FP32To16(rr::RValue<FloatV>);
@@ -546,11 +543,11 @@ class Compiler {
546543
public:
547544
Compiler(
548545
const std::string &expr,
549-
const VSVideoInfo *vo,
550-
const VSVideoInfo * const *vi,
546+
const VSVideoInfo *vo,
547+
const VSVideoInfo * const *vi,
551548
const VSAPI *vsapi,
552-
int numInputs,
553-
int opt = 0,
549+
int numInputs,
550+
int opt = 0,
554551
int mirror = 0
555552
) : ctx(expr, vo, vi, vsapi, numInputs, opt, mirror) {}
556553

@@ -591,51 +588,6 @@ rr::RValue<typename Compiler<lanes>::FloatV> Compiler<lanes>::Exp_(rr::RValue<ty
591588
return x;
592589
}
593590

594-
template<int lanes>
595-
rr::RValue<typename Compiler<lanes>::FloatV> Compiler<lanes>::Log_(rr::RValue<typename Compiler<lanes>::FloatV> x_)
596-
{
597-
FloatV x = x_;
598-
using namespace rr;
599-
const uint32_t min_norm_pos = 0x00800000, inv_mant_mask = ~0x7F800000;
600-
const float float_half = 0.5f, sqrt_1_2 = 0.707106781186547524f, log_p0 = 7.0376836292E-2f, log_p1 = -1.1514610310E-1f,
601-
log_p2 = 1.1676998740E-1f, log_p3 = -1.2420140846E-1f, log_p4 = +1.4249322787E-1f, log_p5 = -1.6668057665E-1f,
602-
log_p6 = +2.0000714765E-1f, log_p7 = -2.4999993993E-1f, log_p8 = +3.3333331174E-1f, log_q2 = 0.693359375f,
603-
log_q1 = -2.12194440e-4f;
604-
const float zero = 0.0f, one = 1.0f;
605-
IntV invalid_mask = CmpLE(x, FloatV(zero));
606-
x = Max(x, As<FloatV>(IntV(min_norm_pos)));
607-
IntV emm0i = As<IntV>(x) >> 23;
608-
x = As<FloatV>(As<IntV>(x) & IntV(inv_mant_mask));
609-
x = As<FloatV>(As<IntV>(x) | As<IntV>(FloatV(float_half)));
610-
emm0i = emm0i - IntV(0x7f);
611-
FloatV emm0 = FloatV(emm0i);
612-
emm0 = emm0 + FloatV(one);
613-
IntV mask = CmpLT(x, FloatV(sqrt_1_2));
614-
FloatV etmp = As<FloatV>(mask & As<IntV>(x));
615-
x = x - FloatV(one);
616-
FloatV maskf = As<FloatV>(mask & As<IntV>(FloatV(one)));
617-
emm0 = emm0 - maskf;
618-
x = x + etmp;
619-
FloatV z = x * x;
620-
FloatV y = FloatV(log_p0);
621-
y = FMA(y, x, FloatV(log_p1));
622-
y = FMA(y, x, FloatV(log_p2));
623-
y = FMA(y, x, FloatV(log_p3));
624-
y = FMA(y, x, FloatV(log_p4));
625-
y = FMA(y, x, FloatV(log_p5));
626-
y = FMA(y, x, FloatV(log_p6));
627-
y = FMA(y, x, FloatV(log_p7));
628-
y = FMA(y, x, FloatV(log_p8));
629-
y = y * x;
630-
y = y * z;
631-
y = FMA(emm0, FloatV(log_q1), y);
632-
y = FMA(z, FloatV(-float_half), y);
633-
x = x + y;
634-
x = FMA(emm0, FloatV(log_q2), x);
635-
x = As<FloatV>(invalid_mask | As<IntV>(x));
636-
return x;
637-
}
638-
639591
template<int lanes>
640592
rr::RValue<typename Compiler<lanes>::FloatV> Compiler<lanes>::SinCos_(rr::RValue<typename Compiler<lanes>::FloatV> x_, bool issin)
641593
{
@@ -1196,16 +1148,14 @@ void Compiler<lanes>::buildOneIter(const Helper &helpers, State &state)
11961148
case ExprOpType::FLOOR: UNARYOPF(Floor);
11971149

11981150
case ExprOpType::EXP: UNARYOPF([&helpers](RValue<FloatV> x) -> FloatV { return helpers.Exp->Call(x); });
1199-
case ExprOpType::LOG: UNARYOPF([&helpers](RValue<FloatV> x) -> FloatV { return helpers.Log->Call(x); });
1151+
case ExprOpType::LOG: {
1152+
LOAD1(x);
1153+
OUT(Log(x.ensureFloat()));
1154+
break;
1155+
}
12001156
case ExprOpType::POW: {
12011157
LOAD2(l, r);
1202-
if (!r.isFloat()) {
1203-
OUT(IfThenElse(RValue<IntV>(r.i()).IsConstant(),
1204-
BuiltinPow(l.ensureFloat(), FloatV(r.i())),
1205-
helpers.Pow->Call(l.ensureFloat(), r.ensureFloat())));
1206-
} else {
1207-
OUT(helpers.Pow->Call(l.ensureFloat(), r.ensureFloat()));
1208-
}
1158+
OUT(Pow(l.ensureFloat(), r.ensureFloat()));
12091159
break;
12101160
}
12111161
case ExprOpType::SIN: UNARYOPF([&helpers](RValue<FloatV> x) -> FloatV { return helpers.Sin->Call(x); });
@@ -1300,19 +1250,6 @@ typename Compiler<lanes>::Helper Compiler<lanes>::buildHelpers(rr::Module &mod)
13001250
FloatV x = h.Sin->template Arg<0>();
13011251
Return(Exp_(x));
13021252
}
1303-
h.Log = std::make_unique<ftype>(mod, "vlog");
1304-
h.Log->setPure();
1305-
{
1306-
FloatV x = h.Sin->template Arg<0>();
1307-
Return(Log_(x));
1308-
}
1309-
h.Pow = std::make_unique<ftype2>(mod, "vpow");
1310-
h.Pow->setPure();
1311-
{
1312-
FloatV x = h.Pow->template Arg<0>();
1313-
FloatV y = h.Pow->template Arg<1>();
1314-
Return(h.Exp->Call(h.Log->Call(x) * y));
1315-
}
13161253

13171254
return h;
13181255
}
@@ -1530,12 +1467,12 @@ static void VS_CC exprCreate(const VSMap *in, VSMap *out, void *userData, VSCore
15301467
if (d->vi.format.numPlanes != f.numPlanes)
15311468
throw std::runtime_error("The number of planes in the inputs and output must match");
15321469
vsapi->queryVideoFormat(
1533-
&d->vi.format,
1534-
d->vi.format.colorFamily,
1535-
f.sampleType,
1536-
f.bitsPerSample,
1537-
d->vi.format.subSamplingW,
1538-
d->vi.format.subSamplingH,
1470+
&d->vi.format,
1471+
d->vi.format.colorFamily,
1472+
f.sampleType,
1473+
f.bitsPerSample,
1474+
d->vi.format.subSamplingW,
1475+
d->vi.format.subSamplingH,
15391476
core
15401477
);
15411478
}

expr2/reactor/Intrinsics.hpp

Lines changed: 0 additions & 33 deletions
This file was deleted.

expr2/reactor/LLVMReactor.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@
3939
# include <xmmintrin.h>
4040
#endif
4141

42-
#include <math.h>
43-
4442
#if defined(__x86_64__) && defined(_WIN32)
4543
extern "C" void X86CompilationCallback()
4644
{
@@ -3664,22 +3662,6 @@ RValue<FloatT> Atan2(RValue<FloatT> x, RValue<FloatT> y)
36643662
return RValue<FloatT>(V(out));
36653663
}
36663664

3667-
template<typename FloatT>
3668-
RValue<FloatT> Pow(RValue<FloatT> x, RValue<FloatT> y)
3669-
{
3670-
RR_DEBUG_INFO_UPDATE_LOC();
3671-
auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::pow, { T(FloatT::type()) });
3672-
return RValue<FloatT>(V(jit->builder->CreateCall(func, { V(x.value()), V(y.value()) })));
3673-
}
3674-
3675-
template<typename FloatT>
3676-
RValue<FloatT> BuiltinPow(RValue<FloatT> x, RValue<FloatT> y)
3677-
{
3678-
RR_DEBUG_INFO_UPDATE_LOC();
3679-
auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::pow, { T(FloatT::type()) });
3680-
return RValue<FloatT>(V(jit->builder->CreateCall(func, { V(x.value()), V(y.value()) })));
3681-
}
3682-
36833665
template<typename FloatT>
36843666
RValue<FloatT> Exp(RValue<FloatT> v)
36853667
{
@@ -3688,14 +3670,6 @@ RValue<FloatT> Exp(RValue<FloatT> v)
36883670
return RValue<FloatT>(V(jit->builder->CreateCall(func, V(v.value()))));
36893671
}
36903672

3691-
template<typename FloatT>
3692-
RValue<FloatT> Log(RValue<FloatT> v)
3693-
{
3694-
RR_DEBUG_INFO_UPDATE_LOC();
3695-
auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::log, { T(FloatT::type()) });
3696-
return RValue<FloatT>(V(jit->builder->CreateCall(func, V(v.value()))));
3697-
}
3698-
36993673
template<typename FloatT>
37003674
RValue<FloatT> Exp2(RValue<FloatT> v)
37013675
{
@@ -3712,30 +3686,6 @@ RValue<FloatT> Log2(RValue<FloatT> v)
37123686
return RValue<FloatT>(V(jit->builder->CreateCall(func, V(v.value()))));
37133687
}
37143688

3715-
#define INSTANTIATE_FUNCS(FloatT) \
3716-
template RValue<FloatT> Sin<FloatT>(RValue<FloatT> v); \
3717-
template RValue<FloatT> Cos<FloatT>(RValue<FloatT> v); \
3718-
template RValue<FloatT> Tan<FloatT>(RValue<FloatT> v); \
3719-
template RValue<FloatT> Asin<FloatT>(RValue<FloatT> v, Precision p); \
3720-
template RValue<FloatT> Acos<FloatT>(RValue<FloatT> v, Precision p); \
3721-
template RValue<FloatT> Atan<FloatT>(RValue<FloatT> v); \
3722-
template RValue<FloatT> Sinh<FloatT>(RValue<FloatT> v); \
3723-
template RValue<FloatT> Cosh<FloatT>(RValue<FloatT> v); \
3724-
template RValue<FloatT> Tanh<FloatT>(RValue<FloatT> v); \
3725-
template RValue<FloatT> Asinh<FloatT>(RValue<FloatT> v); \
3726-
template RValue<FloatT> Acosh<FloatT>(RValue<FloatT> v); \
3727-
template RValue<FloatT> Atanh<FloatT>(RValue<FloatT> v); \
3728-
template RValue<FloatT> Atan2<FloatT>(RValue<FloatT> x, RValue<FloatT> y); \
3729-
template RValue<FloatT> BuiltinPow<FloatT>(RValue<FloatT> x, RValue<FloatT> y); \
3730-
template RValue<FloatT> Pow<FloatT>(RValue<FloatT> x, RValue<FloatT> y); \
3731-
template RValue<FloatT> Exp<FloatT>(RValue<FloatT> v); \
3732-
template RValue<FloatT> Log<FloatT>(RValue<FloatT> v); \
3733-
template RValue<FloatT> Exp2<FloatT>(RValue<FloatT> v); \
3734-
template RValue<FloatT> Log2<FloatT>(RValue<FloatT> v);
3735-
INSTANTIATE_FUNCS(Float4);
3736-
INSTANTIATE_FUNCS(Float8);
3737-
#undef INSTANTIATE_FUNCS
3738-
37393689
RValue<UInt> Ctlz(RValue<UInt> v, bool isZeroUndef)
37403690
{
37413691
RR_DEBUG_INFO_UPDATE_LOC();

expr2/reactor/Reactor.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5381,4 +5381,24 @@ RValue<Float> RcpSqrt(RValue<Float> x, Precision p)
53815381
return DoRcpSqrt(x, p);
53825382
}
53835383

5384+
RValue<Float4> Log(RValue<Float4> x)
5385+
{
5386+
return ScalarizeCall(logf, x);
5387+
}
5388+
5389+
RValue<Float4> Pow(RValue<Float4> x, RValue<Float4> y)
5390+
{
5391+
return ScalarizeCall(powf, x, y);
5392+
}
5393+
5394+
RValue<Float8> Log(RValue<Float8> x)
5395+
{
5396+
return ScalarizeCall(logf, x);
5397+
}
5398+
5399+
RValue<Float8> Pow(RValue<Float8> x, RValue<Float8> y)
5400+
{
5401+
return ScalarizeCall(powf, x, y);
5402+
}
5403+
53845404
} // namespace rr

0 commit comments

Comments
 (0)