@@ -4803,6 +4803,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
48034803 Op :: ConstantFalse | Op :: SpecConstantFalse => {
48044804 self . parse_bool_constant ( inst, false , & mut module)
48054805 }
4806+ Op :: SpecConstantOp => self . parse_spec_constant_op ( inst, & mut module) ,
48064807 Op :: Variable => self . parse_global_variable ( inst, & mut module) ,
48074808 Op :: Function => {
48084809 self . switch ( ModuleState :: Function , inst. op ) ?;
@@ -5899,6 +5900,296 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
58995900 self . insert_parsed_constant ( module, id, type_id, ty, init, span)
59005901 }
59015902
5903+ fn parse_spec_constant_op (
5904+ & mut self ,
5905+ inst : Instruction ,
5906+ module : & mut crate :: Module ,
5907+ ) -> Result < ( ) , Error > {
5908+ use spirv:: Op ;
5909+
5910+ let start = self . data_offset ;
5911+ self . switch ( ModuleState :: Type , inst. op ) ?;
5912+ inst. expect_at_least ( 4 ) ?;
5913+
5914+ let result_type_id = self . next ( ) ?;
5915+ let result_id = self . next ( ) ?;
5916+ let opcode_word = self . next ( ) ?;
5917+
5918+ let type_lookup = self . lookup_type . lookup ( result_type_id) ?;
5919+ let ty = type_lookup. handle ;
5920+ let span = self . span_from_with_op ( start) ;
5921+
5922+ let opcode = Op :: from_u32 ( opcode_word) . ok_or ( Error :: UnsupportedInstruction (
5923+ self . state ,
5924+ Op :: SpecConstantOp ,
5925+ ) ) ?;
5926+
5927+ let mut get_const_expr =
5928+ |frontend : & Self , const_id : spirv:: Word | -> Result < Handle < crate :: Expression > , Error > {
5929+ let lookup = frontend. lookup_constant . lookup ( const_id) ?;
5930+ match lookup. inner {
5931+ // Wrap regular constants in overrides to avoid creating Expression::Constant
5932+ // nodes, which would mark the entire expression tree as Const and fail
5933+ // validation for complex operations (Binary, As, Math) in override
5934+ // initializers.
5935+ //
5936+ // The downside is, that unused intermediate constants will get created, which
5937+ // I would like to avoid.
5938+ Constant :: Constant ( const_handle) => {
5939+ let const_init = module. constants [ const_handle] . init ;
5940+ let const_ty = module. constants [ const_handle] . ty ;
5941+ let wrapper_override = crate :: Override {
5942+ name : Some ( format ! ( "_spec_const_op_const_{const_id}" ) ) ,
5943+ id : None ,
5944+ ty : const_ty,
5945+ init : Some ( const_init) ,
5946+ } ;
5947+ let override_handle = module. overrides . append ( wrapper_override, span) ;
5948+ Ok ( module
5949+ . global_expressions
5950+ . append ( crate :: Expression :: Override ( override_handle) , span) )
5951+ }
5952+ Constant :: Override ( _) => Ok ( module
5953+ . global_expressions
5954+ . append ( lookup. inner . to_expr ( ) , span) ) ,
5955+ }
5956+ } ;
5957+
5958+ let init = match opcode {
5959+ Op :: SConvert | Op :: UConvert | Op :: FConvert => {
5960+ let value_id = self . next ( ) ?;
5961+ let value_expr = get_const_expr ( self , value_id) ?;
5962+
5963+ let scalar = match module. types [ ty] . inner {
5964+ crate :: TypeInner :: Scalar ( scalar)
5965+ | crate :: TypeInner :: Vector { scalar, .. }
5966+ | crate :: TypeInner :: Matrix { scalar, .. } => scalar,
5967+ _ => return Err ( Error :: InvalidAsType ( ty) ) ,
5968+ } ;
5969+
5970+ module. global_expressions . append (
5971+ crate :: Expression :: As {
5972+ expr : value_expr,
5973+ kind : scalar. kind ,
5974+ convert : Some ( scalar. width ) ,
5975+ } ,
5976+ span,
5977+ )
5978+ }
5979+
5980+ Op :: SNegate | Op :: Not | Op :: LogicalNot => {
5981+ let value_id = self . next ( ) ?;
5982+ let value_expr = get_const_expr ( self , value_id) ?;
5983+
5984+ let op = match opcode {
5985+ Op :: SNegate => crate :: UnaryOperator :: Negate ,
5986+ Op :: Not => crate :: UnaryOperator :: BitwiseNot ,
5987+ Op :: LogicalNot => crate :: UnaryOperator :: LogicalNot ,
5988+ _ => unreachable ! ( ) ,
5989+ } ;
5990+
5991+ module. global_expressions . append (
5992+ crate :: Expression :: Unary {
5993+ op,
5994+ expr : value_expr,
5995+ } ,
5996+ span,
5997+ )
5998+ }
5999+
6000+ Op :: IAdd
6001+ | Op :: ISub
6002+ | Op :: IMul
6003+ | Op :: UDiv
6004+ | Op :: SDiv
6005+ | Op :: SRem
6006+ | Op :: UMod
6007+ | Op :: BitwiseOr
6008+ | Op :: BitwiseXor
6009+ | Op :: BitwiseAnd
6010+ | Op :: ShiftLeftLogical
6011+ | Op :: ShiftRightLogical
6012+ | Op :: ShiftRightArithmetic
6013+ | Op :: LogicalOr
6014+ | Op :: LogicalAnd
6015+ | Op :: LogicalEqual
6016+ | Op :: LogicalNotEqual
6017+ | Op :: IEqual
6018+ | Op :: INotEqual
6019+ | Op :: ULessThan
6020+ | Op :: SLessThan
6021+ | Op :: UGreaterThan
6022+ | Op :: SGreaterThan
6023+ | Op :: ULessThanEqual
6024+ | Op :: SLessThanEqual
6025+ | Op :: UGreaterThanEqual
6026+ | Op :: SGreaterThanEqual => {
6027+ let left_id = self . next ( ) ?;
6028+ let right_id = self . next ( ) ?;
6029+ let left_expr = get_const_expr ( self , left_id) ?;
6030+ let right_expr = get_const_expr ( self , right_id) ?;
6031+
6032+ let op = match opcode {
6033+ Op :: IAdd => crate :: BinaryOperator :: Add ,
6034+ Op :: ISub => crate :: BinaryOperator :: Subtract ,
6035+ Op :: IMul => crate :: BinaryOperator :: Multiply ,
6036+ Op :: UDiv | Op :: SDiv => crate :: BinaryOperator :: Divide ,
6037+ Op :: SRem | Op :: UMod => crate :: BinaryOperator :: Modulo ,
6038+ Op :: BitwiseOr => crate :: BinaryOperator :: InclusiveOr ,
6039+ Op :: BitwiseXor => crate :: BinaryOperator :: ExclusiveOr ,
6040+ Op :: BitwiseAnd => crate :: BinaryOperator :: And ,
6041+ Op :: ShiftLeftLogical => crate :: BinaryOperator :: ShiftLeft ,
6042+ Op :: ShiftRightLogical | Op :: ShiftRightArithmetic => {
6043+ crate :: BinaryOperator :: ShiftRight
6044+ }
6045+ Op :: LogicalOr => crate :: BinaryOperator :: LogicalOr ,
6046+ Op :: LogicalAnd => crate :: BinaryOperator :: LogicalAnd ,
6047+ Op :: LogicalEqual => crate :: BinaryOperator :: Equal ,
6048+ Op :: LogicalNotEqual => crate :: BinaryOperator :: NotEqual ,
6049+ Op :: IEqual => crate :: BinaryOperator :: Equal ,
6050+ Op :: INotEqual => crate :: BinaryOperator :: NotEqual ,
6051+ Op :: ULessThan | Op :: SLessThan => crate :: BinaryOperator :: Less ,
6052+ Op :: UGreaterThan | Op :: SGreaterThan => crate :: BinaryOperator :: Greater ,
6053+ Op :: ULessThanEqual | Op :: SLessThanEqual => crate :: BinaryOperator :: LessEqual ,
6054+ Op :: UGreaterThanEqual | Op :: SGreaterThanEqual => {
6055+ crate :: BinaryOperator :: GreaterEqual
6056+ }
6057+ _ => unreachable ! ( ) ,
6058+ } ;
6059+
6060+ module. global_expressions . append (
6061+ crate :: Expression :: Binary {
6062+ op,
6063+ left : left_expr,
6064+ right : right_expr,
6065+ } ,
6066+ span,
6067+ )
6068+ }
6069+
6070+ Op :: SMod => {
6071+ // x - y * int(floor(float(x) / float(y)))
6072+
6073+ let left_id = self . next ( ) ?;
6074+ let right_id = self . next ( ) ?;
6075+ let left = get_const_expr ( self , left_id) ?;
6076+ let right = get_const_expr ( self , right_id) ?;
6077+
6078+ let scalar = match module. types [ ty] . inner {
6079+ crate :: TypeInner :: Scalar ( scalar) => scalar,
6080+ crate :: TypeInner :: Vector { scalar, .. } => scalar,
6081+ _ => return Err ( Error :: InvalidAsType ( ty) ) ,
6082+ } ;
6083+
6084+ let left_cast = module. global_expressions . append (
6085+ crate :: Expression :: As {
6086+ expr : left,
6087+ kind : crate :: ScalarKind :: Float ,
6088+ convert : Some ( scalar. width ) ,
6089+ } ,
6090+ span,
6091+ ) ;
6092+ let right_cast = module. global_expressions . append (
6093+ crate :: Expression :: As {
6094+ expr : right,
6095+ kind : crate :: ScalarKind :: Float ,
6096+ convert : Some ( scalar. width ) ,
6097+ } ,
6098+ span,
6099+ ) ;
6100+ let div = module. global_expressions . append (
6101+ crate :: Expression :: Binary {
6102+ op : crate :: BinaryOperator :: Divide ,
6103+ left : left_cast,
6104+ right : right_cast,
6105+ } ,
6106+ span,
6107+ ) ;
6108+ let floor = module. global_expressions . append (
6109+ crate :: Expression :: Math {
6110+ fun : crate :: MathFunction :: Floor ,
6111+ arg : div,
6112+ arg1 : None ,
6113+ arg2 : None ,
6114+ arg3 : None ,
6115+ } ,
6116+ span,
6117+ ) ;
6118+ let cast = module. global_expressions . append (
6119+ crate :: Expression :: As {
6120+ expr : floor,
6121+ kind : scalar. kind ,
6122+ convert : Some ( scalar. width ) ,
6123+ } ,
6124+ span,
6125+ ) ;
6126+ let mult = module. global_expressions . append (
6127+ crate :: Expression :: Binary {
6128+ op : crate :: BinaryOperator :: Multiply ,
6129+ left : cast,
6130+ right,
6131+ } ,
6132+ span,
6133+ ) ;
6134+ module. global_expressions . append (
6135+ crate :: Expression :: Binary {
6136+ op : crate :: BinaryOperator :: Subtract ,
6137+ left,
6138+ right : mult,
6139+ } ,
6140+ span,
6141+ )
6142+ }
6143+
6144+ Op :: Select => {
6145+ let condition_id = self . next ( ) ?;
6146+ let o1_id = self . next ( ) ?;
6147+ let o2_id = self . next ( ) ?;
6148+
6149+ let cond = get_const_expr ( self , condition_id) ?;
6150+ let o1 = get_const_expr ( self , o1_id) ?;
6151+ let o2 = get_const_expr ( self , o2_id) ?;
6152+
6153+ module. global_expressions . append (
6154+ crate :: Expression :: Select {
6155+ condition : cond,
6156+ accept : o1,
6157+ reject : o2,
6158+ } ,
6159+ span,
6160+ )
6161+ }
6162+
6163+ Op :: VectorShuffle | Op :: CompositeExtract | Op :: CompositeInsert | Op :: QuantizeToF16 => {
6164+ // Nothing stops us from implementing these cases in general.
6165+ // I just couldn't get them to work properly.
6166+ return Err ( Error :: UnsupportedSpecConstantOp ( opcode) ) ;
6167+ }
6168+
6169+ _ => return Err ( Error :: InvalidSpecConstantOp ( opcode) ) ,
6170+ } ;
6171+
6172+ // IMPORTANT: Overrides must have either a name or an id to be processed correctly
6173+ // by process_overrides(). OpSpecConstantOp results don't have a SpecId (they're
6174+ // not user-overridable), so we assign them a name based on the result_id.
6175+ let op_override = crate :: Override {
6176+ name : Some ( format ! ( "_spec_const_op_{result_id}" ) ) ,
6177+ id : None ,
6178+ ty,
6179+ init : Some ( init) ,
6180+ } ;
6181+
6182+ self . lookup_constant . insert (
6183+ result_id,
6184+ LookupConstant {
6185+ inner : Constant :: Override ( module. overrides . append ( op_override, span) ) ,
6186+ type_id : result_type_id,
6187+ } ,
6188+ ) ;
6189+
6190+ Ok ( ( ) )
6191+ }
6192+
59026193 fn insert_parsed_constant (
59036194 & mut self ,
59046195 module : & mut crate :: Module ,
0 commit comments