aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/opts/SkXbyak.cpp
blob: 12f5200939c7cf8484ba1df8c44abc4162e22737 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCpu.h"
#include "SkRasterPipeline.h"
#include <memory>

#if defined(__clang__)
    #pragma clang diagnostic ignored "-Wduplicate-enum"
#endif
#define XBYAK_NO_OP_NAMES   // xor(), not(), etc. -> xor_(), not_(), etc.
#include "xbyak/xbyak.h"

namespace {

    struct Pipeline : public Xbyak::CodeGenerator {

        static std::shared_ptr<Pipeline> Create(const SkRasterPipeline::Stage* stages, int n) {
            if (!SkCpu::Supports(SkCpu::HSW)) {
                // TODO: other targets?
                return nullptr;
            }

            bool supported = true;
            auto pipeline = std::make_shared<Pipeline>(stages, n, &supported);
            if (supported) {
                return pipeline;
            }
            return nullptr;
        }

        Pipeline(const SkRasterPipeline::Stage* stages, int n, bool* supported) {
            // Set up some register name aliases.
            //auto x = rdi, y = rsi, tail = rdx;
            auto r = ymm0,  g = ymm1,  b = ymm2,  a = ymm3,
                dr = ymm4, dg = ymm5, db = ymm6, da = ymm7;

            Xbyak::Label floatOneStorage;
            vbroadcastss(ymm8, ptr[rip + floatOneStorage]);

            // TODO: set up (x+0.5,y+0.5) in (r,g)
            vxorps(r,r);
            vxorps(g,g);
            vxorps(b,b);
            vxorps(a,a);
            vxorps(dr,dr);
            vxorps(dg,dg);
            vxorps(db,db);
            vxorps(da,da);

            for (int i = 0; i < n; i++) {
                switch(stages[i].stage) {

                    default:
                        *supported = false;
                        return;
                }
            }

            ret();
            L(floatOneStorage); df(1.0f);
        }

        void df(float f) {
            union { float f; uint32_t x; } pun = {f};
            dd(pun.x);
        }
    };

}  // namespace

std::function<void(size_t, size_t, size_t)> SkRasterPipeline::jit() const {
    try {
        if (auto pipeline = Pipeline::Create(fStages.data(), SkToInt(fStages.size()))) {
            return [pipeline] (size_t x, size_t y, size_t n) {
                auto call = pipeline->getCode<void(*)(size_t, size_t, size_t)>();
                while (n >= 8) {
                    call(x,y,0);
                    x += 8;
                    n -= 8;
                }
                if (n) {
                    call(x,y,n);
                }
            };
        }
        SkDebugf("Cannot yet JIT with xbyak:\n");
        this->dump();
        return nullptr;
    } catch(...) {
        return nullptr;
    }
}