Skip to content

Commit 1d2bb20

Browse files
committed
Add runtime tests for bf16 <-> f32 conversion
Signed-off-by: sunteng <steng2009@163.com>
1 parent a1e5b64 commit 1d2bb20

1 file changed

Lines changed: 118 additions & 1 deletion

File tree

cutile/tests/type_conversion_ops.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
use cutile;
6+
use cutile::{api::*, tensor::*, tile_kernel::*};
67
use cutile_compiler::compiler::{CUDATileFunctionCompiler, CUDATileModules};
78
use cutile_compiler::cuda_tile_runtime_utils::get_gpu_name;
9+
use half::bf16;
10+
use std::sync::Arc;
811

912
mod common;
1013

@@ -46,7 +49,6 @@ mod type_conversion_ops_module {
4649
output.store(extended);
4750
}
4851

49-
5052
#[cutile::entry()]
5153
fn bf16_conversion_kernel<const S: [i32; 1]>(output: &mut Tensor<bf16, S>) {
5254
// Exercises bf16 <-> f32 tile conversion lowering
@@ -55,9 +57,34 @@ mod type_conversion_ops_module {
5557
let downcast: Tile<bf16, S> = convert_tile(upcast);
5658
output.store(downcast);
5759
}
60+
61+
#[cutile::entry()]
62+
fn bf16_to_f32_conversion_kernel<const S: [i32; 1]>(
63+
output: &mut Tensor<f32, S>,
64+
input: &Tensor<bf16, { [-1] }>,
65+
) {
66+
// Runtime test kernel for bf16 -> f32 tile conversion
67+
let x: Tile<bf16, S> = load_tile_like_1d(input, output);
68+
let y: Tile<f32, S> = convert_tile(x);
69+
output.store(y);
70+
}
71+
72+
#[cutile::entry()]
73+
fn f32_to_bf16_conversion_kernel<const S: [i32; 1]>(
74+
output: &mut Tensor<bf16, S>,
75+
input: &Tensor<f32, { [-1] }>,
76+
) {
77+
// Runtime test kernel for f32 -> bf16 tile conversion
78+
let x: Tile<f32, S> = load_tile_like_1d(input, output);
79+
let y: Tile<bf16, S> = convert_tile(x);
80+
output.store(y);
81+
}
5882
}
5983

6084
use type_conversion_ops_module::_module_asts;
85+
use type_conversion_ops_module::bf16_conversion_kernel_sync;
86+
use type_conversion_ops_module::bf16_to_f32_conversion_kernel_sync;
87+
use type_conversion_ops_module::f32_to_bf16_conversion_kernel_sync;
6188

6289
#[test]
6390
fn compile_conversion_ops() -> () {
@@ -208,3 +235,93 @@ fn compile_bf16_conversion() -> () {
208235
);
209236
});
210237
}
238+
239+
#[test]
240+
fn execute_bf16_f32_roundtrip() -> () {
241+
common::with_test_stack(|| {
242+
let input_host = Arc::new(vec![
243+
bf16::from_f32(-3.5),
244+
bf16::from_f32(-1.0),
245+
bf16::from_f32(-0.0),
246+
bf16::from_f32(0.0),
247+
bf16::from_f32(0.125),
248+
bf16::from_f32(0.1),
249+
bf16::from_f32(1.1),
250+
bf16::from_f32(42.0),
251+
]);
252+
253+
let input: Tensor<bf16> = copy_host_vec_to_device(&input_host)
254+
.sync()
255+
.expect("Failed.");
256+
let (result,) = bf16_conversion_kernel_sync(input.partition([4]))
257+
.sync()
258+
.expect("Failed.");
259+
260+
let result_host: Vec<bf16> = result.unpartition().to_host_vec().sync().expect("Failed.");
261+
262+
// This kernel performs bf16 -> f32 -> bf16, so bf16 bit patterns should round-trip.
263+
assert_eq!(
264+
result_host, *input_host,
265+
"Expected bf16 values to round-trip through f32 conversion"
266+
);
267+
});
268+
}
269+
270+
#[test]
271+
fn execute_bf16_to_f32_conversion() -> () {
272+
common::with_test_stack(|| {
273+
let input_host = Arc::new(vec![
274+
bf16::from_f32(-3.5),
275+
bf16::from_f32(-1.0),
276+
bf16::from_f32(-0.0),
277+
bf16::from_f32(0.0),
278+
bf16::from_f32(0.125),
279+
bf16::from_f32(0.1),
280+
bf16::from_f32(1.1),
281+
bf16::from_f32(42.0),
282+
]);
283+
284+
let input: Tensor<bf16> = copy_host_vec_to_device(&input_host)
285+
.sync()
286+
.expect("Failed.");
287+
let input = Arc::new(input);
288+
let output: Tensor<f32> = zeros([input_host.len()]).sync().expect("Failed.");
289+
290+
let (result, _) = bf16_to_f32_conversion_kernel_sync(output.partition([4]), input)
291+
.sync()
292+
.expect("Failed.");
293+
294+
let result_host: Vec<f32> = result.unpartition().to_host_vec().sync().expect("Failed.");
295+
let expected: Vec<f32> = input_host.iter().map(|x| x.to_f32()).collect();
296+
297+
assert_eq!(
298+
result_host, expected,
299+
"Expected bf16->f32 conversion output to match host-side bf16::to_f32"
300+
);
301+
});
302+
}
303+
304+
#[test]
305+
fn execute_f32_to_bf16_conversion() -> () {
306+
common::with_test_stack(|| {
307+
let input_host = Arc::new(vec![-3.5f32, -1.0, -0.0, 0.0, 0.125, 0.1, 1.1, 42.0]);
308+
309+
let input: Tensor<f32> = copy_host_vec_to_device(&input_host)
310+
.sync()
311+
.expect("Failed.");
312+
let input = Arc::new(input);
313+
let output: Tensor<bf16> = zeros([input_host.len()]).sync().expect("Failed.");
314+
315+
let (result, _) = f32_to_bf16_conversion_kernel_sync(output.partition([4]), input)
316+
.sync()
317+
.expect("Failed.");
318+
319+
let result_host: Vec<bf16> = result.unpartition().to_host_vec().sync().expect("Failed.");
320+
let expected: Vec<bf16> = input_host.iter().map(|x| bf16::from_f32(*x)).collect();
321+
322+
assert_eq!(
323+
result_host, expected,
324+
"Expected f32->bf16 conversion output to match host-side bf16::from_f32"
325+
);
326+
});
327+
}

0 commit comments

Comments
 (0)