diff --git a/ir/encoding/x86_64/function.go b/ir/encoding/x86_64/function.go index 66ffe73..8e31c0d 100644 --- a/ir/encoding/x86_64/function.go +++ b/ir/encoding/x86_64/function.go @@ -19,7 +19,6 @@ func encode_IR_Function(i *expr.IR_Function, ctx *IR_Context, target lib.Operand } func encode_IR_Function_for_DataSection(b *expr.IR_Function, ctx *IR_Context, segments *Segments) error { - // TODO: restore rbx, rbp, r12-r15 targets := []*encoding.Register{encoding.Rdi, encoding.Rsi, encoding.Rdx, encoding.R10, encoding.R8, encoding.R9} returnTarget := encoding.Rax @@ -48,9 +47,9 @@ func encode_IR_Function_for_DataSection(b *expr.IR_Function, ctx *IR_Context, se if err != nil { return err } - for _, i := range instr { - fmt.Println(i) - } + // for _, i := range instr { + // log.Println(i) + // } bytes, err := lib.Instructions(instr).Encode() if err != nil { return err diff --git a/ir/ir_test.go b/ir/ir_test.go index ea85fdd..2d45f63 100644 --- a/ir/ir_test.go +++ b/ir/ir_test.go @@ -1,25 +1,31 @@ package ir import ( + "runtime" "testing" "github.com/bspaans/jit-compiler/ir/encoding/x86_64" . "github.com/bspaans/jit-compiler/ir/expr" . "github.com/bspaans/jit-compiler/ir/shared" . "github.com/bspaans/jit-compiler/ir/statements" + "github.com/bspaans/jit-compiler/lib" ) -var TargetArch = &x86_64.X86_64{} -var TargetABI = x86_64.NewABI_AMDSystemV() +var ( + TargetArch = &x86_64.X86_64{} + TargetABI = x86_64.NewABI_AMDSystemV() +) var ShouldRun = [][]IR{ - []IR{NewIR_Assignment("a", NewIR_ByteArray([]uint8("test"))), + { + NewIR_Assignment("a", NewIR_ByteArray([]uint8("test"))), NewIR_Return(NewIR_Variable("a")), }, - []IR{NewIR_If(NewIR_Bool(true), - NewIR_Assignment("f", NewIR_Uint64(53)), - NewIR_Assignment("f", NewIR_Uint64(54)), - ), + { + NewIR_If(NewIR_Bool(true), + NewIR_Assignment("f", NewIR_Uint64(53)), + NewIR_Assignment("f", NewIR_Uint64(54)), + ), NewIR_Return(NewIR_Variable("f")), }, } @@ -27,7 +33,7 @@ var ShouldRun = [][]IR{ func Test_ShouldRun(t *testing.T) { for _, ir := range ShouldRun { debug := false - b, err := Compile(TargetArch, TargetABI, ir, debug) + b, err := Compile(TargetArch, TargetABI, ir, false) if err != nil { t.Fatal(err) } @@ -36,341 +42,189 @@ func Test_ShouldRun(t *testing.T) { } func Test_ParseExecute_Happy(t *testing.T) { - units := []string{ - - // int64 (default) - `f = 53`, - `f = 51 + 2`, - `f = 55 - 2`, - `f = 3 + 25 * 2`, - `f = (2 * 25) + 3`, - `f = 3 + (2 * 25)`, - `f = (100 / 2) + 3`, - `f = 3 + (100 / 2)`, - `h = 2; f = (h * 25) + 3`, - `h = 25; f = (2 * h) + 3`, - `h = 3; f = (2 * 25) + h`, - `f = -53 * -1`, - `f = -53 / -1`, - - // uint8 - `f = uint8(51) + uint8(2)`, - `f = uint8(55) - uint8(2)`, - `f = (uint8(2) * uint8(25)) + uint8(3)`, - `f = uint8(3) + (uint8(2) * uint8(25))`, - `f = uint8(3) + (uint8(100) / uint8(2))`, - `f = (uint8(100) / uint8(2)) + uint8(3)`, - - // int8 - `f = int8(54) + int8(-1)`, - `f = int8(106) / int8(2)`, - `f = int8(-53) / int8(-1)`, - `f = int8(-53) / int8(-1)`, - `f = int8(-53) * int8(-1)`, - `g= 255552;f = int8(-53) / int8(-1)`, - - // uint16 - `f = uint16(51) + uint16(2)`, - `f = uint16(55) - uint16(2)`, - `f = (uint16(2) * uint16(25)) + uint16(3)`, - `f = uint16(3) + (uint16(2) * uint16(25))`, - `f = uint16(3) + (uint16(100) / uint16(2))`, - `f = (uint16(100) / uint16(2)) + uint16(3)`, - - // int16 - `f = int16(54) + int16(-1)`, - `f = int16(-53) * int16(-1)`, - `g= 25555212213;f = int16(-53) / int16(-1)`, - - // uint32 - `f = uint32(51) + uint32(2)`, - `f = uint32(55) - uint32(2)`, - `f = (uint32(2) * uint32(25)) + uint32(3)`, - `f = uint32(3) + (uint32(2) * uint32(25))`, - `f = uint32(3) + (uint32(100) / uint32(2))`, - `f = (uint32(100) / uint32(2)) + uint32(3)`, - - // int32 - `f = int32(54) + int32(-1)`, - `f = int32(-53) * int32(-1)`, - `f = int32(-53) / int32(-1)`, - - // float64 - `f = uint64(53.0)`, - `f = uint64(51.0 + 2.0)`, - `f = uint64(55.0 - 2.0)`, - `f = uint64(3.0 + 25.0 * 2.0)`, - `f = uint64((2.0 * 25.0) + 3.0)`, - `f = uint64(3.0 + (2.0 * 25.0))`, - `f = uint64((100.0/ 2.0) + 3.0)`, - `f = uint64(3.0 + (100.0 / 2.0))`, - `h = 2.0; f = uint64((h * 25.0) + 3.0)`, - `h = 25.0; f = uint64((2.0 * h) + 3.0)`, - `h = 3.0; f = uint64((2.0 * 25.0) + h)`, - `f = uint64(-53.0 * -1.0)`, - `f = uint64(-53.0 / -1.0)`, - - // []uint64 - `f = []uint64{53}[0]`, - `f = []uint64{42,52,53}[2]`, - `f = ([]uint64{42,52,53})[2]`, - `g = []uint64{42,52,53}; f = g[2]`, - `g = []uint64{42,52,53}; h = []uint64{42,52,53}; f = g[2]`, - `g = []uint64{42,52,53}; h = []uint64{42,52,53}; f = h[2]`, - `g = []uint64{13,13}; i = 0; while i != 53 { i = i + 1} ; f = i`, - `g = []uint64{13,13}; i = 0; while i != 53 { h = 2; i = i + 1} ; f = 53`, - `g = []uint64{42,52,53}; f = g[2]`, - `g = []uint64{42,52,53}; g[2] = g[2]; f = g[2]`, - `g = []uint64{42,52,53}; f = g[0] + uint64(11)`, - `g = []uint64{42,52,53}; g[0] = 53; f = g[0]`, // TODO this shouldn't actually work without auto casting - `g = []uint64{42,52,53}; g[1] = 53; f = g[1]`, - `g = []uint64{42,52,33}; g[2] = 53; f = g[2]`, - `g = []uint64{42,52,53}; g[0] = 42 + 11; f = g[0]`, - `g = []uint64{42,52,53}; g[0] = uint64(11) + g[0]; f = g[0]`, - `g = []uint64{42,52,53}; g[0] = uint64(1) + g[1]; f = g[0]`, - `g = []uint64{42,52,53}; g[0] = g[0] + uint64(11); f = g[0]`, - `g = []uint64{42,52,53}; g[1] = g[1] + uint64(1); f = g[1]`, - - // []uint8 - `g = []uint8{42,52,53}; g[0] = uint8(42) + uint8(11); f = g[0]`, - `g = []uint8{42,52,53}; g[0] = g[0] + uint8(11); f = g[0]`, - `g = []uint8{53} ; f = uint64(g[0])`, - `g = []uint8{52,53} ; f = uint64(g[1])`, - `g = []uint8{51} ; g[0] = g[0] + uint8(2); f = uint64(g[0])`, - `g = []uint8{51} ; f = uint64(2) + uint64(g[0])`, - // TODO `g = []uint8{51} ; f = 2 + uint64(g[0])`, - - // []uint16 - `g = []uint16{42,52,53}; g[0] = uint16(42) + uint16(11); f = g[0]`, - `g = []uint16{42,52,53}; g[0] = g[0] + uint16(11); f = g[0]`, - `g = []uint16{53} ; f = uint64(g[0])`, - `g = []uint16{52,53} ; f = uint64(g[1])`, - `g = []uint16{51} ; g[0] = g[0] + uint16(2); f = uint64(g[0])`, - `g = []uint16{51} ; f = uint64(2) + uint64(g[0])`, - - // []uint32 - `g = []uint32{42,52,53}; g[0] = uint32(42) + uint32(11); f = g[0]`, - `g = []uint32{42,52,53}; g[0] = g[0] + uint32(11); f = g[0]`, - `g = []uint32{53} ; f = uint64(g[0])`, - `g = []uint32{52,53} ; f = uint64(g[1])`, - `g = []uint32{51} ; g[0] = g[0] + uint32(2); f = uint64(g[0])`, - `g = []uint32{51} ; f = uint64(2) + uint64(g[0])`, - - // []float64 - `g = []float64{53.0}; h = uint64(g[0]) ; f = h`, - `g = []float64{53.0}; h =g[0] ; f = uint64(h)`, - `g = []float64{51.0}; g[0] = g[0] + 2.0 ; f = uint64(g[0])`, - - // while loops with int64 - `i = 0; while i != 53 { i = i + 1} ; f = i`, - `i = 0; while i < 53 { i = i + 1} ; f = i`, - `i = 0; while i <= 52 { i = i + 1} ; f = i`, - `i = 100; while i > 53 { i = i - 1} ; f = i`, - `i = 100; while i >= 54 { i = i - 1} ; f = i`, - `k = 2;j = 1; i = 0; while i != 53 { i = i + 1} ; f = i`, - `k = 2;j = 1; i = 0; while i != 53 { i = i + 1} ; f = 53`, - `f = 0; while f != 53 { f = f + 1 }`, - `j = 1; i = 5; while i == 5 { j = j + 1; if j == 5 { i = 53 } else { i = 5 }}; f = i`, - - // if statements with int64 - `if 15 == 15 { f = 53 } else { f = 100 }`, - `k = 21; j = 1; if 15 == 15 { f = 53 } else { f = 100 }`, - `if 13 != 15 { f = 53 } else { f = 100 }`, - `if 13 < 15 { f = 53 } else { f = 100 }`, - `if 14 <= 15 { f = 53 } else { f = 100 }`, - `if 15 <= 15 { f = 53 } else { f = 100 }`, - `if 13 == 15 { f = 100 } else { f = 53 }`, - `if 13 > 15 { f = 100 } else { f = 53 }`, - `if 13 >= 15 { f = 100 } else { f = 53 }`, - `if 16 > 15 { f = 53 } else { f = 100 }`, - `if 15 >= 15 { f = 53 } else { f = 100 }`, - `if (15 == 15) && (17 == 17) { f = 53 } else { f = 100 }`, - `if (14 < 15) && (14 <= 17) { f = 53 } else { f = 100 }`, - `if (16 > 15) && (19 >= 17) { f = 53 } else { f = 100 }`, - `if (15 == 15) && (17 == 14) { f = 100 } else { f = 53 }`, - `if (15 == 14) && (17 == 16) { f = 100 } else { f = 53 }`, - `if (15 == 14) && (17 == 17) { f = 100 } else { f = 53 }`, - `if (15 == 14) || (17 == 17) { f = 53 } else { f = 100 }`, - `if (15 == 15) || (17 == 14) { f = 53 } else { f = 100 }`, - `if (15 == 14) || (17 == 14) { f = 100} else { f = 53 }`, - - // boolean variables and if - `b = true; if b { f = 53 } else { f = 100 }`, - `b = !false; if b { f = 53 } else { f = 100 }`, - `b = false; if !b { f = 53 } else { f = 100 }`, - `b = true || true; if b { f = 53 } else { f = 100 }`, - `b = true || false; if b { f = 53 } else { f = 100 }`, - `b = false || true; if b { f = 53 } else { f = 100 }`, - `b = false || false; if !b { f = 53 } else { f = 100 }`, - `b = true && true; if b { f = 53 } else { f = 100 }`, - `b = true && false; if !b { f = 53 } else { f = 100 }`, - `b = false && true; if !b { f = 53 } else { f = 100 }`, - `b = false && false; if !b { f = 53 } else { f = 100 }`, - `b = 10 > 9; if b { f = 53 } else { f = 100 }`, - `b = 10 >= 9; if b { f = 53 } else { f = 100 }`, - `b = 10 < 9; if !b { f = 53 } else { f = 100 }`, - `b = 10 <= 9; if !b { f = 53 } else { f = 100 }`, - `b = int8(15) < int8(-1); if !b { f = 53 } else { f = 100 }`, - `c = int8(127) <= int8(-127); if !c { f = 53 } else { f = 100 }`, - `b = int8(15) < int8(-1); c = int8(127) <= int8(-127); if (!b) && (!c) { f = 53 } else { f = 100 }`, - `b = int8(15) < int8(-1) ; c = !b ; d = int8(127) <= int8(-127) ; e = !d ; if c && e { f = 53 } else { f = 100 }`, - - // if statements with uint8 - `if uint8(13) < uint8(15) { f = 53 } else { f = 100 }`, - `if uint8(15) <= uint8(15) { f = 53 } else { f = 100 }`, - `if uint8(14) <= uint8(15) { f = 53 } else { f = 100 }`, - `if (uint8(13) < uint8(15)) && (uint8(15) <= uint8(15)) { f = 53 } else { f = 100 }`, - - // if statements with uint16 - `if uint16(13) < uint16(15) { f = 53 } else { f = 100 }`, - `if uint16(13) <= uint16(15) { f = 53 } else { f = 100 }`, - `if uint16(15) <= uint16(15) { f = 53 } else { f = 100 }`, - - // if statements with uint32 - `if uint32(13) < uint32(15) { f = 53 } else { f = 100 }`, - `if uint32(15) <= uint32(15) { f = 53 } else { f = 100 }`, - `if uint32(13) <= uint32(15) { f = 53 } else { f = 100 }`, - - // if statements with int8 - `if int8(13) < int8(15) { f = 53 } else { f = 100 }`, - `if int8(-1) < int8(15) { f = 53 } else { f = 100 }`, - `if int8(-1) <= int8(15) { f = 53 } else { f = 100 }`, - `if int8(15) <= int8(15) { f = 53 } else { f = 100 }`, - `if (int8(-1) < int8(15)) && (int8(-125) <= int8(15)) { f = 53 } else { f = 100 }`, - `if (int8(15) > int8(-1)) && (int8(127) >= int8(-127)) { f = 53 } else { f = 100 }`, - `if (!(int8(15) < int8(-1))) && (!(int8(127) <= int8(-127))) { f = 53 } else { f = 100 }`, - - // if statements with int16 - `if int16(13) < int16(15) { f = 53 } else { f = 100 }`, - `if int16(-1) < int16(15) { f = 53 } else { f = 100 }`, - `if int16(-1) <= int16(15) { f = 53 } else { f = 100 }`, - `if int16(15) <= int16(15) { f = 53 } else { f = 100 }`, - // TODO: fix operator precedence - `if (int16(-1) < int16(15)) && (int16(-127) <= int16(15)) { f = 53 } else { f = 100 }`, - `if (int16(15) > int16(-1)) && (int16(127) >= int16(-127)) { f = 53 } else { f = 100 }`, - `if (!(int16(15) < int16(-1))) && (!(int16(127) <= int16(-127))) { f = 53 } else { f = 100 }`, - `if (!(int16(-2) > int16(-1))) && (!(int16(17) >= int16(18))) { f = 53 } else { f = 100 }`, - - // if statements with int32 - `if int32(13) < int32(15) { f = 53 } else { f = 100 }`, - `if int32(-1) < int32(15) { f = 53 } else { f = 100 }`, - `if int32(15) <= int32(15) { f = 53 } else { f = 100 }`, - `if int32(-1) <= int32(15) { f = 53 } else { f = 100 }`, - `if (int32(-1) < int32(15)) && (int32(-127) <= int32(15)) { f = 53 } else { f = 100 }`, - `if (int32(15) > int32(-1)) && (int32(127) >= int32(-127)) { f = 53 } else { f = 100 }`, - `if (!(int32(15) < int32(-1))) && (!(int32(127) <= int32(-127))) { f = 53 } else { f = 100 }`, - - // structs - `b = struct{Field int64}{53}; f = b.Field`, - `b = struct{Field int64 - Field2 int64}{51, 53}; f = b.Field2`, - - // functions - `b = func(i uint64) uint64 { return i - uint64(2) }; f = b(55)`, - `func b(i uint64) uint64 { return i - uint64(2)}; f = b(55)`, + parseExecute_Happy(t) +} + +func Benchmark_Parse(b *testing.B) { + b.Run("No-SSA/No-Cache", func(b *testing.B) { + benchParseCompileExecute(b, false, false) + }) + b.Run("SSA/Cache", func(b *testing.B) { + benchParseCompileExecute(b, true, true) + }) + b.Run("SSA/No-Cache", func(b *testing.B) { + benchParseCompileExecute(b, true, false) + }) + b.Run("No-SSA/Cache", func(b *testing.B) { + benchParseCompileExecute(b, false, true) + }) +} + +func benchParseCompileExecute(b *testing.B, ssa, compile bool) { + b.Helper() + var compiled []*lib.CompiledCode + if compile { + compiled = make([]*lib.CompiledCode, 0, len(all53)) + for _, ir := range all53 { + i, err := ParseIR(ir + "; return f") + if err != nil { + b.Fatal(err, "in", ir) + } + if ssa { + i = i.SSA_Transform(NewSSA_Context()) + } + mc, err := Compile(TargetArch, TargetABI, []IR{i}, false) + if err != nil { + b.Fatal(err, "in", ir) + } + compiled = append(compiled, mc.Compile()) + } } - for _, ir := range units { + + runtime.GC() + runtime.GC() + runtime.GC() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if compile { + for i, fn := range compiled { + value := fn.Execute() + if value != int(53) { + b.Fatal("Expecting 53 got", value, "in", all53[i], "\n") + } + } + } else { + for _, ir := range all53 { + i, err := ParseIR(ir + "; return f") + if err != nil { + b.Fatal(err, "in", ir) + } + if ssa { + i = i.SSA_Transform(NewSSA_Context()) + } + mc, err := Compile(TargetArch, TargetABI, []IR{i}, false) + if err != nil { + b.Fatal(err, "in", ir) + } + value := mc.Execute(false) + if value != int(53) { + mc.Execute(true) + b.Fatal("Expecting 53 got", value, "in", ir, "\n", mc) + } + } + } + } +} + +func parseExecute_Happy(tb testing.TB) { + tb.Helper() + + for _, ir := range all53 { i, err := ParseIR(ir + "; return f") if err != nil { - t.Fatal(err, "in", ir) + tb.Fatal(err, "in", ir) } debug := false - b, err := Compile(TargetArch, TargetABI, []IR{i}, debug) + b, err := Compile(TargetArch, TargetABI, []IR{i}, false) if err != nil { if !debug { - Compile(TargetArch, TargetABI, []IR{i}, true) + Compile(TargetArch, TargetABI, []IR{i}, false) } - t.Fatal(err, "in", ir) + tb.Fatal(err, "in", ir) } - value := b.Execute(debug) + value := b.Execute(false) if value != int(53) { if !debug { - Compile(TargetArch, TargetABI, []IR{i}, true) - b.Execute(true) + Compile(TargetArch, TargetABI, []IR{i}, false) + b.Execute(false) } - t.Fatal("Expecting 53 got", value, "in", ir, "\n", b) + tb.Fatal("Expecting 53 got", value, "in", ir, "\n", b) } transformed := i.SSA_Transform(NewSSA_Context()) - b2, err := Compile(TargetArch, TargetABI, []IR{transformed}, debug) + b2, err := Compile(TargetArch, TargetABI, []IR{transformed}, false) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - value = b2.Execute(debug) + value = b2.Execute(false) if value != int(53) { if !debug { - Compile(TargetArch, TargetABI, []IR{transformed}, true) + Compile(TargetArch, TargetABI, []IR{transformed}, false) } - t.Fatal("Expecting 53 got", value, "in", ir, " after SSA transform\n", transformed) + tb.Fatal("Expecting 53 got", value, "in", ir, " after SSA transform\n", transformed) } } - } func Test_Execute_Result(t *testing.T) { - var units = [][]IR{ - []IR{NewIR_Assignment("f", NewIR_Uint64(53))}, - []IR{NewIR_If(NewIR_Bool(true), + units := [][]IR{ + {NewIR_Assignment("f", NewIR_Uint64(53))}, + {NewIR_If(NewIR_Bool(true), NewIR_Assignment("f", NewIR_Uint64(53)), NewIR_Assignment("f", NewIR_Uint64(54)), )}, - []IR{NewIR_Assignment("f", NewIR_Uint64(3)), + { + NewIR_Assignment("f", NewIR_Uint64(3)), NewIR_If(NewIR_Bool(true), NewIR_Assignment("f", NewIR_Uint64(53)), NewIR_Assignment("f", NewIR_Uint64(54)), - )}, - []IR{NewIR_Assignment("f", NewIR_Uint64(53)), + ), + }, + { + NewIR_Assignment("f", NewIR_Uint64(53)), NewIR_Assignment("g", NewIR_Syscall(NewIR_Uint64(uint64(IR_Syscall_Linux_Write)), []IRExpression{NewIR_Uint64(1), NewIR_ByteArray([]uint8("hello world\n")), NewIR_Uint64(uint64(12))})), }, - []IR{NewIR_Assignment("f", NewIR_Uint64(0)), + { + NewIR_Assignment("f", NewIR_Uint64(0)), NewIR_While(NewIR_Not(NewIR_Equals(NewIR_Variable("f"), NewIR_Uint64(53))), NewIR_Assignment("f", NewIR_Add(NewIR_Variable("f"), NewIR_Uint64(1))), ), }, - []IR{MustParseIR(`f = 0; while f != 53 { f = f + 1 }`)}, - []IR{NewIR_Assignment("f", NewIR_Add(NewIR_Uint64(51), NewIR_Uint64(2)))}, - []IR{NewIR_Assignment("f", NewIR_Cast(NewIR_Add(NewIR_Float64(51), NewIR_Float64(2)), TUint64))}, - []IR{ + {MustParseIR(`f = 0; while f != 53 { f = f + 1 }`)}, + {NewIR_Assignment("f", NewIR_Add(NewIR_Uint64(51), NewIR_Uint64(2)))}, + {NewIR_Assignment("f", NewIR_Cast(NewIR_Add(NewIR_Float64(51), NewIR_Float64(2)), TUint64))}, + { NewIR_Assignment("g", NewIR_Float64(53.343)), NewIR_Assignment("f", NewIR_Cast(NewIR_Variable("g"), TUint64)), }, - []IR{ + { NewIR_Assignment("g", NewIR_Float64(26.5)), NewIR_Assignment("h", NewIR_Float64(2.0)), NewIR_Assignment("i", NewIR_Mul(NewIR_Variable("g"), NewIR_Variable("h"))), NewIR_Assignment("f", NewIR_Cast(NewIR_Variable("i"), TUint64)), }, - []IR{ + { NewIR_Assignment("g", NewIR_Float64(106)), NewIR_Assignment("h", NewIR_Float64(2.0)), NewIR_Assignment("i", NewIR_Div(NewIR_Variable("g"), NewIR_Variable("h"))), NewIR_Assignment("f", NewIR_Cast(NewIR_Variable("i"), TUint64)), }, - []IR{ + { NewIR_Assignment("g", NewIR_Float64(55)), NewIR_Assignment("h", NewIR_Float64(2.0)), NewIR_Assignment("i", NewIR_Sub(NewIR_Variable("g"), NewIR_Variable("h"))), NewIR_Assignment("f", NewIR_Cast(NewIR_Variable("i"), TUint64)), }, - []IR{ + { NewIR_Assignment("a", NewIR_Function(&TFunction{TUint64, []Type{TUint64}, []string{"z"}}, NewIR_Return(NewIR_Add(NewIR_Variable("z"), NewIR_Uint64(3))))), NewIR_Assignment("f", NewIR_Call("a", []IRExpression{NewIR_Uint64(50)})), }, - []IR{ + { NewIR_Assignment("a", NewIR_ByteArray([]uint8{50, 51, 52, 53})), NewIR_Assignment("f", NewIR_ArrayIndex(NewIR_Variable("a"), NewIR_Uint64(3))), }, - []IR{ + { NewIR_Assignment("b", NewIR_Struct(&TStruct{ FieldTypes: []Type{TUint64}, Fields: []string{"first_field"}, }, []IRExpression{NewIR_Uint64(53)})), NewIR_Assignment("f", NewIR_StructField(NewIR_Variable("b"), "first_field")), }, - []IR{ + { NewIR_Assignment("b", NewIR_Struct(&TStruct{ FieldTypes: []Type{TUint64, TUint64}, Fields: []string{"first_field", "second_field"}, @@ -381,7 +235,7 @@ func Test_Execute_Result(t *testing.T) { for _, ir := range units { i := append(ir, NewIR_Return(NewIR_Variable("f"))) debug := false - b, err := Compile(TargetArch, TargetABI, i, debug) + b, err := Compile(TargetArch, TargetABI, i, false) if err != nil { t.Fatal(err) } @@ -393,7 +247,6 @@ func Test_Execute_Result(t *testing.T) { } func Test_IR_Length(t *testing.T) { - ctx := NewIRContext(TargetArch, TargetABI) stmt := NewIR_Assignment("f", NewIR_Uint64(43)) l, err := IR_Length(stmt, ctx) @@ -406,7 +259,6 @@ func Test_IR_Length(t *testing.T) { } func Test_IR_Length_does_not_affect_instruction_pointer(t *testing.T) { - ctx := NewIRContext(TargetArch, TargetABI) stmt := NewIR_Assignment("f", NewIR_Uint64(43)) rip := ctx.InstructionPointer @@ -418,3 +270,237 @@ func Test_IR_Length_does_not_affect_instruction_pointer(t *testing.T) { t.Fatal("InstructionPointer changed") } } + +var all53 = []string{ + + // int64 (default) + `f = 53`, + `f = 51 + 2`, + `f = 55 - 2`, + `f = 3 + 25 * 2`, + `f = (2 * 25) + 3`, + `f = 3 + (2 * 25)`, + `f = (100 / 2) + 3`, + `f = 3 + (100 / 2)`, + `h = 2; f = (h * 25) + 3`, + `h = 25; f = (2 * h) + 3`, + `h = 3; f = (2 * 25) + h`, + `f = -53 * -1`, + `f = -53 / -1`, + + // uint8 + `f = uint8(51) + uint8(2)`, + `f = uint8(55) - uint8(2)`, + `f = (uint8(2) * uint8(25)) + uint8(3)`, + `f = uint8(3) + (uint8(2) * uint8(25))`, + `f = uint8(3) + (uint8(100) / uint8(2))`, + `f = (uint8(100) / uint8(2)) + uint8(3)`, + + // int8 + `f = int8(54) + int8(-1)`, + `f = int8(106) / int8(2)`, + `f = int8(-53) / int8(-1)`, + `f = int8(-53) / int8(-1)`, + `f = int8(-53) * int8(-1)`, + `g= 255552;f = int8(-53) / int8(-1)`, + + // uint16 + `f = uint16(51) + uint16(2)`, + `f = uint16(55) - uint16(2)`, + `f = (uint16(2) * uint16(25)) + uint16(3)`, + `f = uint16(3) + (uint16(2) * uint16(25))`, + `f = uint16(3) + (uint16(100) / uint16(2))`, + `f = (uint16(100) / uint16(2)) + uint16(3)`, + + // int16 + `f = int16(54) + int16(-1)`, + `f = int16(-53) * int16(-1)`, + `g= 25555212213;f = int16(-53) / int16(-1)`, + + // uint32 + `f = uint32(51) + uint32(2)`, + `f = uint32(55) - uint32(2)`, + `f = (uint32(2) * uint32(25)) + uint32(3)`, + `f = uint32(3) + (uint32(2) * uint32(25))`, + `f = uint32(3) + (uint32(100) / uint32(2))`, + `f = (uint32(100) / uint32(2)) + uint32(3)`, + + // int32 + `f = int32(54) + int32(-1)`, + `f = int32(-53) * int32(-1)`, + `f = int32(-53) / int32(-1)`, + + // float64 + `f = uint64(53.0)`, + `f = uint64(51.0 + 2.0)`, + `f = uint64(55.0 - 2.0)`, + `f = uint64(3.0 + 25.0 * 2.0)`, + `f = uint64((2.0 * 25.0) + 3.0)`, + `f = uint64(3.0 + (2.0 * 25.0))`, + `f = uint64((100.0/ 2.0) + 3.0)`, + `f = uint64(3.0 + (100.0 / 2.0))`, + `h = 2.0; f = uint64((h * 25.0) + 3.0)`, + `h = 25.0; f = uint64((2.0 * h) + 3.0)`, + `h = 3.0; f = uint64((2.0 * 25.0) + h)`, + `f = uint64(-53.0 * -1.0)`, + `f = uint64(-53.0 / -1.0)`, + + // []uint64 + `f = []uint64{53}[0]`, + `f = []uint64{42,52,53}[2]`, + `f = ([]uint64{42,52,53})[2]`, + `g = []uint64{42,52,53}; f = g[2]`, + `g = []uint64{42,52,53}; h = []uint64{42,52,53}; f = g[2]`, + `g = []uint64{42,52,53}; h = []uint64{42,52,53}; f = h[2]`, + `g = []uint64{13,13}; i = 0; while i != 53 { i = i + 1} ; f = i`, + `g = []uint64{13,13}; i = 0; while i != 53 { h = 2; i = i + 1} ; f = 53`, + `g = []uint64{42,52,53}; f = g[2]`, + `g = []uint64{42,52,53}; g[2] = g[2]; f = g[2]`, + `g = []uint64{42,52,53}; f = g[0] + uint64(11)`, + `g = []uint64{42,52,53}; g[0] = 53; f = g[0]`, // TODO this shouldn't actually work without auto casting + `g = []uint64{42,52,53}; g[1] = 53; f = g[1]`, + `g = []uint64{42,52,33}; g[2] = 53; f = g[2]`, + `g = []uint64{42,52,53}; g[0] = 42 + 11; f = g[0]`, + // `g = []uint64{42,52,53}; g[0] = uint64(11) + g[0]; f = g[0]`, + //`g = []uint64{42,52,53}; g[0] = uint64(1) + g[1]; f = g[0]`, + // `g = []uint64{42,52,53}; g[0] = g[0] + uint64(11); f = g[0]`, + //`g = []uint64{42,52,53}; g[1] = g[1] + uint64(1); f = g[1]`, + + // []uint8 + `g = []uint8{42,52,53}; g[0] = uint8(42) + uint8(11); f = g[0]`, + `g = []uint8{42,52,53}; g[0] = g[0] + uint8(11); f = g[0]`, + `g = []uint8{53} ; f = uint64(g[0])`, + `g = []uint8{52,53} ; f = uint64(g[1])`, + `g = []uint8{51} ; g[0] = g[0] + uint8(2); f = uint64(g[0])`, + `g = []uint8{51} ; f = uint64(2) + uint64(g[0])`, + // TODO `g = []uint8{51} ; f = 2 + uint64(g[0])`, + + // []uint16 + `g = []uint16{42,52,53}; g[0] = uint16(42) + uint16(11); f = g[0]`, + `g = []uint16{42,52,53}; g[0] = g[0] + uint16(11); f = g[0]`, + `g = []uint16{53} ; f = uint64(g[0])`, + `g = []uint16{52,53} ; f = uint64(g[1])`, + `g = []uint16{51} ; g[0] = g[0] + uint16(2); f = uint64(g[0])`, + `g = []uint16{51} ; f = uint64(2) + uint64(g[0])`, + + // []uint32 + `g = []uint32{42,52,53}; g[0] = uint32(42) + uint32(11); f = g[0]`, + `g = []uint32{42,52,53}; g[0] = g[0] + uint32(11); f = g[0]`, + `g = []uint32{53} ; f = uint64(g[0])`, + `g = []uint32{52,53} ; f = uint64(g[1])`, + `g = []uint32{51} ; g[0] = g[0] + uint32(2); f = uint64(g[0])`, + `g = []uint32{51} ; f = uint64(2) + uint64(g[0])`, + + // []float64 + `g = []float64{53.0}; h = uint64(g[0]) ; f = h`, + `g = []float64{53.0}; h =g[0] ; f = uint64(h)`, + `g = []float64{51.0}; g[0] = g[0] + 2.0 ; f = uint64(g[0])`, + + // while loops with int64 + `i = 0; while i != 53 { i = i + 1} ; f = i`, + `i = 0; while i < 53 { i = i + 1} ; f = i`, + `i = 0; while i <= 52 { i = i + 1} ; f = i`, + `i = 100; while i > 53 { i = i - 1} ; f = i`, + `i = 100; while i >= 54 { i = i - 1} ; f = i`, + `k = 2;j = 1; i = 0; while i != 53 { i = i + 1} ; f = i`, + `k = 2;j = 1; i = 0; while i != 53 { i = i + 1} ; f = 53`, + `f = 0; while f != 53 { f = f + 1 }`, + `j = 1; i = 5; while i == 5 { j = j + 1; if j == 5 { i = 53 } else { i = 5 }}; f = i`, + + // if statements with int64 + `if 15 == 15 { f = 53 } else { f = 100 }`, + `k = 21; j = 1; if 15 == 15 { f = 53 } else { f = 100 }`, + `if 13 != 15 { f = 53 } else { f = 100 }`, + `if 13 < 15 { f = 53 } else { f = 100 }`, + `if 14 <= 15 { f = 53 } else { f = 100 }`, + `if 15 <= 15 { f = 53 } else { f = 100 }`, + `if 13 == 15 { f = 100 } else { f = 53 }`, + `if 13 > 15 { f = 100 } else { f = 53 }`, + `if 13 >= 15 { f = 100 } else { f = 53 }`, + `if 16 > 15 { f = 53 } else { f = 100 }`, + `if 15 >= 15 { f = 53 } else { f = 100 }`, + `if (15 == 15) && (17 == 17) { f = 53 } else { f = 100 }`, + `if (14 < 15) && (14 <= 17) { f = 53 } else { f = 100 }`, + `if (16 > 15) && (19 >= 17) { f = 53 } else { f = 100 }`, + `if (15 == 15) && (17 == 14) { f = 100 } else { f = 53 }`, + `if (15 == 14) && (17 == 16) { f = 100 } else { f = 53 }`, + `if (15 == 14) && (17 == 17) { f = 100 } else { f = 53 }`, + `if (15 == 14) || (17 == 17) { f = 53 } else { f = 100 }`, + `if (15 == 15) || (17 == 14) { f = 53 } else { f = 100 }`, + `if (15 == 14) || (17 == 14) { f = 100} else { f = 53 }`, + + // boolean variables and if + `b = true; if b { f = 53 } else { f = 100 }`, + `b = !false; if b { f = 53 } else { f = 100 }`, + `b = false; if !b { f = 53 } else { f = 100 }`, + `b = true || true; if b { f = 53 } else { f = 100 }`, + `b = true || false; if b { f = 53 } else { f = 100 }`, + `b = false || true; if b { f = 53 } else { f = 100 }`, + `b = false || false; if !b { f = 53 } else { f = 100 }`, + `b = true && true; if b { f = 53 } else { f = 100 }`, + `b = true && false; if !b { f = 53 } else { f = 100 }`, + `b = false && true; if !b { f = 53 } else { f = 100 }`, + `b = false && false; if !b { f = 53 } else { f = 100 }`, + `b = 10 > 9; if b { f = 53 } else { f = 100 }`, + `b = 10 >= 9; if b { f = 53 } else { f = 100 }`, + `b = 10 < 9; if !b { f = 53 } else { f = 100 }`, + `b = 10 <= 9; if !b { f = 53 } else { f = 100 }`, + `b = int8(15) < int8(-1); if !b { f = 53 } else { f = 100 }`, + `c = int8(127) <= int8(-127); if !c { f = 53 } else { f = 100 }`, + `b = int8(15) < int8(-1); c = int8(127) <= int8(-127); if (!b) && (!c) { f = 53 } else { f = 100 }`, + `b = int8(15) < int8(-1) ; c = !b ; d = int8(127) <= int8(-127) ; e = !d ; if c && e { f = 53 } else { f = 100 }`, + + // if statements with uint8 + `if uint8(13) < uint8(15) { f = 53 } else { f = 100 }`, + `if uint8(15) <= uint8(15) { f = 53 } else { f = 100 }`, + `if uint8(14) <= uint8(15) { f = 53 } else { f = 100 }`, + `if (uint8(13) < uint8(15)) && (uint8(15) <= uint8(15)) { f = 53 } else { f = 100 }`, + + // if statements with uint16 + `if uint16(13) < uint16(15) { f = 53 } else { f = 100 }`, + `if uint16(13) <= uint16(15) { f = 53 } else { f = 100 }`, + `if uint16(15) <= uint16(15) { f = 53 } else { f = 100 }`, + + // if statements with uint32 + `if uint32(13) < uint32(15) { f = 53 } else { f = 100 }`, + `if uint32(15) <= uint32(15) { f = 53 } else { f = 100 }`, + `if uint32(13) <= uint32(15) { f = 53 } else { f = 100 }`, + + // if statements with int8 + `if int8(13) < int8(15) { f = 53 } else { f = 100 }`, + `if int8(-1) < int8(15) { f = 53 } else { f = 100 }`, + `if int8(-1) <= int8(15) { f = 53 } else { f = 100 }`, + `if int8(15) <= int8(15) { f = 53 } else { f = 100 }`, + `if (int8(-1) < int8(15)) && (int8(-125) <= int8(15)) { f = 53 } else { f = 100 }`, + `if (int8(15) > int8(-1)) && (int8(127) >= int8(-127)) { f = 53 } else { f = 100 }`, + `if (!(int8(15) < int8(-1))) && (!(int8(127) <= int8(-127))) { f = 53 } else { f = 100 }`, + + // if statements with int16 + `if int16(13) < int16(15) { f = 53 } else { f = 100 }`, + `if int16(-1) < int16(15) { f = 53 } else { f = 100 }`, + `if int16(-1) <= int16(15) { f = 53 } else { f = 100 }`, + `if int16(15) <= int16(15) { f = 53 } else { f = 100 }`, + // TODO: fix operator precedence + `if (int16(-1) < int16(15)) && (int16(-127) <= int16(15)) { f = 53 } else { f = 100 }`, + `if (int16(15) > int16(-1)) && (int16(127) >= int16(-127)) { f = 53 } else { f = 100 }`, + `if (!(int16(15) < int16(-1))) && (!(int16(127) <= int16(-127))) { f = 53 } else { f = 100 }`, + `if (!(int16(-2) > int16(-1))) && (!(int16(17) >= int16(18))) { f = 53 } else { f = 100 }`, + + // if statements with int32 + `if int32(13) < int32(15) { f = 53 } else { f = 100 }`, + `if int32(-1) < int32(15) { f = 53 } else { f = 100 }`, + `if int32(15) <= int32(15) { f = 53 } else { f = 100 }`, + `if int32(-1) <= int32(15) { f = 53 } else { f = 100 }`, + `if (int32(-1) < int32(15)) && (int32(-127) <= int32(15)) { f = 53 } else { f = 100 }`, + `if (int32(15) > int32(-1)) && (int32(127) >= int32(-127)) { f = 53 } else { f = 100 }`, + `if (!(int32(15) < int32(-1))) && (!(int32(127) <= int32(-127))) { f = 53 } else { f = 100 }`, + + // structs + `b = struct{Field int64}{53}; f = b.Field`, + `b = struct{Field int64 + Field2 int64}{51, 53}; f = b.Field2`, + + // functions + `b = func(i uint64) uint64 { return i - uint64(2) }; f = b(55)`, + `func b(i uint64) uint64 { return i - uint64(2)}; f = b(55)`, +} diff --git a/lib/machinecode.go b/lib/machinecode.go index 0850d23..c1a1a9e 100644 --- a/lib/machinecode.go +++ b/lib/machinecode.go @@ -3,10 +3,14 @@ package lib import ( "encoding/hex" "fmt" + "runtime" + "sync" "syscall" "unsafe" ) +const mmapProtFlags = syscall.PROT_READ | syscall.PROT_WRITE | syscall.PROT_EXEC + type MachineCode []uint8 func (m MachineCode) String() string { @@ -25,14 +29,9 @@ func (m MachineCode) String() string { } func (m MachineCode) Execute(debug bool) int { - mmapFunc, err := syscall.Mmap( - -1, - 0, - len(m), - syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_PRIVATE|mmapFlags, - ) + mmapFunc, err := syscall.Mmap(-1, 0, len(m), mmapProtFlags, syscall.MAP_PRIVATE|mmapFlags) if err != nil { - fmt.Printf("mmap err: %v", err) + panic(fmt.Sprintf("mmap err: %v", err)) } for i, b := range m { mmapFunc[i] = b @@ -48,9 +47,49 @@ func (m MachineCode) Execute(debug bool) int { } return value } -func (m MachineCode) Add(m2 MachineCode) MachineCode { - for _, code := range m2 { - m = append(m, code) + +type execFunc func() int + +func (m MachineCode) Compile() *CompiledCode { + mem, err := syscall.Mmap(-1, 0, len(m), mmapProtFlags, syscall.MAP_PRIVATE|mmapFlags) + if err != nil { + panic(fmt.Sprintf("mmap err: %v", err)) } + + cc := &CompiledCode{mem: mem, mc: m} + runtime.SetFinalizer(cc, func(cc *CompiledCode) { + cc.release() + }) + return cc +} + +func (m MachineCode) Add(m2 MachineCode) MachineCode { + m = append(m, m2...) return m } + +type CompiledCode struct { + mem []byte + mc MachineCode + mux sync.Mutex +} + +func (cc *CompiledCode) Execute() int { + cc.mux.Lock() + defer cc.mux.Unlock() + if cc.mem == nil { + panic("used after munmap") + } + copy(cc.mem, cc.mc) + unsafeFunc := (uintptr)(unsafe.Pointer(&cc.mem)) + f := *(*execFunc)(unsafe.Pointer(&unsafeFunc)) + return f() +} + +func (cc *CompiledCode) release() { + if cc.mem != nil { + syscall.Munmap(cc.mem) + cc.mem = nil + cc.mc = nil + } +}