@@ -8,15 +8,15 @@ use crate::translate::{
88use crate :: { BuiltinFunctionSignatures , TRAP_INTERNAL_ASSERT } ;
99use cranelift_codegen:: cursor:: FuncCursor ;
1010use cranelift_codegen:: ir:: condcodes:: { FloatCC , IntCC } ;
11- use cranelift_codegen:: ir:: immediates:: { Imm64 , Offset32 } ;
11+ use cranelift_codegen:: ir:: immediates:: { Imm64 , Offset32 , V128Imm } ;
1212use cranelift_codegen:: ir:: pcc:: Fact ;
1313use cranelift_codegen:: ir:: types:: * ;
1414use cranelift_codegen:: ir:: { self , types} ;
1515use cranelift_codegen:: ir:: { ArgumentPurpose , ConstantData , Function , InstBuilder , MemFlags } ;
1616use cranelift_codegen:: isa:: { TargetFrontendConfig , TargetIsa } ;
1717use cranelift_entity:: { EntityRef , PrimaryMap , SecondaryMap } ;
18- use cranelift_frontend:: FunctionBuilder ;
1918use cranelift_frontend:: Variable ;
19+ use cranelift_frontend:: { FuncInstBuilder , FunctionBuilder } ;
2020use smallvec:: SmallVec ;
2121use std:: mem;
2222use wasmparser:: { Operator , WasmFeatures } ;
@@ -3319,103 +3319,193 @@ impl FuncEnvironment<'_> {
33193319 let _ = ( builder, num_pages, mem_index) ;
33203320 }
33213321
3322- pub fn ceil_f32 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3323- // If the ISA has rounding instructions, let Cranelift use them. But if
3324- // not, lower to a libcall here, rather than having Cranelift do it. We
3325- // can pass our libcall the vmctx pointer, which we use for stack
3326- // overflow checking.
3322+ /// If the ISA has rounding instructions, let Cranelift use them. But if
3323+ /// not, lower to a libcall here, rather than having Cranelift do it. We
3324+ /// can pass our libcall the vmctx pointer, which we use for stack
3325+ /// overflow checking.
3326+ ///
3327+ /// This helper is generic for all rounding instructions below, both for
3328+ /// scalar and simd types. The `clif_round` argument is the CLIF-level
3329+ /// rounding instruction to use if the ISA has the instruction, and the
3330+ /// `round_builtin` helper is used to determine which element-level
3331+ /// rounding operation builtin is used. Note that this handles the case
3332+ /// when `value` is a vector by doing an element-wise libcall invocation.
3333+ fn isa_round (
3334+ & mut self ,
3335+ builder : & mut FunctionBuilder ,
3336+ value : ir:: Value ,
3337+ clif_round : fn ( FuncInstBuilder < ' _ , ' _ > , ir:: Value ) -> ir:: Value ,
3338+ round_builtin : fn ( & mut BuiltinFunctions , & mut Function ) -> ir:: FuncRef ,
3339+ ) -> ir:: Value {
33273340 if self . isa . has_round ( ) {
3328- builder. ins ( ) . ceil ( value)
3329- } else {
3330- let ceil = self . builtin_functions . ceil_f32 ( builder. func ) ;
3331- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3332- let call = builder. ins ( ) . call ( ceil, & [ vmctx, value] ) ;
3341+ return clif_round ( builder. ins ( ) , value) ;
3342+ }
3343+
3344+ let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3345+ let round = round_builtin ( & mut self . builtin_functions , builder. func ) ;
3346+ let round_one = |builder : & mut FunctionBuilder , value : ir:: Value | {
3347+ let call = builder. ins ( ) . call ( round, & [ vmctx, value] ) ;
33333348 * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3349+ } ;
3350+
3351+ let ty = builder. func . dfg . value_type ( value) ;
3352+ if !ty. is_vector ( ) {
3353+ return round_one ( builder, value) ;
3354+ }
3355+
3356+ assert_eq ! ( ty. bits( ) , 128 ) ;
3357+ let zero = builder. func . dfg . constants . insert ( V128Imm ( [ 0 ; 16 ] ) . into ( ) ) ;
3358+ let mut result = builder. ins ( ) . vconst ( ty, zero) ;
3359+ for i in 0 ..u8:: try_from ( ty. lane_count ( ) ) . unwrap ( ) {
3360+ let element = builder. ins ( ) . extractlane ( value, i) ;
3361+ let element_rounded = round_one ( builder, element) ;
3362+ result = builder. ins ( ) . insertlane ( result, element_rounded, i) ;
33343363 }
3364+ result
3365+ }
3366+
3367+ pub fn ceil_f32 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3368+ self . isa_round (
3369+ builder,
3370+ value,
3371+ |ins, val| ins. ceil ( val) ,
3372+ BuiltinFunctions :: ceil_f32,
3373+ )
33353374 }
33363375
33373376 pub fn ceil_f64 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3338- // See the comments in `ceil_f32` about libcalls.
3339- if self . isa . has_round ( ) {
3340- builder. ins ( ) . ceil ( value)
3341- } else {
3342- let ceil = self . builtin_functions . ceil_f64 ( builder. func ) ;
3343- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3344- let call = builder. ins ( ) . call ( ceil, & [ vmctx, value] ) ;
3345- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3346- }
3377+ self . isa_round (
3378+ builder,
3379+ value,
3380+ |ins, val| ins. ceil ( val) ,
3381+ BuiltinFunctions :: ceil_f64,
3382+ )
3383+ }
3384+
3385+ pub fn ceil_f32x4 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3386+ self . isa_round (
3387+ builder,
3388+ value,
3389+ |ins, val| ins. ceil ( val) ,
3390+ BuiltinFunctions :: ceil_f32,
3391+ )
3392+ }
3393+
3394+ pub fn ceil_f64x2 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3395+ self . isa_round (
3396+ builder,
3397+ value,
3398+ |ins, val| ins. ceil ( val) ,
3399+ BuiltinFunctions :: ceil_f64,
3400+ )
33473401 }
33483402
33493403 pub fn floor_f32 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3350- // See the comments in `ceil_f32` about libcalls.
3351- if self . isa . has_round ( ) {
3352- builder. ins ( ) . floor ( value)
3353- } else {
3354- let floor = self . builtin_functions . floor_f32 ( builder. func ) ;
3355- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3356- let call = builder. ins ( ) . call ( floor, & [ vmctx, value] ) ;
3357- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3358- }
3404+ self . isa_round (
3405+ builder,
3406+ value,
3407+ |ins, val| ins. floor ( val) ,
3408+ BuiltinFunctions :: floor_f32,
3409+ )
33593410 }
33603411
33613412 pub fn floor_f64 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3362- // See the comments in `ceil_f32` about libcalls.
3363- if self . isa . has_round ( ) {
3364- builder. ins ( ) . floor ( value)
3365- } else {
3366- let floor = self . builtin_functions . floor_f64 ( builder. func ) ;
3367- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3368- let call = builder. ins ( ) . call ( floor, & [ vmctx, value] ) ;
3369- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3370- }
3413+ self . isa_round (
3414+ builder,
3415+ value,
3416+ |ins, val| ins. floor ( val) ,
3417+ BuiltinFunctions :: floor_f64,
3418+ )
3419+ }
3420+
3421+ pub fn floor_f32x4 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3422+ self . isa_round (
3423+ builder,
3424+ value,
3425+ |ins, val| ins. floor ( val) ,
3426+ BuiltinFunctions :: floor_f32,
3427+ )
3428+ }
3429+
3430+ pub fn floor_f64x2 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3431+ self . isa_round (
3432+ builder,
3433+ value,
3434+ |ins, val| ins. floor ( val) ,
3435+ BuiltinFunctions :: floor_f64,
3436+ )
33713437 }
33723438
33733439 pub fn trunc_f32 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3374- // See the comments in `ceil_f32` about libcalls.
3375- if self . isa . has_round ( ) {
3376- builder. ins ( ) . trunc ( value)
3377- } else {
3378- let trunc = self . builtin_functions . trunc_f32 ( builder. func ) ;
3379- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3380- let call = builder. ins ( ) . call ( trunc, & [ vmctx, value] ) ;
3381- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3382- }
3440+ self . isa_round (
3441+ builder,
3442+ value,
3443+ |ins, val| ins. trunc ( val) ,
3444+ BuiltinFunctions :: trunc_f32,
3445+ )
33833446 }
33843447
33853448 pub fn trunc_f64 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3386- // See the comments in `ceil_f32` about libcalls.
3387- if self . isa . has_round ( ) {
3388- builder. ins ( ) . trunc ( value)
3389- } else {
3390- let trunc = self . builtin_functions . trunc_f64 ( builder. func ) ;
3391- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3392- let call = builder. ins ( ) . call ( trunc, & [ vmctx, value] ) ;
3393- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3394- }
3449+ self . isa_round (
3450+ builder,
3451+ value,
3452+ |ins, val| ins. trunc ( val) ,
3453+ BuiltinFunctions :: trunc_f64,
3454+ )
3455+ }
3456+
3457+ pub fn trunc_f32x4 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3458+ self . isa_round (
3459+ builder,
3460+ value,
3461+ |ins, val| ins. trunc ( val) ,
3462+ BuiltinFunctions :: trunc_f32,
3463+ )
3464+ }
3465+
3466+ pub fn trunc_f64x2 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3467+ self . isa_round (
3468+ builder,
3469+ value,
3470+ |ins, val| ins. trunc ( val) ,
3471+ BuiltinFunctions :: trunc_f64,
3472+ )
33953473 }
33963474
33973475 pub fn nearest_f32 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3398- // See the comments in `ceil_f32` about libcalls.
3399- if self . isa . has_round ( ) {
3400- builder. ins ( ) . nearest ( value)
3401- } else {
3402- let nearest = self . builtin_functions . nearest_f32 ( builder. func ) ;
3403- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3404- let call = builder. ins ( ) . call ( nearest, & [ vmctx, value] ) ;
3405- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3406- }
3476+ self . isa_round (
3477+ builder,
3478+ value,
3479+ |ins, val| ins. nearest ( val) ,
3480+ BuiltinFunctions :: nearest_f32,
3481+ )
34073482 }
34083483
34093484 pub fn nearest_f64 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3410- // See the comments in `ceil_f32` about libcalls.
3411- if self . isa . has_round ( ) {
3412- builder. ins ( ) . nearest ( value)
3413- } else {
3414- let nearest = self . builtin_functions . nearest_f64 ( builder. func ) ;
3415- let vmctx = self . vmctx_val ( & mut builder. cursor ( ) ) ;
3416- let call = builder. ins ( ) . call ( nearest, & [ vmctx, value] ) ;
3417- * builder. func . dfg . inst_results ( call) . first ( ) . unwrap ( )
3418- }
3485+ self . isa_round (
3486+ builder,
3487+ value,
3488+ |ins, val| ins. nearest ( val) ,
3489+ BuiltinFunctions :: nearest_f64,
3490+ )
3491+ }
3492+
3493+ pub fn nearest_f32x4 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3494+ self . isa_round (
3495+ builder,
3496+ value,
3497+ |ins, val| ins. nearest ( val) ,
3498+ BuiltinFunctions :: nearest_f32,
3499+ )
3500+ }
3501+
3502+ pub fn nearest_f64x2 ( & mut self , builder : & mut FunctionBuilder , value : ir:: Value ) -> ir:: Value {
3503+ self . isa_round (
3504+ builder,
3505+ value,
3506+ |ins, val| ins. nearest ( val) ,
3507+ BuiltinFunctions :: nearest_f64,
3508+ )
34193509 }
34203510
34213511 pub fn swizzle (
0 commit comments