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
11b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein#include "SkJumper.h"  // for memcpy()
12b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
13b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein// Miscellany used by SkJumper_stages.cpp and SkJumper_vectors.h.
14b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein
15b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein// Every function in this file should be marked static and inline using SI.
164de1304297d7220b223c829bf386f97815db1654Herb Derby#if defined(JUMPER)
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
660d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein// LazyCtx doesn't do anything unless you call operator T*(), encapsulating the logic
670d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein// from above that stages without a context pointer are represented by just 1 void*.
680d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Kleinstruct LazyCtx {
690d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    void*   ptr;
700d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    void**& program;
710d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
720d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    explicit LazyCtx(void**& p) : ptr(nullptr), program(p) {}
730d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
740d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    template <typename T>
750d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    operator T*() {
760d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein        if (!ptr) { ptr = load_and_inc(program); }
770d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein        return (T*)ptr;
780d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein    }
790d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein};
800d93010c98e8c6e50c6a0f4d8b16ada5dede81abMike Klein
81b9c4a6fc7de252633f16d11c2df10ee6de16af03Mike Klein#endif//SkJumper_misc_DEFINED
82