Skip to content

Commit 17ef6ca

Browse files
wicastteoxoy
authored andcommitted
fix(spv-out): OpSourceContinued for large source (#5390)
1 parent 911baf3 commit 17ef6ca

7 files changed

+16165
-2
lines changed

naga/src/back/spv/helpers.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ pub(super) fn bytes_to_words(bytes: &[u8]) -> Vec<Word> {
1010

1111
pub(super) fn string_to_words(input: &str) -> Vec<Word> {
1212
let bytes = input.as_bytes();
13-
let mut words = bytes_to_words(bytes);
1413

14+
str_bytes_to_words(bytes)
15+
}
16+
17+
pub(super) fn str_bytes_to_words(bytes: &[u8]) -> Vec<Word> {
18+
let mut words = bytes_to_words(bytes);
1519
if bytes.len() % 4 == 0 {
1620
// nul-termination
1721
words.push(0x0u32);
@@ -20,6 +24,21 @@ pub(super) fn string_to_words(input: &str) -> Vec<Word> {
2024
words
2125
}
2226

27+
/// split a string into chunks and keep utf8 valid
28+
#[allow(unstable_name_collisions)]
29+
pub(super) fn string_to_byte_chunks(input: &str, limit: usize) -> Vec<&[u8]> {
30+
let mut offset: usize = 0;
31+
let mut start: usize = 0;
32+
let mut words = vec![];
33+
while offset < input.len() {
34+
offset = input.floor_char_boundary(offset + limit);
35+
words.push(input[start..offset].as_bytes());
36+
start = offset;
37+
}
38+
39+
words
40+
}
41+
2342
pub(super) const fn map_storage_class(space: crate::AddressSpace) -> spirv::StorageClass {
2443
match space {
2544
crate::AddressSpace::Handle => spirv::StorageClass::UniformConstant,
@@ -107,3 +126,35 @@ pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariab
107126
_ => true,
108127
}
109128
}
129+
130+
///HACK: this is taken from std unstable, remove it when std's floor_char_boundary is stable
131+
trait U8Internal {
132+
fn is_utf8_char_boundary(&self) -> bool;
133+
}
134+
135+
impl U8Internal for u8 {
136+
fn is_utf8_char_boundary(&self) -> bool {
137+
// This is bit magic equivalent to: b < 128 || b >= 192
138+
(*self as i8) >= -0x40
139+
}
140+
}
141+
142+
trait StrUnstable {
143+
fn floor_char_boundary(&self, index: usize) -> usize;
144+
}
145+
146+
impl StrUnstable for str {
147+
fn floor_char_boundary(&self, index: usize) -> usize {
148+
if index >= self.len() {
149+
self.len()
150+
} else {
151+
let lower_bound = index.saturating_sub(3);
152+
let new_index = self.as_bytes()[lower_bound..=index]
153+
.iter()
154+
.rposition(|b| b.is_utf8_char_boundary());
155+
156+
// SAFETY: we know that the character boundary will be within four bytes
157+
unsafe { lower_bound + new_index.unwrap_unchecked() }
158+
}
159+
}
160+
}

naga/src/back/spv/instructions.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,42 @@ impl super::Instruction {
4343
instruction
4444
}
4545

46+
pub(super) fn source_continued(source: &[u8]) -> Self {
47+
let mut instruction = Self::new(Op::SourceContinued);
48+
instruction.add_operands(helpers::str_bytes_to_words(source));
49+
instruction
50+
}
51+
52+
pub(super) fn source_auto_continued(
53+
source_language: spirv::SourceLanguage,
54+
version: u32,
55+
source: &Option<DebugInfoInner>,
56+
) -> Vec<Self> {
57+
let mut instructions = vec![];
58+
59+
let with_continue = source.as_ref().and_then(|debug_info| {
60+
(debug_info.source_code.len() > u16::MAX as usize).then_some(debug_info)
61+
});
62+
if let Some(debug_info) = with_continue {
63+
let mut instruction = Self::new(Op::Source);
64+
instruction.add_operand(source_language as u32);
65+
instruction.add_operands(helpers::bytes_to_words(&version.to_le_bytes()));
66+
67+
let words = helpers::string_to_byte_chunks(debug_info.source_code, u16::MAX as usize);
68+
instruction.add_operand(debug_info.source_file_id);
69+
instruction.add_operands(helpers::str_bytes_to_words(words[0]));
70+
instructions.push(instruction);
71+
for word_bytes in words[1..].iter() {
72+
let instruction_continue = Self::source_continued(word_bytes);
73+
instructions.push(instruction_continue);
74+
}
75+
} else {
76+
let instruction = Self::source(source_language, version, source);
77+
instructions.push(instruction);
78+
}
79+
instructions
80+
}
81+
4682
pub(super) fn name(target_id: Word, name: &str) -> Self {
4783
let mut instruction = Self::new(Op::Name);
4884
instruction.add_operand(target_id);

naga/src/back/spv/writer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1899,7 +1899,7 @@ impl Writer {
18991899
source_code: debug_info.source_code,
19001900
source_file_id,
19011901
});
1902-
self.debugs.push(Instruction::source(
1902+
self.debugs.append(&mut Instruction::source_auto_continued(
19031903
spirv::SourceLanguage::Unknown,
19041904
0,
19051905
&debug_info_inner,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(
2+
spv: (
3+
version: (1, 1),
4+
debug: true,
5+
adjust_coordinate_space: false,
6+
),
7+
)

0 commit comments

Comments
 (0)