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