diff --git a/src/back/glsl/keywords.rs b/src/back/glsl/keywords.rs index 4ce2142671..e6e78b643a 100644 --- a/src/back/glsl/keywords.rs +++ b/src/back/glsl/keywords.rs @@ -480,4 +480,6 @@ pub const RESERVED_KEYWORDS: &[&str] = &[ // Naga utilities: super::MODF_FUNCTION, super::MODF_STRUCT, + super::FREXP_FUNCTION, + super::FREXP_STRUCT, ]; diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 090e98b2bb..7a42536b3e 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -72,6 +72,8 @@ pub const SUPPORTED_ES_VERSIONS: &[u16] = &[300, 310, 320]; /// of detail for bounds checking in `ImageLoad` const CLAMPED_LOD_SUFFIX: &str = "_clamped_lod"; +pub(crate) const FREXP_FUNCTION: &str = "naga_frexp"; +pub(crate) const FREXP_STRUCT: &str = "naga_frexp_struct"; pub(crate) const MODF_FUNCTION: &str = "naga_modf"; pub(crate) const MODF_STRUCT: &str = "naga_modf_struct"; @@ -623,6 +625,22 @@ impl<'a, W: Write> Writer<'a, W> { )?; } + if self.module.special_types.frexp_result.is_some() { + writeln!( + self.out, + "struct {FREXP_STRUCT} {{ + float fract; + float exp; +}}; + +{FREXP_STRUCT} {FREXP_FUNCTION}(float arg) {{ + float exp; + float fract = modf(arg, exp); + return {MODF_STRUCT}(fract, exp); +}}" + )?; + } + // Write struct types. // // This are always ordered because the IR is structured in a way that @@ -879,7 +897,8 @@ impl<'a, W: Write> Writer<'a, W> { | TypeInner::Sampler { .. } | TypeInner::AccelerationStructure | TypeInner::RayQuery - | TypeInner::ModfResultF32 + | TypeInner::ModfResult + | TypeInner::FrexpResult | TypeInner::BindingArray { .. } => { return Err(Error::Custom(format!("Unable to write type {inner:?}"))) } @@ -905,7 +924,11 @@ impl<'a, W: Write> Writer<'a, W> { } // glsl array has the size separated from the base type TypeInner::Array { base, .. } => self.write_type(base), - TypeInner::ModfResultF32 => { + TypeInner::FrexpResult => { + write!(self.out, "{FREXP_STRUCT}")?; + Ok(()) + } + TypeInner::ModfResult => { write!(self.out, "{MODF_STRUCT}")?; Ok(()) } @@ -2349,7 +2372,10 @@ impl<'a, W: Write> Writer<'a, W> { &self.names[&NameKey::StructMember(ty, index)] )? } - TypeInner::ModfResultF32 => { + TypeInner::FrexpResult => { + write!(self.out, ".{}", if index == 0 { "fract" } else { "exp " })? + } + TypeInner::ModfResult => { write!(self.out, ".{}", if index == 0 { "fract" } else { "whole " })? } ref other => return Err(Error::Custom(format!("Cannot index {other:?}"))), diff --git a/src/back/hlsl/help.rs b/src/back/hlsl/help.rs index 4bffd6e4fe..b4dd4da136 100644 --- a/src/back/hlsl/help.rs +++ b/src/back/hlsl/help.rs @@ -782,6 +782,28 @@ impl<'a, W: Write> super::Writer<'a, W> { } pub(super) fn write_special_functions(&mut self, module: &crate::Module) -> BackendResult { + if module.special_types.frexp_result.is_some() { + let function_name = super::writer::FREXP_FUNCTION; + let struct_name = super::writer::FREXP_STRUCT; + writeln!( + self.out, + "struct {struct_name} {{ + float fract; + float exp; +}}; + +{struct_name} {function_name}(in float arg) {{ + float exp; + float fract = modf(arg, exp); + {struct_name} result; + result.exp = exp; + result.fract = fract; + return result; +}}" + )?; + // Write extra new line + writeln!(self.out)?; + } if module.special_types.modf_result.is_some() { let function_name = super::writer::MODF_FUNCTION; let struct_name = super::writer::MODF_STRUCT; diff --git a/src/back/hlsl/keywords.rs b/src/back/hlsl/keywords.rs index b1169dcf8f..b900c1446e 100644 --- a/src/back/hlsl/keywords.rs +++ b/src/back/hlsl/keywords.rs @@ -815,6 +815,8 @@ pub const RESERVED: &[&str] = &[ "ConstantBuffer", "RayQuery", // Naga utilities + super::writer::FREXP_FUNCTION, + super::writer::FREXP_STRUCT, super::writer::MODF_FUNCTION, super::writer::MODF_STRUCT, ]; diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index dcdf862f5f..b0c7b26a77 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -17,6 +17,8 @@ const SPECIAL_BASE_VERTEX: &str = "base_vertex"; const SPECIAL_BASE_INSTANCE: &str = "base_instance"; const SPECIAL_OTHER: &str = "other"; +pub(crate) const FREXP_FUNCTION: &str = "frexp_modf"; +pub(crate) const FREXP_STRUCT: &str = "frexp_modf_result"; pub(crate) const MODF_FUNCTION: &str = "naga_modf"; pub(crate) const MODF_STRUCT: &str = "naga_modf_result"; @@ -1063,7 +1065,10 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { TypeInner::Array { base, size, .. } | TypeInner::BindingArray { base, size } => { self.write_array_size(module, base, size)?; } - TypeInner::ModfResultF32 => { + TypeInner::FrexpResult => { + write!(self.out, "struct {FREXP_STRUCT}")?; + } + TypeInner::ModfResult => { write!(self.out, "struct {MODF_STRUCT}")?; } _ => return Err(Error::Unimplemented(format!("write_value_type {inner:?}"))), @@ -2284,7 +2289,10 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { &writer.names[&NameKey::StructMember(ty, index)] )? } - TypeInner::ModfResultF32 => write!( + TypeInner::FrexpResult => { + write!(writer.out, ".{}", if index == 0 { "fract" } else { "exp" })? + } + TypeInner::ModfResult => write!( writer.out, ".{}", if index == 0 { "fract" } else { "whole" } diff --git a/src/back/msl/keywords.rs b/src/back/msl/keywords.rs index 606c5bb341..27f86894af 100644 --- a/src/back/msl/keywords.rs +++ b/src/back/msl/keywords.rs @@ -214,6 +214,8 @@ pub const RESERVED: &[&str] = &[ // Naga utilities "DefaultConstructible", "clamped_lod_e", + super::writer::FREXP_FUNCTION, + super::writer::FREXP_STRUCT, super::writer::MODF_FUNCTION, super::writer::MODF_STRUCT, ]; diff --git a/src/back/msl/writer.rs b/src/back/msl/writer.rs index 73ec09d092..785c9fc838 100644 --- a/src/back/msl/writer.rs +++ b/src/back/msl/writer.rs @@ -32,6 +32,8 @@ const RAY_QUERY_FIELD_INTERSECTION: &str = "intersection"; const RAY_QUERY_FIELD_READY: &str = "ready"; const RAY_QUERY_FUN_MAP_INTERSECTION: &str = "_map_intersection_type"; +pub(crate) const FREXP_FUNCTION: &str = "naga_frexp"; +pub(crate) const FREXP_STRUCT: &str = "naga_frexp_result"; pub(crate) const MODF_FUNCTION: &str = "naga_modf"; pub(crate) const MODF_STRUCT: &str = "naga_modf_result"; @@ -146,7 +148,10 @@ impl<'a> Display for TypeContext<'a> { crate::TypeInner::Struct { .. } => { unreachable!() } - crate::TypeInner::ModfResultF32 { .. } => { + crate::TypeInner::FrexpResult { .. } => { + write!(out, "{}", FREXP_STRUCT) + } + crate::TypeInner::ModfResult { .. } => { write!(out, "{}", MODF_STRUCT) } crate::TypeInner::Image { @@ -460,7 +465,8 @@ impl crate::Type { | Ti::Sampler { .. } | Ti::AccelerationStructure | Ti::RayQuery - | Ti::ModfResultF32 + | Ti::FrexpResult + | Ti::ModfResult | Ti::BindingArray { .. } => false, } } @@ -1644,6 +1650,15 @@ impl Writer { write!(self.out, "{NAMESPACE}::{op}")?; self.put_call_parameters(iter::once(argument), context)?; } + crate::Expression::Math { + fun: crate::MathFunction::Frexp, + arg, + .. + } => { + write!(self.out, "{FREXP_FUNCTION}(")?; + self.put_expression(arg, context, false)?; + write!(self.out, ")")?; + } crate::Expression::Math { fun: crate::MathFunction::Modf, arg, @@ -2037,7 +2052,8 @@ impl Writer { } match *base_inner { crate::TypeInner::Struct { .. } - | crate::TypeInner::ModfResultF32 { .. } => (base, None), + | crate::TypeInner::FrexpResult + | crate::TypeInner::ModfResult { .. } => (base, None), _ => (base, Some(index::GuardedIndex::Known(index))), } } @@ -2152,7 +2168,7 @@ impl Writer { write!(self.out, ".{}", back::COMPONENTS[index as usize])?; } } - crate::TypeInner::ModfResultF32 => { + crate::TypeInner::ModfResult => { self.put_access_chain(base, policy, context)?; write!(self.out, ".{}", if index == 0 { "fract" } else { "whole" })?; } diff --git a/src/back/spv/block.rs b/src/back/spv/block.rs index 5c76688b34..d6448d3f07 100644 --- a/src/back/spv/block.rs +++ b/src/back/spv/block.rs @@ -396,7 +396,7 @@ impl<'w> BlockContext<'w> { load_id } - crate::TypeInner::ModfResultF32 => { + crate::TypeInner::ModfResult => { let id = self.gen_id(); let base_id = self.cached[base]; block.body.push(Instruction::composite_extract( diff --git a/src/back/spv/mod.rs b/src/back/spv/mod.rs index ee2d53887b..ceb169aae9 100644 --- a/src/back/spv/mod.rs +++ b/src/back/spv/mod.rs @@ -403,7 +403,8 @@ fn make_local(inner: &crate::TypeInner) -> Option { crate::TypeInner::RayQuery => LocalType::RayQuery, crate::TypeInner::Array { .. } | crate::TypeInner::Struct { .. } - | crate::TypeInner::ModfResultF32 + | crate::TypeInner::FrexpResult + | crate::TypeInner::ModfResult | crate::TypeInner::BindingArray { .. } => return None, }) } diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index ab660c8520..b8e5091733 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -1024,7 +1024,7 @@ impl Writer { } Instruction::type_struct(id, member_ids.as_slice()) } - crate::TypeInner::ModfResultF32 => { + crate::TypeInner::FrexpResult | crate::TypeInner::ModfResult => { let float_ty = arena .get(&crate::Type { name: None, @@ -1035,7 +1035,18 @@ impl Writer { }) .unwrap(); // TODO: unwrap self.decorate_struct_member_special(id, 0, 0, Some("fract"), float_ty, arena)?; - self.decorate_struct_member_special(id, 1, 4, Some("whole"), float_ty, arena)?; + self.decorate_struct_member_special( + id, + 1, + 4, + Some(if ty.inner == crate::TypeInner::FrexpResult { + "exp" + } else { + "whole" + }), + float_ty, + arena, + )?; let float_id = self.get_float_type_id(); let member_ids = [float_id; 2]; diff --git a/src/back/wgsl/writer.rs b/src/back/wgsl/writer.rs index 032096106e..eb54acd3f1 100644 --- a/src/back/wgsl/writer.rs +++ b/src/back/wgsl/writer.rs @@ -1223,7 +1223,10 @@ impl Writer { &self.names[&NameKey::StructMember(ty, index)] )? } - TypeInner::ModfResultF32 => { + TypeInner::FrexpResult => { + write!(self.out, ".{}", if index == 0 { "fract" } else { "exp" })? + } + TypeInner::ModfResult => { write!(self.out, ".{}", if index == 0 { "fract" } else { "whole" })? } ref other => return Err(Error::Custom(format!("Cannot index {other:?}"))), diff --git a/src/front/type_gen.rs b/src/front/type_gen.rs index 6983fc0757..c38813bd48 100644 --- a/src/front/type_gen.rs +++ b/src/front/type_gen.rs @@ -322,11 +322,26 @@ impl crate::Module { let handle = self.types.insert( crate::Type { name: Some("__naga_modf_result".to_string()), - inner: crate::TypeInner::ModfResultF32, + inner: crate::TypeInner::ModfResult, }, Span::UNDEFINED, ); self.special_types.modf_result = Some(handle); handle } + + pub fn generate_frexp_result(&mut self) -> Handle { + if let Some(handle) = self.special_types.frexp_result { + return handle; + } + let handle = self.types.insert( + crate::Type { + name: Some("__naga_frexp_result".to_string()), + inner: crate::TypeInner::FrexpResult, + }, + Span::UNDEFINED, + ); + self.special_types.frexp_result = Some(handle); + handle + } } diff --git a/src/front/wgsl/lower/mod.rs b/src/front/wgsl/lower/mod.rs index f76daf42a9..80791f1f28 100644 --- a/src/front/wgsl/lower/mod.rs +++ b/src/front/wgsl/lower/mod.rs @@ -1587,7 +1587,23 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ), } } - crate::TypeInner::ModfResultF32 => { + crate::TypeInner::FrexpResult => { + let index = if field.name == "fract" { + 0 + } else if field.name == "exp" { + 1 + } else { + return Err(Error::BadAccessor(field.span)); + }; + ( + crate::Expression::AccessIndex { + base: handle, + index, + }, + is_reference, + ) + } + crate::TypeInner::ModfResult => { let index = if field.name == "fract" { 0 } else if field.name == "whole" { @@ -1731,9 +1747,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { // Handle special functions return structures match fun { - crate::MathFunction::Modf => { + crate::MathFunction::Frexp | crate::MathFunction::Modf => { args.finish()?; - let _ = ctx.module.generate_modf_result(); + let _ = if fun == crate::MathFunction::Frexp { + ctx.module.generate_frexp_result() + } else { + ctx.module.generate_modf_result() + }; crate::Expression::Math { fun, arg, @@ -2122,8 +2142,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { return Ok(Some(result)); } "rayQueryGetCommittedIntersection" => { - let mut args: ArgumentContext<'_, '_> = - ctx.prepare_args(arguments, 1, span); + let mut args = ctx.prepare_args(arguments, 1, span); let query = self.ray_query_pointer(args.next()?, ctx.reborrow())?; args.finish()?; diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index 63447804b4..c7ff07559d 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -185,7 +185,8 @@ impl crate::TypeInner { Ti::Sampler { .. } => "sampler".to_string(), Ti::AccelerationStructure => "acceleration_structure".to_string(), Ti::RayQuery => "ray_query".to_string(), - Ti::ModfResultF32 => "__modf_result_f32".to_string(), + Ti::FrexpResult => "__frexp_result_f32".to_string(), + Ti::ModfResult => "__modf_result_f32".to_string(), Ti::BindingArray { base, size, .. } => { let member_type = &gctx.types[base]; let base = member_type.name.as_deref().unwrap_or("unknown"); diff --git a/src/front/wgsl/tests.rs b/src/front/wgsl/tests.rs index 02fc110cae..3f39c7cb44 100644 --- a/src/front/wgsl/tests.rs +++ b/src/front/wgsl/tests.rs @@ -438,10 +438,11 @@ fn binary_expression_mixed_scalar_and_vector_operands() { #[test] fn parse_pointers() { parse_str( - "fn foo() { + "fn foo(a: ptr) -> f32 { return *a; } + fn bar() { var x: f32 = 1.0; let px = &x; - let py = frexp(0.5, px); + let py = foo(px); }", ) .unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 81c95aad20..242bc0f91f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -812,7 +812,10 @@ pub enum TypeInner { RayQuery, // TODO: document - ModfResultF32, + FrexpResult, + + // TODO: document + ModfResult, /// Array of bindings. /// @@ -1979,6 +1982,10 @@ pub struct SpecialTypes { // Type for `__modf_result_f32`. // pub modf_result: Option>, + + // Type for `__frexp_result_f32 `. + // + pub frexp_result: Option>, } /// Shader module. diff --git a/src/proc/layouter.rs b/src/proc/layouter.rs index 3425e5e0e8..7ee902aa9c 100644 --- a/src/proc/layouter.rs +++ b/src/proc/layouter.rs @@ -234,7 +234,7 @@ impl Layouter { alignment, } } - Ti::ModfResultF32 { .. } => TypeLayout { + Ti::FrexpResult { .. } | Ti::ModfResult { .. } => TypeLayout { size: 8, alignment: Alignment::EIGHT, }, diff --git a/src/proc/mod.rs b/src/proc/mod.rs index 3f273d5d7d..0b2ad3869f 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -229,7 +229,7 @@ impl super::TypeInner { | Self::AccelerationStructure | Self::RayQuery | Self::BindingArray { .. } => 0, - Self::ModfResultF32 { .. } => 8, + Self::FrexpResult { .. } | Self::ModfResult { .. } => 8, } } diff --git a/src/proc/typifier.rs b/src/proc/typifier.rs index b9dcfc260a..c8b0066cdf 100644 --- a/src/proc/typifier.rs +++ b/src/proc/typifier.rs @@ -391,7 +391,7 @@ impl<'a> ResolveContext<'a> { } } Ti::BindingArray { base, .. } => Ti::Pointer { base, space }, - Ti::ModfResultF32 if (0..=1).contains(&index) => Ti::ValuePointer { + Ti::ModfResult if (0..=1).contains(&index) => Ti::ValuePointer { size: None, kind: crate::ScalarKind::Float, width: 4, @@ -406,7 +406,7 @@ impl<'a> ResolveContext<'a> { } }), Ti::BindingArray { base, .. } => TypeResolution::Handle(base), - Ti::ModfResultF32 if (0..=1).contains(&index) => { + Ti::FrexpResult | Ti::ModfResult if (0..=1).contains(&index) => { TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Float, width: 4, diff --git a/src/valid/expression.rs b/src/valid/expression.rs index da0f08fedb..3516a2315e 100644 --- a/src/valid/expression.rs +++ b/src/valid/expression.rs @@ -270,7 +270,7 @@ impl super::Validator { resolve_index_limit(module, top, &module.types[base].inner, false)? } Ti::Struct { ref members, .. } => members.len() as u32, - Ti::ModfResultF32 => 2, + Ti::ModfResult => 2, ref other => { log::error!("Indexing of {:?}", other); return Err(ExpressionError::InvalidBaseType(top)); diff --git a/src/valid/handles.rs b/src/valid/handles.rs index eb3f87fe25..e0a8450931 100644 --- a/src/valid/handles.rs +++ b/src/valid/handles.rs @@ -54,7 +54,8 @@ impl super::Validator { | crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } | crate::TypeInner::AccelerationStructure - | crate::TypeInner::ModfResultF32 + | crate::TypeInner::FrexpResult + | crate::TypeInner::ModfResult | crate::TypeInner::RayQuery => (), crate::TypeInner::Pointer { base, space: _ } => { this_handle.check_dep(base)?; diff --git a/src/valid/mod.rs b/src/valid/mod.rs index 6389d1e819..be0fd6a31f 100644 --- a/src/valid/mod.rs +++ b/src/valid/mod.rs @@ -255,7 +255,8 @@ impl crate::TypeInner { | Self::Atomic { .. } | Self::Pointer { .. } | Self::ValuePointer { .. } - | Self::ModfResultF32 { .. } + | Self::FrexpResult { .. } + | Self::ModfResult { .. } | Self::Struct { .. } => true, Self::Array { .. } | Self::Image { .. } diff --git a/src/valid/type.rs b/src/valid/type.rs index 2901bde993..0b423cff37 100644 --- a/src/valid/type.rs +++ b/src/valid/type.rs @@ -568,7 +568,7 @@ impl super::Validator { self.require_type_capability(Capabilities::RAY_QUERY)?; TypeInfo::new(TypeFlags::DATA | TypeFlags::SIZED, Alignment::ONE) } - Ti::ModfResultF32 => { + Ti::FrexpResult | Ti::ModfResult => { TypeInfo::new(TypeFlags::DATA | TypeFlags::SIZED, Alignment::EIGHT) } Ti::BindingArray { base, size } => {