Комментарии 5
С Int_VecDo3
разве не ошибка в анализаторе? Смотрите, GetNumVectorElements
возвращает числа из множества {0, 1, 2, 3, 4}
. Если n >= 1
, то проблемы с n + n - 2
нет. Значит, беда будет в случае n == 0
.
Это бывает, если аргумент GetNumVectorElements
, полученный в строке VectorSize sz = GetVecSize(op);
, не лежит во множестве {V_Single, V_Pair, V_Triple, V_Quad} == {1, 2, 3, 4}
. Хорошо, а что же такое GetVecSize
?
static inline VectorSize GetVecSize(MIPSOpcode op) {
int a = (op >> 7) & 1;
int b = (op >> 14) & 2;
return (VectorSize)(a + b + 1); // Safe, there are no other possibilities
}
MIPSOpcode
- просто обёртка над uint32_t
. Как видим, здесь вычисляются a
и b
. Первое - либо 0, либо 1. Второе - либо 0, либо 2. Поэтому их сумма принадлежит множеству {0, 1, 2, 3}
. Докидывая в сумму единичку, получаем {1, 2, 3, 4}
, т.е. sz
всегда корректно, а значит, n
тоже.
Спасибо за интересное замечание!
Мне понятна ваша логика. Однако, если следовать ей, то можно сделать вывод, что дефолтная ветвь в GetNumVectorElements
является недостижимым кодом:
static inline int GetNumVectorElements(VectorSize sz)
{
switch (sz)
{
case V_Single: return 1;
case V_Pair: return 2;
case V_Triple: return 3;
case V_Quad: return 4;
default: return 0; //unreachable code
}
}
Недостижимый код тоже является ошибкой и в данном случае можно сказать, что является меньшим злом. Итак, имеем недостижимый код в виде default: return 0;
Можно убрать эту ветвь, но тогда получим предупреждение от компилятора, что control flow graph функции имеет путь без возвращаемого значения. Хорошо, заменим возвращаемое значение на std::optional
и на этом казалось бы всё.
Но! Можно всё же заметить, что VectorSize
имеет такой вариант значения как V_Invalid = -1
, который как раз обрабатывается этой ветвью и может прийти из указанной вами функции GetVecSize
.
Предположим даже, что обёртка MIPSOpcode
, которая представляет из себя Memory::Opcode
всегда будет иметь значения из того же диапазона, что и uint32_t
, а переменные a
и b
, которые удачно объявлены как int
, никогда не будут отрицательными. И результат каста (VectorSize)(a + b + 1)
тоже никогда не будет V_Invalid
(-1).
Есть ли гарантия, что в результате рефакторинга или других изменений в коде всё это не рассыплется как карточный домик?
Предположим даже, что обёртка
MIPSOpcode
, которая представляет из себяMemory::Opcode
всегда будет иметь значения из того же диапазона, что иuint32_t
, а переменныеa
иb
, которые удачно объявлены какint
, никогда не будут отрицательными.
Сейчас вообще не понял)
Ну, Memory::Opcode
олицетворяет 4 байта, в которых закодирована команда процессору (RISC, всё такое, удобно), конечно, он будет принимать значения, как и то, что у него под капотом - uint32_t
. А как объявлены переменные a
и b
, неважно, т.к. мы срезаем битовыми масками по степени двойки в каждом случае.
Что же касается рефакторинга... Ну, у нас есть тесты. Их мы гоняем на каждый PR, чтобы сравнить, не перестали ли мы походить на реальную PSP. Да-да-да, покрытия идеального не бывает, избыточность тестирования... Это всё ясно, но лучше варианта нет. Те же статические анализаторы могут ошибаться, как мы видим.
Что касается dummyThreadHackAddr
, я его просто ещё не отрефакторил. Месяц назад я вытащил код, относящийся к системе AdhocMatching
, в отдельные файлы, а потом почистил hadouken codestyle. На очереди AdhocCtl
как раз, просто руки не дошли.
Вы контрибьютор? У пиписисипипи вроде не русскоязычный автор
Верно, можете посмотреть мой вклад: https://github.com/hrydgard/ppsspp/pulls/Nemoumbra
PPSSPP или всё же psp? Смотрим баги в коде из прошлого