1use crate::opcodes::Shape;
16use crate::{ConstantTable, DebugInfo, Opcode, Result, Stage, Version, error};
17
18const MAX_WORDS: usize = 1_048_576;
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub enum RegisterType {
26 Temp,
28 Input,
30 Const,
32 Address,
34 Texture,
36 RasterizerOut,
38 AttributeOut,
40 Output,
42 ConstInt,
44 ColorOut,
46 DepthOut,
48 Sampler,
50 Const2,
52 Const3,
54 Const4,
56 ConstBool,
58 Loop,
60 Misc,
62 Label,
64 Predicate,
66}
67
68impl RegisterType {
69 pub fn code(self) -> u8 {
71 use RegisterType::*;
72 match self {
73 Temp => 0,
74 Input => 1,
75 Const => 2,
76 Address | Texture => 3,
77 RasterizerOut => 4,
78 AttributeOut => 5,
79 Output => 6,
80 ConstInt => 7,
81 ColorOut => 8,
82 DepthOut => 9,
83 Sampler => 10,
84 Const2 => 11,
85 Const3 => 12,
86 Const4 => 13,
87 ConstBool => 14,
88 Loop => 15,
89 Misc => 17,
90 Label => 18,
91 Predicate => 19,
92 }
93 }
94
95 fn of(code: u32, version: Version) -> std::result::Result<(Self, Option<u32>), String> {
98 use RegisterType::*;
99 let vertex = version.stage == Stage::Vertex;
100 let sm1 = version.major == 1;
101 let sm3 = version.major == 3;
102 let flow = !sm1 && (vertex || version.minor > 0 || sm3);
103 Ok(match code {
104 0 => (Temp, None),
105 1 => (Input, None),
106 2 => (Const, None),
107 3 if vertex => (Address, Some(0)),
108 3 if !sm3 => (Texture, None),
109 4 if vertex && !sm3 => (RasterizerOut, Some(2)),
110 5 if vertex && !sm3 => (AttributeOut, None),
111 6 if vertex => (Output, None),
112 7 if flow => (ConstInt, None),
113 8 if !vertex => (ColorOut, None),
114 9 if !vertex && !(sm1 && version.minor < 4) => (DepthOut, Some(0)),
115 10 if (!vertex && !sm1) || sm3 => (Sampler, None),
116 11 if vertex => (Const2, None),
117 12 if vertex => (Const3, None),
118 13 if vertex => (Const4, None),
119 14 if flow => (ConstBool, None),
120 15 if !sm1 && (vertex || sm3) => (Loop, Some(0)),
121 17 if !vertex && sm3 => (Misc, Some(1)),
122 18 if flow => (Label, None),
123 19 if !sm1 && (version.minor > 0 || sm3) => (Predicate, Some(0)),
124 16 | 20.. => return Err("is not a Direct3D 9 register type".into()),
125 _ => return Err(format!("is not a register of {version}")),
126 })
127 }
128}
129
130#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
132pub struct Register {
133 pub kind: RegisterType,
135 pub number: u32,
137}
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
141pub enum Modifier {
142 None,
144 Negate,
146 Bias,
148 BiasNegate,
150 Sign,
152 SignNegate,
154 Complement,
156 X2,
158 X2Negate,
160 DivideZ,
162 DivideW,
164 Abs,
166 AbsNegate,
168 Not,
170}
171
172impl Modifier {
173 pub fn code(self) -> u8 {
175 use Modifier::*;
176 match self {
177 None => 0,
178 Negate => 1,
179 Bias => 2,
180 BiasNegate => 3,
181 Sign => 4,
182 SignNegate => 5,
183 Complement => 6,
184 X2 => 7,
185 X2Negate => 8,
186 DivideZ => 9,
187 DivideW => 10,
188 Abs => 11,
189 AbsNegate => 12,
190 Not => 13,
191 }
192 }
193
194 fn of(code: u32) -> Option<Self> {
195 use Modifier::*;
196 Some(match code {
197 0 => None,
198 1 => Negate,
199 2 => Bias,
200 3 => BiasNegate,
201 4 => Sign,
202 5 => SignNegate,
203 6 => Complement,
204 7 => X2,
205 8 => X2Negate,
206 9 => DivideZ,
207 10 => DivideW,
208 11 => Abs,
209 12 => AbsNegate,
210 13 => Not,
211 _ => return Option::None,
212 })
213 }
214}
215
216#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
218pub struct Relative {
219 pub word: Option<usize>,
222 pub register: Register,
224 pub swizzle: [u8; 4],
228}
229
230#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
232pub struct Destination {
233 pub word: usize,
235 pub register: Register,
237 pub mask: u8,
239 pub saturate: bool,
241 pub partial_precision: bool,
243 pub centroid: bool,
245 pub shift: i8,
248 pub relative: Option<Relative>,
250}
251
252#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
254pub struct Source {
255 pub word: usize,
257 pub register: Register,
259 pub swizzle: [u8; 4],
261 pub modifier: Modifier,
263 pub relative: Option<Relative>,
265}
266
267#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
270pub enum Comparison {
271 Greater,
273 Equal,
275 GreaterEqual,
277 Less,
279 NotEqual,
281 LessEqual,
283}
284
285#[derive(Clone, Debug, PartialEq, Eq)]
287pub struct Instruction {
288 pub word: usize,
290 pub opcode: Opcode,
292 pub control: u8,
295 pub coissue: bool,
297 pub predicate: Option<Source>,
300 pub destination: Option<Destination>,
302 pub sources: Vec<Source>,
304}
305
306impl Instruction {
307 pub fn comparison(&self) -> Option<Comparison> {
309 if !matches!(self.opcode, Opcode::IfC | Opcode::BreakC | Opcode::SetP) {
310 return None;
311 }
312 Some(match self.control {
313 1 => Comparison::Greater,
314 2 => Comparison::Equal,
315 3 => Comparison::GreaterEqual,
316 4 => Comparison::Less,
317 5 => Comparison::NotEqual,
318 _ => Comparison::LessEqual,
319 })
320 }
321}
322
323#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
325pub enum TextureType {
326 D2,
328 Cube,
330 Volume,
332}
333
334#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
336pub enum Declared {
337 Sampler(TextureType),
339 Semantic {
344 usage: u8,
346 index: u8,
348 },
349}
350
351#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
353pub struct Declaration {
354 pub word: usize,
356 pub token: u32,
358 pub declared: Declared,
360 pub destination: Destination,
362}
363
364#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
366pub enum Literal {
367 Float([u32; 4]),
369 Integer([i32; 4]),
371 Bool(u32),
373}
374
375#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
377pub struct Definition {
378 pub word: usize,
380 pub destination: Destination,
382 pub literal: Literal,
384}
385
386#[derive(Clone, Debug, PartialEq, Eq)]
388pub struct Comment {
389 pub word: usize,
391 pub data: Vec<u32>,
393}
394
395#[derive(Clone, Debug, PartialEq, Eq)]
397pub enum Item {
398 Comment(Comment),
400 Declaration(Declaration),
402 Definition(Definition),
404 Instruction(Instruction),
406}
407
408impl Item {
409 pub fn word(&self) -> usize {
411 match self {
412 Item::Comment(c) => c.word,
413 Item::Declaration(d) => d.word,
414 Item::Definition(d) => d.word,
415 Item::Instruction(i) => i.word,
416 }
417 }
418}
419
420#[derive(Clone, Debug, PartialEq, Eq)]
422pub struct Program {
423 pub version: Version,
425 pub items: Vec<Item>,
427 pub end: usize,
429 pub constants: Option<ConstantTable>,
431 pub debug: Option<DebugInfo>,
433}
434
435impl Program {
436 pub fn comments(&self) -> impl Iterator<Item = &Comment> {
438 self.items.iter().filter_map(|i| match i {
439 Item::Comment(c) => Some(c),
440 _ => None,
441 })
442 }
443 pub fn declarations(&self) -> impl Iterator<Item = &Declaration> {
445 self.items.iter().filter_map(|i| match i {
446 Item::Declaration(d) => Some(d),
447 _ => None,
448 })
449 }
450 pub fn definitions(&self) -> impl Iterator<Item = &Definition> {
452 self.items.iter().filter_map(|i| match i {
453 Item::Definition(d) => Some(d),
454 _ => None,
455 })
456 }
457 pub fn instructions(&self) -> impl Iterator<Item = &Instruction> {
459 self.items.iter().filter_map(|i| match i {
460 Item::Instruction(i) => Some(i),
461 _ => None,
462 })
463 }
464}
465
466pub fn read(bytes: &[u8]) -> Result<Program> {
468 collect(records(bytes)?)
469}
470
471pub fn frame(bytes: &[u8]) -> Result<(Program, &[u8])> {
475 let program = collect(start(bytes, false)?)?;
476 let span = bytes
477 .get(..program.end.saturating_add(1).saturating_mul(4))
478 .ok_or_else(|| error(program.end, "END is past the buffer"))?;
479 Ok((program, span))
480}
481
482pub fn records(bytes: &[u8]) -> Result<Records<'_>> {
487 if !bytes.len().is_multiple_of(4) || bytes.len() > MAX_WORDS.saturating_mul(4) {
488 return Err(error(
489 0,
490 format!(
491 "token stream of {} bytes is not whole words or exceeds 1,048,576 words",
492 bytes.len()
493 ),
494 ));
495 }
496 start(bytes, true)
497}
498
499fn start(bytes: &[u8], whole: bool) -> Result<Records<'_>> {
500 let words = Words { bytes };
501 let token = words.get(0).ok_or_else(|| error(0, "no version token"))?;
502 let version = Version::from_token(token).ok_or_else(|| {
503 error(
504 0,
505 format!(
506 "version token {token:#010x} is not a Direct3D 9 vertex (0xfffe) or pixel (0xffff) program of \
507 version 1.0 to 3.0"
508 ),
509 )
510 })?;
511 Ok(Records {
512 words,
513 version,
514 at: 1,
515 whole,
516 end: None,
517 done: false,
518 constants: None,
519 debug: None,
520 })
521}
522
523fn collect(mut records: Records<'_>) -> Result<Program> {
524 let mut items = Vec::new();
525 for item in records.by_ref() {
526 items.push(item?);
527 }
528 Ok(Program {
529 version: records.version,
530 items,
531 end: records.end.unwrap_or(0),
532 constants: records.constants,
533 debug: records.debug,
534 })
535}
536
537#[derive(Debug)]
539pub struct Records<'a> {
540 words: Words<'a>,
541 version: Version,
542 at: usize,
544 whole: bool,
546 end: Option<usize>,
547 done: bool,
548 constants: Option<ConstantTable>,
549 debug: Option<DebugInfo>,
550}
551
552impl Records<'_> {
553 pub fn version(&self) -> Version {
555 self.version
556 }
557 pub fn constants(&self) -> Option<&ConstantTable> {
559 self.constants.as_ref()
560 }
561 pub fn debug(&self) -> Option<&DebugInfo> {
563 self.debug.as_ref()
564 }
565 pub fn end(&self) -> Option<usize> {
567 self.end
568 }
569}
570
571impl Iterator for Records<'_> {
572 type Item = Result<Item>;
573
574 fn next(&mut self) -> Option<Result<Item>> {
575 if self.done {
576 return None;
577 }
578 match self.record() {
579 Ok(Some(item)) => Some(Ok(item)),
580 Ok(None) => {
581 self.done = true;
582 let words = self.words.len();
583 (self.whole && self.at != words).then(|| {
584 Err(error(
585 self.at,
586 format!("{} words after END", words.saturating_sub(self.at)),
587 ))
588 })
589 }
590 Err(e) => {
591 self.done = true;
592 Some(Err(e))
593 }
594 }
595 }
596}
597
598#[derive(Debug)]
600struct Words<'a> {
601 bytes: &'a [u8],
602}
603
604impl Words<'_> {
605 fn len(&self) -> usize {
606 (self.bytes.len() / 4).min(MAX_WORDS)
607 }
608 fn get(&self, at: usize) -> Option<u32> {
609 if at >= MAX_WORDS {
610 return None;
611 }
612 let start = at.checked_mul(4)?;
613 let word: [u8; 4] = self.bytes.get(start..start.checked_add(4)?)?.try_into().ok()?;
614 Some(u32::from_le_bytes(word))
615 }
616}
617
618fn bits(word: u32, shift: u32, mask: u32) -> u8 {
620 u8::try_from(word.checked_shr(shift).unwrap_or(0) & mask & 0xff).unwrap_or(u8::MAX)
621}
622
623fn register(token: u32, at: usize, version: Version) -> Result<Register> {
625 if token & 0x8000_0000 == 0 {
626 return Err(error(at, format!("operand token {token:#010x} lacks bit 31")));
627 }
628 if token & 0xc000 != 0 {
629 return Err(error(
630 at,
631 format!("operand token {token:#010x} sets reserved bits 14 to 15"),
632 ));
633 }
634 let code = ((token >> 28) & 7) | ((token >> 8) & 0x18);
635 let number = token & 0x7ff;
636 let (kind, last) =
637 RegisterType::of(code, version).map_err(|why| error(at, format!("register type {code} {why}")))?;
638 if last.is_some_and(|last| number > last) {
639 return Err(error(
640 at,
641 format!(
642 "register {kind:?} {number}, where the type has registers 0 to {}",
643 last.unwrap_or(0)
644 ),
645 ));
646 }
647 Ok(Register { kind, number })
648}
649
650struct Operands<'a> {
653 words: &'a Words<'a>,
654 at: usize,
655 end: usize,
656 instruction: usize,
658 version: Version,
659}
660
661impl Operands<'_> {
662 fn next(&mut self) -> Result<(usize, u32)> {
663 let at = self.at;
664 let token = (at < self.end)
665 .then(|| self.words.get(at))
666 .flatten()
667 .ok_or_else(|| {
668 error(
669 self.instruction,
670 format!(
671 "instruction's operand span extends past {} (it ends at word {})",
672 if self.end < self.words.len() {
673 "its stated length"
674 } else {
675 "the stream"
676 },
677 self.end.min(self.words.len())
678 ),
679 )
680 })?;
681 self.at = at.saturating_add(1);
682 Ok((at, token))
683 }
684
685 fn relative(&mut self, operand: usize, what: &str) -> Result<Relative> {
687 let version = self.version;
688 if version.major == 1 {
689 return Ok(Relative {
690 word: None,
691 register: Register {
692 kind: RegisterType::Address,
693 number: 0,
694 },
695 swizzle: [0; 4],
696 });
697 }
698 let (at, token) = self.next().map_err(|e| {
699 error(
700 operand,
701 format!(
702 "relative addressing of {what} without its address token: {}",
703 e.detail
704 ),
705 )
706 })?;
707 let register = register(token & !0x2000, at, version)?;
708 if !matches!(register.kind, RegisterType::Address | RegisterType::Loop) || token & 0x2000 != 0 {
709 return Err(error(
710 at,
711 format!(
712 "relative address token of {what} names {register:?}{}, where it is the address register a0 or the \
713 loop counter aL",
714 if token & 0x2000 != 0 {
715 " relatively addressed itself"
716 } else {
717 ""
718 }
719 ),
720 ));
721 }
722 if (token >> 24) & 15 != 0 {
723 return Err(error(
724 at,
725 format!(
726 "relative address token of {what} has source modifier {}, where it has none",
727 (token >> 24) & 15
728 ),
729 ));
730 }
731 Ok(Relative {
732 word: Some(at),
733 register,
734 swizzle: [16, 18, 20, 22].map(|shift| bits(token, shift, 3)),
735 })
736 }
737
738 fn destination(&mut self) -> Result<Destination> {
739 let (at, token) = self.next()?;
740 let version = self.version;
741 let register = register(token & !0x2000, at, version)?;
742 let modifiers = (token >> 20) & 15;
743 if modifiers & 8 != 0 {
744 return Err(error(
745 at,
746 format!("destination {token:#010x} sets result modifier bit 23"),
747 ));
748 }
749 let shift = bits(token, 24, 15);
750 let shift = if shift >= 8 {
751 i8::try_from(i16::from(shift).saturating_sub(16)).unwrap_or(0)
752 } else {
753 i8::try_from(shift).unwrap_or(0)
754 };
755 let pixel1 = version.stage == Stage::Pixel && version.major == 1;
756 if !(shift == 0 || (pixel1 && (-3..=3).contains(&shift))) {
757 return Err(error(
758 at,
759 format!(
760 "destination {token:#010x} has result shift {shift}, where it is 0 (or -3 to 3 in pixel 1.x)"
761 ),
762 ));
763 }
764 let relative = if token & 0x2000 != 0 {
765 if version.major == 1 {
766 return Err(error(
767 at,
768 "relative addressing of a destination in Shader Model 1",
769 ));
770 }
771 Some(self.relative(at, "a destination")?)
772 } else {
773 None
774 };
775 Ok(Destination {
776 word: at,
777 register,
778 mask: bits(token, 16, 15),
779 saturate: modifiers & 1 != 0,
780 partial_precision: modifiers & 2 != 0,
781 centroid: modifiers & 4 != 0,
782 shift,
783 relative,
784 })
785 }
786
787 fn source(&mut self) -> Result<Source> {
788 let (at, token) = self.next()?;
789 let version = self.version;
790 let register = register(token & !0x2000, at, version)?;
791 let modifier = Modifier::of((token >> 24) & 15).ok_or_else(|| {
792 error(
793 at,
794 format!("source modifier {} is not one of 0 to 13", (token >> 24) & 15),
795 )
796 })?;
797 let relative = if token & 0x2000 != 0 {
798 if version.major == 1 && version.stage == Stage::Pixel {
799 return Err(error(at, "relative addressing in a pixel 1.x program"));
800 }
801 Some(self.relative(at, "a source")?)
802 } else {
803 None
804 };
805 Ok(Source {
806 word: at,
807 register,
808 swizzle: [16, 18, 20, 22].map(|shift| bits(token, shift, 3)),
809 modifier,
810 relative,
811 })
812 }
813}
814
815impl Records<'_> {
816 fn record(&mut self) -> Result<Option<Item>> {
818 let version = self.version;
819 let words = &self.words;
820 let mut at = self.at;
821 let word = at;
822 let token = words.get(word).ok_or_else(|| {
823 error(
824 word,
825 if word >= MAX_WORDS {
826 "the program exceeds 1,048,576 words without END"
827 } else {
828 "missing END"
829 },
830 )
831 })?;
832 at = at.saturating_add(1);
833 if token == 0xffff {
834 self.end = Some(word);
835 self.at = at;
836 return Ok(None);
837 }
838 let op = token & 0xffff;
839 if op == 0xfffe {
840 if token & 0x8000_0000 != 0 {
841 return Err(error(word, "COMMENT reserved bit"));
842 }
843 let count = usize::try_from((token >> 16) & 0x7fff).unwrap_or(usize::MAX);
844 let end = at.saturating_add(count);
845 let data: Vec<u32> = (at..end).map_while(|n| words.get(n)).collect();
846 if data.len() != count {
847 return Err(error(
848 word,
849 format!(
850 "instruction/comment span of {count} words extends past the stream's {} words",
851 words.len()
852 ),
853 ));
854 }
855 if let Some((&tag, rest)) = data.split_first() {
856 let bytes = || -> Vec<u8> { rest.iter().flat_map(|w| w.to_le_bytes()).collect() };
857 if tag == u32::from_le_bytes(*b"CTAB") {
858 if self.constants.is_some() {
859 return Err(error(word, "duplicate CTAB"));
860 }
861 self.constants = Some(crate::ctab::read(
862 &bytes(),
863 word.saturating_add(2),
864 version.token(),
865 )?);
866 } else if tag == u32::from_le_bytes(*b"DBUG") {
867 if self.debug.is_some() {
868 return Err(error(word, "duplicate DBUG"));
869 }
870 self.debug = Some(crate::debug::read(&bytes(), word.saturating_add(2))?);
871 }
872 }
873 self.at = end;
874 return Ok(Some(Item::Comment(Comment { word, data })));
875 }
876 let opcode = u16::try_from(op)
877 .ok()
878 .and_then(Opcode::from_code)
879 .ok_or_else(|| error(word, format!("opcode {op} is not a Direct3D 9 instruction")))?;
880 if !opcode.in_version(version) {
881 let other = Version {
882 stage: match version.stage {
883 Stage::Vertex => Stage::Pixel,
884 Stage::Pixel => Stage::Vertex,
885 },
886 ..version
887 };
888 let detail = if opcode.in_version(other) {
889 let stage = match other.stage {
890 Stage::Vertex => "vertex",
891 Stage::Pixel => "pixel",
892 };
893 format!(
894 "{} (opcode {op}) is a {stage} instruction, not one of {version}",
895 opcode.name()
896 )
897 } else {
898 format!(
899 "{} (opcode {op}) is not an instruction of {version}",
900 opcode.name()
901 )
902 };
903 return Err(error(word, detail));
904 }
905 let shape = opcode.shape(version);
906 let sm1 = version.major == 1;
907 let length = usize::from(bits(token, 24, 15));
908 let predicated = token & 0x1000_0000 != 0;
909 let coissue = token & 0x4000_0000 != 0;
910 let control = bits(token, 16, 0xff);
911 if token & 0xa000_0000 != 0 {
912 return Err(error(
913 word,
914 format!("instruction token {token:#010x} sets reserved bit 29 or 31"),
915 ));
916 }
917 if coissue && !(sm1 && version.stage == Stage::Pixel) {
918 return Err(error(word, "co-issue outside a pixel 1.x program"));
919 }
920 if predicated && (sm1 || (version.major == 2 && version.minor == 0)) {
921 return Err(error(
922 word,
923 format!("predication in {version}, which has no predicate register"),
924 ));
925 }
926 if shape == Shape::Phase && token != 0xfffd {
927 return Err(error(
928 word,
929 format!("phase token {token:#010x} has bits beyond the opcode"),
930 ));
931 }
932 let controlled = match opcode {
933 Opcode::Tex if !sm1 => (0..=2).contains(&control),
934 Opcode::IfC | Opcode::BreakC | Opcode::SetP => (1..=6).contains(&control),
935 _ => control == 0,
936 };
937 if !controlled {
938 return Err(error(
939 word,
940 format!(
941 "{} has control bits {control:#x}, which it does not define",
942 opcode.name()
943 ),
944 ));
945 }
946 let end = if sm1 {
947 words.len()
948 } else {
949 let end = at.saturating_add(length);
950 if end > words.len() {
951 return Err(error(
952 word,
953 format!(
954 "instruction/comment span of {length} operands extends past the stream's {} words",
955 words.len()
956 ),
957 ));
958 }
959 end
960 };
961 let mut operands = Operands {
962 words,
963 at,
964 end,
965 instruction: word,
966 version,
967 };
968 let item = match shape {
969 Shape::Phase => Item::Instruction(Instruction {
970 word,
971 opcode,
972 control,
973 coissue,
974 predicate: None,
975 destination: None,
976 sources: Vec::new(),
977 }),
978 Shape::Declaration => {
979 if predicated {
980 return Err(error(word, "predicated dcl"));
981 }
982 let (token_at, token) = operands.next()?;
983 let destination = operands.destination()?;
984 Item::Declaration(Declaration {
985 word,
986 token,
987 declared: declared(token, token_at, destination.register)?,
988 destination,
989 })
990 }
991 Shape::Definition { words: count } => {
992 if predicated {
993 return Err(error(word, format!("predicated {}", opcode.name())));
994 }
995 let destination = operands.destination()?;
996 let expected = match opcode {
997 Opcode::Def => RegisterType::Const,
998 Opcode::DefI => RegisterType::ConstInt,
999 _ => RegisterType::ConstBool,
1000 };
1001 if destination.register.kind != expected || destination.relative.is_some() {
1002 return Err(error(
1003 destination.word,
1004 format!(
1005 "{} defines {:?}, where it defines a {expected:?} register",
1006 opcode.name(),
1007 destination.register
1008 ),
1009 ));
1010 }
1011 let mut values = [0u32; 4];
1012 for value in values.iter_mut().take(count) {
1013 *value = operands.next()?.1;
1014 }
1015 let literal = match opcode {
1016 Opcode::Def => Literal::Float(values),
1017 Opcode::DefI => Literal::Integer(values.map(|v| i32::from_le_bytes(v.to_le_bytes()))),
1018 _ => {
1019 let [value, ..] = values;
1020 Literal::Bool(value)
1021 }
1022 };
1023 Item::Definition(Definition {
1024 word,
1025 destination,
1026 literal,
1027 })
1028 }
1029 Shape::Operands { destination, sources } => {
1030 let destination = if destination {
1031 Some(operands.destination()?)
1032 } else {
1033 None
1034 };
1035 let predicate = if predicated {
1036 let p = operands.source()?;
1037 if p.register.kind != RegisterType::Predicate
1038 || !matches!(p.modifier, Modifier::None | Modifier::Not)
1039 {
1040 return Err(error(
1041 p.word,
1042 format!(
1043 "the predicate token names {:?} with {:?}, where it is p0 or !p0",
1044 p.register, p.modifier
1045 ),
1046 ));
1047 }
1048 Some(p)
1049 } else {
1050 None
1051 };
1052 let mut read = Vec::with_capacity(sources);
1053 for _ in 0..sources {
1054 read.push(operands.source()?);
1055 }
1056 Item::Instruction(Instruction {
1057 word,
1058 opcode,
1059 control,
1060 coissue,
1061 predicate,
1062 destination,
1063 sources: read,
1064 })
1065 }
1066 };
1067 let used = operands.at.saturating_sub(at);
1068 if sm1 {
1069 if length != 0 && length != used {
1071 return Err(error(
1072 word,
1073 format!(
1074 "{} states {length} operand tokens, where its operands take {used}",
1075 opcode.name()
1076 ),
1077 ));
1078 }
1079 } else if used != length {
1080 return Err(error(
1081 word,
1082 format!(
1083 "{} states {length} operand tokens, where its operands take {used}",
1084 opcode.name()
1085 ),
1086 ));
1087 }
1088 self.at = operands.at;
1089 Ok(Some(item))
1090 }
1091}
1092
1093fn declared(token: u32, at: usize, register: Register) -> Result<Declared> {
1095 if token & 0x8000_0000 == 0 {
1096 return Err(error(at, format!("DCL token {token:#010x} lacks bit 31")));
1097 }
1098 if register.kind == RegisterType::Sampler {
1099 return Ok(Declared::Sampler(match token {
1100 0x9000_0000 => TextureType::D2,
1101 0x9800_0000 => TextureType::Cube,
1102 0xa000_0000 => TextureType::Volume,
1103 _ => {
1104 return Err(error(
1105 at,
1106 format!(
1107 "DCL sampler texture type {token:#x}, where it is 0x90000000 (2d), 0x98000000 (cube) or \
1108 0xa0000000 (volume)"
1109 ),
1110 ));
1111 }
1112 }));
1113 }
1114 if token & !0x800f_000f != 0 {
1115 return Err(error(at, "DCL semantic reserved bits"));
1116 }
1117 let usage = bits(token, 0, 15);
1118 if usage > 13 {
1119 return Err(error(at, format!("DCL usage {usage}, where it is 0 to 13")));
1120 }
1121 Ok(Declared::Semantic {
1122 usage,
1123 index: bits(token, 16, 15),
1124 })
1125}