ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
graph_ir_expr.h
Go to the documentation of this file.
1#pragma once
2// The IR's `expr` op on the CPU: a runtime-defined elementwise operation (a
3// paper's new activation or gate) written in paperkiln's closed grammar
4// (paperkiln include/microtorch/ir.hpp, op `expr`; microtorch/expr.hpp).
5//
6// The parser is vendored from paperkiln src/expr.cpp (1159d63e) with its
7// error messages unchanged, so both engines accept the same strings and reject
8// the rest at the same column. The evaluator is ember's own forward over row-
9// major [T, w] buffers with paperkiln's semantics: every primitive in f32 and
10// rounded after it (this file's .cpp is compiled with -ffp-contract=off), a
11// constant subexpression folded with the same operations, row reductions
12// [T, 1] in ascending column order, broadcast back where they meet a full
13// value. tools/ir_expr_eval.cpp exposes it with paperkiln's expr_eval JSON
14// contract, so paperkiln's tests/test_ir_expr.py gates it (EXPR_EVAL_BIN).
15#include <cstddef>
16#include <string>
17#include <vector>
18
19namespace ember_ir {
20namespace expr {
21
22enum class Kind {
24 EXP, LOG, SQRT, TANH, SIGMOID, ERF, ABS, RELU, // one argument
25 MAX, MIN, // two
26 WHERE, // three
27 ROWSUM, ROWMEAN, ROWMAX, // one, over the row
28};
29
30struct Node {
32 float value = 0.0f; // NUMBER
33 size_t input = 0; // INPUT: 0 for x, 1 for a, 2 for b, ...
34 std::vector<Node> args; // operands, in order
35 size_t column = 0; // where the node starts in the text (1-based)
36};
37
38class Expr {
39 public:
40 static constexpr size_t kMaxInputs = 23; // x, then a .. v
41 static constexpr size_t kMaxDepth = 200; // nesting, so a hostile string cannot exhaust the stack
42
43 // Throws std::invalid_argument naming the problem and its column, e.g.
44 // expr: expected an operand at column 5 in "x + * 2".
45 static Expr parse(const std::string& text, size_t n_inputs = 1);
46
47 const std::string& text() const { return text_; }
48 size_t n_inputs() const { return n_inputs_; }
49 const Node& root() const { return root_; }
50
51 private:
52 std::string text_;
53 size_t n_inputs_ = 1;
55};
56
57// out [T, w] = the expression over ins (n_inputs() buffers, each [T, w] row-major).
58void eval(const Expr& e, const std::vector<const float*>& ins, int T, int w, float* out);
59
60// The parse of (text, n_inputs), cached: an IR's expressions are parsed once at load.
61const Expr& cached(const std::string& text, size_t n_inputs);
62
63// The device form (graph_ir_cuda.h ir_expr_cuda): the expression as stages of
64// a per-element stack program over [T, w]. A row reduction's argument is a
65// stage of its own, reduced to a column [T] in ascending columns as eval
66// reduces it; a later stage reads column k (stage k's) broadcast along its row.
67// Constant subexpressions are folded here with eval's own operations, so both
68// paths compute with the same constants; every other primitive is one
69// instruction, rounded on its own.
70enum class Op : int {
71 CONST, INPUT, COL, WIDTH, // push c, input idx at (t, j), column idx at t, (float) w
72 NEG, EXP, LOG, SQRT, TANH, SIGMOID, ERF, ABS, RELU, // pop a, push f(a)
73 ADD, SUB, MUL, DIV, POW, MAX, MIN, // pop b, pop a, push f(a, b)
74 WHERE, // pop b, a, c; push c > 0 ? a : b
75};
76struct Instr {
78 int idx = 0;
79 float c = 0.0f;
80};
81struct Stage {
82 std::vector<Instr> code;
83 int reduce = 0; // 0 for the last stage (the result); 1 rowsum, 2 rowmax: column k for the later stages
84};
85constexpr size_t kMaxCode = 96; // instructions per stage
86constexpr size_t kMaxStack = 16; // stack depth
87constexpr size_t kMaxColumns = 8; // row reductions
88// Throws std::invalid_argument naming the limit an expression exceeds.
89std::vector<Stage> lower(const Expr& e);
90
91} // namespace expr
92} // namespace ember_ir
const Node & root() const
static constexpr size_t kMaxDepth
static Expr parse(const std::string &text, size_t n_inputs=1)
size_t n_inputs() const
static constexpr size_t kMaxInputs
const std::string & text() const
std::string text
node expr
node out
size_t j
std::vector< Stage > lower(const Expr &e)
constexpr size_t kMaxCode
constexpr size_t kMaxColumns
void eval(const Expr &e, const std::vector< const float * > &ins, int T, int w, float *out)
constexpr size_t kMaxStack
const Expr & cached(const std::string &text, size_t n_inputs)
Definition api.h:20
std::vector< Node > args
std::vector< Instr > code