@@ -2455,7 +2455,7 @@ impl<'a> Parser<'a> { |
| 2455 | 2455 | if self.peek_is_scalar_fp_reg() { |
| 2456 | 2456 | return self.parse_simd_lane_extract(); |
| 2457 | 2457 | } |
| 2458 | | - let (rd, sf) = self.parse_gp_reg_with_size()?; |
| 2458 | + let (rd, sf, rd_kind) = self.parse_gp_reg_with_size_kind()?; |
| 2459 | 2459 | self.expect(&Tok::Comma)?; |
| 2460 | 2460 | if self.starts_immediate_expr() { |
| 2461 | 2461 | let imm = self.parse_immediate_const_expr("mov immediate")?; |
@@ -2468,8 +2468,8 @@ impl<'a> Parser<'a> { |
| 2468 | 2468 | ))) |
| 2469 | 2469 | } |
| 2470 | 2470 | } else { |
| 2471 | | - let (rm, _) = self.parse_gp_reg_with_size()?; |
| 2472 | | - if rm == SP || rd == SP { |
| 2471 | + let (rm, _, rm_kind) = self.parse_gp_reg_with_size_kind()?; |
| 2472 | + if rm_kind == GpRegKind::Sp || rd_kind == GpRegKind::Sp { |
| 2473 | 2473 | // MOV involving SP → ADD Xd, Xn, #0 (SP can't be used in ORR shifted reg) |
| 2474 | 2474 | Ok(Inst::AddImm { |
| 2475 | 2475 | rd, |
@@ -2944,6 +2944,54 @@ impl<'a> Parser<'a> { |
| 2944 | 2944 | } |
| 2945 | 2945 | } |
| 2946 | 2946 | |
| 2947 | + fn fp_mem_offset_inst( |
| 2948 | + &self, |
| 2949 | + is_load: bool, |
| 2950 | + width: FpMemWidth, |
| 2951 | + rt: FpReg, |
| 2952 | + rn: GpReg, |
| 2953 | + offset: i64, |
| 2954 | + ) -> Result<Inst, ParseError> { |
| 2955 | + let scale = 1i64 << width.scale(); |
| 2956 | + let fits_unsigned = offset >= 0 && offset % scale == 0 && (offset >> width.scale()) <= 0xFFF; |
| 2957 | + if fits_unsigned { |
| 2958 | + let offset = offset as u16; |
| 2959 | + return Ok(match (is_load, width) { |
| 2960 | + (true, FpMemWidth::H16) => Inst::LdrFpImm16 { rt, rn, offset }, |
| 2961 | + (false, FpMemWidth::H16) => Inst::StrFpImm16 { rt, rn, offset }, |
| 2962 | + (true, FpMemWidth::B8) => Inst::LdrFpImm8 { rt, rn, offset }, |
| 2963 | + (false, FpMemWidth::B8) => Inst::StrFpImm8 { rt, rn, offset }, |
| 2964 | + (true, FpMemWidth::D64) => Inst::LdrFpImm64 { rt, rn, offset }, |
| 2965 | + (false, FpMemWidth::D64) => Inst::StrFpImm64 { rt, rn, offset }, |
| 2966 | + (true, FpMemWidth::S32) => Inst::LdrFpImm32 { rt, rn, offset }, |
| 2967 | + (false, FpMemWidth::S32) => Inst::StrFpImm32 { rt, rn, offset }, |
| 2968 | + (true, FpMemWidth::Q128) => Inst::LdrFpImm128 { rt, rn, offset }, |
| 2969 | + (false, FpMemWidth::Q128) => Inst::StrFpImm128 { rt, rn, offset }, |
| 2970 | + }); |
| 2971 | + } |
| 2972 | + |
| 2973 | + if (-256..=255).contains(&offset) { |
| 2974 | + let offset = offset as i16; |
| 2975 | + return Ok(match (is_load, width) { |
| 2976 | + (true, FpMemWidth::H16) => Inst::LdurFp16 { rt, rn, offset }, |
| 2977 | + (false, FpMemWidth::H16) => Inst::SturFp16 { rt, rn, offset }, |
| 2978 | + (true, FpMemWidth::B8) => Inst::LdurFp8 { rt, rn, offset }, |
| 2979 | + (false, FpMemWidth::B8) => Inst::SturFp8 { rt, rn, offset }, |
| 2980 | + (true, FpMemWidth::D64) => Inst::LdurFp64 { rt, rn, offset }, |
| 2981 | + (false, FpMemWidth::D64) => Inst::SturFp64 { rt, rn, offset }, |
| 2982 | + (true, FpMemWidth::S32) => Inst::LdurFp32 { rt, rn, offset }, |
| 2983 | + (false, FpMemWidth::S32) => Inst::SturFp32 { rt, rn, offset }, |
| 2984 | + (true, FpMemWidth::Q128) => Inst::LdurFp128 { rt, rn, offset }, |
| 2985 | + (false, FpMemWidth::Q128) => Inst::SturFp128 { rt, rn, offset }, |
| 2986 | + }); |
| 2987 | + } |
| 2988 | + |
| 2989 | + Err(self.err(format!( |
| 2990 | + "FP/SIMD memory offset {offset} is out of range for {}", |
| 2991 | + if is_load { "LDR" } else { "STR" } |
| 2992 | + ))) |
| 2993 | + } |
| 2994 | + |
| 2947 | 2995 | fn parse_ldur_stur(&mut self, is_load: bool) -> Result<Stmt, ParseError> { |
| 2948 | 2996 | let (rt, sf) = self.parse_gp_reg_with_size()?; |
| 2949 | 2997 | self.expect(&Tok::Comma)?; |
@@ -3328,58 +3376,7 @@ impl<'a> Parser<'a> { |
| 3328 | 3376 | return Ok(Stmt::Instruction(inst)); |
| 3329 | 3377 | } |
| 3330 | 3378 | |
| 3331 | | - let inst = match (is_load, width) { |
| 3332 | | - (true, FpMemWidth::H16) => Inst::LdrFpImm16 { |
| 3333 | | - rt, |
| 3334 | | - rn, |
| 3335 | | - offset: offset as u16, |
| 3336 | | - }, |
| 3337 | | - (false, FpMemWidth::H16) => Inst::StrFpImm16 { |
| 3338 | | - rt, |
| 3339 | | - rn, |
| 3340 | | - offset: offset as u16, |
| 3341 | | - }, |
| 3342 | | - (true, FpMemWidth::B8) => Inst::LdrFpImm8 { |
| 3343 | | - rt, |
| 3344 | | - rn, |
| 3345 | | - offset: offset as u16, |
| 3346 | | - }, |
| 3347 | | - (false, FpMemWidth::B8) => Inst::StrFpImm8 { |
| 3348 | | - rt, |
| 3349 | | - rn, |
| 3350 | | - offset: offset as u16, |
| 3351 | | - }, |
| 3352 | | - (true, FpMemWidth::D64) => Inst::LdrFpImm64 { |
| 3353 | | - rt, |
| 3354 | | - rn, |
| 3355 | | - offset: offset as u16, |
| 3356 | | - }, |
| 3357 | | - (false, FpMemWidth::D64) => Inst::StrFpImm64 { |
| 3358 | | - rt, |
| 3359 | | - rn, |
| 3360 | | - offset: offset as u16, |
| 3361 | | - }, |
| 3362 | | - (true, FpMemWidth::S32) => Inst::LdrFpImm32 { |
| 3363 | | - rt, |
| 3364 | | - rn, |
| 3365 | | - offset: offset as u16, |
| 3366 | | - }, |
| 3367 | | - (false, FpMemWidth::S32) => Inst::StrFpImm32 { |
| 3368 | | - rt, |
| 3369 | | - rn, |
| 3370 | | - offset: offset as u16, |
| 3371 | | - }, |
| 3372 | | - (true, FpMemWidth::Q128) => Inst::LdrFpImm128 { |
| 3373 | | - rt, |
| 3374 | | - rn, |
| 3375 | | - offset: offset as u16, |
| 3376 | | - }, |
| 3377 | | - (false, FpMemWidth::Q128) => Inst::StrFpImm128 { |
| 3378 | | - rt, |
| 3379 | | - rn, |
| 3380 | | - offset: offset as u16, |
| 3381 | | - }, |
| 3382 | | - }; |
| 3379 | + let inst = self.fp_mem_offset_inst(is_load, width, rt, rn, offset)?; |
| 3383 | 3380 | Ok(Stmt::Instruction(inst)) |
| 3384 | 3381 | } |
| 3385 | 3382 | |
@@ -5758,6 +5755,19 @@ mod tests { |
| 5758 | 5755 | ); |
| 5759 | 5756 | } |
| 5760 | 5757 | |
| 5758 | + #[test] |
| 5759 | + fn parse_mov_wzr_keeps_zero_register() { |
| 5760 | + assert_eq!( |
| 5761 | + parse_inst("mov w26, wzr"), |
| 5762 | + Inst::OrrReg { |
| 5763 | + rd: W26, |
| 5764 | + rn: WZR, |
| 5765 | + rm: WZR, |
| 5766 | + sf: false |
| 5767 | + } |
| 5768 | + ); |
| 5769 | + } |
| 5770 | + |
| 5761 | 5771 | #[test] |
| 5762 | 5772 | fn parse_ubfiz_() { |
| 5763 | 5773 | assert_eq!( |
@@ -6583,6 +6593,30 @@ mod tests { |
| 6583 | 6593 | ); |
| 6584 | 6594 | } |
| 6585 | 6595 | |
| 6596 | + #[test] |
| 6597 | + fn parse_str_s_negative_offset_uses_unscaled() { |
| 6598 | + assert_eq!( |
| 6599 | + parse_inst("str s8, [x29, #-4]"), |
| 6600 | + Inst::SturFp32 { |
| 6601 | + rt: S8, |
| 6602 | + rn: X29, |
| 6603 | + offset: -4 |
| 6604 | + } |
| 6605 | + ); |
| 6606 | + } |
| 6607 | + |
| 6608 | + #[test] |
| 6609 | + fn parse_ldr_s_negative_offset_uses_unscaled() { |
| 6610 | + assert_eq!( |
| 6611 | + parse_inst("ldr s9, [x29, #-4]"), |
| 6612 | + Inst::LdurFp32 { |
| 6613 | + rt: S9, |
| 6614 | + rn: X29, |
| 6615 | + offset: -4 |
| 6616 | + } |
| 6617 | + ); |
| 6618 | + } |
| 6619 | + |
| 6586 | 6620 | #[test] |
| 6587 | 6621 | fn parse_ldr_s_register_offset() { |
| 6588 | 6622 | assert_eq!( |