Skip to content

Commit

Permalink
[glsl-in] Use intermediate local if storage class isn't function
Browse files Browse the repository at this point in the history
Automatically spills to a local variable function call arguments to
parameters expecting a pointer where the argument storage class isn't
function since the storage classes wouldn't match.
  • Loading branch information
JCapucho committed Sep 27, 2021
1 parent aa08cf9 commit 38d74a7
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 57 deletions.
7 changes: 6 additions & 1 deletion src/front/glsl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,12 @@ impl Context {
HirExprKind::Access { base, index } => {
let (index, index_meta) =
self.lower_expect_inner(stmt, parser, index, ExprPos::Rhs, body)?;
let maybe_constant_index = parser.solve_constant(self, index, index_meta).ok();
let maybe_constant_index = match pos {
// Don't try to generate `AccessIndex` if in a LHS position, since it
// wouldn't produce a pointer.
ExprPos::Lhs => None,
_ => parser.solve_constant(self, index, index_meta).ok(),
};

let base = self
.lower_expect_inner(
Expand Down
126 changes: 81 additions & 45 deletions src/front/glsl/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use super::{
use crate::{
front::glsl::types::type_power, proc::ensure_block_returns, Arena, Block, Constant,
ConstantInner, EntryPoint, Expression, FastHashMap, Function, FunctionArgument, FunctionResult,
Handle, LocalVariable, ScalarKind, ScalarValue, Span, Statement, StructMember, Type, TypeInner,
Handle, LocalVariable, ScalarKind, ScalarValue, Span, Statement, StorageClass, StructMember,
Type, TypeInner,
};
use std::iter;

Expand Down Expand Up @@ -549,47 +550,85 @@ impl Parser {
ctx.lower_expect_inner(stmt, self, *expr, parameter_info.qualifier.as_pos(), body)?;

if parameter_info.qualifier.is_lhs() {
// If the argument is to be passed as a pointer but the type of the
// expression returns a vector it must mean that it was for example
// swizzled and it must be spilled into a local before calling
if let TypeInner::Vector { size, kind, width } =
*self.resolve_type(ctx, handle, meta)?
{
let ty = self.module.types.insert(
Type {
name: None,
inner: TypeInner::Vector { size, kind, width },
},
Span::default(),
);
let temp_var = ctx.locals.append(
LocalVariable {
name: None,
ty,
init: None,
},
Span::default(),
);
let temp_expr = ctx.add_expression(
Expression::LocalVariable(temp_var),
Span::default(),
body,
);
let (ty, value) = match *self.resolve_type(ctx, handle, meta)? {
// If the argument is to be passed as a pointer but the type of the
// expression returns a vector it must mean that it was for example
// swizzled and it must be spilled into a local before calling
// TODO: this part doesn't work because of #1385 once that's sorted out
// revisit this part.
TypeInner::Vector { size, kind, width } => (
self.module.types.insert(
Type {
name: None,
inner: TypeInner::Vector { size, kind, width },
},
Span::default(),
),
handle,
),
// If the argument is a pointer whose storage class isn't `Function` an
// indirection trough a local variable is needed to align the storage
// classes of the call argument and the overload parameter
TypeInner::Pointer { base, class } if class != StorageClass::Function => (
base,
ctx.add_expression(
Expression::Load { pointer: handle },
Span::default(),
body,
),
),
TypeInner::ValuePointer {
size,
kind,
width,
class,
} if class != StorageClass::Function => {
let inner = match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
};

(
self.module
.types
.insert(Type { name: None, inner }, Span::default()),
ctx.add_expression(
Expression::Load { pointer: handle },
Span::default(),
body,
),
)
}
_ => {
arguments.push(handle);
continue;
}
};

body.push(
Statement::Store {
pointer: temp_expr,
value: handle,
},
Span::default(),
);
let temp_var = ctx.locals.append(
LocalVariable {
name: None,
ty,
init: None,
},
Span::default(),
);
let temp_expr =
ctx.add_expression(Expression::LocalVariable(temp_var), Span::default(), body);

arguments.push(temp_expr);
// Register the temporary local to be written back to it's original
// place after the function call
proxy_writes.push((*expr, temp_expr));
continue;
}
body.push(
Statement::Store {
pointer: temp_expr,
value,
},
Span::default(),
);

arguments.push(temp_expr);
// Register the temporary local to be written back to it's original
// place after the function call
proxy_writes.push((handle, temp_expr));
continue;
}

// Apply implicit conversions as needed
Expand Down Expand Up @@ -623,18 +662,15 @@ impl Parser {
ctx.emit_start();

// Write back all the variables that were scheduled to their original place
for (tgt, pointer) in proxy_writes {
for (original, pointer) in proxy_writes {
let value = ctx.add_expression(Expression::Load { pointer }, meta, body);
let target = ctx
.lower_expect_inner(stmt, self, tgt, ExprPos::Rhs, body)?
.0;

ctx.emit_flush(body);
ctx.emit_start();

body.push(
Statement::Store {
pointer: target,
pointer: original,
value,
},
meta,
Expand Down
14 changes: 9 additions & 5 deletions tests/in/glsl/expressions.frag
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,22 @@ void testBinOpUintUVec(uint a, uvec4 b) {
}

void testStructConstructor() {
struct BST {
int data;
};
struct BST {
int data;
};

BST tree = BST(1);
BST tree = BST(1);
}

void testArrayConstructor() {
float tree[1] = float[1](0.0);
float tree[1] = float[1](0.0);
}

float global;
void privatePointer(inout float a) {}

out vec4 o_color;
void main() {
privatePointer(global);
o_color.rgba = vec4(1.0);
}
24 changes: 18 additions & 6 deletions tests/out/wgsl/expressions-frag.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ struct BST {
data: i32;
};

var<private> global: f32;
var<private> o_color: vec4<f32>;

fn testBinOpVecFloat(a: vec4<f32>, b: f32) {
Expand Down Expand Up @@ -184,13 +185,24 @@ fn testArrayConstructor() {

}

fn privatePointer(a12: ptr<function, f32>) {
return;
}

fn main1() {
let e1: vec4<f32> = o_color;
let e4: vec4<f32> = vec4<f32>(1.0);
o_color.x = e4.x;
o_color.y = e4.y;
o_color.z = e4.z;
o_color.w = e4.w;
var local: f32;

let e3: f32 = global;
local = e3;
privatePointer((&local));
let e5: f32 = local;
global = e5;
let e6: vec4<f32> = o_color;
let e9: vec4<f32> = vec4<f32>(1.0);
o_color.x = e9.x;
o_color.y = e9.y;
o_color.z = e9.z;
o_color.w = e9.w;
return;
}

Expand Down

0 comments on commit 38d74a7

Please sign in to comment.