Skip to content

Add backend divergence probes - #2

Open
erichanwang wants to merge 1 commit into
mainfrom
backend-divergence-audit
Open

Add backend divergence probes#2
erichanwang wants to merge 1 commit into
mainfrom
backend-divergence-audit

Conversation

@erichanwang

Copy link
Copy Markdown
Owner

Summary

  • Add 13 focused language programs covering the requested backend disagreement boundaries.
  • Leave compiler.cpp, runtime.c, and .github/ unchanged so the array work can proceed independently.
  • Preserve seven divergences as exact repros and six agreement cases as coverage.

Exact divergences

Each named .lang file is the exact input.

Missing arguments read uninitialized registers

Input: audit_calls_missing.lang

Interpreter exit: 0. Compiled exit: 139.

-1.000000
-EMPTY
-EMPTY
-EMPTY
-EMPTY
-EMPTY

The interpreter fills omitted parameters with EMPTY. The generated callee spills all six parameter registers even though the caller initialized only %rdi.

Seven arguments are accepted only by the interpreter

Input: audit_calls_over_limit.lang

-1.000000
-2.000000
-3.000000
-4.000000
-5.000000
-6.000000
-7.000000
+Error: 'seven' called with 7 arguments; the codegen supports at most 6 (System V register arguments).

The interpreter exits 0 after executing the call. Assembly generation exits 1.

Mixed relational comparisons use different boolean payloads

Input: audit_comparisons.lang. The other 46 printed comparisons agree. These 10 differ:

-prt (1 == 1) < 1 => true
+prt (1 == 1) < 1 => false
-prt (1 == 1) >= 1 => false
+prt (1 == 1) >= 1 => true
-prt 1 > (1 == 1) => true
+prt 1 > (1 == 1) => false
-prt 1 <= (1 == 1) => false
+prt 1 <= (1 == 1) => true
-prt (1 == 1) > "true" => false
+prt (1 == 1) > "true" => true
-prt (1 == 1) <= "true" => true
+prt (1 == 1) <= "true" => false
-prt "true" < (1 == 1) => false
+prt "true" < (1 == 1) => true
-prt "true" >= (1 == 1) => true
+prt "true" >= (1 == 1) => false
-prt (1 == 1) > missing => false
+prt (1 == 1) > missing => true
-prt (1 == 1) <= missing => true
+prt (1 == 1) <= missing => false

Interpreter booleans use b_val, but generic relational comparison reads n_val. Runtime booleans store their payload in num, which runtime comparison reads.

Stored and parameter-passed EMPTY values become unknown identifiers

Input: audit_empty_values.lang

-EMPTY
-EMPTY
-EMPTY
+ERROR: Unknown identifier: 'saved'
+ERROR: Unknown identifier: 'value'
+ERROR: Unknown identifier: 'value'

The compiled representation uses null for both a valid EMPTY value and an unassigned slot, so the undefined-identifier guard cannot distinguish them.

Long undefined identifiers are truncated

Input: audit_identifier_long.lang, containing a 392-character identifier.

-ERROR: Unknown identifier: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ERROR: Unknown identifier: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

The interpreter line is 421 characters. The compiled line is 255 characters because rt_undef and rt_print use fixed buffers.

Numeric literals lose precision and long formatted values truncate

Input: audit_numeric.lang

-1.234568
+1.234570
+0.000000
 0.000000
-0.000001
 -0.000000
-9007199254740991.000000
-9007199254740992.000000
-9007199254740992.000000
-123456789012345677877719597056.000000
-1000000000000000052504760255204420248704468581108159154915854115511802457988908195786371375080447864043704443832883878176942523235360430575644792184786706982848387200926575803737830233794788090059368953234970799945081119038967640880074652742780142494579258788820056842838115669472196386865459400540160.000000
+9007200000000000.000000
+9007200000000000.000000
+9007200000000000.000000
+123456999999999998385612390400.000000
+100000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936895323497079994508111903896764088007465274278014249457925

Assembly literals are emitted with the stream's default significant-digit precision. Independently, compiled numeric printing truncates the longest value to the runtime's fixed output buffer. Negative zero agrees.

Interpreter recursion exhausts the stack first

Input: audit_recursion.lang

Interpreter exit: 139. Compiled exit: 0.

+0.000000

With an 8192 KiB stack and address randomization disabled for repeatability, descend(8055) is the largest successful interpreter input and descend(8056) exits 139. The compiled backend succeeds through descend(261958) and exits 139 at descend(261959).

Covered without divergence

  • audit_calls.lang: six arguments, left-to-right observable evaluation, and nested calls.
  • audit_spills.lang: expression depth beyond the five-register pool while a nested function call runs.
  • audit_strings.lang: empty strings, quote-shaped input, backslashes, a 300-character string, long concatenation, and mixed string-number concatenation.
  • audit_strings_unterminated.lang: unterminated string at EOF. Both outputs agree; the assembler emits a warning.
  • audit_loops.lang: three nested loops with break and continue inside if blocks inside a function.
  • audit_scoping.lang: assignment and parameter shadowing preserve the global value.

Verification

  • g++ -O2 -std=c++17 -Wall -Wextra -o /tmp/axc compiler.cpp: exits 0. The unhandled array enumerator warnings are left for the in-flight array work.
  • ./run_tests.sh: exits 1 with the seven exact repro failures above; 19 programs pass.

Add focused language programs that exercise ABI call edges, value representation, numeric formatting, control flow, scoping, strings, and recursion.

The differential suite was green because it lacked inputs that distinguish EMPTY from unassigned storage, boolean payload layouts, literal precision, and fixed runtime buffers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant