@@ -1768,6 +1768,48 @@ pub fn broadcast<'ctx>(
17681768 . map_err ( |e| Error :: InvalidType { msg : format ! ( "failed to build tt.broadcast: {e}" ) } )
17691769}
17701770
1771+ /// Build a `tt.trans` operation.
1772+ ///
1773+ /// Rearranges the dimensions of a tensor according to a permutation order.
1774+ /// For example, a `tensor<1x2x4xf32>` transposed with `order = [2, 0, 1]`
1775+ /// produces a `tensor<4x1x2xf32>`. This op implements both `tl.trans()` and
1776+ /// `tl.permute()`.
1777+ ///
1778+ /// Traits: `Pure`, `SameOperandsAndResultElementType`.
1779+ ///
1780+ /// # Arguments
1781+ /// * `src` – source tensor to transpose.
1782+ /// * `order` – permutation of dimension indices (length == tensor rank).
1783+ /// * `result_ty` – result tensor type (same element type, dimensions permuted
1784+ /// according to `order`).
1785+ ///
1786+ /// # Example
1787+ ///
1788+ /// ```text
1789+ /// // Swap the two dimensions of a 2-D tensor:
1790+ /// %1 = tt.trans %src {order = array<i32: 1, 0>} : tensor<4x8xf32> -> tensor<8x4xf32>
1791+ /// ```
1792+ ///
1793+ /// Assembly format (from TableGen):
1794+ /// ```text
1795+ /// $src attr-dict `:` type($src) `->` type($result)
1796+ /// ```
1797+ pub fn trans < ' ctx > (
1798+ context : & ' ctx Context ,
1799+ location : Location < ' ctx > ,
1800+ src : Value < ' ctx , ' _ > ,
1801+ order : & [ i32 ] ,
1802+ result_ty : Type < ' ctx > ,
1803+ ) -> Result < Operation < ' ctx > , Error > {
1804+ let order_attr = DenseI32ArrayAttribute :: new ( context, order) ;
1805+ OperationBuilder :: new ( "tt.trans" , location)
1806+ . add_operands ( & [ src] )
1807+ . add_attributes ( & [ ( Identifier :: new ( context, "order" ) , Attribute :: from ( order_attr) ) ] )
1808+ . add_results ( & [ result_ty] )
1809+ . build ( )
1810+ . map_err ( |e| Error :: InvalidType { msg : format ! ( "failed to build tt.trans: {e}" ) } )
1811+ }
1812+
17711813/// Build a `tt.bitcast` operation.
17721814///
17731815/// Reinterprets the bits of `src` as `result_ty` without any conversion.
@@ -6149,6 +6191,110 @@ mod tests {
61496191 assert ! ( output. contains( "tensor<2x32x4xf32>" ) , "missing result tensor type:\n {output}" ) ;
61506192 }
61516193
6194+ /// Verify that `trans` emits the correct `tt.trans` IR for a 2-D swap.
6195+ ///
6196+ /// Transposes `tensor<4x8xf32>` with order `[1, 0]` to `tensor<8x4xf32>`.
6197+ ///
6198+ /// Expected assembly fragment:
6199+ /// ```text
6200+ /// %0 = tt.trans %arg0 {order = array<i32: 1, 0>} : tensor<4x8xf32> -> tensor<8x4xf32>
6201+ /// ```
6202+ #[ test]
6203+ fn test_trans_2d ( ) {
6204+ let context = create_test_context ( ) ;
6205+ load_triton_dialect ( & context) ;
6206+
6207+ let location = Location :: unknown ( & context) ;
6208+ let module = Module :: new ( location) ;
6209+
6210+ let f32_type = melior:: ir:: Type :: float32 ( & context) ;
6211+ let src_ty: Type = tensor_type ( & [ 4 , 8 ] , f32_type) . into ( ) ;
6212+ let result_ty: Type = tensor_type ( & [ 8 , 4 ] , f32_type) . into ( ) ;
6213+
6214+ let func_op = create_func (
6215+ & context,
6216+ location,
6217+ "test_trans_2d" ,
6218+ "public" ,
6219+ & [ src_ty] ,
6220+ & [ result_ty] ,
6221+ 0 ,
6222+ )
6223+ . unwrap ( ) ;
6224+
6225+ let block = Block :: new ( & [ ( src_ty, location) ] ) ;
6226+ let src: Value = block. argument ( 0 ) . unwrap ( ) . into ( ) ;
6227+
6228+ let trans_op: Operation < ' _ > =
6229+ super :: trans ( & context, location, src, & [ 1 , 0 ] , result_ty) . unwrap ( ) ;
6230+ let result_val: Value = trans_op. result ( 0 ) . unwrap ( ) . into ( ) ;
6231+ let ret_op = ReturnOperation :: builder ( & context, location) . srcs ( & [ result_val] ) . build ( ) ;
6232+
6233+ block. append_operation ( trans_op) ;
6234+ block. append_operation ( ret_op. into ( ) ) ;
6235+ func_op. body ( ) . unwrap ( ) . append_block ( block) ;
6236+ module. body ( ) . append_operation ( func_op. into ( ) ) ;
6237+
6238+ let output = module. as_operation ( ) . to_string ( ) ;
6239+
6240+ assert ! ( output. contains( "tt.trans" ) , "missing op mnemonic:\n {output}" ) ;
6241+ assert ! ( output. contains( "tensor<4x8xf32>" ) , "missing src tensor type:\n {output}" ) ;
6242+ assert ! ( output. contains( "tensor<8x4xf32>" ) , "missing result tensor type:\n {output}" ) ;
6243+ assert ! ( output. contains( "order" ) , "missing order attribute:\n {output}" ) ;
6244+ }
6245+
6246+ /// Verify that `trans` emits the correct `tt.trans` IR for a 3-D permutation.
6247+ ///
6248+ /// Permutes `tensor<1x2x4xf32>` with order `[2, 0, 1]` to `tensor<4x1x2xf32>`.
6249+ ///
6250+ /// Expected assembly fragment:
6251+ /// ```text
6252+ /// %0 = tt.trans %arg0 {order = array<i32: 2, 0, 1>} : tensor<1x2x4xf32> -> tensor<4x1x2xf32>
6253+ /// ```
6254+ #[ test]
6255+ fn test_trans_3d_permute ( ) {
6256+ let context = create_test_context ( ) ;
6257+ load_triton_dialect ( & context) ;
6258+
6259+ let location = Location :: unknown ( & context) ;
6260+ let module = Module :: new ( location) ;
6261+
6262+ let f32_type = melior:: ir:: Type :: float32 ( & context) ;
6263+ let src_ty: Type = tensor_type ( & [ 1 , 2 , 4 ] , f32_type) . into ( ) ;
6264+ let result_ty: Type = tensor_type ( & [ 4 , 1 , 2 ] , f32_type) . into ( ) ;
6265+
6266+ let func_op = create_func (
6267+ & context,
6268+ location,
6269+ "test_trans_3d_permute" ,
6270+ "public" ,
6271+ & [ src_ty] ,
6272+ & [ result_ty] ,
6273+ 0 ,
6274+ )
6275+ . unwrap ( ) ;
6276+
6277+ let block = Block :: new ( & [ ( src_ty, location) ] ) ;
6278+ let src: Value = block. argument ( 0 ) . unwrap ( ) . into ( ) ;
6279+
6280+ let trans_op: Operation < ' _ > =
6281+ super :: trans ( & context, location, src, & [ 2 , 0 , 1 ] , result_ty) . unwrap ( ) ;
6282+ let result_val: Value = trans_op. result ( 0 ) . unwrap ( ) . into ( ) ;
6283+ let ret_op = ReturnOperation :: builder ( & context, location) . srcs ( & [ result_val] ) . build ( ) ;
6284+
6285+ block. append_operation ( trans_op) ;
6286+ block. append_operation ( ret_op. into ( ) ) ;
6287+ func_op. body ( ) . unwrap ( ) . append_block ( block) ;
6288+ module. body ( ) . append_operation ( func_op. into ( ) ) ;
6289+
6290+ let output = module. as_operation ( ) . to_string ( ) ;
6291+
6292+ assert ! ( output. contains( "tt.trans" ) , "missing op mnemonic:\n {output}" ) ;
6293+ assert ! ( output. contains( "tensor<1x2x4xf32>" ) , "missing src tensor type:\n {output}" ) ;
6294+ assert ! ( output. contains( "tensor<4x1x2xf32>" ) , "missing result tensor type:\n {output}" ) ;
6295+ assert ! ( output. contains( "order" ) , "missing order attribute:\n {output}" ) ;
6296+ }
6297+
61526298 /// Verify that `bitcast` emits the correct `tt.bitcast` IR for a scalar cast.
61536299 ///
61546300 /// Casts `f32` to `i32` (same bitwidth, scalar).
0 commit comments