packages feed

kempe 0.2.0.4 → 0.2.0.5

raw patch · 23 files changed

+206/−118 lines, 23 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,12 @@ # kempe +## 0.2.0.5++  * Fix bug in arm control-flow analysis+  * Fix bugs in IR optimization pass+  * Improve IR optimization+  * Add `fromMaybe` and `fromRight` functions+ ## 0.2.0.4    * Kind-check external function declarations
+ golden/Golden.hs view
@@ -0,0 +1,29 @@+module Main (main) where++import           Data.Tuple.Extra (uncurry3)+import           Harness+import           System.Info      (arch)+import           Test.Tasty++main :: IO ()+main = defaultMain $+    testGroup "Golden output tests" $+        fmap (uncurry3 goldenOutput) allGoldens ++ crossTests++-- These are redundant on arm+crossTests :: [TestTree]+crossTests = case arch of+    "x86_64"  -> fmap (uncurry3 crossGolden) allGoldens+    "aarch64" -> []+    _         -> error "Test suite must be run on x86_64 or aarch64"++allGoldens :: [(FilePath, FilePath, FilePath)]+allGoldens =+    [ ("examples/factorial.kmp", "test/harness/factorial.c", "test/golden/factorial.out")+    , ("test/examples/splitmix.kmp", "test/harness/splitmix.c", "test/golden/splitmix.out")+    , ("lib/numbertheory.kmp", "test/harness/numbertheory.c", "test/golden/numbertheory.out")+    , ("test/examples/hamming.kmp", "test/harness/hamming.c", "test/golden/hamming.out")+    , ("test/examples/bool.kmp", "test/harness/bool.c", "test/golden/bool.out")+    , ("test/examples/const.kmp", "test/harness/const.c", "test/golden/const.out")+    , ("test/data/badCodegen.kmp", "test/harness/id.c", "test/golden/id.out")+    ]
+ golden/Harness.hs view
@@ -0,0 +1,72 @@+module Harness ( goldenOutput+               , crossGolden+               ) where++import qualified Data.ByteString.Lazy       as BSL+import qualified Data.ByteString.Lazy.Char8 as ASCII+import           Data.Functor               (void)+import           Kempe.File+import           System.FilePath            ((</>))+import           System.IO.Temp+import           System.Info                (arch)+import           System.Process             (CreateProcess (env, std_err), StdStream (Inherit), proc, readCreateProcess)+import           Test.Tasty+import           Test.Tasty.Golden          (goldenVsString)+import           Test.Tasty.HUnit           (assertBool, testCase)++data CC = CC+        | ArmCC++instance Show CC where+    show CC    = "cc"+    show ArmCC = "aarch64-linux-gnu-gcc"++runGcc :: CC+       -> [FilePath]+       -> FilePath+       -> IO ()+runGcc cc fps o =+    void $ readCreateProcess ((proc (show cc) (fps ++ ["-o", o])) { std_err = Inherit }) ""++compileOutput :: FilePath+              -> FilePath+              -> IO BSL.ByteString+compileOutput fp harness =+    withSystemTempDirectory "kmp" $ \dir -> do+        let oFile = dir </> "kempe.o"+            exe = dir </> "kempe"+            compiler = case arch of+                "x86_64"  -> compile+                "aarch64" -> armCompile+                _         -> error "Internal error in test suite! Must run on either x86_64 or aarch64"+        compiler fp oFile False+        runGcc CC [oFile, harness] exe+        readExe exe+    where readExe fp' = ASCII.pack <$> readCreateProcess ((proc fp' []) { std_err = Inherit }) ""++crossCompileOutput :: FilePath+                   -> FilePath+                   -> IO BSL.ByteString+crossCompileOutput fp harness =+    withSystemTempDirectory "kmp" $ \dir -> do+        let oFile = dir </> "kempe.o"+            exe = dir </> "kempe"+        armCompile fp oFile False+        runGcc ArmCC [oFile, harness] exe+        readExe exe+    where readExe fp' = ASCII.pack <$> readCreateProcess ((proc "qemu-aarch64-static" [fp']) { std_err = Inherit, env = qemuEnv }) ""+          qemuEnv = Just [("QEMU_LD_PREFIX", "/usr/aarch64-linux-gnu/")]++goldenOutput :: FilePath -- ^ Kempe file+             -> FilePath -- ^ C test harness+             -> FilePath -- ^ Golden file path+             -> TestTree+goldenOutput kFp cFp golden =+    goldenVsString kFp golden (compileOutput kFp cFp)++crossGolden :: FilePath -- ^ Kempe file+            -> FilePath -- ^ C test harness+            -> FilePath -- ^ Golden file path+            -> TestTree+crossGolden kFp cFp golden =+    goldenVsString kFp golden (crossCompileOutput kFp cFp)
kempe.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.0 name:            kempe-version:         0.2.0.4+version:         0.2.0.5 license:         BSD-3-Clause license-file:    LICENSE copyright:       Copyright: (c) 2020-2021 Vanessa McHale@@ -12,6 +12,7 @@ build-type:      Simple data-files:     test/data/*.kmp+    test/data/diamond/*.kmp     test/err/*.kmp     test/examples/*.kmp     test/golden/*.out@@ -208,7 +209,7 @@ test-suite kempe-golden     type:             exitcode-stdio-1.0     main-is:          Golden.hs-    hs-source-dirs:   test+    hs-source-dirs:   golden     other-modules:    Harness     default-language: Haskell2010     ghc-options:      -threaded -rtsopts "-with-rtsopts=-N -K1K" -Wall
lib/either.kmp view
@@ -3,6 +3,14 @@  type Either a b { Left a | Right b } +fromRight : b ((Either a) b) -- b+          =: [+    { case+        | Left  -> drop+        | Right -> dip(drop)+    }+]+ isLeft : ((Either a) b) -- Bool        =: [     { case
lib/maybe.kmp view
@@ -1,5 +1,13 @@ type Maybe a { Just a | Nothing } +fromMaybe : a (Maybe a) -- a+          =: [+    { case+        | Just    -> dip(drop)+        | Nothing ->+    }+]+ isJust : (Maybe a) -- Bool        =: [     { case
src/Kempe/Asm/Arm/ControlFlow.hs view
@@ -79,6 +79,12 @@     ; l_i <- lookupLabel l     ; pure (BranchLink (ControlAnn i [l_i] IS.empty IS.empty) l : nextAsms)     }+addControlFlow ((Branch _ l):asms) = do+    { i <- getFresh+    ; nextAsms <- addControlFlow asms+    ; l_i <- lookupLabel l+    ; pure (Branch (ControlAnn i [l_i] IS.empty IS.empty) l : nextAsms)+    } addControlFlow (Ret{}:asms) = do     { i <- getFresh     ; nextAsms <- addControlFlow asms
src/Kempe/Check/Lint.hs view
@@ -8,6 +8,8 @@ lint :: Declarations a b b -> Maybe (Warning b) lint = foldMapAlternative lintDecl +-- TODO: lint for something like dip(0) -> replace with 0 swap+ lintDecl :: KempeDecl a b b -> Maybe (Warning b) lintDecl Export{}             = Nothing lintDecl TyDecl{}             = Nothing
src/Kempe/IR.hs view
@@ -254,6 +254,7 @@             ret <- newLabel             let meat' = (++ [Jump ret]) . toList <$> meat             pure $ dataPointerDec decSz : concatMap toList switches ++ concat meat' ++ [Labeled ret]+            -- TODO: why dataPointerDec decSz??  zipWithM :: (Applicative m) => (a -> b -> m c) -> NonEmpty a -> NonEmpty b -> m (NonEmpty c) zipWithM f xs ys = sequenceA (NE.zipWith f xs ys)@@ -268,13 +269,15 @@ patternSwitch :: SizeEnv -> Pattern (ConsAnn MonoStackType) MonoStackType -> Label -> [Stmt] patternSwitch _ (PatternBool _ True) l                   = [MJump (Mem 1 (Reg DataPointer)) l] patternSwitch _ (PatternBool _ False) l                  = [MJump (EqByte (Mem 1 (Reg DataPointer)) (ConstTag 0)) l]-patternSwitch _ (PatternWildcard _) l                    = [Jump l]+patternSwitch _ (PatternWildcard _) l                    = [Jump l] -- FIXME: what about padding? when standing in for a constructor... patternSwitch _ (PatternInt _ i) l                       = [MJump (ExprIntRel IntEqIR (Mem 8 (Reg DataPointer)) (ConstInt $ fromInteger i)) l] patternSwitch env (PatternCons ann@(ConsAnn _ tag' _) _) l =     let padAt = padBytes env ann + 1         -- decrement by padAt bytes (to discard padding), then we need to access         -- the tag at [datapointer+padAt] when we check         in [ dataPointerDec padAt, MJump (EqByte (Mem 1 (ExprIntBinOp IntPlusIR (Reg DataPointer) (ConstInt padAt))) (ConstTag tag')) l]+        -- FIXME: do we need dataPointerInc padAt at the end? not all+        -- constructors will have the same padding, it will fall through...  -- | Constructors may need to be padded, this computes the number of bytes of -- padding
src/Kempe/IR/Opt.hs view
@@ -43,12 +43,12 @@     ((MovTemp DataPointer (ExprIntBinOp IntPlusIR (Reg DataPointer) (ConstInt i)))         :(MovTemp DataPointer (ExprIntBinOp IntMinusIR (Reg DataPointer) (ConstInt i')))         :ss) =-            MovTemp DataPointer (ExprIntBinOp IntMinusIR (Reg DataPointer) (ConstInt $ i-i')) : successiveBumps ss+            MovTemp DataPointer (ExprIntBinOp IntPlusIR (Reg DataPointer) (ConstInt $ i-i')) : successiveBumps ss successiveBumps     ((MovTemp DataPointer (ExprIntBinOp IntMinusIR (Reg DataPointer) (ConstInt i)))         :(MovTemp DataPointer (ExprIntBinOp IntPlusIR (Reg DataPointer) (ConstInt i')))-        :ss) =-            MovTemp DataPointer (ExprIntBinOp IntMinusIR (Reg DataPointer) (ConstInt $ i'-i)) : successiveBumps ss+        :ss) = -- TODO: is this particular one right?+            MovTemp DataPointer (ExprIntBinOp IntMinusIR (Reg DataPointer) (ConstInt $ i-i')) : successiveBumps ss successiveBumps     (st@(MovMem e0 k (Mem 8 e1))         :(MovMem e0' k' (Mem 8 e1'))@@ -74,11 +74,18 @@ liftOptE []                       = [] liftOptE ((MovMem e0 sz e1) : ss) = MovMem (optE e0) sz (optE e1) : liftOptE ss liftOptE ((MovTemp t e) : ss)     = MovTemp t (optE e) : liftOptE ss+liftOptE ((MJump e l) : ss)       = MJump (optE e) l : liftOptE ss+liftOptE ((CJump e l0 l1) : ss)   = CJump (optE e) l0 l1 : liftOptE ss liftOptE (s:ss)                   = s : liftOptE ss  optE :: Exp -> Exp optE (ExprIntBinOp IntPlusIR e (ConstInt 0))  = optE e optE (ExprIntBinOp IntMinusIR e (ConstInt 0)) = optE e+optE (BoolBinOp op e e')                      = BoolBinOp op (optE e) (optE e')+optE (Mem sz e)                               = Mem sz (optE e)+optE (PopcountIR e)                           = PopcountIR (optE e)+optE (IntNegIR e)                             = IntNegIR (optE e)+optE (EqByte e e')                            = EqByte (optE e) (optE e') optE e                                        = e  removeNop :: [Stmt] -> [Stmt]
src/Kempe/TyAssign.hs view
@@ -492,7 +492,7 @@ tyPattern :: Pattern b a -> TypeM () (StackType ()) tyPattern PatternWildcard{} = do     aN <- dummyName "a"-    pure $ StackType (S.singleton aN) [TyVar () aN] []+    pure $ StackType (S.singleton aN) [TyVar () aN] [] -- FIXME: this is wrong for constructors, could be a -- b c (for instance) tyPattern PatternInt{} = pure $ StackType S.empty [TyBuiltin () TyInt] [] tyPattern PatternBool{} = pure $ StackType S.empty [TyBuiltin () TyBool] [] tyPattern (PatternCons _ tn) = renameStack . flipStackType =<< consLookup (void tn)
− test/Golden.hs
@@ -1,28 +0,0 @@-module Main (main) where--import           Data.Tuple.Extra (uncurry3)-import           Harness-import           System.Info      (arch)-import           Test.Tasty--main :: IO ()-main = defaultMain $-    testGroup "Golden output tests" $-        fmap (uncurry3 goldenOutput) allGoldens ++ crossTests---- These are redundant on arm-crossTests :: [TestTree]-crossTests = case arch of-    "x86_64"  -> fmap (uncurry3 crossGolden) allGoldens-    "aarch64" -> []-    _         -> error "Test suite must be run on x86_64 or aarch64"--allGoldens :: [(FilePath, FilePath, FilePath)]-allGoldens =-    [ ("examples/factorial.kmp", "test/harness/factorial.c", "test/golden/factorial.out")-    , ("test/examples/splitmix.kmp", "test/harness/splitmix.c", "test/golden/splitmix.out")-    , ("lib/numbertheory.kmp", "test/harness/numbertheory.c", "test/golden/numbertheory.out")-    , ("test/examples/hamming.kmp", "test/harness/hamming.c", "test/golden/hamming.out")-    , ("test/examples/bool.kmp", "test/harness/bool.c", "test/golden/bool.out")-    , ("test/examples/const.kmp", "test/harness/const.c", "test/golden/const.out")-    ]
− test/Harness.hs
@@ -1,72 +0,0 @@-module Harness ( goldenOutput-               , crossGolden-               ) where--import qualified Data.ByteString.Lazy       as BSL-import qualified Data.ByteString.Lazy.Char8 as ASCII-import           Data.Functor               (void)-import           Kempe.File-import           System.FilePath            ((</>))-import           System.IO.Temp-import           System.Info                (arch)-import           System.Process             (CreateProcess (env, std_err), StdStream (Inherit), proc, readCreateProcess)-import           Test.Tasty-import           Test.Tasty.Golden          (goldenVsString)-import           Test.Tasty.HUnit           (assertBool, testCase)--data CC = CC-        | ArmCC--instance Show CC where-    show CC    = "cc"-    show ArmCC = "aarch64-linux-gnu-gcc"--runGcc :: CC-       -> [FilePath]-       -> FilePath-       -> IO ()-runGcc cc fps o =-    void $ readCreateProcess ((proc (show cc) (fps ++ ["-o", o])) { std_err = Inherit }) ""--compileOutput :: FilePath-              -> FilePath-              -> IO BSL.ByteString-compileOutput fp harness =-    withSystemTempDirectory "kmp" $ \dir -> do-        let oFile = dir </> "kempe.o"-            exe = dir </> "kempe"-            compiler = case arch of-                "x86_64"  -> compile-                "aarch64" -> armCompile-                _         -> error "Internal error in test suite! Must run on either x86_64 or aarch64"-        compiler fp oFile False-        runGcc CC [oFile, harness] exe-        readExe exe-    where readExe fp' = ASCII.pack <$> readCreateProcess ((proc fp' []) { std_err = Inherit }) ""--crossCompileOutput :: FilePath-                   -> FilePath-                   -> IO BSL.ByteString-crossCompileOutput fp harness =-    withSystemTempDirectory "kmp" $ \dir -> do-        let oFile = dir </> "kempe.o"-            exe = dir </> "kempe"-        armCompile fp oFile False-        runGcc ArmCC [oFile, harness] exe-        readExe exe-    where readExe fp' = ASCII.pack <$> readCreateProcess ((proc "qemu-aarch64-static" [fp']) { std_err = Inherit, env = qemuEnv }) ""-          qemuEnv = Just [("QEMU_LD_PREFIX", "/usr/aarch64-linux-gnu/")]--goldenOutput :: FilePath -- ^ Kempe file-             -> FilePath -- ^ C test harness-             -> FilePath -- ^ Golden file path-             -> TestTree-goldenOutput kFp cFp golden =-    goldenVsString kFp golden (compileOutput kFp cFp)--crossGolden :: FilePath -- ^ Kempe file-            -> FilePath -- ^ C test harness-            -> FilePath -- ^ Golden file path-            -> TestTree-crossGolden kFp cFp golden =-    goldenVsString kFp golden (crossCompileOutput kFp cFp)
test/Type.hs view
@@ -27,6 +27,7 @@         , tyInfer "lib/gaussian.kmp"         , tyInfer "test/data/transitive.kmp"         , tyInfer "lib/tuple.kmp"+        , tyInfer "test/data/type.kmp"         , badType "test/err/merge.kmp" "Type a_5 -- Int a_4 is not as general as type a_3 -- a_3 a_3"         , badType "test/err/kind.kmp" "Ill-kinded type: '(Maybe_1 Maybe_1)'. Note that type variables have kind \11089 in Kempe."         , badType "test/err/patternMatch.kmp" "Inexhaustive pattern match."
+ test/data/badCodegen.kmp view
@@ -0,0 +1,15 @@+import "lib/maybe.kmp"++id0 : Int -- Int+      =: [ Just dip(0) fromMaybe ]++id1 : Int -- Int+     =: [ Just {case | Nothing -> 0 | Just ->} ]++id2 : Int -- Int+    =: [ Just 0 swap {case | Just -> dip(drop) | Nothing ->} ]+    ; Just 0 swap drop swap works++%foreign cabi id0+%foreign cabi id1+%foreign cabi id2
+ test/data/diamond/a.kmp view
@@ -0,0 +1,7 @@+import "test/data/diamond/c.kmp"+import "test/data/diamond/b.kmp"++forExport : -- Int+          =: [ res 2 * ]++%foreign cabi forExport
+ test/data/diamond/b.kmp view
@@ -0,0 +1,2 @@+rand : -- Int+     =: $cfun"rand"
+ test/data/diamond/c.kmp view
@@ -0,0 +1,4 @@+import "test/data/diamond/d.kmp"++res : -- Int+    =: [ rand 1 + ]
+ test/data/diamond/d.kmp view
@@ -0,0 +1,2 @@+rand : -- Int+     =: [ 17 ]
+ test/data/type.kmp view
@@ -0,0 +1,4 @@+import"lib/maybe.kmp"++id1 : Int -- Int+     =: [ Just {case | Nothing -> 0 | _ ->} ]
test/golden/gaussian.ir view
@@ -6,7 +6,7 @@ (movmem (+ (reg datapointer) (int 16)) (mem [1] (+ (reg datapointer) (int 33)))) (movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 24)))) (movmem (- (reg datapointer) (int 24)) (mem [8] (- (reg datapointer) (int 16))))-(movmem (- (reg datapointer) (int 16)) (mem [8] (- (reg datapointer) (int 0))))+(movmem (- (reg datapointer) (int 16)) (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 8))) (movtemp t_1 (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 8)))@@ -31,7 +31,6 @@ (movmem (- (reg datapointer) (int 17)) (mem [8] (- (reg datapointer) (int 34)))) (movmem (- (reg datapointer) (int 9)) (mem [8] (- (reg datapointer) (int 26)))) (movmem (- (reg datapointer) (int 1)) (mem [1] (- (reg datapointer) (int 18))))-(movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 0)))) (movtemp datapointer (+ (reg datapointer) (int 17))) (movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 34)))) (movmem (+ (reg datapointer) (int 8)) (mem [8] (- (reg datapointer) (int 26))))@@ -39,7 +38,7 @@ (movmem (- (reg datapointer) (int 34)) (mem [8] (- (reg datapointer) (int 17)))) (movmem (- (reg datapointer) (int 26)) (mem [8] (- (reg datapointer) (int 9)))) (movmem (- (reg datapointer) (int 18)) (mem [1] (- (reg datapointer) (int 1))))-(movmem (- (reg datapointer) (int 17)) (mem [8] (- (reg datapointer) (int 0))))+(movmem (- (reg datapointer) (int 17)) (mem [8] (reg datapointer))) (movmem (- (reg datapointer) (int 9)) (mem [8] (+ (reg datapointer) (int 8)))) (movmem (- (reg datapointer) (int 1)) (mem [1] (+ (reg datapointer) (int 16)))) (movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 17))))@@ -48,7 +47,6 @@ (movmem (- (reg datapointer) (int 17)) (mem [8] (- (reg datapointer) (int 34)))) (movmem (- (reg datapointer) (int 9)) (mem [8] (- (reg datapointer) (int 26)))) (movmem (- (reg datapointer) (int 1)) (mem [1] (- (reg datapointer) (int 18))))-(movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 0)))) (movtemp datapointer (+ (reg datapointer) (int 17))) (movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 34)))) (movmem (+ (reg datapointer) (int 8)) (mem [8] (- (reg datapointer) (int 26))))@@ -56,7 +54,7 @@ (movmem (- (reg datapointer) (int 34)) (mem [8] (- (reg datapointer) (int 17)))) (movmem (- (reg datapointer) (int 26)) (mem [8] (- (reg datapointer) (int 9)))) (movmem (- (reg datapointer) (int 18)) (mem [1] (- (reg datapointer) (int 1))))-(movmem (- (reg datapointer) (int 17)) (mem [8] (- (reg datapointer) (int 0))))+(movmem (- (reg datapointer) (int 17)) (mem [8] (reg datapointer))) (movmem (- (reg datapointer) (int 9)) (mem [8] (+ (reg datapointer) (int 8)))) (movmem (- (reg datapointer) (int 1)) (mem [1] (+ (reg datapointer) (int 16)))) (movtemp datapointer (- (reg datapointer) (int 34)))@@ -73,7 +71,7 @@ (movtemp datapointer (+ (reg datapointer) (int 8))) (movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 16)))) (movmem (- (reg datapointer) (int 16)) (mem [8] (- (reg datapointer) (int 8))))-(movmem (- (reg datapointer) (int 8)) (mem [8] (- (reg datapointer) (int 0))))+(movmem (- (reg datapointer) (int 8)) (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 16))) (movtemp t_7 (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 8)))@@ -85,17 +83,16 @@ (movtemp datapointer (- (reg datapointer) (int 8))) (movtemp t_10 (mem [8] (reg datapointer))) (movmem (reg datapointer) (+ (reg t_10) (reg t_9)))-(movtemp datapointer (- (reg datapointer) (int 0)))+(movtemp datapointer (+ (reg datapointer) (int -34))) (movmem (reg datapointer) (mem [8] (+ (reg datapointer) (int 25)))) (movmem (+ (reg datapointer) (int 8)) (mem [8] (+ (reg datapointer) (int 33)))) (movmem (+ (reg datapointer) (int 16)) (mem [8] (+ (reg datapointer) (int 41)))) (movmem (+ (reg datapointer) (int 24)) (mem [1] (+ (reg datapointer) (int 49))))-(movtemp datapointer (- (reg datapointer) (int 34))) (movmem (reg datapointer) (mem [8] (+ (reg datapointer) (int 8)))) (movtemp datapointer (+ (reg datapointer) (int 8))) (movmem (reg datapointer) (mem [8] (- (reg datapointer) (int 32)))) (movmem (- (reg datapointer) (int 32)) (mem [8] (- (reg datapointer) (int 24))))-(movmem (- (reg datapointer) (int 24)) (mem [8] (- (reg datapointer) (int 0))))+(movmem (- (reg datapointer) (int 24)) (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 16))) (movtemp t_11 (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 8)))@@ -103,7 +100,7 @@ (movmem (reg datapointer) (* (reg t_12) (reg t_11))) (movtemp datapointer (+ (reg datapointer) (int 8))) (movmem (reg datapointer) (mem [8] (+ (reg datapointer) (int 8))))-(movtemp datapointer (- (reg datapointer) (int 0)))+(movtemp datapointer (+ (reg datapointer) (int -16))) (movtemp t_13 (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 8))) (movtemp t_14 (mem [8] (reg datapointer)))@@ -111,7 +108,6 @@ (movtemp datapointer (+ (reg datapointer) (int 8))) (movmem (reg datapointer) (mem [8] (+ (reg datapointer) (int 16)))) (movmem (+ (reg datapointer) (int 8)) (mem [8] (+ (reg datapointer) (int 24))))-(movtemp datapointer (- (reg datapointer) (int 16))) (movtemp t_15 (mem [8] (reg datapointer))) (movtemp datapointer (- (reg datapointer) (int 8))) (movtemp t_16 (mem [8] (reg datapointer)))
+ test/golden/id.out view
@@ -0,0 +1,3 @@+4+4+4
+ test/harness/id.c view
@@ -0,0 +1,11 @@+#include <stdio.h>++extern int id0(int);+extern int id1(int);+extern int id2(int);++int main(int argc, char *argv[]) {+    printf("%d\n", id0(4));+    printf("%d\n", id1(4));+    printf("%d", id2(4));+}