Skip to content

Commit 902c51c

Browse files
authored
Inline calls that look like f(&s.x) (#777)
1 parent c10a1ca commit 902c51c

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

crates/rustc_codegen_spirv/src/linker/inline.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,25 @@ fn should_inline(
218218
|| disallowed_return_types.contains(&function.def.as_ref().unwrap().result_type.unwrap())
219219
}
220220

221+
// This should be more general, but a very common problem is passing an OpAccessChain to an
222+
// OpFunctionCall (i.e. `f(&s.x)`, or more commonly, `s.x.f()` where `f` takes `&self`), so detect
223+
// that case and inline the call.
224+
fn args_invalid(function: &Function, call: &Instruction) -> bool {
225+
for inst in function.all_inst_iter() {
226+
if inst.class.opcode == Op::AccessChain {
227+
let inst_result = inst.result_id.unwrap();
228+
if call
229+
.operands
230+
.iter()
231+
.any(|op| *op == Operand::IdRef(inst_result))
232+
{
233+
return true;
234+
}
235+
}
236+
}
237+
false
238+
}
239+
221240
// Steps:
222241
// Move OpVariable decls
223242
// Rewrite return
@@ -292,12 +311,12 @@ impl Inliner<'_, '_> {
292311
.unwrap(),
293312
)
294313
})
295-
.find(|(_, _, f)| {
314+
.find(|(_, inst, f)| {
296315
should_inline(
297316
self.disallowed_argument_types,
298317
self.disallowed_return_types,
299318
f,
300-
)
319+
) || args_invalid(caller, inst)
301320
});
302321
let (call_index, call_inst, callee) = match call {
303322
None => return false,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// build-pass
2+
3+
use spirv_std as _;
4+
5+
struct S {
6+
x: u32,
7+
y: u32,
8+
}
9+
10+
fn f(x: &u32) {}
11+
12+
#[spirv(fragment)]
13+
pub fn main() {
14+
let s = S { x: 2, y: 2 };
15+
f(&s.x);
16+
}

0 commit comments

Comments
 (0)