1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Backend (backendTests) where67import Data.Maybe (fromJust)8import Language.QBE.Backend.DFS (findUnexplored, newPathSel, trackTrace)9import Language.QBE.Backend.Model qualified as Model10import Language.QBE.Backend.Tracer qualified as ST11import Language.QBE.Simulator.Concolic.Expression qualified as CE12import Language.QBE.Simulator.Default.Expression qualified as DE13import Language.QBE.Simulator.Explorer (defSolver)14import Language.QBE.Simulator.Symbolic.Expression qualified as SE15import Language.QBE.Types qualified as QBE16import Test.Tasty17import Test.Tasty.HUnit18import Util1920traceTests :: TestTree21traceTests =22 testGroup23 "Tests for the Symbolic Tracer"24 [ testCase "Branch tracing with single concrete branch" $25 do26 t <-27 parseAndExec28 (QBE.GlobalIdent "main")29 []30 "function $main() {\n\31 \@start.1\n\32 \%cond =w add 0, 1\n\33 \jnz %cond, @branch.1, @branch.2\n\34 \@branch.1\n\35 \ret\n\36 \@branch.2\n\37 \ret\n\38 \}"3940 -- Trace must be empty because it doesn't branch on symbolic values.41 length t @?= 0,42 testCase "Branch tracing and solving with single symbolic branch" $43 do44 s <- defSolver45 c <- unconstrained s 0 "input" QBE.Word46 assertBool "created value is symbolic" $ CE.hasSymbolic c47 let inputs = [(SE.toSExpr . fromJust . CE.symbolic) c]4849 t <-50 parseAndExec51 (QBE.GlobalIdent "branchOnInput")52 [c]53 "function $branchOnInput(w %cond) {\n\54 \@start.1\n\55 \jnz %cond, @branch.1, @branch.2\n\56 \@branch.1\n\57 \ret\n\58 \@branch.2\n\59 \ret\n\60 \}"6162 t @?= [(False, ST.newBranch (fromJust $ CE.symbolic c))]6364 let pathSel = trackTrace newPathSel t65 (mm, nextPathSel) <- findUnexplored s inputs pathSel6667 let assign = Model.toList (fromJust mm)68 case assign of69 [(_, DE.VWord v)] ->70 assertBool "condition must be /= 0" (v /= 0)71 _ -> assertFailure "unexpected model"7273 -- There are only two branches: input == 0 and input /= 074 (nxt, _) <- findUnexplored s inputs nextPathSel75 nxt @?= Nothing,76 testCase "Tracing with multiple branches" $77 do78 s <- defSolver79 c1 <- unconstrained s 0 "cond1" QBE.Word80 c2 <- unconstrained s 0 "cond2" QBE.Word8182 t <-83 parseAndExec84 (QBE.GlobalIdent "branchOnInput")85 [c1, c2]86 "function $branchOnInput(w %cond1, w %cond2) {\n\87 \@jump.1\n\88 \jnz %cond1, @branch.1, @branch.2\n\89 \@branch.1\n\90 \jmp @jump.2\n\91 \@branch.2\n\92 \jmp @jump.2\n\93 \@jump.2\n\94 \jnz %cond2, @branch.3, @branch.4\n\95 \@branch.3\n\96 \ret\n\97 \@branch.4\n\98 \ret\n\99 \}"100101 length t @?= 2102 ]103104backendTests :: TestTree105backendTests =106 testGroup107 "Tests for the Symbolic Data Structures"108 [traceTests]