This repository has been archived by the owner on Sep 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy pathsc_compiler.h
169 lines (150 loc) · 5.13 KB
/
sc_compiler.h
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright 2016-2021 Doug Moen
// Licensed under the Apache License, version 2.0
// See accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0
#ifndef LIBCURV_SC_COMPILER_H
#define LIBCURV_SC_COMPILER_H
#include <libcurv/function.h>
#include <libcurv/meaning.h>
#include <libcurv/sc_frame.h>
#include <tsl/ordered_map.h>
#include <unordered_map>
#include <vector>
namespace curv {
struct Context;
/// SubCurv is a low level, strongly-typed subset of Curv
/// that can be efficiently translated into a low level language (currently
/// C++ or GLSL), for fast evaluation on a CPU or GPU.
///
/// SubCurv is a set of types and operations on those types. It is a statically
/// typed subset of Curv which is also a subset of GLSL (but with different
/// type and operation names). Curv distance functions must be restricted to the
/// SC subset or the SubCurv Compiler will report an error during rendering.
///
/// The compiler operates on Curv function *values*. Non-local variables
/// captured by closures become compile time constants. Intermediate function
/// calls are inline expanded: this eliminates first-class function values,
/// which aren't supported by GLSL, and it eliminates run-time polymorphism,
/// where different calls to the same function have different argument types.
/// The generated code is statically typed, and uses SSA style, where each
/// operation is represented by an assignment to an SSA variable.
enum class SC_Target
{
glsl, // output GLSL code
cpp // output C++ code using GLM library
};
struct Op_Hash
{
size_t operator()(Shared<const Operation> op) const noexcept
{
return op->hash();
}
};
struct Op_Hash_Eq
{
bool operator()(
Shared<const Operation> op1, Shared<const Operation> op2)
const noexcept
{
return op1->hash_eq(*op2);
}
};
using Op_Cache =
std::unordered_map<Shared<const Operation>, SC_Value, Op_Hash, Op_Hash_Eq>;
struct SC_Object : public Shared_Base
{
virtual void emit(SC_Compiler&, Symbol_Ref, std::ostream&) const = 0;
};
/// Global state for the GLSL/C++ code generator.
struct SC_Compiler
{
std::stringstream constants_{};
std::stringstream body_{};
bool in_constants_ = false;
SC_Target target_;
unsigned valcount_;
Source_State &sstate_;
std::unordered_map<Value, SC_Value, Value::Hash, Value::Hash_Eq>
valcache_{};
std::vector<Op_Cache> opcaches_{};
tsl::ordered_map<Symbol_Ref, Shared<const SC_Object>> objects_;
SC_Compiler(SC_Target t, Source_State& ss)
:
target_(t), valcount_(0), sstate_(ss)
{
}
std::ostream& out()
{
if (in_constants_)
return constants_;
else
return body_;
}
// This is the main entry point to the SubCurv Compiler.
void define_function(
const char* name, SC_Type param_type, SC_Type result_type,
Shared<const Function> func, const Context&);
void define_function(
const char* name,
std::vector<SC_Type> param_types,
SC_Type result_type,
Shared<const Function> func,
const Context& cx);
inline void push_object(Symbol_Ref n, Shared<const SC_Object> o)
{ objects_.insert(std::pair<Symbol_Ref,Shared<const SC_Object>>{n,o}); }
void emit_objects(std::ostream&);
inline SC_Value newvalue(SC_Type type)
{
return SC_Value(valcount_++, type);
}
};
struct SC_Uniform_Variable : public SC_Object
{
SC_Type type_;
SC_Uniform_Variable(SC_Type t) : type_(t) {}
virtual void emit(SC_Compiler&, Symbol_Ref, std::ostream&) const override;
};
struct SC_Function : public SC_Object
{
std::vector<SC_Value> params_;
SC_Value result_;
std::stringstream constants_{};
std::stringstream body_{};
SC_Function(
std::vector<SC_Value> p, SC_Value r,
std::stringstream c, std::stringstream b)
:
params_(p),
result_(r),
constants_(std::move(c)),
body_(std::move(b))
{}
virtual void emit(SC_Compiler&, Symbol_Ref, std::ostream&) const override;
};
// Encapsulate an SC_Value as an expression (Operation).
// This will never be evaluated; it's only used as an argument
// to Function::sc_call_expr.
struct SC_Value_Expr : public Operation
{
SC_Value val_;
SC_Value_Expr(Shared<const Phrase> syntax, SC_Value val)
:
Operation(syntax, true),
val_(val)
{
}
virtual void exec(Frame&, Executor&) const override;
virtual SC_Value sc_eval(SC_Frame&) const override;
};
SC_Value sc_eval_op(SC_Frame&, const Operation& op);
SC_Value sc_eval_expr(SC_Frame&, const Operation& op, SC_Type);
SC_Value sc_eval_const(SC_Frame&, Value val, const Phrase&);
SC_Value sc_vec_element(SC_Frame&, SC_Value, int);
void sc_plex_unify(SC_Frame&, SC_Value& a, SC_Value& b, const Context& cx);
bool sc_try_extend(SC_Frame&, SC_Value& a, SC_Type b);
SC_Value sc_binop(
SC_Frame&, SC_Type rtype, SC_Value x, const char* op, SC_Value y);
SC_Value sc_bincall(
SC_Frame&, SC_Type rtype, const char* fn, SC_Value x, SC_Value y);
SC_Value sc_unary_call(SC_Frame&, SC_Type rtype, const char* fn, SC_Value x);
} // namespace
#endif // header guard