The parser parses the MPCL input files, including any referenced packages, and creates an abstract syntax tree (AST).
The AST is then converted into Static Single Assignment form (SSA) where each variable is defined and assigned only once. The SSA transformation does also type checks so that all variable assignments and function call arguments and return values are checked (or converted) to be or correct type.
Name | Size | Signed |
---|---|---|
bool | 1 | no |
uint | unspecified | no |
int | unspecified | yes |
uintN | N | no |
intN | N | yes |
floatN | N | yes |
stringN | N | no |
The unsized uint
and int
types can be used as function arguments
and return values. Their sizes are resolved during compilation
time. The following example shows a MinMax
function that returns the
minimum and maximum arguments. This function works for all argument
sizes.
func MinMax(a, b int) (int, int) {
if a < b {
return a, b
} else {
return b, a
}
}
Typecast is implemented for static values Call.Eval
and dynamic values Call.SSA
.
Value identity for const values is computed from the value's Name
,
Scope
, and Version
. These values remain the same for all constant
value instances so the static cast can creates a new constant instance
with the casted Type
.
package main
func main(a, b int4) int4 {
if a > b {
return a
}
return b
}
The compiler creates the following SSA form assembly:
# Input0: a{1,0}i4:int4
# Input1: b{1,0}i4:int4
# Output0: %_{0,1}i4:int4
# main#0:
igt a{1,0}i4 b{1,0}i4 %_{0,0}b1
mov a{1,0}i4 %ret0{1,1}i4
mov b{1,0}i4 %ret0{1,2}i4
# main.ret#0:
phi %_{0,0}b1 %ret0{1,1}i4 %ret0{1,2}i4 %_{0,1}i4
gc %_{0,0}b1
gc %ret0{1,1}i4
gc %ret0{1,2}i4
gc a{1,0}i4
gc b{1,0}i4
ret %_{0,1}i4
The SSA assembly (and logical circuit) form a Directed Acyclic Graph
(DAG) without any mutable storage locations. This means that all
alternative execution paths must be evaluate and when the program is
returning its computation results, any conflicting values from
different execution paths must be resolved with the branching
condition. This value resolution is implemented as the phi
assembly
instruction, which effectively implements a MUX logical circuit:
O=(D0 XOR D1)C XOR D0
D0 | D1 | C | D0 XOR D1 | AND C | XOR D0 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 | 0 |
1 | 0 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 0 | 1 |
0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 1 | 1 | 1 |
1 | 0 | 1 | 1 | 1 | 0 |
1 | 1 | 1 | 0 | 0 | 1 |
The 3rd compiler phase converts SSA form assembly into logic gate circuit. The following circuit was generated from the previous SSA form assembly:
package main
func main(a, b int) (int, int) {
q, r := a / b
return q, r
}