-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathm1block_int4mm.metal
More file actions
120 lines (98 loc) · 3.75 KB
/
Copy pathm1block_int4mm.metal
File metadata and controls
120 lines (98 loc) · 3.75 KB
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
#include <metal_stdlib>
using namespace metal;
template <typename T> struct Vec4Type {};
template <> struct Vec4Type<float> {
using type = float4;
};
template <> struct Vec4Type<half> {
using type = half4;
};
#if __METAL_VERSION__ >= 310
template <> struct Vec4Type<bfloat> {
using type = bfloat4;
};
#endif
template <typename T> struct Vec2Type {};
template <> struct Vec2Type<float> {
using type = float2;
};
template <> struct Vec2Type<half> {
using type = half2;
};
#if __METAL_VERSION__ >= 310
template <> struct Vec2Type<bfloat> {
using type = bfloat2;
};
#endif
// [encoder dispatchThreads:MTLSizeMake(N / 2, 4, 1)
// threadsPerThreadgroup:MTLSizeMake(16, 4, 1)];
template<typename T, unsigned groupSize>
kernel void int4pack_mm(
constant T * A [[buffer(0)]],
constant uchar * B [[buffer(1)]],
constant T * scalesAndZeros [[buffer(2)]],
device T * outputData [[buffer(3)]],
constant uint3 & sizes [[buffer(4)]], // M, K, N
uint2 group_index [[threadgroup_position_in_grid]],
uint2 threadgroup_index [[thread_position_in_threadgroup]]) {
const uint K = sizes.y;
const uint N = sizes.z;
const uint nb = group_index.x; // 0..N/32-1
const uint n2 = 16 * nb + threadgroup_index.x; // 0..N/2-1
const uint ldb = min(32U, N - nb * 32);
const uint32_t k_block = (K + groupSize - 1) / groupSize;
using vecT = typename Vec2Type<T>::type;
constant T *A_ptr = A;
constant uchar *B_ptr = B + (nb * 16 * K);
float2 rc = 0.0;
for (uint k = threadgroup_index.y; k < K; k += 4) {
threadgroup_barrier(mem_flags::mem_none);
const auto a_val = float(A_ptr[k]);
uchar b_byte = B_ptr[(k * ldb + (2*n2 % 32))/2];
float2 b_val = float2(
float(b_byte & 0x0f),
float(b_byte >> 4));
uint kb = k / groupSize;
float2 scales, zeros;
for (int i = 0; i < 2; ++i) {
scales[i] = scalesAndZeros[(kb * N + 2*n2 + i) * 2 + 0];
zeros[i] = scalesAndZeros[(kb * N + 2*n2 + i) * 2 + 1] - scales[i] * T(8);
}
float2 b_vec = scales * b_val + zeros;
rc += a_val * b_vec;
}
threadgroup float2 tgp_memory[16][4];
tgp_memory[threadgroup_index.x][threadgroup_index.y] = rc;
threadgroup_barrier(mem_flags::mem_threadgroup);
if (threadgroup_index.y == 0) {
for (unsigned i = 1; i < 4; i++) {
rc += tgp_memory[threadgroup_index.x][i];
}
reinterpret_cast<device vecT*>(outputData)[n2] = vecT(rc);
}
}
#define INSTANTIATE_INT4MM(DTYPE, GSIZE) \
template \
[[host_name("int4pack_mm_" #GSIZE "_" #DTYPE)]] \
kernel void int4pack_mm<DTYPE, GSIZE>( \
constant DTYPE * A [[buffer(0)]], \
constant uchar * B [[buffer(1)]], \
constant DTYPE * scalesAndZeros [[buffer(2)]], \
device DTYPE * outputData [[buffer(3)]], \
constant uint3 & sizes [[buffer(4)]], \
uint2 group_index [[threadgroup_position_in_grid]], \
uint2 threadgroup_index [[thread_position_in_threadgroup]])
INSTANTIATE_INT4MM(float, 32);
INSTANTIATE_INT4MM(half, 32);
INSTANTIATE_INT4MM(float, 64);
INSTANTIATE_INT4MM(half, 64);
INSTANTIATE_INT4MM(float, 128);
INSTANTIATE_INT4MM(half, 128);
INSTANTIATE_INT4MM(float, 256);
INSTANTIATE_INT4MM(half, 256);
#if __METAL_VERSION__ >= 310
INSTANTIATE_INT4MM(bfloat, 32);
INSTANTIATE_INT4MM(bfloat, 64);
INSTANTIATE_INT4MM(bfloat, 128);
INSTANTIATE_INT4MM(bfloat, 256);
#endif