Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
kernel/cpu/contract.hpp
Go to the documentation of this file.
1#pragma once
2
5
12namespace uni20::kernel
13{
14
15namespace cpu
16{
17
26template <typename T, std::size_t MR, std::size_t NR, std::size_t KR> class GemmLoop {
27 public:
36 static_vector<extent_strides<2>, KR> const& Kgrp, T alpha, T beta) noexcept
37 : Mgrp_(Mgrp), Ngrp_(Ngrp), Kgrp_(Kgrp), alpha_(alpha), beta_(beta)
38 {}
39
45 void run(T const* A0, T const* B0, T* C0) noexcept { this->loopM(0, A0, B0, C0); }
46
47 private:
48 static_vector<extent_strides<2>, MR> const Mgrp_;
49 static_vector<extent_strides<2>, NR> const Ngrp_;
50 static_vector<extent_strides<2>, KR> const Kgrp_;
51 T const alpha_, beta_;
52
59 void loopM(std::size_t dim, T const* a_ptr, T const* b_ptr, T* c_ptr) noexcept
60 {
61 if (dim == Mgrp_.size())
62 {
63 loopN(0, a_ptr, b_ptr, c_ptr);
64 return;
65 }
66 auto extent = Mgrp_[dim].extent;
67 auto sA = Mgrp_[dim].strides[0];
68 auto sC = Mgrp_[dim].strides[1];
69 for (decltype(extent) i = 0; i < extent; ++i)
70 {
71 loopM(dim + 1, a_ptr, b_ptr, c_ptr);
72 a_ptr += sA;
73 c_ptr += sC;
74 }
75 }
76
83 void loopN(std::size_t dim, T const* a_ptr, T const* b_ptr, T* c_ptr) noexcept
84 {
85 if (dim == Ngrp_.size())
86 {
87 // At each M×N “cell” we do the dot-product over all K dims:
88 T acc{};
89 dotK(0, a_ptr, b_ptr, acc);
90 *c_ptr = (beta_ * *c_ptr) + (alpha_ * acc);
91 return;
92 }
93 auto extent = Ngrp_[dim].extent;
94 auto sB = Ngrp_[dim].strides[0];
95 auto sC = Ngrp_[dim].strides[1];
96 for (decltype(extent) j = 0; j < extent; ++j)
97 {
98 loopN(dim + 1, a_ptr, b_ptr, c_ptr);
99 b_ptr += sB;
100 c_ptr += sC;
101 }
102 }
103
110 void dotK(std::size_t dim, T const* a_ptr, T const* b_ptr, T& acc) noexcept
111 {
112 if (dim == Kgrp_.size())
113 {
114 // we’ve arrived at a single element to multiply:
115 acc += *a_ptr * *b_ptr;
116 return;
117 }
118 auto extent = Kgrp_[dim].extent;
119 auto sA = Kgrp_[dim].strides[0];
120 auto sB = Kgrp_[dim].strides[1];
121 for (decltype(extent) k = 0; k < extent; ++k)
122 {
123 dotK(dim + 1, a_ptr, b_ptr, acc);
124 a_ptr += sA;
125 b_ptr += sB;
126 }
127 }
128};
129
130} // namespace cpu
131
132template <typename T, std::size_t MR, std::size_t NR, std::size_t KR>
148 static_vector<extent_strides<2>, NR> const& Ngrp,
149 static_vector<extent_strides<2>, KR> const& Kgrp, T alpha, T const* A, T const* B, T beta, T* C)
150{
151 cpu::GemmLoop Loop(Mgrp, Ngrp, Kgrp, alpha, beta);
152 Loop.run(A, B, C);
153}
154
155} // namespace uni20::kernel
A fixed-capacity vector with stack storage and std::vector-like API.
Definition static_vector.hpp:24
size_type size() const noexcept
Definition static_vector.hpp:211
Generic M×N×K contraction engine with full K-dimension recursion.
Definition kernel/cpu/contract.hpp:26
void run(T const *A0, T const *B0, T *C0) noexcept
Perform C = β·C + α·(A ⋅ B) over all fused M, N, and K dimensions.
Definition kernel/cpu/contract.hpp:45
void contract_strided(static_vector< extent_strides< 2 >, MR > const &Mgrp, static_vector< extent_strides< 2 >, NR > const &Ngrp, static_vector< extent_strides< 2 >, KR > const &Kgrp, T alpha, T const *A, T const *B, T beta, T *C)
Execute the CPU tensor contraction using precomputed stride groupings.
Definition kernel/cpu/contract.hpp:147
GemmLoop(static_vector< extent_strides< 2 >, MR > const &Mgrp, static_vector< extent_strides< 2 >, NR > const &Ngrp, static_vector< extent_strides< 2 >, KR > const &Kgrp, T alpha, T beta) noexcept
Build the loop engine for a fused contraction.
Definition kernel/cpu/contract.hpp:35
Configured gateway to Uni20's mdspan implementation.
Definition kernel/contract.hpp:15
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
Stride utilities for mdspan-like tensors.
Structure to represent a common extent and an array of strides.
Definition strides.hpp:28