Skip to content

Commit bc68a6c

Browse files
committed
fix: Cleanup messy code in LoadStoreRegFromImmUnsigned.
Fixes #42
1 parent c25313c commit bc68a6c

2 files changed

Lines changed: 74 additions & 41 deletions

File tree

Disarm.Tests/LoadStoreTests.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ public class LoadStoreTests : BaseDisarmTest
88
public LoadStoreTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
99

1010
[Fact]
11-
public void LoadStoreRegisterFromImm()
12-
=> DisassembleAndCheckMnemonic(0x38420F59U, Arm64Mnemonic.LDRB);
11+
public void LoadStoreRegisterFromImm()
12+
{
13+
DisassembleAndCheckMnemonic(0x38420F59U, Arm64Mnemonic.LDRB);
14+
15+
var instruction = DisassembleAndCheckMnemonic(0xFD41C100U, Arm64Mnemonic.LDR);
16+
17+
Assert.Equal("0x00000000 LDR D0, [X8 + 0x380]", instruction.ToString());
18+
}
1319

1420
[Fact]
1521
public void LoadStoreRegFromRegOffset()

Disarm/InternalDisassembly/Arm64LoadsStores.cs

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -682,46 +682,89 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction)
682682
var imm12 = (instruction >> 10) & 0b1111_1111_1111; //Bits 10-21
683683
var rn = (int)(instruction >> 5) & 0b11111; //Bits 5-9
684684
var rt = (int)(instruction & 0b11111); //Bits 0-4
685+
686+
//Zero extend imm12 to 64-bit
687+
var immediate = (long)imm12;
688+
immediate <<= (int) size; //Shift left by the size... apparently?
689+
690+
Arm64Register baseReg;
691+
Arm64Mnemonic mnemonic;
692+
693+
if (isVector)
694+
{
695+
//For once, SIMD/FP is the simple path. It's always LDR or STR, and for all but the 128-bit version, the register depends on size
696+
//Let's get the 128-bit check out first
697+
if (opc is 0b10 or 0b11)
698+
{
699+
//128-bit. Ensure size is 00
700+
if (size != 0)
701+
throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b10/0b11 unallocated for size > 0");
702+
703+
mnemonic = opc == 0b10 ? Arm64Mnemonic.STR : Arm64Mnemonic.LDR;
704+
baseReg = Arm64Register.V0; //128-bit variant
705+
}
706+
else
707+
{
708+
mnemonic = opc == 0b00 ? Arm64Mnemonic.STR : Arm64Mnemonic.LDR;
709+
baseReg = size switch
710+
{
711+
0b00 => Arm64Register.B0, //8-bit variant
712+
0b01 => Arm64Register.H0, //16-bit variant
713+
0b10 => Arm64Register.S0, //32-bit variant
714+
0b11 => Arm64Register.D0, //64-bit variant
715+
_ => throw new("Impossible size")
716+
};
717+
}
718+
719+
return new()
720+
{
721+
Mnemonic = mnemonic,
722+
Op0Kind = Arm64OperandKind.Register,
723+
Op1Kind = Arm64OperandKind.Memory,
724+
Op0Reg = baseReg + rt,
725+
MemBase = Arm64Register.X0 + rn,
726+
MemOffset = immediate,
727+
MemIndexMode = Arm64MemoryIndexMode.Offset,
728+
MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister,
729+
};
730+
}
731+
732+
//Now we have to deal with the non-SIMD/FP case.
685733

686734
//This is considerably less clean than it perhaps could be because they don't stick to patterns and
687735
//the mnemonics are different for different sizes.
688736
//Example - in general, even opc is a store, odd is a load. But opc == 11 && !v && size = 0 => LDRSB. :(
689-
var mnemonic = opc switch
737+
mnemonic = opc switch
690738
{
691739
0b00 => size switch
692740
{
693-
0b00 when !isVector => Arm64Mnemonic.STRB,
694-
0b01 when !isVector => Arm64Mnemonic.STRH,
695-
0b10 or 0b11 when !isVector => Arm64Mnemonic.STR,
696-
_ when isVector => Arm64Mnemonic.STR,
741+
0b00 => Arm64Mnemonic.STRB,
742+
0b01 => Arm64Mnemonic.STRH,
743+
0b10 or 0b11 => Arm64Mnemonic.STR, //32 or 64-bit
697744
_ => throw new($"Impossible size: {size}")
698745
},
699746
0b01 => size switch
700747
{
701-
0b00 when !isVector => Arm64Mnemonic.LDRB,
702-
0b01 when !isVector => Arm64Mnemonic.LDRH,
703-
0b10 or 0b11 when !isVector => Arm64Mnemonic.LDR,
704-
_ when isVector => Arm64Mnemonic.LDR,
748+
0b00 => Arm64Mnemonic.LDRB,
749+
0b01 => Arm64Mnemonic.LDRH,
750+
0b10 or 0b11 => Arm64Mnemonic.LDR, //32 or 64-bit
705751
_ => throw new($"Impossible size: {size}")
706752
},
707753
0b10 => size switch
708754
{
709-
0b00 when !isVector => Arm64Mnemonic.LDRSB, //64-bit variant
710-
0b01 when !isVector => Arm64Mnemonic.LDRSH, //64-bit variant
711-
0b10 when !isVector => Arm64Mnemonic.LDRSW,
712-
0b00 when isVector => Arm64Mnemonic.STR, //128-bit store
755+
//These all break the rules, they are loads but they are even opc
756+
0b00 => Arm64Mnemonic.LDRSB, //64-bit variant
757+
0b01 => Arm64Mnemonic.LDRSH, //64-bit variant
758+
0b10 => Arm64Mnemonic.LDRSW,
713759
0b11 => throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b10 unallocated for size 0b11"),
714-
_ when isVector => throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b10 unallocated for vectors when size > 0"),
715760
_ => throw new($"Impossible size: {size}")
716761
},
717762
0b11 => size switch
718763
{
719-
0b00 when !isVector => Arm64Mnemonic.LDRSB, //32-bit variant
720-
0b01 when !isVector => Arm64Mnemonic.LDRSH, //32-bit variant
721-
0b10 when !isVector => Arm64Mnemonic.PRFM, //TODO?
722-
0b00 when isVector => Arm64Mnemonic.LDR, //128-bit load
764+
0b00 => Arm64Mnemonic.LDRSB, //32-bit variant
765+
0b01 => Arm64Mnemonic.LDRSH, //32-bit variant
766+
0b10 => Arm64Mnemonic.PRFM, //TODO?
723767
0b11 => throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b11 unallocated for size 0b11"),
724-
_ when isVector => throw new Arm64UndefinedInstructionException("Load/store register from immediate (unsigned): opc 0b11 unallocated for vectors when size > 0"),
725768
_ => throw new($"Impossible size: {size}")
726769
},
727770
_ => throw new("Impossible opc value")
@@ -730,17 +773,8 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction)
730773
if (mnemonic == Arm64Mnemonic.PRFM)
731774
throw new NotImplementedException("If you're seeing this, reach out, because PRFM is not implemented.");
732775

733-
var baseReg = mnemonic switch
776+
baseReg = mnemonic switch
734777
{
735-
Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector && opc is 0 => size switch
736-
{
737-
0 => Arm64Register.B0,
738-
1 => Arm64Register.H0,
739-
2 => Arm64Register.S0,
740-
3 => Arm64Register.D0,
741-
_ => throw new("Impossible size")
742-
},
743-
Arm64Mnemonic.STR or Arm64Mnemonic.LDR when isVector => Arm64Register.V0, //128-bit vector
744778
Arm64Mnemonic.STRB or Arm64Mnemonic.LDRB or Arm64Mnemonic.STRH or Arm64Mnemonic.LDRH => Arm64Register.W0,
745779
Arm64Mnemonic.STR or Arm64Mnemonic.LDR when size is 0b10 => Arm64Register.W0,
746780
Arm64Mnemonic.STR or Arm64Mnemonic.LDR => Arm64Register.X0,
@@ -749,21 +783,14 @@ private static Arm64Instruction LoadStoreRegFromImmUnsigned(uint instruction)
749783
Arm64Mnemonic.LDRSW => Arm64Register.X0,
750784
_ => throw new("Impossible mnemonic")
751785
};
752-
753-
var regT = baseReg + rt;
754-
var regN = Arm64Register.X0 + rn;
755-
756-
//Zero extend imm12 to 64-bit
757-
var immediate = (long)imm12;
758-
immediate <<= (int) size; //Shift left by the size... apparently?
759-
786+
760787
return new()
761788
{
762789
Mnemonic = mnemonic,
763790
Op0Kind = Arm64OperandKind.Register,
764791
Op1Kind = Arm64OperandKind.Memory,
765-
Op0Reg = regT,
766-
MemBase = regN,
792+
Op0Reg = baseReg + rt,
793+
MemBase = Arm64Register.X0 + rn,
767794
MemOffset = immediate,
768795
MemIndexMode = Arm64MemoryIndexMode.Offset,
769796
MnemonicCategory = Arm64MnemonicCategory.MemoryToOrFromRegister,

0 commit comments

Comments
 (0)