1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2017 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifndef SkJumper_misc_DEFINED
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define SkJumper_misc_DEFINED
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <string.h>  // for memcpy()
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Miscellany used by SkJumper_stages.cpp and SkJumper_stages_lowp.cpp.
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Every function in this file should be marked static and inline using SI.
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined(__clang__)
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define SI __attribute__((always_inline)) static inline
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #define SI static inline
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T, typename P>
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSI T unaligned_load(const P* p) {  // const void* would work too, but const P* helps ARMv7 codegen.
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    T v;
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(&v, p, sizeof(v));
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return v;
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T, typename P>
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSI void unaligned_store(P* p, T v) {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(p, &v, sizeof(v));
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename Dst, typename Src>
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSI Dst bit_cast(const Src& src) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static_assert(sizeof(Dst) == sizeof(Src), "");
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return unaligned_load<Dst>(&src);
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename Dst, typename Src>
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSI Dst widen_cast(const Src& src) {
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static_assert(sizeof(Dst) > sizeof(Src), "");
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Dst dst;
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(&dst, &src, sizeof(Src));
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return dst;
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Our program is an array of void*, either
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//   - 1 void* per stage with no context pointer, the next stage;
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//   - 2 void* per stage with a context pointer, first the context pointer, then the next stage.
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// load_and_inc() steps the program forward by 1 void*, returning that pointer.
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSI void* load_and_inc(void**& program) {
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined(__GNUC__) && defined(__x86_64__)
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // If program is in %rsi (we try to make this likely) then this is a single instruction.
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* rax;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    asm("lodsq" : "=a"(rax), "+S"(program));  // Write-only %rax, read-write %rsi.
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return rax;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // On ARM *program++ compiles into pretty ideal code without any handholding.
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return *program++;
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Lazily resolved on first cast.  Does nothing if cast to Ctx::None.
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct Ctx {
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct None {};
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void*   ptr;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void**& program;
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    explicit Ctx(void**& p) : ptr(nullptr), program(p) {}
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    template <typename T>
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    operator T*() {
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!ptr) { ptr = load_and_inc(program); }
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (T*)ptr;
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    operator None() { return None{}; }
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif//SkJumper_misc_DEFINED
84