Skip to content

Commit f975994

Browse files
authored
Fix TryDecodeLoadStoreDualHalfSignedBIL (#564)
* correct comment with correct register UNPREDICTABLE behavior * possibly fixed * Update block comment on TryDecodeLoadStoreDualHalfSignedBReg * allow unpredictable inst behavior for strdp only * more relevant comments * added check for kRegAction * corrected if statement I think * remove LOG(ERROR) << inst.Serialize()
1 parent 7d33dec commit f975994

File tree

1 file changed

+88
-23
lines changed

1 file changed

+88
-23
lines changed

lib/Arch/AArch32/Decode.cpp

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,12 +1904,16 @@ static const char *const kLoadStoreDHSB[] = {
19041904

19051905
// P:W o1 Rn op2
19061906
// 0 1111 10 LDRD (literal) if Rt<0> == '1' t2 == 15 || wback then UNPREDICTABLE;
1907+
// Note(sonya): For LDRD (literal), <Rt> is the first general-purpose register to be transferred, encoded
1908+
// in the "Rt" field. This register must be even-numbered and not R14.
19071909
// != 01 1 1111 01 LDRH (literal) if t == 15 || wback then UNPREDICTABLE;
19081910
// != 01 1 1111 10 LDRSB (literal) if t == 15 || wback then UNPREDICTABLE;
19091911
// != 01 1 1111 11 LDRSH (literal) if t == 15 || wback then UNPREDICTABLE;
1910-
// 00 0 != 1111 10 LDRD (immediate) — post-indexed if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE;
1912+
// 00 0 != 1111 10 LDRD (immediate) — post-indexed if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
1913+
// Note(sonya): For LDRD (immediate), <Rt> is the first general-purpose register to be transferred, encoded
1914+
// in the "Rt" field. This register must be even-numbered and not R14.
19111915
// 00 0 01 STRH (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
1912-
// 00 0 11 STRD (immediate) — post-indexed if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
1916+
// 00 0 11 STRD (immediate) — post-indexed if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; (t != 15)
19131917
// 00 1 != 1111 01 LDRH (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
19141918
// 00 1 != 1111 10 LDRSB (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
19151919
// 00 1 != 1111 11 LDRSH (immediate) — post-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
@@ -1919,15 +1923,19 @@ static const char *const kLoadStoreDHSB[] = {
19191923
// 01 1 01 LDRHT if t == 15 || n == 15 || n == t then UNPREDICTABLE;
19201924
// 01 1 10 LDRSBT if t == 15 || n == 15 || n == t then UNPREDICTABLE;
19211925
// 01 1 11 LDRSHT if t == 15 || n == 15 || n == t then UNPREDICTABLE;
1922-
// 10 0 != 1111 10 LDRD (immediate) — offset if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE;
1926+
// 10 0 != 1111 10 LDRD (immediate) — offset if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
1927+
// Note(sonya): For LDRD (immediate), <Rt> is the first general-purpose register to be transferred, encoded
1928+
// in the "Rt" field. This register must be even-numbered and not R14.
19231929
// 10 0 01 STRH (immediate) — offset if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
1924-
// 10 0 11 STRD (immediate) — offset if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
1930+
// 10 0 11 STRD (immediate) — offset if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; (t != 15)
19251931
// 10 1 != 1111 01 LDRH (immediate) — offset if t == 15 wback && n == t then UNPREDICTABLE;
19261932
// 10 1 != 1111 10 LDRSB (immediate) — offset if t == 15 wback && n == t then UNPREDICTABLE;
19271933
// 10 1 != 1111 11 LDRSH (immediate) — offset if t == 15 wback && n == t then UNPREDICTABLE;
1928-
// 11 0 != 1111 10 LDRD (immediate) — pre-indexed if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE;
1934+
// 11 0 != 1111 10 LDRD (immediate) — pre-indexed if t2 == 15 wback && (n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
1935+
// Note(sonya): For LDRD (immediate), <Rt> is the first general-purpose register to be transferred, encoded
1936+
// in the "Rt" field. This register must be even-numbered and not R14.
19291937
// 11 0 01 STRH (immediate) — pre-indexed if t == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
1930-
// 11 0 11 STRD (immediate) — pre-indexed if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
1938+
// 11 0 11 STRD (immediate) — pre-indexed if t2 == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; (t != 15)
19311939
// 11 1 != 1111 01 LDRH (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE;
19321940
// 11 1 != 1111 10 LDRSB (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE;
19331941
// 11 1 != 1111 11 LDRSH (immediate) — pre-indexed if t == 15 wback && n == t then UNPREDICTABLE;
@@ -1939,11 +1947,14 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst,
19391947
const LoadStoreDualHSBIL enc = {bits};
19401948
auto instruction =
19411949
kLoadStoreDHSB[enc.P << 4 | enc.W << 3 | enc.o1 << 2 | enc.op2];
1950+
19421951
if (enc.rn == kPCRegNum && !instruction && enc.op2 == 0b10) {
1943-
if (enc.rt & 0b1) {
1944-
inst.category = Instruction::kCategoryError;
1945-
return false;
1946-
}
1952+
// LDRD (literal), LDRH (literal), LDRSB (literal), LDRSH (literal)
1953+
// if (enc.rt & 0b1) {
1954+
// // Catches if Rt<0> == '1' then UNPREDICTABLE;
1955+
// inst.category = Instruction::kCategoryError;
1956+
// return false;
1957+
// }
19471958
inst.function = "LDRDp";
19481959
} else if (instruction) {
19491960
inst.function = instruction;
@@ -1952,15 +1963,28 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst,
19521963
return false;
19531964
}
19541965

1966+
// write_back: All insts but LDRD, STRH, STRD, LDRH, LDRSB, LDRSH (immediate) — offset
19551967
bool write_back = (!enc.P || enc.W);
1968+
19561969
bool is_add = enc.U;
19571970
bool is_index = enc.P;
1971+
1972+
// is_dual: LDRD (literal and immediate) && STRD (immediate)
19581973
bool is_dual = !enc.o1 && enc.op2 >> 1;
1974+
19591975
uint32_t rt2 = enc.rt + 1;
19601976

1961-
if ((!is_dual && enc.rt == kPCRegNum) || (is_dual && rt2 == kPCRegNum) ||
1962-
(write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt ||
1963-
(is_dual && enc.rn == rt2)))) {
1977+
if (
1978+
// rt != 15 for any instruction
1979+
(enc.rt == kPCRegNum) ||
1980+
// rt must be even && rt != 14 for all LDRD insts
1981+
(!enc.o1 && (enc.op2 == 0b10) && ((enc.rt & 0b1) || enc.rt != kLRRegNum)) ||
1982+
// t2 != 15 for all dual instructions
1983+
(is_dual && rt2 == kPCRegNum) ||
1984+
// if wback && (n == t || n == t2) then UNPREDICTABLE; (LDRD)
1985+
// if wback && (n == 15 || n == t ) then UNPREDICTABLE; (STRH && LDRH)
1986+
// if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; (STRD)
1987+
(write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt || (is_dual && enc.rn == rt2)))) {
19641988
inst.category = Instruction::kCategoryError;
19651989
return false;
19661990
}
@@ -2041,8 +2065,10 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst,
20412065

20422066
// P W o1 op2
20432067
// 0 0 0 01 STRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
2044-
// 0 0 0 10 LDRD (register) — post-indexed if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
2045-
// 0 0 0 11 STRD (register) — post-indexed if t2 == 15 || m == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
2068+
// 0 0 0 10 LDRD (register) — post-indexed if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
2069+
// 0 0 0 11 STRD (register) — post-indexed if t2 == 15 || m == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
2070+
// Note(sonya): For LDRD (register) and STRD (register), <Rt> Is the first general-purpose register to be transferred,
2071+
// encoded in the "Rt" field. This register must be even-numbered and not R14. If Rt == 15 then CONSTRAINED UNPREDICTABLE behavior occurs.
20462072
// 0 0 1 01 LDRH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
20472073
// 0 0 1 10 LDRSB (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
20482074
// 0 0 1 11 LDRSH (register) — post-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE
@@ -2053,8 +2079,10 @@ static bool TryDecodeLoadStoreDualHalfSignedBIL(Instruction &inst,
20532079
// 0 1 1 10 LDRSBT if t == 15 || n == 15 || n == t || m == 15 then UNPREDICTABLE;
20542080
// 0 1 1 11 LDRSHT if t == 15 || n == 15 || n == t || m == 15 then UNPREDICTABLE;
20552081
// 1 0 01 STRH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
2056-
// 1 0 10 LDRD (register) — pre-indexed if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
2057-
// 1 0 11 STRD (register) — pre-indexed if t2 == 15 || m == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
2082+
// 1 0 10 LDRD (register) — pre-indexed if t2 == 15 || m == 15 || m == t || m == t2 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
2083+
// 1 0 11 STRD (register) — pre-indexed if t2 == 15 || m == 15 wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; if Rt<0> == '1' then UNPREDICTABLE;
2084+
// Note(sonya): For LDRD (register) and STRD (register), <Rt> Is the first general-purpose register to be transferred,
2085+
// encoded in the "Rt" field. This register must be even-numbered and not R14. If Rt == 15 then CONSTRAINED UNPREDICTABLE behavior occurs.
20582086
// 1 1 01 LDRH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
20592087
// 1 1 10 LDRSB (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE;
20602088
// 1 1 11 LDRSH (register) — pre-indexed if t == 15 || m == 15 wback && (n == 15 || n == t) then UNPREDICTABLE
@@ -2074,17 +2102,54 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst,
20742102
bool is_unpriv = enc.W && !enc.P;
20752103
uint32_t rt2 = enc.rt + 1;
20762104

2077-
if (!instruction ||
2078-
(write_back &&
2079-
(enc.rn == kPCRegNum || enc.rn == enc.rt || (is_dual && enc.rn == rt2) ||
2080-
(is_unpriv && (enc.rt == kPCRegNum || enc.rm == kPCRegNum)))) ||
2105+
if (
2106+
// UNALLOCATED instruction
2107+
!instruction ||
2108+
2109+
// Rt cannot be 15 for any instruction except STRDp as a special exception
2110+
(enc.rt == kPCRegNum && !(!enc.o1 && enc.op2 == 0b11u)) ||
2111+
2112+
// all dual insts (except STRDp) must be even and not the link register
2113+
(is_dual && (((enc.rt & 0b1)) || enc.rt == kLRRegNum) && !(!enc.o1 && enc.op2 == 0b11u) ) ||
2114+
2115+
// for STRDp rt can be r15 or must be even and not LR
2116+
((!enc.o1 && enc.op2 == 0b11u) && (((enc.rt & 0b1) && enc.rt != kPCRegNum) || enc.rt == kLRRegNum))||
2117+
2118+
(write_back && (enc.rn == kPCRegNum || enc.rn == enc.rt ||
2119+
(is_dual && enc.rn == rt2) || (is_unpriv && enc.rm == kPCRegNum))) ||
20812120
(is_dual && (enc.rt == kLRRegNum || enc.rm == kPCRegNum ||
2082-
(enc.op2 == 0b10 && (enc.rm == enc.rt || enc.rm == rt2))))) {
2121+
(enc.op2 == 0b10 && (enc.rm == enc.rt || enc.rm == rt2))))
2122+
) {
20832123
inst.category = Instruction::kCategoryError;
20842124
return false;
20852125
} else {
20862126
inst.function = instruction;
20872127
}
2128+
2129+
// CONSTRAINED UNPREDICTABLE behavior for STRD (register):
2130+
//
2131+
// If Rt<0> == '1', then one of the following behaviors must occur:
2132+
// - The instruction is undefined.
2133+
// - The instruction executes as NOP.
2134+
// - The instruction executes with the additional decode: t<0> = '0'.
2135+
// - The instruction executes with the additional decode: t2 = t.
2136+
// - The instruction executes as described, with no change to its behavior
2137+
// and no additional side-effects. This does not apply when Rt == '1111'.
2138+
//
2139+
// If t == 15 || t2 == 15, then one of the following behaviors must occur:
2140+
// - The instruction is undefined.
2141+
// - The instruction executes as NOP.
2142+
// - The store instruction performs the store using the specified
2143+
// addressing mode but the value corresponding to R15 is unknown.
2144+
//
2145+
// Permitted UNPREDICTABLE behavior for STRDp only when rt is r15 only
2146+
if (enc.rt == kPCRegNum) {
2147+
// The instruction executes with the additional decode: t2 = t.
2148+
CHECK(!enc.o1 && enc.op2 == 0b11u)
2149+
<< "Rt is R15 for an instruction other than STRDp!!";
2150+
rt2 = enc.rt;
2151+
}
2152+
20882153
auto is_cond = DecodeCondition(inst, enc.cond);
20892154

20902155
// LDR & LDRB (literal) are pc relative. Need to align the PC to the next nearest 4 bytes
@@ -2135,7 +2200,7 @@ static bool TryDecodeLoadStoreDualHalfSignedBReg(Instruction &inst,
21352200
// The semantics for these instructions take `next_pc` as
21362201
// arguments and should update it accordingly.
21372202

2138-
if (enc.rt == kPCRegNum) {
2203+
if (enc.rt == kPCRegNum && kRegAction == Operand::Action::kActionWrite) {
21392204
AddAddrRegOp(inst, kNextPCVariableName.data(), kAddressSize,
21402205
Operand::kActionWrite, 0);
21412206

0 commit comments

Comments
 (0)