1b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein/*
2b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein * Copyright 2017 Google Inc.
3b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein *
4b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein * Use of this source code is governed by a BSD-style license that can be
5b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein * found in the LICENSE file.
6b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein */
7b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
8b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein#ifndef SkJumper_misc_DEFINED
9b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein#define SkJumper_misc_DEFINED
10b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
11376fd31ad485c3df35d934c56364ff0c34eacdfaMike Klein#include <string.h>  // for memcpy()
12b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
13adc78d52024fc546df61aff091a0d522a8fb95f2Mike Klein// Miscellany used by SkJumper_stages.cpp and SkJumper_stages_lowp.cpp.
14b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
15b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein// Every function in this file should be marked static and inline using SI.
16be22636c3d9e8d73dd408c241c183e923e149574Mike Klein#if defined(__clang__)
174de1304297d7220b223c829bf386f97815db1654Herb Derby    #define SI __attribute__((always_inline)) static inline
184de1304297d7220b223c829bf386f97815db1654Herb Derby#else
194de1304297d7220b223c829bf386f97815db1654Herb Derby    #define SI static inline
204de1304297d7220b223c829bf386f97815db1654Herb Derby#endif
214de1304297d7220b223c829bf386f97815db1654Herb Derby
22b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
23b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Kleintemplate <typename T, typename P>
24b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike KleinSI T unaligned_load(const P* p) {  // const void* would work too, but const P* helps ARMv7 codegen.
25b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein    T v;
26b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein    memcpy(&v, p, sizeof(v));
27b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein    return v;
28b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein}
29b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
30c33aa9090cd62bd1ea8dd89f9f7c9954e067a1f7Mike Kleintemplate <typename T, typename P>
31c33aa9090cd62bd1ea8dd89f9f7c9954e067a1f7Mike KleinSI void unaligned_store(P* p, T v) {
32c33aa9090cd62bd1ea8dd89f9f7c9954e067a1f7Mike Klein    memcpy(p, &v, sizeof(v));
33c33aa9090cd62bd1ea8dd89f9f7c9954e067a1f7Mike Klein}
34c33aa9090cd62bd1ea8dd89f9f7c9954e067a1f7Mike Klein
35b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Kleintemplate <typename Dst, typename Src>
36b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike KleinSI Dst bit_cast(const Src& src) {
37b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein    static_assert(sizeof(Dst) == sizeof(Src), "");
38b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein    return unaligned_load<Dst>(&src);
39b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein}
40b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
4195f53be0059940da50d4fce10da5c4dcf037b6aeMike Kleintemplate <typename Dst, typename Src>
4295f53be0059940da50d4fce10da5c4dcf037b6aeMike KleinSI Dst widen_cast(const Src& src) {
4395f53be0059940da50d4fce10da5c4dcf037b6aeMike Klein    static_assert(sizeof(Dst) > sizeof(Src), "");
4495f53be0059940da50d4fce10da5c4dcf037b6aeMike Klein    Dst dst;
4595f53be0059940da50d4fce10da5c4dcf037b6aeMike Klein    memcpy(&dst, &src, sizeof(Src));
4695f53be0059940da50d4fce10da5c4dcf037b6aeMike Klein    return dst;
4795f53be0059940da50d4fce10da5c4dcf037b6aeMike Klein}
4895f53be0059940da50d4fce10da5c4dcf037b6aeMike Klein
490d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein// Our program is an array of void*, either
500d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein//   - 1 void* per stage with no context pointer, the next stage;
510d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein//   - 2 void* per stage with a context pointer, first the context pointer, then the next stage.
520d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
530d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein// load_and_inc() steps the program forward by 1 void*, returning that pointer.
540d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike KleinSI void* load_and_inc(void**& program) {
550d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein#if defined(__GNUC__) && defined(__x86_64__)
560d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    // If program is in %rsi (we try to make this likely) then this is a single instruction.
570d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    void* rax;
580d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    asm("lodsq" : "=a"(rax), "+S"(program));  // Write-only %rax, read-write %rsi.
590d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    return rax;
600d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein#else
610d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    // On ARM *program++ compiles into pretty ideal code without any handholding.
620d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    return *program++;
630d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein#endif
640d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein}
650d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
667c55726156a6b2bda10035188be0077848bd3edeMike Klein// Lazily resolved on first cast.  Does nothing if cast to Ctx::None.
677c55726156a6b2bda10035188be0077848bd3edeMike Kleinstruct Ctx {
68f7729c262076b88b2635e7f8d09e7f3340eea79bMike Klein    struct None {};
697c55726156a6b2bda10035188be0077848bd3edeMike Klein
700d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    void*   ptr;
710d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    void**& program;
720d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
737c55726156a6b2bda10035188be0077848bd3edeMike Klein    explicit Ctx(void**& p) : ptr(nullptr), program(p) {}
740d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
750d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    template <typename T>
760d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    operator T*() {
770d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein        if (!ptr) { ptr = load_and_inc(program); }
780d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein        return (T*)ptr;
790d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    }
80f7729c262076b88b2635e7f8d09e7f3340eea79bMike Klein    operator None() { return None{}; }
810d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein};
820d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
83b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein#endif//SkJumper_misc_DEFINED
84