Compare commits
15 Commits
1405020497
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 64be009635 | |||
| ab7cc053a4 | |||
| e61853e7a6 | |||
| 25b62cb69d | |||
| e03e918bf4 | |||
| 540a5e03fe | |||
|
|
f552132241 | ||
|
|
8130eefc48 | ||
|
|
ee46313617 | ||
|
|
76735e82ac | ||
|
|
2c4bbf659f | ||
|
|
b5f10a6dab | ||
|
|
34642bf965 | ||
|
|
970e85a25c | ||
|
|
630a29e8c6 |
@@ -29,6 +29,7 @@ tasks:
|
||||
"$HOME/.ghcup/bin/ghcup" install ghc "ghc-8.10.7"
|
||||
"$HOME/.ghcup/bin/ghcup" install ghc "ghc-9.0.2"
|
||||
"$HOME/.ghcup/bin/ghcup" install ghc "ghc-9.2.2"
|
||||
"$HOME/.ghcup/bin/ghcup" install ghc "ghc-9.4.2"
|
||||
cabal update
|
||||
- 8_10_7-prepare: |
|
||||
cd qbe-hs
|
||||
@@ -87,6 +88,25 @@ tasks:
|
||||
- 9_2_2-haddock: |
|
||||
cd qbe-hs
|
||||
cabal haddock all
|
||||
- 9_4_2-prepare: |
|
||||
cd qbe-hs
|
||||
cabal configure -w ghc-9.2.2
|
||||
- 9_4_2-check: |
|
||||
cd qbe-hs
|
||||
cabal check
|
||||
- 9_4_2-dependencies: |
|
||||
cd qbe-hs
|
||||
cabal build all --enable-tests --only-dependencies
|
||||
cabal build all --only-dependencies
|
||||
- 9_4_2-build: |
|
||||
cd qbe-hs
|
||||
cabal build all
|
||||
- 9_4_2-test: |
|
||||
cd qbe-hs
|
||||
cabal test all --enable-tests
|
||||
- 9_4_2-haddock: |
|
||||
cd qbe-hs
|
||||
cabal haddock all
|
||||
triggers:
|
||||
- action: email
|
||||
condition: failure
|
||||
|
||||
11
.gitea/workflows/build.yaml
Normal file
11
.gitea/workflows/build.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
name: build
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: nixos
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
- name: build qbe-hs
|
||||
run: nix build -L .
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,3 +6,5 @@ dist-newstyle
|
||||
*.hi
|
||||
.ghc.environment.*
|
||||
*.tix
|
||||
.direnv
|
||||
result
|
||||
@@ -1,5 +1,5 @@
|
||||
# Revision history for qbe-hs
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
## 1.1.0.0 -- 2022-07-10
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
||||
* First version.
|
||||
|
||||
53
README.md
Normal file
53
README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# qbe-hs
|
||||
|
||||
[](https://hackage.haskell.org/package/qbe)
|
||||
[](https://builds.sr.ht/~fgaz/qbe-hs/commits/master?)
|
||||
|
||||
Haskell types and prettyprinter for the [IL](https://c9x.me/compile/doc/il.html)
|
||||
of the [QBE](https://c9x.me/compile/) compiler backend
|
||||
|
||||
## Example
|
||||
|
||||
```haskell
|
||||
helloWorld :: Program
|
||||
helloWorld = Program [] [helloString] [helloMain]
|
||||
where
|
||||
helloString = DataDef [] "str" Nothing
|
||||
[ FieldExtTy Byte $ String "hello world" :| []
|
||||
, FieldExtTy Byte $ Const (CInt False 0) :| []
|
||||
]
|
||||
helloMain = FuncDef [Export] (Just $ AbiBaseTy Word) "main"
|
||||
Nothing [] NoVariadic $
|
||||
Block "start"
|
||||
[]
|
||||
[ Call (Just ("r", AbiBaseTy Word)) (ValGlobal "puts")
|
||||
Nothing
|
||||
[Arg (AbiBaseTy Long) $ ValGlobal "str"]
|
||||
[]
|
||||
]
|
||||
(Ret $ Just $ ValConst $ CInt False 0)
|
||||
:| []
|
||||
```
|
||||
|
||||
Gets rendered to
|
||||
|
||||
```
|
||||
data $str =
|
||||
{b "hello world", b 0}
|
||||
export
|
||||
function w $main () {
|
||||
@start
|
||||
%r =w call $puts (l $str)
|
||||
ret 0
|
||||
}
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
You can send patches to my
|
||||
[public-inbox mailing list](https://lists.sr.ht/~fgaz/public-inbox)
|
||||
or to any of the contacts listed at [fgaz.me/about](https://fgaz.me/about).
|
||||
Or you can send a pull request to the
|
||||
[GitHub mirror](https://github.com/fgaz/qbe-hs).
|
||||
|
||||
Issues are tracked at https://todo.sr.ht/~fgaz/qbe-hs
|
||||
616
flake.lock
generated
Normal file
616
flake.lock
generated
Normal file
@@ -0,0 +1,616 @@
|
||||
{
|
||||
"nodes": {
|
||||
"HTTP": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1451647621,
|
||||
"narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=",
|
||||
"owner": "phadej",
|
||||
"repo": "HTTP",
|
||||
"rev": "9bc0996d412fef1787449d841277ef663ad9a915",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "phadej",
|
||||
"repo": "HTTP",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"cabal-34": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1645834128,
|
||||
"narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=",
|
||||
"owner": "haskell",
|
||||
"repo": "cabal",
|
||||
"rev": "5ff598c67f53f7c4f48e31d722ba37172230c462",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "3.4",
|
||||
"repo": "cabal",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"cabal-36": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1669081697,
|
||||
"narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=",
|
||||
"owner": "haskell",
|
||||
"repo": "cabal",
|
||||
"rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "3.6",
|
||||
"repo": "cabal",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"cardano-shell": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1608537748,
|
||||
"narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "cardano-shell",
|
||||
"rev": "9392c75087cb9a3d453998f4230930dea3a95725",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"repo": "cardano-shell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1672831974,
|
||||
"narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "flake-compat",
|
||||
"rev": "45f2638735f8cdc40fe302742b79f248d23eb368",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"ref": "hkm/gitlab-fix",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hackage": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1776991436,
|
||||
"narHash": "sha256-nR65DbgoJ8Qm8qEtqmVXzeWZS+cc3FeqaZgFon8qdtc=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "hackage.nix",
|
||||
"rev": "2a5e0e1854e7f651ce13df74a60d7c2990a63528",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"repo": "hackage.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hackage-for-stackage": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1776991429,
|
||||
"narHash": "sha256-uiuvT6/wp2uNdtVl8kQ70WSyrye6EdRRQ+yor9kIJLU=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "hackage.nix",
|
||||
"rev": "793f260668f3f8d34f64056e6941d234093fc51e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"ref": "for-stackage",
|
||||
"repo": "hackage.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hackage-internal": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1750307553,
|
||||
"narHash": "sha256-iiafNoeLHwlSLQTyvy8nPe2t6g5AV4PPcpMeH/2/DLs=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "hackage.nix",
|
||||
"rev": "f7867baa8817fab296528f4a4ec39d1c7c4da4f3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"repo": "hackage.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"haskellNix": {
|
||||
"inputs": {
|
||||
"HTTP": "HTTP",
|
||||
"cabal-34": "cabal-34",
|
||||
"cabal-36": "cabal-36",
|
||||
"cardano-shell": "cardano-shell",
|
||||
"flake-compat": "flake-compat",
|
||||
"hackage": "hackage",
|
||||
"hackage-for-stackage": "hackage-for-stackage",
|
||||
"hackage-internal": "hackage-internal",
|
||||
"hls": "hls",
|
||||
"hls-1.10": "hls-1.10",
|
||||
"hls-2.0": "hls-2.0",
|
||||
"hls-2.10": "hls-2.10",
|
||||
"hls-2.11": "hls-2.11",
|
||||
"hls-2.12": "hls-2.12",
|
||||
"hls-2.2": "hls-2.2",
|
||||
"hls-2.3": "hls-2.3",
|
||||
"hls-2.4": "hls-2.4",
|
||||
"hls-2.5": "hls-2.5",
|
||||
"hls-2.6": "hls-2.6",
|
||||
"hls-2.7": "hls-2.7",
|
||||
"hls-2.8": "hls-2.8",
|
||||
"hls-2.9": "hls-2.9",
|
||||
"hpc-coveralls": "hpc-coveralls",
|
||||
"iserv-proxy": "iserv-proxy",
|
||||
"nixpkgs": [
|
||||
"haskellNix",
|
||||
"nixpkgs-unstable"
|
||||
],
|
||||
"nixpkgs-2305": "nixpkgs-2305",
|
||||
"nixpkgs-2311": "nixpkgs-2311",
|
||||
"nixpkgs-2405": "nixpkgs-2405",
|
||||
"nixpkgs-2411": "nixpkgs-2411",
|
||||
"nixpkgs-2505": "nixpkgs-2505",
|
||||
"nixpkgs-2511": "nixpkgs-2511",
|
||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||
"old-ghc-nix": "old-ghc-nix",
|
||||
"stackage": "stackage"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1776993036,
|
||||
"narHash": "sha256-M770+TVYcqAlBAGWEi9HeljqNxujcNBlsNmZCwnxQaI=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "haskell.nix",
|
||||
"rev": "902f9c7fee56b7550293dd691264f0c889e7af26",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"repo": "haskell.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1741604408,
|
||||
"narHash": "sha256-tuq3+Ip70yu89GswZ7DSINBpwRprnWnl6xDYnS4GOsc=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "682d6894c94087da5e566771f25311c47e145359",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-1.10": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1680000865,
|
||||
"narHash": "sha256-rc7iiUAcrHxwRM/s0ErEsSPxOR3u8t7DvFeWlMycWgo=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "b08691db779f7a35ff322b71e72a12f6e3376fd9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "1.10.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.0": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1687698105,
|
||||
"narHash": "sha256-OHXlgRzs/kuJH8q7Sxh507H+0Rb8b7VOiPAjcY9sM1k=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "783905f211ac63edf982dd1889c671653327e441",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.0.0.1",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.10": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1743069404,
|
||||
"narHash": "sha256-q4kDFyJDDeoGqfEtrZRx4iqMVEC2MOzCToWsFY+TOzY=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "2318c61db3a01e03700bd4b05665662929b7fe8b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.10.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.11": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747306193,
|
||||
"narHash": "sha256-/MmtpF8+FyQlwfKHqHK05BdsxC9LHV70d/FiMM7pzBM=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "46ef4523ea4949f47f6d2752476239f1c6d806fe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.11.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.12": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1758709460,
|
||||
"narHash": "sha256-xkI8MIIVEVARskfWbGAgP5sHG/lyeKnkm0LIOJ19X5w=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "7d983de4fa7ff54369f6dd31444bdb9869aec83e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.12.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1693064058,
|
||||
"narHash": "sha256-8DGIyz5GjuCFmohY6Fa79hHA/p1iIqubfJUTGQElbNk=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "b30f4b6cf5822f3112c35d14a0cba51f3fe23b85",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.2.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.3": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1695910642,
|
||||
"narHash": "sha256-tR58doOs3DncFehHwCLczJgntyG/zlsSd7DgDgMPOkI=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "458ccdb55c9ea22cd5d13ec3051aaefb295321be",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.3.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.4": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1699862708,
|
||||
"narHash": "sha256-YHXSkdz53zd0fYGIYOgLt6HrA0eaRJi9mXVqDgmvrjk=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "54507ef7e85fa8e9d0eb9a669832a3287ffccd57",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.4.0.1",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.5": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1701080174,
|
||||
"narHash": "sha256-fyiR9TaHGJIIR0UmcCb73Xv9TJq3ht2ioxQ2mT7kVdc=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "27f8c3d3892e38edaef5bea3870161815c4d014c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.5.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.6": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1705325287,
|
||||
"narHash": "sha256-+P87oLdlPyMw8Mgoul7HMWdEvWP/fNlo8jyNtwME8E8=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "6e0b342fa0327e628610f2711f8c3e4eaaa08b1e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.6.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.7": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1708965829,
|
||||
"narHash": "sha256-LfJ+TBcBFq/XKoiNI7pc4VoHg4WmuzsFxYJ3Fu+Jf+M=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "50322b0a4aefb27adc5ec42f5055aaa8f8e38001",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.7.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.8": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1715153580,
|
||||
"narHash": "sha256-Vi/iUt2pWyUJlo9VrYgTcbRviWE0cFO6rmGi9rmALw0=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "dd1be1beb16700de59e0d6801957290bcf956a0a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.8.0.0",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hls-2.9": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1719993701,
|
||||
"narHash": "sha256-wy348++MiMm/xwtI9M3vVpqj2qfGgnDcZIGXw8sF1sA=",
|
||||
"owner": "haskell",
|
||||
"repo": "haskell-language-server",
|
||||
"rev": "90319a7e62ab93ab65a95f8f2bcf537e34dae76a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "haskell",
|
||||
"ref": "2.9.0.1",
|
||||
"repo": "haskell-language-server",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hpc-coveralls": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1607498076,
|
||||
"narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=",
|
||||
"owner": "sevanspowell",
|
||||
"repo": "hpc-coveralls",
|
||||
"rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "sevanspowell",
|
||||
"repo": "hpc-coveralls",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"iserv-proxy": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1775620557,
|
||||
"narHash": "sha256-10x8/G0x3eR/++XRHPx4MBuqlnc6+N+ajIxXyLkG+nU=",
|
||||
"owner": "stable-haskell",
|
||||
"repo": "iserv-proxy",
|
||||
"rev": "3f7b2815307c20a0dfd816bdf4a39ab86af3e0d4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "stable-haskell",
|
||||
"ref": "iserv-syms",
|
||||
"repo": "iserv-proxy",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2305": {
|
||||
"locked": {
|
||||
"lastModified": 1705033721,
|
||||
"narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-23.05-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2311": {
|
||||
"locked": {
|
||||
"lastModified": 1719957072,
|
||||
"narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7144d6241f02d171d25fba3edeaf15e0f2592105",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-23.11-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2405": {
|
||||
"locked": {
|
||||
"lastModified": 1735564410,
|
||||
"narHash": "sha256-HB/FA0+1gpSs8+/boEavrGJH+Eq08/R2wWNph1sM1Dg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1e7a8f391f1a490460760065fa0630b5520f9cf8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-24.05-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2411": {
|
||||
"locked": {
|
||||
"lastModified": 1751290243,
|
||||
"narHash": "sha256-kNf+obkpJZWar7HZymXZbW+Rlk3HTEIMlpc6FCNz0Ds=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5ab036a8d97cb9476fbe81b09076e6e91d15e1b6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-24.11-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2505": {
|
||||
"locked": {
|
||||
"lastModified": 1764560356,
|
||||
"narHash": "sha256-M5aFEFPppI4UhdOxwdmceJ9bDJC4T6C6CzCK1E2FZyo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6c8f0cca84510cc79e09ea99a299c9bc17d03cb6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-25.05-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-2511": {
|
||||
"locked": {
|
||||
"lastModified": 1775749320,
|
||||
"narHash": "sha256-msT6frWJSQ2WR+0cpk+KPcZdLTLagUIsJwQwIX9JNSo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "74b87959b2d16f59f54d8559cf3cf26b9d907949",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-25.11-darwin",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1775888245,
|
||||
"narHash": "sha256-nwASzrRDD1JBEu/o8ekKYEXm/oJW6EMCzCRdrwcLe90=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "13043924aaa7375ce482ebe2494338e058282925",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"old-ghc-nix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1631092763,
|
||||
"narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=",
|
||||
"owner": "angerman",
|
||||
"repo": "old-ghc-nix",
|
||||
"rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "angerman",
|
||||
"ref": "master",
|
||||
"repo": "old-ghc-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"haskellNix": "haskellNix",
|
||||
"nixpkgs": [
|
||||
"haskellNix",
|
||||
"nixpkgs-unstable"
|
||||
]
|
||||
}
|
||||
},
|
||||
"stackage": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1776990505,
|
||||
"narHash": "sha256-PC/DD76TdzSvs18mL3O7V4wwt6WRHlzxmdrpKFwz68A=",
|
||||
"owner": "input-output-hk",
|
||||
"repo": "stackage.nix",
|
||||
"rev": "c8e2fb3340b2316c84fede31ac01b5446fe2c880",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "input-output-hk",
|
||||
"repo": "stackage.nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
82
flake.nix
Normal file
82
flake.nix
Normal file
@@ -0,0 +1,82 @@
|
||||
{
|
||||
inputs = {
|
||||
haskellNix.url = "github:input-output-hk/haskell.nix";
|
||||
# nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
nixpkgs.follows = "haskellNix/nixpkgs-unstable";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, haskellNix, ... }@inputs:
|
||||
let
|
||||
supportedSystems = [
|
||||
"aarch64-darwin" "aarch64-linux"
|
||||
"x86_64-darwin" "x86_64-linux"
|
||||
];
|
||||
|
||||
overlays = [
|
||||
haskellNix.overlay
|
||||
(final: _prev: {
|
||||
# This overlay adds our project to pkgs
|
||||
qbe-hs = final.haskell-nix.project' {
|
||||
src = ./.;
|
||||
compiler-nix-name = "ghc912";
|
||||
# This is used by `nix develop .` to open a shell for use with
|
||||
# `cabal`, `hlint` and `haskell-language-server`
|
||||
shell.tools = {
|
||||
cabal = {};
|
||||
# hlint = {};
|
||||
haskell-language-server = {};
|
||||
};
|
||||
# Non-Haskell shell tools go here
|
||||
shell.buildInputs = with final; [
|
||||
gcc
|
||||
qbe
|
||||
];
|
||||
# passthru = { inherit (final) qbe; };
|
||||
# This adds `js-unknown-ghcjs-cabal` to the shell.
|
||||
# shell.crossPlatforms = p: [p.ghcjs];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
each-system = f: nixpkgs.lib.genAttrs supportedSystems (system: f rec {
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
inherit (pkgs) lib;
|
||||
inherit system;
|
||||
});
|
||||
|
||||
# haskell-flake
|
||||
hf =
|
||||
let
|
||||
keys = [
|
||||
"packages" "apps" "devShells"
|
||||
"hydraJobs" "ciJobs" "checks"
|
||||
];
|
||||
in nixpkgs.lib.genAttrs keys
|
||||
(k: each-system ({ pkgs, ... }: (pkgs.qbe-hs.flake {}).${k}));
|
||||
in {
|
||||
# Exposed as a REPL convenience.
|
||||
_pkgs = each-system ({ pkgs, ... }: pkgs);
|
||||
|
||||
packages = each-system ({ pkgs, system, ... }:
|
||||
hf.packages.${system} // {
|
||||
default = hf.packages.${system}."qbe:lib:qbe";
|
||||
});
|
||||
|
||||
devShells = each-system
|
||||
({ pkgs, system, ... }: hf.devShells.${system});
|
||||
};
|
||||
|
||||
nixConfig = {
|
||||
extra-substituters = [
|
||||
"https://cache.iog.io"
|
||||
"https://cache.zw3rk.com"
|
||||
];
|
||||
extra-trusted-public-keys = [
|
||||
"hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ="
|
||||
"loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk="
|
||||
];
|
||||
allow-import-from-derivation = "true";
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
export
|
||||
data $d = align 8
|
||||
{z 16, b $g + 32 "foo\nbar\NULbaz" -1}
|
||||
{z 16, b $g + 32 "foo\012bar\000baz" -1}
|
||||
@@ -1,5 +1,5 @@
|
||||
export
|
||||
function :t $f
|
||||
(env %env, w %a, d %b, ...)
|
||||
{@l
|
||||
ret }
|
||||
function :t $f (env %env, w %a, d %b, ...) {
|
||||
@l
|
||||
ret
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
data $str =
|
||||
{b "hello world", b 0}
|
||||
export
|
||||
function w $main
|
||||
()
|
||||
{@start
|
||||
%r =w call $puts (l $str)
|
||||
ret 0}
|
||||
function w $main () {
|
||||
@start
|
||||
%r =w call $puts (l $str)
|
||||
ret 0
|
||||
}
|
||||
23
qbe.cabal
23
qbe.cabal
@@ -4,8 +4,9 @@ name: qbe
|
||||
version: 1.1.0.0
|
||||
synopsis: Types and prettyprinter for the IL of the QBE compiler backend
|
||||
description:
|
||||
This library provides types representing the intermediate language of the QBE
|
||||
compiler backend.
|
||||
This library provides types representing
|
||||
the [intermediate language](https://c9x.me/compile/doc/il.html)
|
||||
of the [QBE](https://c9x.me/compile/) compiler backend.
|
||||
It also provides pretty-printing instances based on
|
||||
the [@prettyprinter@](https://hackage.haskell.org/package/prettyprinter)
|
||||
library, that emit the textual representation of the IL.
|
||||
@@ -19,11 +20,13 @@ copyright: 2022 Francesco Gazzetta
|
||||
category: Language
|
||||
build-type: Simple
|
||||
extra-doc-files: CHANGELOG.md
|
||||
extra-source-files: golden/*.qbe
|
||||
extra-source-files: README.md golden/*.qbe
|
||||
tested-with:
|
||||
, GHC == 8.10.7
|
||||
, GHC == 9.0.2
|
||||
, GHC == 9.2.2
|
||||
, GHC == 9.4.2
|
||||
, GHC == 9.10.3
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
@@ -51,12 +54,18 @@ library
|
||||
build-depends: base ^>= 4.16.1.0
|
||||
|| ^>= 4.14
|
||||
|| ^>= 4.15
|
||||
|| ^>= 4.17
|
||||
|| ^>= 4.20
|
||||
|| ^>= 4.21
|
||||
|| ^>= 4.22
|
||||
, text ^>= 1.2.5
|
||||
|| ^>= 2.0
|
||||
, text-short ^>= 0.1
|
||||
|| ^>= 2.1.4
|
||||
, text-short >= 0.1 || ^>= 0.1.6.1
|
||||
, bytestring ^>= 0.11.3
|
||||
|| ^>= 0.12
|
||||
, hashable ^>= 1.4.0
|
||||
, deepseq ^>= 1.4.4
|
||||
|| ^>= 1.5.0
|
||||
, deepseq ^>= 1.4.4 || ^>= 1.5
|
||||
, prettyprinter ^>= 1.7.1
|
||||
hs-source-dirs: src
|
||||
|
||||
@@ -70,7 +79,7 @@ test-suite golden
|
||||
, prettyprinter
|
||||
, filepath ^>= 1.4.2.2
|
||||
, tasty ^>= 1.4.2.3
|
||||
, tasty-silver ^>= 3.3.1.1
|
||||
, tasty-silver ^>= 3.3.1.1 || ^>= 3.3.2.1
|
||||
other-extensions: TypeApplications
|
||||
OverloadedStrings
|
||||
DataKinds
|
||||
|
||||
@@ -4,34 +4,116 @@
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
module Language.QBE where
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE DuplicateRecordFields, NoFieldSelectors #-}
|
||||
{-|
|
||||
Module : Language.QBE
|
||||
Description : Types and Pretty instances for the QBE IL
|
||||
Copyright : (c) Francesco Gazzetta, 2022
|
||||
License : BSD-3-Clause
|
||||
Maintainer : Francesco Gazzetta <fgaz@fgaz.me>
|
||||
|
||||
This module contains datatypes representing the various structures of
|
||||
the [intermediate language](https://c9x.me/compile/doc/il.html)
|
||||
of the [QBE](https://c9x.me/compile/) compiler backend.
|
||||
|
||||
All datatypes also have 'Pretty' instances from
|
||||
the [@prettyprinter@](https://hackage.haskell.org/package/prettyprinter)
|
||||
library.
|
||||
You can render QBE IL source files, or any part of them, with something like:
|
||||
|
||||
> render :: Pretty a => a -> Text
|
||||
> render = renderStrict . layoutPretty defaultLayoutOptions . pretty
|
||||
|
||||
>>> render $ Ret $ Just $ ValTemporary "a"
|
||||
"ret %a"
|
||||
>>> Text.putStrLn $ render $ Program [] [] [FuncDef [] Nothing "main" …
|
||||
function w $main () {
|
||||
@start
|
||||
⋮
|
||||
-}
|
||||
module Language.QBE
|
||||
(
|
||||
-- * Identifiers
|
||||
RawIdent
|
||||
, Sigil(..)
|
||||
, Ident(..)
|
||||
-- * Types
|
||||
, BaseTy(..)
|
||||
, ExtTy(..)
|
||||
-- * Constants
|
||||
, Const(..)
|
||||
-- * Linkage
|
||||
, Linkage(..)
|
||||
-- * Definitions
|
||||
, Alignment
|
||||
, Size
|
||||
, Amount
|
||||
-- ** Aggregate types
|
||||
, TypeDef(..)
|
||||
, SubTy(..)
|
||||
-- ** Data
|
||||
, DataDef(..)
|
||||
, DataItem(..)
|
||||
, Field(..)
|
||||
-- ** Functions
|
||||
, FuncDef(..)
|
||||
, AbiTy(..)
|
||||
, Param(..)
|
||||
, Variadic(..)
|
||||
, prettyVariadic
|
||||
-- * Control
|
||||
, Val(..)
|
||||
, Block(..)
|
||||
, Jump(..)
|
||||
-- * Instructions
|
||||
, Phi(..)
|
||||
, PhiArg(..)
|
||||
, Inst(..)
|
||||
, Assignment(..)
|
||||
, pattern (:=)
|
||||
, IntRepr(..)
|
||||
, BinaryOp(..)
|
||||
, Comparison(..)
|
||||
, Arg(..)
|
||||
-- * Program
|
||||
, Program(..)
|
||||
) where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Data.Text.Short (ShortText)
|
||||
import qualified Data.Text.Short as TS
|
||||
import Data.ByteString (ByteString)
|
||||
import qualified Data.ByteString as BS
|
||||
import Data.ByteString.Internal (w2c)
|
||||
import Data.Word (Word64)
|
||||
import Data.List.NonEmpty (NonEmpty, toList)
|
||||
import Data.Maybe (maybeToList)
|
||||
import Prettyprinter
|
||||
( Pretty(pretty), Doc, (<+>), vsep, hsep, hang, punctuate, group, flatAlt
|
||||
, space, encloseSep, tupled, comma, equals, braces )
|
||||
, space, encloseSep, tupled, comma, equals, braces, lbrace, rbrace, enclose )
|
||||
-- Instances
|
||||
import Data.Hashable (Hashable)
|
||||
import Control.DeepSeq (NFData)
|
||||
import Data.String (IsString)
|
||||
import Data.Data (Data)
|
||||
import Numeric (showOct)
|
||||
import Data.Char (isPrint, isAscii)
|
||||
|
||||
-- * Identifiers
|
||||
----------------
|
||||
|
||||
-- | A raw identifier string, with no sigil information attached
|
||||
type RawIdent = ShortText
|
||||
|
||||
data Sigil
|
||||
= AggregateTy -- ^ @:@
|
||||
| Global -- ^ @$@
|
||||
| Temporary -- ^ @%@
|
||||
| Label -- ^ @\@@
|
||||
deriving (Show, Eq)
|
||||
-- | Sigils are used to differentiate the verious types of 'Ident'ifier.
|
||||
data Sigil where
|
||||
AggregateTy :: Sigil
|
||||
Global :: Sigil
|
||||
Temporary :: Sigil
|
||||
Label :: Sigil
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
-- | QBE identifiers. The sigil is represented at the type level, so that
|
||||
-- mixing incompatible identifiers is impossible.
|
||||
@@ -50,7 +132,7 @@ data Sigil
|
||||
-- In the second argument of ‘($)’, namely ‘Jmp $ Ident @'Global "a"’
|
||||
-- In the expression: pretty $ Jmp $ Ident @'Global "a"
|
||||
newtype Ident (t :: Sigil) = Ident RawIdent
|
||||
deriving (Show, Eq, Ord, IsString, NFData, Hashable)
|
||||
deriving (Show, Eq, Ord, IsString, NFData, Hashable, Data)
|
||||
|
||||
instance Pretty (Ident 'AggregateTy) where
|
||||
pretty (Ident raw) = pretty ':' <> pretty (TS.toText raw)
|
||||
@@ -64,8 +146,13 @@ instance Pretty (Ident 'Label) where
|
||||
-- * Types
|
||||
----------
|
||||
|
||||
data BaseTy = Word | Long | Single | Double
|
||||
deriving (Show, Eq)
|
||||
-- | Base types
|
||||
data BaseTy
|
||||
= Word -- ^ @w@
|
||||
| Long -- ^ @l@
|
||||
| Single -- ^ @s@
|
||||
| Double -- ^ @d@
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty BaseTy where
|
||||
pretty Word = pretty 'w'
|
||||
@@ -73,8 +160,12 @@ instance Pretty BaseTy where
|
||||
pretty Single = pretty 's'
|
||||
pretty Double = pretty 'd'
|
||||
|
||||
data ExtTy = BaseTy BaseTy | Byte | HalfWord
|
||||
deriving (Show, Eq)
|
||||
-- | Extended types
|
||||
data ExtTy
|
||||
= BaseTy BaseTy
|
||||
| Byte -- ^ @b@
|
||||
| HalfWord -- ^ @h@
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty ExtTy where
|
||||
pretty (BaseTy baseTy) = pretty baseTy
|
||||
@@ -84,17 +175,17 @@ instance Pretty ExtTy where
|
||||
-- * Constants
|
||||
--------------
|
||||
|
||||
-- | Constant/immediate
|
||||
data Const
|
||||
-- MAYBE just use a signed type
|
||||
= CInt Bool Word64 -- ^ The 'Bool' is whether to negate
|
||||
| CSingle Float
|
||||
| CDouble Double
|
||||
| CGlobal (Ident 'Global)
|
||||
deriving (Show, Eq)
|
||||
= CInt Integer -- ^ Integer
|
||||
| CSingle Float -- ^ Single-precision float
|
||||
| CDouble Double -- ^ Double-precision float
|
||||
| CGlobal (Ident 'Global) -- ^ Global symbol
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Const where
|
||||
pretty (CInt negative int) | negative = pretty '-' <> pretty int
|
||||
| otherwise = pretty int
|
||||
pretty (CInt int) = pretty int
|
||||
pretty (CSingle float) = "s_" <> pretty float
|
||||
pretty (CDouble double) = "d_" <> pretty double
|
||||
pretty (CGlobal ident) = pretty ident
|
||||
@@ -103,9 +194,9 @@ instance Pretty Const where
|
||||
------------
|
||||
|
||||
data Linkage
|
||||
= Export
|
||||
| Section ShortText (Maybe Text)
|
||||
deriving (Show, Eq)
|
||||
= Export -- ^ Marks the defined item as visible outside the current file's scope
|
||||
| Section ShortText (Maybe Text) -- ^ Section name, with optional linker flags
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Linkage where
|
||||
pretty Export = "export"
|
||||
@@ -123,10 +214,11 @@ type Amount = Word64
|
||||
-- ** Aggregate types
|
||||
---------------------
|
||||
|
||||
-- | Aggregate type
|
||||
data TypeDef
|
||||
= TypeDef (Ident 'AggregateTy) (Maybe Alignment) [(SubTy, Maybe Amount)]
|
||||
| Opaque (Ident 'AggregateTy) Alignment Size
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty TypeDef where
|
||||
pretty (TypeDef ident alignment def) =
|
||||
@@ -140,10 +232,11 @@ instance Pretty TypeDef where
|
||||
"type" <+> pretty ident <+> equals
|
||||
<+> "align" <+> pretty alignment <+> braces (pretty size)
|
||||
|
||||
-- | A type that can be part of an aggregate type
|
||||
data SubTy
|
||||
= SubExtTy ExtTy
|
||||
| SubAggregateTy (Ident 'AggregateTy)
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty SubTy where
|
||||
pretty (SubExtTy extTy) = pretty extTy
|
||||
@@ -152,8 +245,9 @@ instance Pretty SubTy where
|
||||
-- ** Data
|
||||
----------
|
||||
|
||||
-- | Global object definition
|
||||
data DataDef = DataDef [Linkage] (Ident 'Global) (Maybe Alignment) [Field]
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty DataDef where
|
||||
pretty (DataDef linkage ident alignment fields) = vsep
|
||||
@@ -167,18 +261,28 @@ data DataItem
|
||||
= Symbol (Ident 'Global) (Maybe Alignment)
|
||||
| String ByteString
|
||||
| Const Const
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty DataItem where
|
||||
pretty (Symbol ident alignment) =
|
||||
hsep $ pretty ident : maybeToList ((pretty '+' <+>) . pretty <$> alignment)
|
||||
pretty (String bs) = pretty $ show bs -- HACK: hoping that the escape sequences are the same...
|
||||
-- ~~HACK: hoping that the escape sequences are the same...~~
|
||||
-- ↑ wrong bitch (it's undocumented; i don't blame you babe.)
|
||||
pretty (String bs) =
|
||||
enclose "\"" "\"" . pretty . showHexSequences . BS.unpack $ bs
|
||||
where
|
||||
showHexSequences =
|
||||
foldr (\a acc -> char a <> acc) ""
|
||||
char c
|
||||
| isAscii (w2c c) && isPrint (w2c c) = [w2c c]
|
||||
| otherwise = "\\" <> pad 3 (showOct c "")
|
||||
pad n s = replicate (max 0 (n - length s)) '0' <> s
|
||||
pretty (Const c) = pretty c
|
||||
|
||||
data Field
|
||||
= FieldExtTy ExtTy (NonEmpty DataItem)
|
||||
| FieldZero Size
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Field where
|
||||
pretty (FieldExtTy extTy items) = pretty extTy <+> hsep (toList $ pretty <$> items)
|
||||
@@ -187,37 +291,51 @@ instance Pretty Field where
|
||||
-- ** Functions
|
||||
---------------
|
||||
|
||||
-- TODO use record syntax on long types like this one
|
||||
-- | Function definition. The 'Maybe (Ident \'Temporary)' is the environment
|
||||
data FuncDef = FuncDef [Linkage] (Maybe AbiTy) (Ident 'Global) (Maybe (Ident 'Temporary)) [Param] Variadic (NonEmpty Block)
|
||||
deriving (Show, Eq)
|
||||
data FuncDef = FuncDef
|
||||
{ linkage :: [Linkage]
|
||||
, returnType :: Maybe AbiTy
|
||||
, name :: Ident 'Global
|
||||
, env :: Maybe (Ident 'Temporary)
|
||||
, params :: [Param]
|
||||
, variadic :: Variadic
|
||||
, code :: NonEmpty Block
|
||||
}
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty FuncDef where
|
||||
pretty (FuncDef linkage abiTy ident env params variadic blocks) = vsep
|
||||
[ vsep $ pretty <$> linkage
|
||||
, "function" <+> pretty abiTy <+> pretty ident
|
||||
, tupled $
|
||||
, "function" <+> pretty abiTy <+> pretty ident <+> tupled (
|
||||
maybeToList (("env" <+>) . pretty <$> env)
|
||||
++ fmap pretty params
|
||||
++ maybeToList (prettyVariadic variadic)
|
||||
, braces $ vsep $ toList $ pretty <$> blocks
|
||||
) <+> lbrace
|
||||
, vsep $ toList $ pretty <$> blocks
|
||||
, rbrace
|
||||
]
|
||||
|
||||
data AbiTy = AbiBaseTy BaseTy | AbiAggregateTy (Ident 'AggregateTy)
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty AbiTy where
|
||||
pretty (AbiBaseTy baseTy) = pretty baseTy
|
||||
pretty (AbiAggregateTy ident) = pretty ident
|
||||
|
||||
-- | Function parameter
|
||||
data Param = Param AbiTy (Ident 'Temporary)
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Param where
|
||||
pretty (Param abiTy ident) = pretty abiTy <+> pretty ident
|
||||
|
||||
-- | Indicates the presence or absence of a variadic marker
|
||||
data Variadic = Variadic | NoVariadic
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
-- | 'Variadic' → @Just "..."@
|
||||
-- 'NoVariadic' → @Nothing@
|
||||
prettyVariadic :: Variadic -> Maybe (Doc a)
|
||||
prettyVariadic Variadic = Just "..."
|
||||
prettyVariadic NoVariadic = Nothing
|
||||
@@ -225,19 +343,26 @@ prettyVariadic NoVariadic = Nothing
|
||||
-- * Control
|
||||
------------
|
||||
|
||||
-- | Value, either an immediate or a global or temporary identifier.
|
||||
data Val
|
||||
= ValConst Const
|
||||
| ValTemporary (Ident 'Temporary)
|
||||
| ValGlobal (Ident 'Global)
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Val where
|
||||
pretty (ValConst c) = pretty c
|
||||
pretty (ValTemporary ident) = pretty ident
|
||||
pretty (ValGlobal ident) = pretty ident
|
||||
|
||||
data Block = Block (Ident 'Label) [Phi] [Inst] Jump
|
||||
deriving (Show, Eq)
|
||||
-- | Block of instructions beginning with a label and ending with a jump
|
||||
data Block = Block
|
||||
{ label :: Ident 'Label
|
||||
, phis :: [Phi]
|
||||
, insts :: [Inst]
|
||||
, jump :: Jump
|
||||
}
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Block where
|
||||
pretty (Block ident phis insts jump) = hang 4 $ vsep $ concat
|
||||
@@ -247,11 +372,12 @@ instance Pretty Block where
|
||||
, [pretty jump]
|
||||
]
|
||||
|
||||
-- | Jump instructions
|
||||
data Jump
|
||||
= Jmp (Ident 'Label)
|
||||
| Jnz Val (Ident 'Label) (Ident 'Label)
|
||||
| Ret (Maybe Val)
|
||||
deriving (Show, Eq)
|
||||
= Jmp (Ident 'Label) -- ^ Unconditional jump
|
||||
| Jnz Val (Ident 'Label) (Ident 'Label) -- ^ Conditional jump
|
||||
| Ret (Maybe Val) -- ^ Function return
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Jump where
|
||||
pretty (Jmp ident) = "jmp" <+> pretty ident
|
||||
@@ -264,30 +390,39 @@ instance Pretty Jump where
|
||||
-- * Instructions
|
||||
-----------------
|
||||
|
||||
-- MAYBE change [PhiArg] to Map (Ident 'Label) Val
|
||||
-- | Phi instruction
|
||||
data Phi = Phi Assignment [PhiArg]
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Phi where
|
||||
pretty (Phi assignment args) =
|
||||
pretty assignment <+> "phi" <+> hsep (punctuate comma $ pretty <$> args)
|
||||
|
||||
-- | Phi instruction argument, associating a 'Val' to a 'Label'
|
||||
data PhiArg = PhiArg (Ident 'Label) Val
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty PhiArg where
|
||||
pretty (PhiArg label val) = pretty label <+> pretty val
|
||||
|
||||
-- | Instruction
|
||||
data Inst
|
||||
-- Arithmetic and Bits
|
||||
= BinaryOp Assignment BinaryOp Val Val
|
||||
| Neg Assignment Val
|
||||
= BinaryOp Assignment BinaryOp Val Val -- ^ Binary arithmetic and bit operations
|
||||
| Neg Assignment Val -- ^ @neg@
|
||||
-- Memory
|
||||
-- | @stored@/@stores@/@storel@/@storew@/@storeh@/@storeb@
|
||||
| Store ExtTy Val Val
|
||||
-- MAYBE collapse all the Loads in a single Load constructor and just discard
|
||||
-- the intrepr when unused.
|
||||
| Load Assignment BaseTy Val -- ^ @\<ident\> =\<baseTy\> load\<baseTy\> \<val\>@
|
||||
| LoadW Assignment IntRepr Val -- ^ @\<ident\> =\<baseTy\> load\<intRepr\>w \<val\>@
|
||||
-- | @loadw@/@loadl@/@loads@/@loadd@
|
||||
| Load Assignment BaseTy Val
|
||||
-- | @loadsw@/@loaduw@
|
||||
| LoadW Assignment IntRepr Val
|
||||
-- | @loadsh@/@loaduh@
|
||||
| LoadH Assignment IntRepr Val
|
||||
-- | @loadsb@/@loadub@
|
||||
| LoadB Assignment IntRepr Val
|
||||
-- Comparisons
|
||||
| Compare Assignment Comparison BaseTy Val Val
|
||||
@@ -313,15 +448,19 @@ data Inst
|
||||
-- | @sltof@/@ultof@
|
||||
| LtoF Assignment IntRepr Val
|
||||
-- Cast and Copy
|
||||
-- | @cast@
|
||||
| Cast Assignment Val
|
||||
-- | @copy@
|
||||
| Copy Assignment Val
|
||||
-- Calls
|
||||
-- | the fields are: assignment, function name, environment, arguments, variadic arguments
|
||||
-- | @call@. The fields are: assignment, function name, environment, arguments, variadic arguments
|
||||
| Call (Maybe (Ident 'Temporary, AbiTy)) Val (Maybe Val) [Arg] [Arg]
|
||||
-- Variadic
|
||||
-- | @vastart@, initializes a variable argument list
|
||||
| VaStart (Ident 'Temporary)
|
||||
-- | @vaarg@, fetches the next argument from a variable argument list
|
||||
| VaArg Assignment (Ident 'Temporary)
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Inst where
|
||||
pretty (BinaryOp assignment op v1 v2) =
|
||||
@@ -368,8 +507,9 @@ instance Pretty Inst where
|
||||
pretty (VaStart argList) = "vastart" <+> pretty argList
|
||||
pretty (VaArg assignment argList) = pretty assignment <+> "vaarg" <+> pretty argList
|
||||
|
||||
-- | Represents the @%x =t@ part of an instruction.
|
||||
data Assignment = Assignment (Ident 'Temporary) BaseTy
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
-- | Infix synonym of 'Assignment'
|
||||
pattern (:=) :: Ident 'Temporary -> BaseTy -> Assignment
|
||||
@@ -378,9 +518,11 @@ pattern (:=) ident ty = Assignment ident ty
|
||||
instance Pretty Assignment where
|
||||
pretty (Assignment ident ty) = pretty ident <+> equals <> pretty ty
|
||||
|
||||
-- | Integer representation
|
||||
data IntRepr = Signed | Unsigned
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
-- | Binary arithmetic and bit operations
|
||||
data BinaryOp
|
||||
-- | @add@
|
||||
= Add
|
||||
@@ -405,7 +547,7 @@ data BinaryOp
|
||||
| Shr
|
||||
-- | @shl@
|
||||
| Shl
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty BinaryOp where
|
||||
pretty Add = "add"
|
||||
@@ -437,7 +579,7 @@ data Comparison
|
||||
-- Floating point only comparison
|
||||
| O -- ^ ordered (no operand is a NaN) (floating point only)
|
||||
| Uo -- ^ unordered (at least one operand is a NaN) (floating point only)
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Comparison where
|
||||
pretty Eq = "eq"
|
||||
@@ -453,8 +595,9 @@ instance Pretty IntRepr where
|
||||
pretty Signed = pretty 's'
|
||||
pretty Unsigned = pretty 'u'
|
||||
|
||||
-- | Function argument
|
||||
data Arg = Arg AbiTy Val
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Arg where
|
||||
pretty (Arg abiTy val) = pretty abiTy <+> pretty val
|
||||
@@ -462,8 +605,9 @@ instance Pretty Arg where
|
||||
-- * Program
|
||||
------------
|
||||
|
||||
-- | Datatypre representing a QBE IL source file
|
||||
data Program = Program [TypeDef] [DataDef] [FuncDef]
|
||||
deriving (Show, Eq)
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
instance Pretty Program where
|
||||
pretty (Program typeDefs dataDefs funcDefs) = vsep $ concat
|
||||
@@ -475,7 +619,7 @@ instance Pretty Program where
|
||||
-- * Utilities
|
||||
--------------
|
||||
|
||||
-- like 'list' and 'tupled'
|
||||
-- | Like 'list' and 'tupled', but with braces
|
||||
braced :: [Doc ann] -> Doc ann
|
||||
braced = group . encloseSep (flatAlt "{ " "{")
|
||||
(flatAlt " }" "}")
|
||||
|
||||
26
test/Main.hs
26
test/Main.hs
@@ -6,8 +6,9 @@ module Main (main) where
|
||||
|
||||
import Language.QBE
|
||||
|
||||
import Test.Tasty (TestTree, defaultMain, testGroup)
|
||||
import Test.Tasty (TestTree, testGroup)
|
||||
import Test.Tasty.Silver (goldenVsAction)
|
||||
import Test.Tasty.Silver.Interactive (defaultMain)
|
||||
import System.FilePath ((</>), (<.>))
|
||||
import Prettyprinter (Pretty(pretty), layoutPretty, defaultLayoutOptions)
|
||||
import Prettyprinter.Render.Text (renderStrict)
|
||||
@@ -31,8 +32,8 @@ goldenTests = testGroup "golden tests"
|
||||
]
|
||||
, t "type" ([Word, Long, Single, Double], [BaseTy Word, Byte, HalfWord])
|
||||
, t "const"
|
||||
[ CInt True 1
|
||||
, CInt False 2
|
||||
[ CInt (-1)
|
||||
, CInt 2
|
||||
, CSingle 0.1
|
||||
, CDouble (-0.2)
|
||||
, CGlobal "global"
|
||||
@@ -45,17 +46,17 @@ goldenTests = testGroup "golden tests"
|
||||
, t "opaque" $ Opaque "t" 8 16
|
||||
, t "data" $ DataDef [Export] "d" (Just 8)
|
||||
[ FieldZero 16
|
||||
, FieldExtTy Byte $ Symbol "g" (Just 32) :| [String "foo\nbar\0baz", Const $ CInt True 1]
|
||||
, FieldExtTy Byte $ Symbol "g" (Just 32) :| [String "foo\nbar\0baz", Const $ CInt (-1)]
|
||||
]
|
||||
, t "function" $ FuncDef [Export] (Just $ AbiAggregateTy "t") "f"
|
||||
(Just "env") [Param (AbiBaseTy Word) "a", Param (AbiBaseTy Double) "b"] Variadic $
|
||||
Block "l" [] [] (Ret Nothing) :| []
|
||||
, t "val" [valInt 0, ValTemporary "temporary", ValGlobal "global"]
|
||||
, t "val" [valInt 0, ValTemporary "temporary", ValConst (CGlobal "global")]
|
||||
, t "jmp" $ Jmp "target"
|
||||
, t "jnz" $ Jnz (valInt 0) "target1" "target2"
|
||||
, t "ret" $ Ret $ Just $ ValTemporary "x"
|
||||
, t "phi" $ Phi (Assignment "a" Word) [PhiArg "b" $ valInt 1, PhiArg "c" $ valInt 2]
|
||||
, t "call" $ Call (Just ("r", AbiBaseTy Word)) (ValGlobal "f") (Just $ valInt 1)
|
||||
, t "call" $ Call (Just ("r", AbiBaseTy Word)) (ValConst (CGlobal "f")) (Just $ valInt 1)
|
||||
[Arg (AbiBaseTy Word) $ valInt 2, Arg (AbiAggregateTy "t") $ ValTemporary "a"]
|
||||
[Arg (AbiBaseTy Word) $ valInt 3, Arg (AbiAggregateTy "t1") $ ValTemporary "b"]
|
||||
, t "inst" $ Block "l" []
|
||||
@@ -92,8 +93,7 @@ goldenTests = testGroup "golden tests"
|
||||
(renderStrict . layoutPretty defaultLayoutOptions)
|
||||
|
||||
valInt :: Int -> Val
|
||||
valInt i | i >= 0 = ValConst $ CInt False $ fromIntegral i
|
||||
| otherwise = ValConst $ CInt True $ fromIntegral $ negate i
|
||||
valInt i = ValConst $ CInt $ fromIntegral i
|
||||
|
||||
one, two :: Val
|
||||
one = valInt 1
|
||||
@@ -107,12 +107,16 @@ helloWorld = Program [] [helloString] [helloMain]
|
||||
where
|
||||
helloString = DataDef [] "str" Nothing
|
||||
[ FieldExtTy Byte $ String "hello world" :| []
|
||||
, FieldExtTy Byte $ Const (CInt False 0) :| []
|
||||
, FieldExtTy Byte $ Const (CInt 0) :| []
|
||||
]
|
||||
helloMain = FuncDef [Export] (Just $ AbiBaseTy Word) "main"
|
||||
Nothing [] NoVariadic $
|
||||
Block "start"
|
||||
[]
|
||||
[Call (Just ("r", AbiBaseTy Word)) (ValGlobal "puts") Nothing [Arg (AbiBaseTy Long) $ ValGlobal "str"] []]
|
||||
(Ret $ Just $ ValConst $ CInt False 0)
|
||||
[ Call (Just ("r", AbiBaseTy Word)) (ValConst (CGlobal "puts"))
|
||||
Nothing
|
||||
[Arg (AbiBaseTy Long) $ ValConst (CGlobal "str")]
|
||||
[]
|
||||
]
|
||||
(Ret $ Just $ ValConst $ CInt 0)
|
||||
:| []
|
||||
|
||||
Reference in New Issue
Block a user