packages feed

linearscan-hoopl-0.1.0.0: test/Main.hs

module Main where

import AsmTest
import Assembly
import LinearScan.Hoopl.DSL
import Test.Hspec

-- | The objective of these tests is to present a program to the register
--   allocator algorithm, and verify that for certain inputs we get the
--   expected outputs.

main :: IO ()
main = hspec $ do
  describe "Sanity tests" sanityTests
  describe "Block tests" blockTests

sanityTests :: SpecWith ()
sanityTests = do
  it "Single instruction" $ asmTest 32
    (label "entry" $ do
        add v0 v1 v2
        return_) $

    label "entry" $ do
        add r0 r1 r2
        return_

  it "Single, repeated instruction" $ asmTest 32
    (label "entry" $ do
        add v0 v1 v2
        add v0 v1 v2
        add v0 v1 v2
        return_) $

    label "entry" $ do
        add r0 r1 r2
        add r0 r1 r2
        add r0 r1 r2
        return_

  it "Multiple instructions" $ asmTest 32
    (label "entry" $ do
        add v0 v1 v2
        add v0 v1 v3
        add v0 v1 v2
        return_) $

    label "entry" $ do
        add r0 r1 r2
        add r0 r1 r3
        add r0 r1 r2
        return_

  it "More variables used than registers" $ asmTest 32
    (label "entry" $ do
        add v0 v1 v2
        add v3 v4 v5
        add v6 v7 v8
        add v9 v10 v11
        add v12 v13 v14
        add v15 v16 v17
        add v18 v19 v20
        add v21 v22 v23
        add v24 v25 v26
        add v27 v28 v29
        add v30 v31 v32
        add v33 v34 v35
        return_) $

    label "entry" $ do
        add r0 r1 r24
        add r2 r3 r0
        add r4 r5 r1
        add r6 r7 r2
        add r8 r9 r3
        add r10 r11 r4
        add r12 r13 r5
        add r14 r15 r6
        add r16 r17 r7
        add r18 r19 r8
        add r20 r21 r9
        add r22 r23 r10
        return_

  it "Single long-lived variable" $ asmTest 32
    (label "entry" $ do
        add v0 v1 v2
        add v0 v4 v5
        add v0 v7 v8
        add v0 v10 v11
        return_) $

    label "entry" $ do
        add r0 r1 r5
        add r0 r2 r1
        add r0 r3 r2
        add r0 r4 r3
        return_

  it "Two long-lived variables" $ asmTest 32
    (label "entry" $ do
        add v0 v1 v2
        add v0 v4 v5
        add v0 v4 v8
        add v0 v4 v11
        return_) $

    label "entry" $ do
        add r0 r1 r3
        add r0 r2 r1
        add r0 r2 r4
        add r0 r2 r5
        return_

  it "One variable with a long interval" $ asmTest 32
    (label "entry" $ do
        add v0   v1  v2
        add v3   v4  v5
        add v6   v7  v8
        add v9  v10 v11
        add v12 v13 v14
        add v15 v16 v17
        add v18 v19 v20
        add v21 v22 v23
        add v24 v25 v26
        add v27 v28 v29
        add v30 v31 v32
        add v0  v34 v35
        return_) $

    label "entry" $ do
        add r0 r1 r23
        add r2 r3 r1
        add r4 r5 r2
        add r6 r7 r3
        add r8 r9 r4
        add r10 r11 r5
        add r12 r13 r6
        add r14 r15 r7
        add r16 r17 r8
        add r18 r19 r9
        add r20 r21 r10
        add r0 r22 r11
        return_

  it "Many variables with long intervals" $ asmTest 32
    (label "entry" $ do
        add v0   v1  v2
        add v3   v4  v5
        add v6   v7  v8
        add v9  v10 v11
        add v12 v13 v14
        add v15 v16 v17
        add v18 v19 v20
        add v21 v22 v23
        add v24 v25 v26
        add v27 v28 v29
        add v0   v1  v2
        add v3   v4  v5
        add v6   v7  v8
        add v9  v10 v11
        add v12 v13 v14
        add v15 v16 v17
        add v18 v19 v20
        add v21 v22 v23
        add v24 v25 v26
        add v27 v28 v29
        return_) $

    label "entry" $ do
        add r0 r1 r20
        add r2 r3 r21
        add r4 r5 r22
        add r6 r7 r23
        add r8 r9 r24
        add r10 r11 r25
        add r12 r13 r26
        add r14 r15 r27
        add r16 r17 r28
        add r18 r19 r29
        add r0 r1 r20
        add r2 r3 r21
        add r4 r5 r22
        add r6 r7 r23
        add r8 r9 r24
        add r10 r11 r25
        add r12 r13 r26
        add r14 r15 r27
        add r16 r17 r28
        add r18 r19 r29
        return_

  it "Spilling one variable" $ asmTest 32
    (label "entry" $ do
        add v0   v1  v2
        add v3   v4  v5
        add v6   v7  v8
        add v9  v10 v11
        add v12 v13 v14
        add v15 v16 v17
        add v18 v19 v20
        add v21 v22 v23
        add v24 v25 v26
        add v27 v28 v29
        add v30 v31 v32
        add v0   v1  v2
        add v3   v4  v5
        add v6   v7  v8
        add v9  v10 v11
        add v12 v13 v14
        add v15 v16 v17
        add v18 v19 v20
        add v21 v22 v23
        add v24 v25 v26
        add v27 v28 v29
        add v30 v31 v32
        return_) $

    label "entry" $ do
        add r0 r1 r22
        add r2 r3 r23
        add r4 r5 r24
        add r6 r7 r25
        add r8 r9 r26
        add r10 r11 r27
        add r12 r13 r28
        add r14 r15 r29
        add r16 r17 r30
        add r18 r19 r31

        -- When we reach the 32nd variable considered (which happens to be
        -- v30), we must spill a register because there are not 32 registers.
        -- So we pick the first register, counting from 0, whose next use
        -- position is the furthest from this position.  That happens to be
        -- r18, which is next used at position 41.
        save r18 0
        add r20 r21 r18
        add r0 r1 r22
        add r2 r3 r23
        add r4 r5 r24
        add r6 r7 r25
        add r8 r9 r26
        add r10 r11 r27
        add r12 r13 r28
        add r14 r15 r29
        add r16 r17 r30

        -- When it comes time to reload v29 (which had been allocated to r18),
        -- we pick the first available register which happens to be r0 in this
        -- case.
        restore 0 r0
        add r0 r19 r31
        add r20 r21 r18
        return_

  it "Inserts only necessary saves and restores" $ asmTest 4
    (label "entry" $ do
        add v0 v1 v2
        add v2 v1 v3
        add v3 v2 v4
        add v4 v1 v0
        return_) $

    label "entry" $ do
        add r1 r0 r2
        add r2 r0 r3
        save r0 0
        add r3 r2 r0
        restore 0 r2
        add r0 r2 r1
        return_

blockTests :: SpecWith ()
blockTests = do
  it "Allocates across blocks" $ asmTest 32
    (do label "entry" $ do
            add v0 v1 v2
            jump "L2"

        label "L2" $ do
            add v2 v3 v4
            add v2 v4 v5
            jump "L3"

        label "L3" $ do
            add v2 v5 v6
            add v2 v6 v7
            add v2 v7 v8
            return_) $

    do label "entry" $ do
           add r0 r1 r3
           jump "L2"

       label "L2" $ do
           add r3 r2 r0
           add r3 r0 r1
           jump "L3"

       label "L3" $ do
           add r3 r1 r0
           add r3 r0 r1
           add r3 r1 r0
           return_

  it "Inserts resolving moves" $ asmTest 4
    (do label "entry" $ do
            add v0 v1 v2
            branch Zero v2 "B3" "B2"

        label "B2" $ do
            add v1 v2 v3
            add v0 v0 v4
            add v0 v0 v5
            add v0 v4 v6
            add v0 v5 v6
            jump "B4"

        label "B3" $ do
            add v1 v2 v3
            jump "B4"

        label "B4" $ do
            add v3 v3 v0
            return_) $

    do label "entry" $ do
           add r0 r1 r2
           branch Zero r2 "B2" "B3"

       label "B2" $ do
           add r1 r2 r3
           jump "B4"

       label "B3" $ do
           add r1 r2 r3
           save r3 16
           save r2 8
           save r1 0
           add r0 r0 r1
           add r0 r0 r2
           add r0 r1 r3
           add r0 r2 r3
           restore 16 r3
           jump "B4"

       label "B4" $ do
           add r3 r3 r0
           return_

  it "Inserts resolving moves another way" $ asmTest 4
    (do label "entry" $ do
            add v0 v1 v2
            branch Zero v2 "B3" "B2"

        label "B2" $ do
            add v1 v2 v3
            jump "B4"

        label "B3" $ do
            add v1 v2 v3
            add v0 v0 v4
            add v0 v0 v5
            add v0 v4 v6
            add v0 v5 v6
            jump "B4"

        label "B4" $ do
            add v3 v3 v0
            return_) $

    do label "entry" $ do
           add r0 r1 r2
           branch Zero r2 "B2" "B3"

       label "B2" $ do
           add r1 r2 r3
           save r3 0
           add r0 r0 r1
           add r0 r0 r2
           add r0 r1 r3
           add r0 r2 r3
           restore 0 r1
           jump "B4"

       label "B3" $ do
           add r1 r2 r3
           move r3 r1
           jump "B4"

       label "B4" $ do
           add r1 r1 r0
           return_

  it "Another resolution case" $ asmTest 4
    (do label "entry" $ do
            lc v3
            lc v4
            lc v15
            lc v20
            jump "L3"

        label "L3" $ do
            move v3 v9
            move v9 v11
            move v11 v10
            move v10 v12
            move v12 v13
            lc v14
            move v15 v5
            jump "L6"

        label "L6" $
	    branch Zero v4 "L3" "L2"

        label "L2" $ do
            lc v21
            move v21 v18
            move v5 v4
            lc v19
            move v20 v17
            jump "L6") $

    do label "entry" $ do
           lc r0
           lc r1
           lc r2
           lc r3
           save r3 0
           jump "L3"

       label "L3" $ do
           restore 8 r0
           move r0 r3
           save r0 8
           move r3 r0
           move r0 r3
           move r3 r0
           move r0 r3
           lc r0
           save r0 16
           move r2 r0
           save r2 24
           jump "L6"

       label "L6" $
           branch Zero r1 "L3" "L2"

       label "L2" $ do
           lc r3
           move r3 r2
           move r0 r1
           save r1 40
           save r0 32
           lc r3
           restore 0 r1
           move r1 r0
           restore 40 r1
           restore 32 r0
           restore 24 r2
           save r1 0
           jump "L6"