33 * SPDX-License-Identifier: Apache-2.0
44 */
55use cutile;
6+ use cutile:: { api:: * , tensor:: * , tile_kernel:: * } ;
67use cutile_compiler:: compiler:: { CUDATileFunctionCompiler , CUDATileModules } ;
78use cutile_compiler:: cuda_tile_runtime_utils:: get_gpu_name;
9+ use half:: bf16;
10+ use std:: sync:: Arc ;
811
912mod 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
6084use 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]
6390fn 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