Skip to content

Commit 2f3754a

Browse files
Merge pull request #3191 from bkmgit:patch-1
PiperOrigin-RevId: 943704604
2 parents 11732eb + 7e17072 commit 2f3754a

3 files changed

Lines changed: 135 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,15 @@ target_link_libraries(dot_product_unroll PRIVATE ${ATOMICS_LIBRARIES})
811811
set_target_properties(dot_product_unroll
812812
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "examples/")
813813

814+
# Mixed precision dot product
815+
add_executable(dot_product_mixed_precision hwy/examples/dot_product_mixed_precision.cc)
816+
target_compile_options(dot_product_mixed_precision PRIVATE ${HWY_FLAGS})
817+
target_compile_features(dot_product_mixed_precision PRIVATE ${HWY_CXX_STD_TGT_COMPILE_FEATURE})
818+
target_link_libraries(dot_product_mixed_precision PRIVATE hwy)
819+
target_link_libraries(dot_product_mixed_precision PRIVATE ${ATOMICS_LIBRARIES})
820+
set_target_properties(dot_product_mixed_precision
821+
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "examples/")
822+
814823
# AES capture the flag example
815824
add_executable(ctf_aes hwy/examples/ctf_aes.cc)
816825
target_compile_options(ctf_aes PRIVATE ${HWY_FLAGS})

hwy/examples/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ Similar to sum_array_advanced, but for dot products. Adds:
2727
- Duff's device for vector remainders
2828
- Horizontal sum (reduction/fold) using `ReduceSum`.
2929

30+
### `dot_product_mixed_precision.cc
31+
32+
Similar to array simple but uses type promtion to allow for
33+
a greater range in resulting integer sum values before an
34+
overflow occurs.
35+
3036
### `matrix_transpose_scatter_gather.cc`
3137

3238
Matrix transposition via Gather and Scatter, showing:
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2026 Google LLC
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
#include <stddef.h>
17+
#include <stdint.h>
18+
19+
#include <iostream>
20+
#include <numeric>
21+
#include <vector>
22+
23+
#undef HWY_TARGET_INCLUDE
24+
#define HWY_TARGET_INCLUDE "hwy/examples/dot_product_mixed_precision.cc"
25+
#include "hwy/foreach_target.h" // IWYU pragma: keep
26+
#include "hwy/highway.h"
27+
#include "hwy/nanobenchmark.h"
28+
#include "hwy/timer.h"
29+
30+
/*
31+
Highway SIMD Tutorial: Mixed precision dot product
32+
33+
This example demonstrates how to perform a dot product where the inputs are
34+
uint8_t and are promoted uint32_t to prevent overflow.
35+
36+
*/
37+
38+
HWY_BEFORE_NAMESPACE();
39+
namespace hwy {
40+
namespace HWY_NAMESPACE {
41+
namespace hn = hwy::HWY_NAMESPACE;
42+
43+
uint32_t DotProductSIMD(const uint8_t* HWY_RESTRICT a,
44+
const uint8_t* HWY_RESTRICT b, size_t count) {
45+
using DU8 = hn::ScalableTag<uint8_t>;
46+
const DU8 du8;
47+
using DU32 = hn::ScalableTag<uint32_t>;
48+
const DU32 du32;
49+
using V = hn::Vec<DU32>;
50+
V sum = hn::Zero(du32);
51+
const size_t N8 = hn::Lanes(du8);
52+
size_t i = 0;
53+
if (count >= N8) {
54+
for (; i <= count - N8; i += N8) {
55+
sum = hn::SumOfMulQuadAccumulate(du32, hn::LoadU(du8, a + i),
56+
hn::LoadU(du8, b + i), sum);
57+
}
58+
}
59+
60+
// Use LoadN for remainder, sets 0 for values beyond remainder
61+
size_t remainder = count - i;
62+
HWY_DASSERT(remainder < N8);
63+
if (remainder > 0) {
64+
sum = hn::SumOfMulQuadAccumulate(du32, hn::LoadN(du8, a + i, remainder),
65+
hn::LoadN(du8, b + i, remainder), sum);
66+
}
67+
68+
uint32_t total = hn::ReduceSum(du32, sum);
69+
70+
return total;
71+
}
72+
73+
} // namespace HWY_NAMESPACE
74+
} // namespace hwy
75+
HWY_AFTER_NAMESPACE();
76+
77+
#if HWY_ONCE
78+
namespace hwy {
79+
HWY_EXPORT(DotProductSIMD);
80+
81+
uint32_t DotProductScalar(const uint8_t* HWY_RESTRICT a,
82+
const uint8_t* HWY_RESTRICT b, size_t count) {
83+
size_t i = 0;
84+
uint32_t total = 0;
85+
// Scalar dot product with type casting
86+
for (; i < count; ++i) {
87+
total += static_cast<uint32_t>(a[i]) * static_cast<uint32_t>(b[i]);
88+
}
89+
return total;
90+
}
91+
92+
int Run() {
93+
const size_t count = 10000025;
94+
std::vector<uint8_t> a(count);
95+
std::vector<uint8_t> b(count);
96+
std::iota(a.begin(), a.end(), 1);
97+
std::iota(b.begin(), b.end(), 1);
98+
// Record start time
99+
const double t_scalar_0 = hwy::platform::Now();
100+
uint32_t dpScalar = hwy::DotProductScalar(a.data(), b.data(), count);
101+
// Record end time and print execution time and dot product
102+
const double t_scalar_1 = hwy::platform::Now();
103+
const double dt_scalar = 1000.0 * (t_scalar_1 - t_scalar_0);
104+
std::cout << "Scalar Execution time: " << dt_scalar << " ms" << std::endl;
105+
std::cout << "Scalar Dot product: " << dpScalar << std::endl;
106+
// Record start time
107+
const double t_simd_0 = hwy::platform::Now();
108+
uint32_t dpSIMD =
109+
HWY_DYNAMIC_DISPATCH(DotProductSIMD)(a.data(), b.data(), count);
110+
// Record stop timer and print time and dot product
111+
const double t_simd_1 = hwy::platform::Now();
112+
const double dt_simd = 1000.0 * (t_simd_1 - t_simd_0);
113+
std::cout << "SIMD Execution time: " << dt_simd << " ms" << std::endl;
114+
std::cout << "SIMD Dot product: " << dpSIMD << std::endl;
115+
return 0;
116+
}
117+
} // namespace hwy
118+
119+
int main() { return hwy::Run(); }
120+
#endif // HWY_ONCE

0 commit comments

Comments
 (0)