Stop the linter recommending a change that a faster helper would break
SplitLint knew that CALL restores A, B and Data Pointers 0 to 2, so a pointer set before a call is still set after it. That is true, and it made the tool give advice that was correct today and unsafe to take. Of the 178 redundant SETDs it found across the corpus, 122 were redundant ONLY because of that restore - the shape is everywhere, because it is how a helper is given its arguments: SETD.0 SbfsBlock SETD.2 SbfsFileStart CALL sbfsSetWord SETD.0 SbfsBlock <- flagged Removing that last line is right until sbfsSetWord is reached with RCAL, which restores nothing - and that is not hypothetical, it is what RCAL was added to this machine for, measured at close to halving the assembler's memory traffic. The failure would also be silent from the linter's side: it forgets everything across an RCAL, so it would stop reporting while the removals stayed removed. So a claim now ends at any call, for pointers and for registers, the way a claim about carry already did. 257 warnings become 127, and the redundant SETDs 178 become 54 - which is exactly the number an independent count of "no CALL in between" had arrived at separately. The fixture gained a SETD and an INIA repeated across a CALL, which must stay quiet, and the harness fails with the old behaviour put back. Two mistakes worth recording: the new expectations first pointed at the LABEL above the repeats rather than the repeats, which passes for free because nothing ever warns about a label; and the block landed in the middle of another check's comment, leaving that comment describing the code below it instead of its own.
This commit is contained in:
+36
-5
@@ -99,6 +99,13 @@ printf '%s\n' \
|
||||
' NOP' \
|
||||
' "INIA 0d0; DPUA.0"' \
|
||||
' ; INIB 0d0' \
|
||||
'acrossACall:' \
|
||||
' SETD.2 Thing' \
|
||||
' CALL somewhere' \
|
||||
' SETD.2 Thing' \
|
||||
' INIA 0d9' \
|
||||
' CALL somewhere' \
|
||||
' INIA 0d9' \
|
||||
> "$fixture"
|
||||
|
||||
"$LINT" "$fixture" > "$output" 2>&1
|
||||
@@ -146,14 +153,38 @@ expect 56 "BRC is always taken because carry is known set"
|
||||
expect 60 "BRC is never taken because carry is known clear"
|
||||
expect 61 "BNC is always taken because carry is known clear"
|
||||
|
||||
# ---- And a claim does not survive a call ----
|
||||
#
|
||||
# CALL really does restore A, B and DP0 to DP2, so both repeats below are genuinely
|
||||
# redundant and the linter used to say so. It no longer does, on purpose: that advice is
|
||||
# correct only while the callee is reached with CALL, and RCAL exists precisely so hot
|
||||
# helpers can stop being one. 122 of the 178 redundant SETDs in the corpus were of this
|
||||
# kind, and removing them would have become wrong the day a helper was made faster.
|
||||
#
|
||||
# THE LINE NUMBERS ARE THE REPEATS, not the label above them. Checking the label instead
|
||||
# passes for free, because a label is never warned about by anything.
|
||||
quiet=0
|
||||
for line in 70 73; do
|
||||
if grep -q "^${fixture}:${line}: style:" "$output"; then
|
||||
FAIL=$((FAIL + 1)); MISSING+=("line $line should be quiet across a CALL")
|
||||
printf " [%sFAIL%s] line %-3s no claim survives a CALL\n" "$RED" "$RESET" "$line"
|
||||
else
|
||||
PASS=$((PASS + 1)); quiet=$((quiet + 1))
|
||||
printf " [%sok %s] line %-3s no claim survives a CALL\n" "$GREEN" "$RESET" "$line"
|
||||
fi
|
||||
done
|
||||
|
||||
# ---- And nothing it does not know about ----
|
||||
#
|
||||
# The fixture carries four lines that must stay quiet: a device read whose result is
|
||||
# overwritten, a self-restoring push pair that is NOT one, a string that happens to spell
|
||||
# instructions, and a commented-out instruction. A rule that started firing on any of
|
||||
# those would be a rule reading source that is not code.
|
||||
# The fixture carries four lines that must stay quiet for a different reason: a device read
|
||||
# whose result is overwritten, a self-restoring push pair that is NOT one, a string that
|
||||
# happens to spell instructions, and a commented-out instruction. A rule that started
|
||||
# firing on any of those would be a rule reading source that is not code.
|
||||
#
|
||||
# Every pass so far is either a warning that was expected or a line that stayed quiet, so
|
||||
# the warnings that came out should be the passes less the quiet ones.
|
||||
total=$(grep -c "^${fixture}:[0-9]*: style:" "$output")
|
||||
if [ "$total" = "$PASS" ] && [ "$FAIL" = "0" ]; then
|
||||
if [ "$total" = "$((PASS - quiet))" ] && [ "$FAIL" = "0" ]; then
|
||||
printf " [%sok %s] and nothing else %s warnings, no more\n" "$GREEN" "$RESET" "$total"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user