From f69ef191dd0af175c7628b4fa7b7d57778070b7f Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 15 Oct 2018 20:15:58 +0200 Subject: [PATCH 01/70] asm: add scaffolding for Translate Note, this is the first of potential several attempted approaches at finding a clean and performant way of resolving identifiers, translating from AST to IR form and validating the IR. We iterate and learn until we arrive at a successful approach for doing this. --- asm/translate.go | 18 ++++++++++++++++++ cmd/l-tm/main.go | 19 +++---------------- 2 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 asm/translate.go diff --git a/asm/translate.go b/asm/translate.go new file mode 100644 index 00000000..8f494a9c --- /dev/null +++ b/asm/translate.go @@ -0,0 +1,18 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// Translate translates the AST of the given module to an equivalent LLVM IR +// module. +func Translate(module *ast.Module) *ir.Module { + m := &ir.Module{} + for _, entity := range module.TopLevelEntities() { + fmt.Printf("entity: %T\n", entity) + } + return m +} diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index 97ce0fc3..4ab7ccd0 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -6,8 +6,8 @@ import ( "log" "time" + "github.com/kr/pretty" "github.com/mewmew/l-tm/asm" - "github.com/mewmew/l-tm/asm/ll/ast" ) func main() { @@ -22,20 +22,7 @@ func main() { } fmt.Println("took:", time.Since(start)) fmt.Println() - fmt.Println("module:", module.Text()) - for _, entity := range module.TopLevelEntities() { - fmt.Printf("entity %T: %v\n", entity, entity.Text()) - switch entity := entity.(type) { - case *ast.SourceFilename: - fmt.Println(" name:", entity.Name().Text()) - case *ast.TargetDataLayout: - fmt.Println(" datalayout:", entity.DataLayout().Text()) - case *ast.TargetTriple: - fmt.Println(" target triple:", entity.TargetTriple().Text()) - case *ast.ModuleAsm: - fmt.Println(" module asm:", entity.Asm().Text()) - } - } - fmt.Println() + m := asm.Translate(module) + pretty.Println(m) } } From aadbc6bfe7f95a1a2e5ba9dd8595d0f20351a385 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 15 Oct 2018 20:37:58 +0200 Subject: [PATCH 02/70] enc: copy enc without modification from llir/l@31e24a3e7a2b61d2e981af92c6446db3e6f6ef04. Note, this copy will be removed, once the repos are merged. Alternatively. The parser repo will be kept distinct from the IR repo, mainly to keep the size of the repo down. As the generated parser and lexer are quite large, it may be wise to keep the autogenerated code in a contained repo; e.g. llir/parser or llir/ll or llir/asm. This way, we can force push to that repo whenever the parser is regenerated, and keep the size of the main llir/llvm repo manageable. --- internal/enc/enc.go | 284 +++++++++++++++++++++++++++ internal/enc/enc_test.go | 414 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 698 insertions(+) create mode 100644 internal/enc/enc.go create mode 100644 internal/enc/enc_test.go diff --git a/internal/enc/enc.go b/internal/enc/enc.go new file mode 100644 index 00000000..3cf7a3e0 --- /dev/null +++ b/internal/enc/enc.go @@ -0,0 +1,284 @@ +// Package enc implements encoding of identifiers for LLVM IR assembly. +package enc + +import ( + "fmt" + "strings" +) + +// Global encodes a global name to its LLVM IR assembly representation. +// +// Examples: +// "foo" -> "@foo" +// "a b" -> `@"a\20b"` +// "世" -> `@"\E4\B8\96"` +// +// References: +// http://www.llvm.org/docs/LangRef.html#identifiers +func Global(name string) string { + return "@" + EscapeIdent(name) +} + +// Local encodes a local name to its LLVM IR assembly representation. +// +// Examples: +// "foo" -> "%foo" +// "a b" -> `%"a\20b"` +// "世" -> `%"\E4\B8\96"` +// +// References: +// http://www.llvm.org/docs/LangRef.html#identifiers +func Local(name string) string { + return "%" + EscapeIdent(name) +} + +// Label encodes a label name to its LLVM IR assembly representation. +// +// Examples: +// "foo" -> "foo:" +// "a b" -> `"a\20b":` +// "世" -> `"\E4\B8\96":` +// +// References: +// http://www.llvm.org/docs/LangRef.html#identifiers +func Label(name string) string { + return EscapeIdent(name) + ":" +} + +// AttrGroupID encodes a attribute group ID to its LLVM IR assembly +// representation. +// +// Examples: +// "42" -> "#42" +// +// References: +// http://www.llvm.org/docs/LangRef.html#identifiers +func AttrGroupID(id string) string { + return "#" + id +} + +// Comdat encodes a comdat name to its LLVM IR assembly representation. +// +// Examples: +// "foo" -> $%foo" +// "a b" -> `$"a\20b"` +// "世" -> `$"\E4\B8\96"` +// +// References: +// http://www.llvm.org/docs/LangRef.html#identifiers +func Comdat(name string) string { + return "$" + EscapeIdent(name) +} + +// Metadata encodes a metadata name to its LLVM IR assembly representation. +// +// Examples: +// "foo" -> "!foo" +// "a b" -> `!a\20b` +// "世" -> `!\E4\B8\96` +// +// References: +// http://www.llvm.org/docs/LangRef.html#identifiers +func Metadata(name string) string { + valid := func(b byte) bool { + const metadataCharset = tail + `\` + return strings.IndexByte(metadataCharset, b) != -1 + } + return "!" + string(Escape([]byte(name), valid)) +} + +const ( + // decimal specifies the decimal digit characters. + decimal = "0123456789" + // upper specifies the uppercase letters. + upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + // lower specifies the lowercase letters. + lower = "abcdefghijklmnopqrstuvwxyz" + // alpha specifies the alphabetic characters. + alpha = upper + lower + // head is the set of valid characters for the first character of an + // identifier. + head = alpha + "$-._" + // tail is the set of valid characters for the remaining characters of an + // identifier (i.e. all characters in the identifier except the first). All + // characters of a label may be from the tail set, even the first character. + tail = head + decimal +) + +/* +// TODO: Replace when the compiler catches up. +// +// Alternative, but slower implementation of EscapeIdent. +// +// benchmark old ns/op new ns/op delta +// BenchmarkGlobalNoReplace-4 97.2 126 +29.63% +// BenchmarkGlobalReplace-4 233 311 +33.48% +// BenchmarkLocalNoReplace-4 97.1 126 +29.76% +// BenchmarkLocalReplace-4 233 312 +33.91% + +// EscapeIdent replaces any characters which are not valid in identifiers with +// corresponding hexadecimal escape sequence (\XX). +func EscapeIdent(s string) string { + valid := func(b byte) bool { + const identCharset = tail + return strings.IndexByte(identCharset, b) != -1 + } + if new := Escape(s, valid); len(new) > len(s) { + return `"` + new + `"` + } + return s +} +*/ + +// EscapeIdent replaces any characters which are not valid in identifiers with +// corresponding hexadecimal escape sequence (\XX). +func EscapeIdent(s string) string { + // Check if a replacement is required. + extra := 0 + for i := 0; i < len(s); i++ { + if strings.IndexByte(tail, s[i]) == -1 { + // Two extra bytes are required for each invalid byte; e.g. + // "#" -> `\23` + // "世" -> `\E4\B8\96` + extra += 2 + } + } + if extra == 0 { + return s + } + + // Replace invalid characters. + const hextable = "0123456789ABCDEF" + buf := make([]byte, len(s)+extra) + j := 0 + for i := 0; i < len(s); i++ { + b := s[i] + if strings.IndexByte(tail, b) != -1 { + buf[j] = b + j++ + continue + } + buf[j] = '\\' + buf[j+1] = hextable[b>>4] + buf[j+2] = hextable[b&0x0F] + j += 3 + } + // Add surrounding quotes. + return `"` + string(buf) + `"` +} + +// EscapeString replaces any characters in s categorized as invalid in string +// literals with corresponding hexadecimal escape sequence (\XX). +func EscapeString(s []byte) string { + valid := func(b byte) bool { + return ' ' <= b && b <= '~' && b != '"' && b != '\\' + } + return string(Escape(s, valid)) +} + +// Escape replaces any characters in s categorized as invalid by the valid +// function with corresponding hexadecimal escape sequence (\XX). +func Escape(s []byte, valid func(b byte) bool) string { + // Check if a replacement is required. + extra := 0 + for i := 0; i < len(s); i++ { + if !valid(s[i]) { // TODO: Check if there is a strings.IndexFunc. + // Two extra bytes are required for each invalid byte; e.g. + // "#" -> `\23` + // "世" -> `\E4\B8\96` + extra += 2 + } + } + if extra == 0 { + return string(s) + } + + // Replace invalid characters. + const hextable = "0123456789ABCDEF" + buf := make([]byte, len(s)+extra) + j := 0 + for i := 0; i < len(s); i++ { + b := s[i] + if valid(b) { + buf[j] = b + j++ + continue + } + buf[j] = '\\' + buf[j+1] = hextable[b>>4] + buf[j+2] = hextable[b&0x0F] + j += 3 + } + return string(buf) +} + +// Unescape replaces hexadecimal escape sequences (\xx) in s with their +// corresponding characters. +func Unescape(s string) []byte { + if !strings.ContainsRune(s, '\\') { + return []byte(s) + } + j := 0 + buf := []byte(s) + for i := 0; i < len(s); i++ { + b := s[i] + if b == '\\' && i+2 < len(s) { + if s[i+1] == '\\' { + b = '\\' + i++ + } else { + x1, ok := unhex(s[i+1]) + if ok { + x2, ok := unhex(s[i+2]) + if ok { + b = x1<<4 | x2 + i += 2 + } + } + } + } + if i != j { + buf[j] = b + } + j++ + } + return buf[:j] +} + +// Quote returns s as a double-quoted string literal. +func Quote(s []byte) string { + return `"` + string(EscapeString(s)) + `"` +} + +// Unquote interprets s as a double-quoted string literal, returning the string +// value that s quotes. +func Unquote(s string) []byte { + if len(s) < 2 { + panic(fmt.Errorf("invalid length of quoted string; expected >= 2, got %d", len(s))) + } + if !strings.HasPrefix(s, `"`) { + panic(fmt.Errorf("invalid quoted string `%s`; missing quote character prefix", s)) + } + if !strings.HasSuffix(s, `"`) { + panic(fmt.Errorf("invalid quoted string `%s`; missing quote character suffix", s)) + } + // Skip double-quotes. + s = s[1 : len(s)-1] + return Unescape(s) +} + +// unhex returns the numeric value represented by the hexadecimal digit b. It +// returns false if b is not a hexadecimal digit. +func unhex(b byte) (v byte, ok bool) { + // This is an adapted copy of the unhex function from the strconv package, + // which is governed by a BSD-style license. + switch { + case '0' <= b && b <= '9': + return b - '0', true + case 'a' <= b && b <= 'f': + return b - 'a' + 10, true + case 'A' <= b && b <= 'F': + return b - 'A' + 10, true + } + return 0, false +} diff --git a/internal/enc/enc_test.go b/internal/enc/enc_test.go new file mode 100644 index 00000000..c10de333 --- /dev/null +++ b/internal/enc/enc_test.go @@ -0,0 +1,414 @@ +package enc + +import ( + "reflect" + "testing" +) + +func TestGlobal(t *testing.T) { + golden := []struct { + s string + want string + }{ + // i=0 + {s: "foo", want: "@foo"}, + // i=1 + {s: "a b", want: `@"a\20b"`}, + // i=2 + {s: "$a", want: "@$a"}, + // i=3 + {s: "-a", want: "@-a"}, + // i=4 + {s: ".a", want: "@.a"}, + // i=5 + {s: "_a", want: "@_a"}, + // i=6 + {s: "#a", want: `@"\23a"`}, + // i=7 + {s: "a b#c", want: `@"a\20b\23c"`}, + // i=8 + {s: "2", want: "@2"}, + // i=9 + {s: "foo世bar", want: `@"foo\E4\B8\96bar"`}, + } + for i, g := range golden { + got := Global(g.s) + if g.want != got { + t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestLocal(t *testing.T) { + golden := []struct { + s string + want string + }{ + // i=0 + {s: "foo", want: "%foo"}, + // i=1 + {s: "a b", want: `%"a\20b"`}, + // i=2 + {s: "$a", want: "%$a"}, + // i=3 + {s: "-a", want: "%-a"}, + // i=4 + {s: ".a", want: "%.a"}, + // i=5 + {s: "_a", want: "%_a"}, + // i=6 + {s: "#a", want: `%"\23a"`}, + // i=7 + {s: "a b#c", want: `%"a\20b\23c"`}, + // i=8 + {s: "2", want: "%2"}, + // i=9 + {s: "foo世bar", want: `%"foo\E4\B8\96bar"`}, + } + for i, g := range golden { + got := Local(g.s) + if g.want != got { + t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestLabel(t *testing.T) { + golden := []struct { + s string + want string + }{ + // i=0 + {s: "foo", want: "foo:"}, + // i=1 + {s: "a b", want: `"a\20b":`}, + // i=2 + {s: "$a", want: "$a:"}, + // i=3 + {s: "-a", want: "-a:"}, + // i=4 + {s: ".a", want: ".a:"}, + // i=5 + {s: "_a", want: "_a:"}, + // i=6 + {s: "#a", want: `"\23a":`}, + // i=7 + {s: "a b#c", want: `"a\20b\23c":`}, + // i=8 + {s: "2", want: "2:"}, + // i=9 + {s: "foo世bar", want: `"foo\E4\B8\96bar":`}, + } + for i, g := range golden { + got := Label(g.s) + if g.want != got { + t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestAttrGroupID(t *testing.T) { + golden := []struct { + s string + want string + }{ + // i=0 + {s: "42", want: "#42"}, + } + for i, g := range golden { + got := AttrGroupID(g.s) + if g.want != got { + t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestComdat(t *testing.T) { + golden := []struct { + s string + want string + }{ + // i=0 + {s: "foo", want: "$foo"}, + // i=1 + {s: "a b", want: `$"a\20b"`}, + // i=2 + {s: "$a", want: "$$a"}, + // i=3 + {s: "-a", want: "$-a"}, + // i=4 + {s: ".a", want: "$.a"}, + // i=5 + {s: "_a", want: "$_a"}, + // i=6 + {s: "#a", want: `$"\23a"`}, + // i=7 + {s: "a b#c", want: `$"a\20b\23c"`}, + // i=8 + {s: "2", want: "$2"}, + // i=9 + {s: "foo世bar", want: `$"foo\E4\B8\96bar"`}, + } + for i, g := range golden { + got := Comdat(g.s) + if g.want != got { + t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestMetadata(t *testing.T) { + golden := []struct { + s string + want string + }{ + // i=0 + {s: "foo", want: "!foo"}, + // i=1 + {s: "a b", want: `!a\20b`}, + // i=2 + {s: "$a", want: "!$a"}, + // i=3 + {s: "-a", want: "!-a"}, + // i=4 + {s: ".a", want: "!.a"}, + // i=5 + {s: "_a", want: "!_a"}, + // i=6 + {s: "#a", want: `!\23a`}, + // i=7 + {s: "a b#c", want: `!a\20b\23c`}, + // i=8 + {s: "2", want: "!2"}, + // i=9 + {s: "foo世bar", want: `!foo\E4\B8\96bar`}, + } + for i, g := range golden { + got := Metadata(g.s) + if g.want != got { + t.Errorf("i=%d: name mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestEscapeString(t *testing.T) { + golden := []struct { + s []byte + want string + }{ + // i=0 + {s: []byte("foo"), want: "foo"}, + // i=1 + {s: []byte("a b"), want: `a b`}, + // i=2 + {s: []byte("$a"), want: "$a"}, + // i=3 + {s: []byte("-a"), want: "-a"}, + // i=4 + {s: []byte(".a"), want: ".a"}, + // i=5 + {s: []byte("_a"), want: "_a"}, + // i=6 + {s: []byte("#a"), want: `#a`}, + // i=7 + {s: []byte("a b#c"), want: `a b#c`}, + // i=8 + {s: []byte("2"), want: "2"}, + // i=9 + {s: []byte("foo世bar"), want: `foo\E4\B8\96bar`}, + // i=10 + {s: []byte(`foo \ bar`), want: `foo \5C bar`}, + // i=11 (arbitrary data, invalid UTF-8) + {s: []byte{'f', 'o', 'o', 0x81, 0x82, 'b', 'a', 'r'}, want: `foo\81\82bar`}, + } + for i, g := range golden { + got := EscapeString(g.s) + if g.want != got { + t.Errorf("i=%d: string mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestEscape(t *testing.T) { + golden := []struct { + s []byte + want string + }{ + // i=0 + {s: []byte("foo"), want: "foo"}, + // i=1 + {s: []byte("a b"), want: `a b`}, + // i=2 + {s: []byte("$a"), want: "$a"}, + // i=3 + {s: []byte("-a"), want: "-a"}, + // i=4 + {s: []byte(".a"), want: ".a"}, + // i=5 + {s: []byte("_a"), want: "_a"}, + // i=6 + {s: []byte("#a"), want: `#a`}, + // i=7 + {s: []byte("a b#c"), want: `a b#c`}, + // i=8 + {s: []byte("2"), want: "2"}, + // i=9 + {s: []byte("foo世bar"), want: `foo\E4\B8\96bar`}, + // i=10 + {s: []byte(`foo \ bar`), want: `foo \5C bar`}, + // i=11 (arbitrary data, invalid UTF-8) + {s: []byte{'f', 'o', 'o', 0x81, 0x82, 'b', 'a', 'r'}, want: `foo\81\82bar`}, + } + // isPrint reports whether the given byte is printable in ASCII. + isPrint := func(b byte) bool { + return ' ' <= b && b <= '~' && b != '"' && b != '\\' + } + for i, g := range golden { + got := Escape(g.s, isPrint) + if g.want != got { + t.Errorf("i=%d: string mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestUnescape(t *testing.T) { + golden := []struct { + s string + want []byte + }{ + // i=0 + {s: "foo", want: []byte("foo")}, + // i=1 + {s: `a\20b`, want: []byte("a b")}, + // i=2 + {s: "$a", want: []byte("$a")}, + // i=3 + {s: "-a", want: []byte("-a")}, + // i=4 + {s: ".a", want: []byte(".a")}, + // i=5 + {s: "_a", want: []byte("_a")}, + // i=6 + {s: `\23a`, want: []byte("#a")}, + // i=7 + {s: `a\20b\23c`, want: []byte("a b#c")}, + // i=8 + {s: "2", want: []byte("2")}, + // i=9 + {s: `foo\E4\B8\96bar`, want: []byte("foo世bar")}, + // i=10 + {s: `foo \5C bar`, want: []byte(`foo \ bar`)}, + // i=11 + {s: `foo \\ bar`, want: []byte(`foo \ bar`)}, + // i=12 (arbitrary data, invalid UTF-8) + {s: `foo\81\82bar`, want: []byte{'f', 'o', 'o', 0x81, 0x82, 'b', 'a', 'r'}}, + } + for i, g := range golden { + got := Unescape(g.s) + if !reflect.DeepEqual(g.want, got) { + t.Errorf("i=%d: string mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestQuote(t *testing.T) { + golden := []struct { + s []byte + want string + }{ + // i=0 + {s: []byte("foo"), want: `"foo"`}, + // i=1 + {s: []byte("a b"), want: `"a b"`}, + // i=2 + {s: []byte("$a"), want: `"$a"`}, + // i=3 + {s: []byte("-a"), want: `"-a"`}, + // i=4 + {s: []byte(".a"), want: `".a"`}, + // i=5 + {s: []byte("_a"), want: `"_a"`}, + // i=6 + {s: []byte("#a"), want: `"#a"`}, + // i=7 + {s: []byte("a b#c"), want: `"a b#c"`}, + // i=8 + {s: []byte("2"), want: `"2"`}, + // i=9 + {s: []byte("foo世bar"), want: `"foo\E4\B8\96bar"`}, + // i=10 + {s: []byte(`foo \ bar`), want: `"foo \5C bar"`}, + // i=11 (arbitrary data, invalid UTF-8) + {s: []byte{'f', 'o', 'o', 0x81, 0x82, 'b', 'a', 'r'}, want: `"foo\81\82bar"`}, + } + for i, g := range golden { + got := Quote(g.s) + if g.want != got { + t.Errorf("i=%d: string mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func TestUnquote(t *testing.T) { + golden := []struct { + s string + want []byte + }{ + // i=0 + {s: `"foo"`, want: []byte("foo")}, + // i=1 + {s: `"a\20b"`, want: []byte("a b")}, + // i=2 + {s: `"$a"`, want: []byte("$a")}, + // i=3 + {s: `"-a"`, want: []byte("-a")}, + // i=4 + {s: `".a"`, want: []byte(".a")}, + // i=5 + {s: `"_a"`, want: []byte("_a")}, + // i=6 + {s: `"\23a"`, want: []byte("#a")}, + // i=7 + {s: `"a\20b\23c"`, want: []byte("a b#c")}, + // i=8 + {s: `"2"`, want: []byte("2")}, + // i=9 + {s: `"foo\E4\B8\96bar"`, want: []byte("foo世bar")}, + // i=10 + {s: `"foo \5C bar"`, want: []byte(`foo \ bar`)}, + // i=11 + {s: `"foo \\ bar"`, want: []byte(`foo \ bar`)}, + // i=12 (arbitrary data, invalid UTF-8) + {s: `"foo\81\82bar"`, want: []byte{'f', 'o', 'o', 0x81, 0x82, 'b', 'a', 'r'}}, + } + for i, g := range golden { + got := Unquote(g.s) + if !reflect.DeepEqual(g.want, got) { + t.Errorf("i=%d: string mismatch; expected %q, got %q", i, g.want, got) + } + } +} + +func BenchmarkGlobalNoReplace(b *testing.B) { + for i := 0; i < b.N; i++ { + Global("$foo_bar_baz") + } +} + +func BenchmarkGlobalReplace(b *testing.B) { + for i := 0; i < b.N; i++ { + Global("$foo bar#baz") + } +} + +func BenchmarkLocalNoReplace(b *testing.B) { + for i := 0; i < b.N; i++ { + Local("$foo_bar_baz") + } +} + +func BenchmarkLocalReplace(b *testing.B) { + for i := 0; i < b.N; i++ { + Local("$foo bar#baz") + } +} From 3f7c8740681f73ba2abd4d9e0ce2c01edc556b81 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 15 Oct 2018 21:02:19 +0200 Subject: [PATCH 03/70] asm: add scaffolding for translating type definitions --- asm/translate.go | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/asm/translate.go b/asm/translate.go index 8f494a9c..97fc3f56 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -2,17 +2,45 @@ package asm import ( "fmt" + "strings" "github.com/llir/l/ir" "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" ) // Translate translates the AST of the given module to an equivalent LLVM IR // module. func Translate(module *ast.Module) *ir.Module { m := &ir.Module{} + // Translate type definitions. for _, entity := range module.TopLevelEntities() { - fmt.Printf("entity: %T\n", entity) + switch entity := entity.(type) { + case *ast.TypeDef: + fmt.Println("alias:", local(entity.Alias())) + default: + fmt.Printf("entity: %T\n", entity) + } } return m } + +// local returns the name of the local identifier. +func local(l ast.LocalIdent) string { + text := l.Text() + const prefix = "%" + if !strings.HasPrefix(text, prefix) { + panic(fmt.Errorf("invalid local identifier `%s`; missing '%s' prefix", text, prefix)) + } + text = text[len(prefix):] + return unquote(text) +} + +// unquote returns the unquoted version of s if quoted, and the original string +// otherwise. +func unquote(s string) string { + if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { + return string(enc.Unquote(s)) + } + return s +} From 640828f758d9a404d4cee7d8da57eea4b7dec495 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 15 Oct 2018 22:42:56 +0200 Subject: [PATCH 04/70] asm: create IR type skeletons and identify self-referential type names Test on the following input ; valid type %a = type { %a* } ; valid type %b = type %b* ; invalid named type; self-referential with type name(s) %c, %d, %e, %f %c = type %d %d = type %e %e = type %f %f = type %c --- asm/translate.go | 125 ++++++++++++++++++++++++++++++++++++++++++++--- cmd/l-tm/main.go | 5 +- 2 files changed, 123 insertions(+), 7 deletions(-) diff --git a/asm/translate.go b/asm/translate.go index 97fc3f56..0c6c82f0 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -2,27 +2,138 @@ package asm import ( "fmt" + "sort" "strings" + "github.com/kr/pretty" "github.com/llir/l/ir" + "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" + "github.com/pkg/errors" ) // Translate translates the AST of the given module to an equivalent LLVM IR // module. -func Translate(module *ast.Module) *ir.Module { +func Translate(module *ast.Module) (*ir.Module, error) { m := &ir.Module{} - // Translate type definitions. + ts, err := resolveTypeDefs(module) + if err != nil { + return nil, errors.WithStack(err) + } + pretty.Println(ts) + return m, nil +} + +// resolveTypeDefs resolves the type definitions of the given module. The +// returned value maps from type name (without '%' prefix) to the underlying +// type. +func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { + // index maps from type name to underlying AST type. + index := make(map[string]ast.LlvmNode) + // Index named AST types. for _, entity := range module.TopLevelEntities() { switch entity := entity.(type) { case *ast.TypeDef: - fmt.Println("alias:", local(entity.Alias())) - default: fmt.Printf("entity: %T\n", entity) + alias := local(entity.Alias()) + fmt.Println(" alias:", alias) + typ := entity.Typ() + switch typ.(type) { + case *ast.OpaqueType: + case ast.Type: + default: + panic(fmt.Errorf("support for type %T not yet implemented", typ)) + } + fmt.Println(" typ:", typ.Text()) + if prev, ok := index[alias]; ok { + return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) + } + index[alias] = typ + } + } + + // ts maps from type name to underlying IR type. + ts := make(map[string]types.Type) + // Create corresponding named IR types; without bodies. + for alias, typ := range index { + track := make(map[string]bool) + t, err := newIRType(alias, typ, index, track) + if err != nil { + return nil, errors.WithStack(err) + } + if prev, ok := ts[alias]; ok { + return nil, errors.Errorf("IR type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Def(), t.Def()) + } + ts[alias] = t + } + + // Translate type definitions. + + return ts, nil +} + +// newIRType returns a new IR type (without body) based on the given AST type. +// Named types are resolved to their underlying type through lookup in index. An +// error is returned for (potentially recursive) self-referential name types. +// +// For instance, the following is disallowed. +// +// ; self-referential named type. +// %a = type %a +// +// ; recursively self-referential named types. +// %b = type %c +// %c = type %b +// +// The following is allowed, however. +// +// ; struct type containing pointer to itself. +// %d = type { %d* } +func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, track map[string]bool) (types.Type, error) { + switch typ := typ.(type) { + case *ast.OpaqueType: + return &types.StructType{Alias: alias, Opaque: true}, nil + case *ast.ArrayType: + return &types.ArrayType{Alias: alias}, nil + case *ast.FloatType: + return &types.FloatType{Alias: alias}, nil + case *ast.FuncType: + return &types.FuncType{Alias: alias}, nil + case *ast.IntType: + return &types.IntType{Alias: alias}, nil + case *ast.LabelType: + return &types.LabelType{Alias: alias}, nil + case *ast.MMXType: + return &types.MMXType{Alias: alias}, nil + case *ast.MetadataType: + return &types.MetadataType{Alias: alias}, nil + case *ast.NamedType: + if track[alias] { + var names []string + for name := range track { + names = append(names, enc.Local(name)) + } + sort.Strings(names) + return nil, errors.Errorf("self-referential named type with type name(s) %s", strings.Join(names, ", ")) } + track[alias] = true + newAlias := local(typ.Name()) + newTyp := index[newAlias] + return newIRType(newAlias, newTyp, index, track) + case *ast.PointerType: + return &types.PointerType{Alias: alias}, nil + case *ast.StructType: + return &types.StructType{Alias: alias}, nil + case *ast.TokenType: + return &types.TokenType{Alias: alias}, nil + case *ast.VectorType: + return &types.VectorType{Alias: alias}, nil + case *ast.VoidType: + return &types.VoidType{Alias: alias}, nil + default: + panic(fmt.Errorf("support for type %T not yet implemented", typ)) } - return m } // local returns the name of the local identifier. @@ -30,7 +141,9 @@ func local(l ast.LocalIdent) string { text := l.Text() const prefix = "%" if !strings.HasPrefix(text, prefix) { - panic(fmt.Errorf("invalid local identifier `%s`; missing '%s' prefix", text, prefix)) + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid local identifier %q; missing '%s' prefix", text, prefix)) } text = text[len(prefix):] return unquote(text) diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index 4ab7ccd0..12bc84b4 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -22,7 +22,10 @@ func main() { } fmt.Println("took:", time.Since(start)) fmt.Println() - m := asm.Translate(module) + m, err := asm.Translate(module) + if err != nil { + log.Fatalf("%q: %+v", llPath, err) + } pretty.Println(m) } } From d8b47fed78e6d3686d42b528389b5b54a443d5de Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 15 Oct 2018 23:46:33 +0200 Subject: [PATCH 05/70] grammar: add Variadic to Params --- asm/ll/ll.tm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 7430153d..a0fc01b9 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -4328,6 +4328,10 @@ DLLStorageClass -> DLLStorageClass | 'dllimport' ; +Ellipsis -> Ellipsis + : '...' +; + Exact -> Exact : 'exact' ; @@ -4567,11 +4571,12 @@ OverflowFlags -> OverflowFlags # ::= ArgTypeList ',' '...' # ::= ArgType (',' ArgType)* -# TODO: Figure out how to handle variadic. ref: https://github.com/inspirer/textmapper/issues/14 +# NOTE: The grammar for Params of FuncType contains Attrs and Name. However, the +# semantic check will report an error if any of those are present in the input. Params -> Params - : '...'? - | Params=(Param separator ',')+ (',' '...')? + : Variadic=Ellipsisopt + | Params=(Param separator ',')+ Variadic=(',' Ellipsis)? ; Param -> Param From ca4bc73254867f4e886c0487ef5693a7459c157a Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 00:23:12 +0200 Subject: [PATCH 06/70] asm: translate types to IR after type resolution --- asm/translate.go | 290 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 285 insertions(+), 5 deletions(-) diff --git a/asm/translate.go b/asm/translate.go index 0c6c82f0..5ede5386 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -3,6 +3,7 @@ package asm import ( "fmt" "sort" + "strconv" "strings" "github.com/kr/pretty" @@ -47,7 +48,9 @@ func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { } fmt.Println(" typ:", typ.Text()) if prev, ok := index[alias]; ok { - return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) + if _, ok := prev.(*ast.OpaqueType); !ok { + return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) + } } index[alias] = typ } @@ -55,7 +58,7 @@ func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { // ts maps from type name to underlying IR type. ts := make(map[string]types.Type) - // Create corresponding named IR types; without bodies. + // Create corresponding named IR types (without bodies). for alias, typ := range index { track := make(map[string]bool) t, err := newIRType(alias, typ, index, track) @@ -68,11 +71,206 @@ func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { ts[alias] = t } - // Translate type definitions. + // Translate type defintions (including bodies). + for alias, typ := range index { + t := ts[alias] + _, err := translateIRType(t, typ, ts) + if err != nil { + return nil, errors.WithStack(err) + } + } return ts, nil } +// translateIRType translates the AST type into an equivalent IR type. A new IR +// type correspoding to the AST type is created if t is nil, otherwise the body +// of t is populated. Named types are resolved through ts. +func translateIRType(t types.Type, old ast.LlvmNode, ts map[string]types.Type) (types.Type, error) { + switch old := old.(type) { + case *ast.OpaqueType: + typ, ok := t.(*types.StructType) + if t == nil { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic("invalid use of opaque type; only allowed in type definitions") + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST opaque type; expected *types.StructType, got %T", t)) + } + // nothing to do. + return typ, nil + case *ast.ArrayType: + typ, ok := t.(*types.ArrayType) + if t == nil { + typ = &types.ArrayType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST array type; expected *types.ArrayType, got %T", t)) + } + // Array length. + len := uintLit(old.Len()) + typ.Len = int64(len) + // Element type. + elem, err := translateIRType(nil, old.Elem(), ts) + if err != nil { + return nil, errors.WithStack(err) + } + typ.ElemType = elem + return typ, nil + case *ast.FloatType: + typ, ok := t.(*types.FloatType) + if t == nil { + typ = &types.FloatType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST floating-point type; expected *types.FloatType, got %T", t)) + } + // Floating-point kind. + typ.Kind = irFloatKind(old.FloatKind()) + return typ, nil + case *ast.FuncType: + typ, ok := t.(*types.FuncType) + if t == nil { + typ = &types.FuncType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST function type; expected *types.FuncType, got %T", t)) + } + // Return type. + retType, err := translateIRType(nil, old.RetType(), ts) + if err != nil { + return nil, errors.WithStack(err) + } + typ.RetType = retType + // Function parameters. + ps := old.Params() + for _, p := range ps.Params() { + param, err := translateIRType(nil, p.Typ(), ts) + if err != nil { + return nil, errors.WithStack(err) + } + typ.Params = append(typ.Params, param) + } + // Variadic. + typ.Variadic = irOptVariadic(ps.Variadic()) + return typ, nil + case *ast.IntType: + typ, ok := t.(*types.IntType) + if t == nil { + typ = &types.IntType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST integer type; expected *types.IntType, got %T", t)) + } + // Bit size. + typ.BitSize = irIntTypeBitSize(old) + return typ, nil + case *ast.LabelType: + typ, ok := t.(*types.LabelType) + if t == nil { + typ = &types.LabelType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST label type; expected *types.LabelType, got %T", t)) + } + // nothing to do. + return typ, nil + case *ast.MMXType: + typ, ok := t.(*types.MMXType) + if t == nil { + typ = &types.MMXType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST MMX type; expected *types.MMXType, got %T", t)) + } + // nothing to do. + return typ, nil + case *ast.MetadataType: + typ, ok := t.(*types.MetadataType) + if t == nil { + typ = &types.MetadataType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST metadata type; expected *types.MetadataType, got %T", t)) + } + // nothing to do. + return typ, nil + case *ast.NamedType: + // Resolve named type. + alias := local(old.Name()) + if _, ok := ts[alias]; !ok { + return nil, errors.Errorf("unable to locate type definition of named type %q", enc.Local(alias)) + } + return ts[alias], nil + case *ast.PointerType: + typ, ok := t.(*types.PointerType) + if t == nil { + typ = &types.PointerType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST pointer type; expected *types.PointerType, got %T", t)) + } + // Element type. + elemType, err := translateIRType(nil, old.Elem(), ts) + if err != nil { + return nil, errors.WithStack(err) + } + typ.ElemType = elemType + // Address space. + typ.AddrSpace = irOptAddrSpace(old.AddrSpace()) + return typ, nil + case *ast.StructType: + typ, ok := t.(*types.StructType) + if t == nil { + typ = &types.StructType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST struct type; expected *types.StructType, got %T", t)) + } + // Packed. + // TODO: Figure out how to represent packed in grammar. + // Fields. + for _, f := range old.Fields() { + field, err := translateIRType(nil, f, ts) + if err != nil { + return nil, errors.WithStack(err) + } + typ.Fields = append(typ.Fields, field) + } + // struct body now present. + typ.Opaque = false + return typ, nil + case *ast.TokenType: + typ, ok := t.(*types.TokenType) + if t == nil { + typ = &types.TokenType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST token type; expected *types.TokenType, got %T", t)) + } + // nothing to do. + return typ, nil + case *ast.VectorType: + typ, ok := t.(*types.VectorType) + if t == nil { + typ = &types.VectorType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST vector type; expected *types.VectorType, got %T", t)) + } + // Vector length. + len := uintLit(old.Len()) + typ.Len = int64(len) + // Element type. + elem, err := translateIRType(nil, old.Elem(), ts) + if err != nil { + return nil, errors.WithStack(err) + } + typ.ElemType = elem + return typ, nil + case *ast.VoidType: + typ, ok := t.(*types.VoidType) + if t == nil { + typ = &types.VoidType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST void type; expected *types.VoidType, got %T", t)) + } + // nothing to do. + return typ, nil + default: + panic(fmt.Errorf("support for type %T not yet implemented", old)) + } +} + // newIRType returns a new IR type (without body) based on the given AST type. // Named types are resolved to their underlying type through lookup in index. An // error is returned for (potentially recursive) self-referential name types. @@ -115,7 +313,7 @@ func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, tr names = append(names, enc.Local(name)) } sort.Strings(names) - return nil, errors.Errorf("self-referential named type with type name(s) %s", strings.Join(names, ", ")) + return nil, errors.Errorf("invalid named type; self-referential with type name(s) %s", strings.Join(names, ", ")) } track[alias] = true newAlias := local(typ.Name()) @@ -136,7 +334,7 @@ func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, tr } } -// local returns the name of the local identifier. +// local returns the name (without '%' prefix) of the given local identifier. func local(l ast.LocalIdent) string { text := l.Text() const prefix = "%" @@ -149,6 +347,22 @@ func local(l ast.LocalIdent) string { return unquote(text) } +// uintLit returns the unsigned integer value corresponding to the given +// unsigned integer literal. +func uintLit(l ast.UintLit) uint64 { + text := l.Text() + x, err := strconv.ParseUint(text, 10, 64) + if err != nil { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + + // TODO: figure out how to update the grammar for UintLit to remove the + // optional sign. + panic(fmt.Errorf("unable to parse unsigned integer literal %q; %v", text, err)) + } + return x +} + // unquote returns the unquoted version of s if quoted, and the original string // otherwise. func unquote(s string) string { @@ -157,3 +371,69 @@ func unquote(s string) string { } return s } + +// irFloatKind returns the IR floating-point kind corresponding to the given AST +// floating-point kind. +func irFloatKind(kind ast.FloatKind) types.FloatKind { + text := kind.Text() + switch text { + case "half": + return types.FloatKindHalf + case "float": + return types.FloatKindFloat + case "double": + return types.FloatKindDouble + case "x86_fp80": + return types.FloatKindX86FP80 + case "fp128": + return types.FloatKindFP128 + case "ppc_fp128": + return types.FloatKindPPCFP128 + default: + panic(fmt.Errorf("support for floating-point kind %q not yet implemented", text)) + } +} + +// irOptVariadic returns the variadic boolean corresponding to the given AST +// ellipsis. +func irOptVariadic(n *ast.Ellipsis) bool { + // TODO: check why Variadic is non-nil for `Variadic=Ellipsisopt`, regardless + // of whether the input is (...) or (). + // + // It seems that the Variadic.Text simply returns empty string when + // Ellipsisopt reduces to \empty. + // + // Using `n.Text() == "..."` for now, would like to use `n != nil`. + return n.Text() == "..." +} + +// irIntTypeBitSize returns the integer type bit size corresponding to the given +// AST integer type. +func irIntTypeBitSize(n *ast.IntType) int64 { + text := n.Text() + const prefix = "i" + if !strings.HasPrefix(text, prefix) { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid integer type %q; missing '%s' prefix", text, prefix)) + } + text = text[len(prefix):] + x, err := strconv.ParseInt(text, 10, 64) + if err != nil { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("unable to parse integer type bit size %q; %v", text, err)) + } + return x +} + +// irOptAddrSpace returns the IR address space corresponding to the given AST +// address space. +func irOptAddrSpace(n *ast.AddrSpace) types.AddrSpace { + // \empty is used when address space not present. + if n.Text() == "" { + return 0 + } + x := uintLit(n.N()) + return types.AddrSpace(x) +} From f0c647664085fda8adb877989b134f932f67fea0 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 00:30:13 +0200 Subject: [PATCH 07/70] asm: print time take for type resolution of type definitions --- asm/translate.go | 7 ++++--- cmd/l-tm/main.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/asm/translate.go b/asm/translate.go index 5ede5386..188673a2 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -5,6 +5,7 @@ import ( "sort" "strconv" "strings" + "time" "github.com/kr/pretty" "github.com/llir/l/ir" @@ -18,10 +19,13 @@ import ( // module. func Translate(module *ast.Module) (*ir.Module, error) { m := &ir.Module{} + start := time.Now() ts, err := resolveTypeDefs(module) if err != nil { return nil, errors.WithStack(err) } + fmt.Println("type resolution of type definitions took:", time.Since(start)) + fmt.Println() pretty.Println(ts) return m, nil } @@ -36,9 +40,7 @@ func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { for _, entity := range module.TopLevelEntities() { switch entity := entity.(type) { case *ast.TypeDef: - fmt.Printf("entity: %T\n", entity) alias := local(entity.Alias()) - fmt.Println(" alias:", alias) typ := entity.Typ() switch typ.(type) { case *ast.OpaqueType: @@ -46,7 +48,6 @@ func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { default: panic(fmt.Errorf("support for type %T not yet implemented", typ)) } - fmt.Println(" typ:", typ.Text()) if prev, ok := index[alias]; ok { if _, ok := prev.(*ast.OpaqueType); !ok { return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index 12bc84b4..bfdb166e 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -20,7 +20,7 @@ func main() { if err != nil { log.Fatalf("%q: %+v", llPath, err) } - fmt.Println("took:", time.Since(start)) + fmt.Println("parsing into AST took:", time.Since(start)) fmt.Println() m, err := asm.Translate(module) if err != nil { From 96d25daf299e8251dda94169c6bfc168bf42250d Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 00:40:28 +0200 Subject: [PATCH 08/70] cmd/l-tm: add -types flag to enable/diable type resolution of type definitions --- asm/translate.go | 23 +++++++++++++++-------- cmd/l-tm/main.go | 11 +++++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/asm/translate.go b/asm/translate.go index 188673a2..8582e2b9 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/kr/pretty" "github.com/llir/l/ir" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" @@ -15,18 +14,26 @@ import ( "github.com/pkg/errors" ) +// TODO: remove flag after we reach our performance goals. + +// DoTypeResolution enables type resolution of type defintions. +var DoTypeResolution = true + // Translate translates the AST of the given module to an equivalent LLVM IR // module. func Translate(module *ast.Module) (*ir.Module, error) { m := &ir.Module{} - start := time.Now() - ts, err := resolveTypeDefs(module) - if err != nil { - return nil, errors.WithStack(err) + if DoTypeResolution { + typeResolutionStart := time.Now() + ts, err := resolveTypeDefs(module) + if err != nil { + return nil, errors.WithStack(err) + } + fmt.Println("type resolution of type definitions took:", time.Since(typeResolutionStart)) + fmt.Println() + _ = ts + //pretty.Println(ts) } - fmt.Println("type resolution of type definitions took:", time.Since(start)) - fmt.Println() - pretty.Println(ts) return m, nil } diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index bfdb166e..649c96b4 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -6,26 +6,29 @@ import ( "log" "time" - "github.com/kr/pretty" "github.com/mewmew/l-tm/asm" ) func main() { + flag.BoolVar(&asm.DoTypeResolution, "types", true, "enable type resolution of type definitions") flag.Parse() for _, llPath := range flag.Args() { fmt.Printf("=== [ %v ] =======================\n", llPath) fmt.Println() - start := time.Now() + fileStart := time.Now() + parseStart := time.Now() module, err := asm.ParseFile(llPath) if err != nil { log.Fatalf("%q: %+v", llPath, err) } - fmt.Println("parsing into AST took:", time.Since(start)) + fmt.Println("parsing into AST took:", time.Since(parseStart)) fmt.Println() m, err := asm.Translate(module) if err != nil { log.Fatalf("%q: %+v", llPath, err) } - pretty.Println(m) + _ = m + //pretty.Println(m) + fmt.Printf("total time for file %q: %v\n", llPath, time.Since(fileStart)) } } From dd59331b706acfe8a105ffe134afd4f9b40162e9 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 01:55:41 +0200 Subject: [PATCH 09/70] asm: add type definitions to IR module --- asm/translate.go | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/asm/translate.go b/asm/translate.go index 8582e2b9..10494f03 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -22,32 +22,47 @@ var DoTypeResolution = true // Translate translates the AST of the given module to an equivalent LLVM IR // module. func Translate(module *ast.Module) (*ir.Module, error) { - m := &ir.Module{} + gen := newGenerator() if DoTypeResolution { typeResolutionStart := time.Now() - ts, err := resolveTypeDefs(module) + _, err := gen.resolveTypeDefs(module) if err != nil { return nil, errors.WithStack(err) } fmt.Println("type resolution of type definitions took:", time.Since(typeResolutionStart)) fmt.Println() - _ = ts - //pretty.Println(ts) } - return m, nil + return gen.m, nil +} + +// generator keeps track of global and local identifiers when translating values +// and types from AST to IR representation. +type generator struct { + // LLVM IR module being generated. + m *ir.Module +} + +// newGenerator returns a new generator for translating an LLVM IR module from +// AST to IR representation. +func newGenerator() *generator { + return &generator{ + m: &ir.Module{}, + } } // resolveTypeDefs resolves the type definitions of the given module. The // returned value maps from type name (without '%' prefix) to the underlying // type. -func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { +func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { // index maps from type name to underlying AST type. index := make(map[string]ast.LlvmNode) // Index named AST types. + var order []string for _, entity := range module.TopLevelEntities() { switch entity := entity.(type) { case *ast.TypeDef: alias := local(entity.Alias()) + order = append(order, alias) typ := entity.Typ() switch typ.(type) { case *ast.OpaqueType: @@ -88,6 +103,22 @@ func resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { } } + // Add type definitions to the IR module, in the same order of occurrance as + // the input. + added := make(map[string]bool) + for _, key := range order { + if added[key] { + // Add only the first type definition of each type name. + // + // Type definitions of opaque types may contain several type + // definitions with the same type name. + continue + } + added[key] = true + t := ts[key] + gen.m.TypeDefs = append(gen.m.TypeDefs, t) + } + return ts, nil } From 3f3e5ea760dacd53a93d281b28933e034a3deaa4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 02:29:17 +0200 Subject: [PATCH 10/70] asm: refactor type resolution code --- asm/helper.go | 73 ++++++++ asm/translate.go | 441 +-------------------------------------------- asm/type.go | 461 +++++++++++++++++++++++++++++++++++++++++++++++ cmd/l-tm/main.go | 3 +- 4 files changed, 543 insertions(+), 435 deletions(-) create mode 100644 asm/helper.go create mode 100644 asm/type.go diff --git a/asm/helper.go b/asm/helper.go new file mode 100644 index 00000000..aa7bffcf --- /dev/null +++ b/asm/helper.go @@ -0,0 +1,73 @@ +package asm + +import ( + "fmt" + "strconv" + "strings" + + "github.com/llir/l/ir/types" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" +) + +// irAddrSpace returns the IR address space corresponding to the given optional +// AST address space. +func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { + // \empty is used when address space not present. + if n.Text() == "" { + return 0 + } + x := uintLit(n.N()) + return types.AddrSpace(x) +} + +// local returns the name (without '%' prefix) of the given local identifier. +func local(l ast.LocalIdent) string { + text := l.Text() + const prefix = "%" + if !strings.HasPrefix(text, prefix) { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid local identifier %q; missing '%s' prefix", text, prefix)) + } + text = text[len(prefix):] + return unquote(text) +} + +// uintLit returns the unsigned integer value corresponding to the given +// unsigned integer literal. +func uintLit(l ast.UintLit) uint64 { + text := l.Text() + x, err := strconv.ParseUint(text, 10, 64) + if err != nil { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + + // TODO: figure out how to update the grammar for UintLit to remove the + // optional sign. + panic(fmt.Errorf("unable to parse unsigned integer literal %q; %v", text, err)) + } + return x +} + +// unquote returns the unquoted version of s if quoted, and the original string +// otherwise. +func unquote(s string) string { + if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { + return string(enc.Unquote(s)) + } + return s +} + +// irVariadic returns the variadic boolean corresponding to the given optional +// AST ellipsis. +func irVariadic(n *ast.Ellipsis) bool { + // TODO: check why Variadic is non-nil for `Variadic=Ellipsisopt`, regardless + // of whether the input is (...) or (). + // + // It seems that the Variadic.Text simply returns empty string when + // Ellipsisopt reduces to \empty. + // + // Using `n.Text() == "..."` for now, would like to use `n != nil`. + return n.Text() == "..." +} diff --git a/asm/translate.go b/asm/translate.go index 10494f03..3b10ce0a 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -2,22 +2,19 @@ package asm import ( "fmt" - "sort" - "strconv" - "strings" "time" "github.com/llir/l/ir" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" - "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" ) // TODO: remove flag after we reach our performance goals. - -// DoTypeResolution enables type resolution of type defintions. -var DoTypeResolution = true +var ( + // DoTypeResolution enables type resolution of type defintions. + DoTypeResolution = true +) // Translate translates the AST of the given module to an equivalent LLVM IR // module. @@ -40,6 +37,9 @@ func Translate(module *ast.Module) (*ir.Module, error) { type generator struct { // LLVM IR module being generated. m *ir.Module + + // ts maps from type name to underlying IR type. + ts map[string]types.Type } // newGenerator returns a new generator for translating an LLVM IR module from @@ -49,430 +49,3 @@ func newGenerator() *generator { m: &ir.Module{}, } } - -// resolveTypeDefs resolves the type definitions of the given module. The -// returned value maps from type name (without '%' prefix) to the underlying -// type. -func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { - // index maps from type name to underlying AST type. - index := make(map[string]ast.LlvmNode) - // Index named AST types. - var order []string - for _, entity := range module.TopLevelEntities() { - switch entity := entity.(type) { - case *ast.TypeDef: - alias := local(entity.Alias()) - order = append(order, alias) - typ := entity.Typ() - switch typ.(type) { - case *ast.OpaqueType: - case ast.Type: - default: - panic(fmt.Errorf("support for type %T not yet implemented", typ)) - } - if prev, ok := index[alias]; ok { - if _, ok := prev.(*ast.OpaqueType); !ok { - return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) - } - } - index[alias] = typ - } - } - - // ts maps from type name to underlying IR type. - ts := make(map[string]types.Type) - // Create corresponding named IR types (without bodies). - for alias, typ := range index { - track := make(map[string]bool) - t, err := newIRType(alias, typ, index, track) - if err != nil { - return nil, errors.WithStack(err) - } - if prev, ok := ts[alias]; ok { - return nil, errors.Errorf("IR type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Def(), t.Def()) - } - ts[alias] = t - } - - // Translate type defintions (including bodies). - for alias, typ := range index { - t := ts[alias] - _, err := translateIRType(t, typ, ts) - if err != nil { - return nil, errors.WithStack(err) - } - } - - // Add type definitions to the IR module, in the same order of occurrance as - // the input. - added := make(map[string]bool) - for _, key := range order { - if added[key] { - // Add only the first type definition of each type name. - // - // Type definitions of opaque types may contain several type - // definitions with the same type name. - continue - } - added[key] = true - t := ts[key] - gen.m.TypeDefs = append(gen.m.TypeDefs, t) - } - - return ts, nil -} - -// translateIRType translates the AST type into an equivalent IR type. A new IR -// type correspoding to the AST type is created if t is nil, otherwise the body -// of t is populated. Named types are resolved through ts. -func translateIRType(t types.Type, old ast.LlvmNode, ts map[string]types.Type) (types.Type, error) { - switch old := old.(type) { - case *ast.OpaqueType: - typ, ok := t.(*types.StructType) - if t == nil { - // NOTE: Panic instead of returning error as this case should not be - // possible given the grammar. - panic("invalid use of opaque type; only allowed in type definitions") - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST opaque type; expected *types.StructType, got %T", t)) - } - // nothing to do. - return typ, nil - case *ast.ArrayType: - typ, ok := t.(*types.ArrayType) - if t == nil { - typ = &types.ArrayType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST array type; expected *types.ArrayType, got %T", t)) - } - // Array length. - len := uintLit(old.Len()) - typ.Len = int64(len) - // Element type. - elem, err := translateIRType(nil, old.Elem(), ts) - if err != nil { - return nil, errors.WithStack(err) - } - typ.ElemType = elem - return typ, nil - case *ast.FloatType: - typ, ok := t.(*types.FloatType) - if t == nil { - typ = &types.FloatType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST floating-point type; expected *types.FloatType, got %T", t)) - } - // Floating-point kind. - typ.Kind = irFloatKind(old.FloatKind()) - return typ, nil - case *ast.FuncType: - typ, ok := t.(*types.FuncType) - if t == nil { - typ = &types.FuncType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST function type; expected *types.FuncType, got %T", t)) - } - // Return type. - retType, err := translateIRType(nil, old.RetType(), ts) - if err != nil { - return nil, errors.WithStack(err) - } - typ.RetType = retType - // Function parameters. - ps := old.Params() - for _, p := range ps.Params() { - param, err := translateIRType(nil, p.Typ(), ts) - if err != nil { - return nil, errors.WithStack(err) - } - typ.Params = append(typ.Params, param) - } - // Variadic. - typ.Variadic = irOptVariadic(ps.Variadic()) - return typ, nil - case *ast.IntType: - typ, ok := t.(*types.IntType) - if t == nil { - typ = &types.IntType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST integer type; expected *types.IntType, got %T", t)) - } - // Bit size. - typ.BitSize = irIntTypeBitSize(old) - return typ, nil - case *ast.LabelType: - typ, ok := t.(*types.LabelType) - if t == nil { - typ = &types.LabelType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST label type; expected *types.LabelType, got %T", t)) - } - // nothing to do. - return typ, nil - case *ast.MMXType: - typ, ok := t.(*types.MMXType) - if t == nil { - typ = &types.MMXType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST MMX type; expected *types.MMXType, got %T", t)) - } - // nothing to do. - return typ, nil - case *ast.MetadataType: - typ, ok := t.(*types.MetadataType) - if t == nil { - typ = &types.MetadataType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST metadata type; expected *types.MetadataType, got %T", t)) - } - // nothing to do. - return typ, nil - case *ast.NamedType: - // Resolve named type. - alias := local(old.Name()) - if _, ok := ts[alias]; !ok { - return nil, errors.Errorf("unable to locate type definition of named type %q", enc.Local(alias)) - } - return ts[alias], nil - case *ast.PointerType: - typ, ok := t.(*types.PointerType) - if t == nil { - typ = &types.PointerType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST pointer type; expected *types.PointerType, got %T", t)) - } - // Element type. - elemType, err := translateIRType(nil, old.Elem(), ts) - if err != nil { - return nil, errors.WithStack(err) - } - typ.ElemType = elemType - // Address space. - typ.AddrSpace = irOptAddrSpace(old.AddrSpace()) - return typ, nil - case *ast.StructType: - typ, ok := t.(*types.StructType) - if t == nil { - typ = &types.StructType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST struct type; expected *types.StructType, got %T", t)) - } - // Packed. - // TODO: Figure out how to represent packed in grammar. - // Fields. - for _, f := range old.Fields() { - field, err := translateIRType(nil, f, ts) - if err != nil { - return nil, errors.WithStack(err) - } - typ.Fields = append(typ.Fields, field) - } - // struct body now present. - typ.Opaque = false - return typ, nil - case *ast.TokenType: - typ, ok := t.(*types.TokenType) - if t == nil { - typ = &types.TokenType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST token type; expected *types.TokenType, got %T", t)) - } - // nothing to do. - return typ, nil - case *ast.VectorType: - typ, ok := t.(*types.VectorType) - if t == nil { - typ = &types.VectorType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST vector type; expected *types.VectorType, got %T", t)) - } - // Vector length. - len := uintLit(old.Len()) - typ.Len = int64(len) - // Element type. - elem, err := translateIRType(nil, old.Elem(), ts) - if err != nil { - return nil, errors.WithStack(err) - } - typ.ElemType = elem - return typ, nil - case *ast.VoidType: - typ, ok := t.(*types.VoidType) - if t == nil { - typ = &types.VoidType{} - } else if !ok { - panic(fmt.Errorf("invalid IR type for AST void type; expected *types.VoidType, got %T", t)) - } - // nothing to do. - return typ, nil - default: - panic(fmt.Errorf("support for type %T not yet implemented", old)) - } -} - -// newIRType returns a new IR type (without body) based on the given AST type. -// Named types are resolved to their underlying type through lookup in index. An -// error is returned for (potentially recursive) self-referential name types. -// -// For instance, the following is disallowed. -// -// ; self-referential named type. -// %a = type %a -// -// ; recursively self-referential named types. -// %b = type %c -// %c = type %b -// -// The following is allowed, however. -// -// ; struct type containing pointer to itself. -// %d = type { %d* } -func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, track map[string]bool) (types.Type, error) { - switch typ := typ.(type) { - case *ast.OpaqueType: - return &types.StructType{Alias: alias, Opaque: true}, nil - case *ast.ArrayType: - return &types.ArrayType{Alias: alias}, nil - case *ast.FloatType: - return &types.FloatType{Alias: alias}, nil - case *ast.FuncType: - return &types.FuncType{Alias: alias}, nil - case *ast.IntType: - return &types.IntType{Alias: alias}, nil - case *ast.LabelType: - return &types.LabelType{Alias: alias}, nil - case *ast.MMXType: - return &types.MMXType{Alias: alias}, nil - case *ast.MetadataType: - return &types.MetadataType{Alias: alias}, nil - case *ast.NamedType: - if track[alias] { - var names []string - for name := range track { - names = append(names, enc.Local(name)) - } - sort.Strings(names) - return nil, errors.Errorf("invalid named type; self-referential with type name(s) %s", strings.Join(names, ", ")) - } - track[alias] = true - newAlias := local(typ.Name()) - newTyp := index[newAlias] - return newIRType(newAlias, newTyp, index, track) - case *ast.PointerType: - return &types.PointerType{Alias: alias}, nil - case *ast.StructType: - return &types.StructType{Alias: alias}, nil - case *ast.TokenType: - return &types.TokenType{Alias: alias}, nil - case *ast.VectorType: - return &types.VectorType{Alias: alias}, nil - case *ast.VoidType: - return &types.VoidType{Alias: alias}, nil - default: - panic(fmt.Errorf("support for type %T not yet implemented", typ)) - } -} - -// local returns the name (without '%' prefix) of the given local identifier. -func local(l ast.LocalIdent) string { - text := l.Text() - const prefix = "%" - if !strings.HasPrefix(text, prefix) { - // NOTE: Panic instead of returning error as this case should not be - // possible given the grammar. - panic(fmt.Errorf("invalid local identifier %q; missing '%s' prefix", text, prefix)) - } - text = text[len(prefix):] - return unquote(text) -} - -// uintLit returns the unsigned integer value corresponding to the given -// unsigned integer literal. -func uintLit(l ast.UintLit) uint64 { - text := l.Text() - x, err := strconv.ParseUint(text, 10, 64) - if err != nil { - // NOTE: Panic instead of returning error as this case should not be - // possible given the grammar. - - // TODO: figure out how to update the grammar for UintLit to remove the - // optional sign. - panic(fmt.Errorf("unable to parse unsigned integer literal %q; %v", text, err)) - } - return x -} - -// unquote returns the unquoted version of s if quoted, and the original string -// otherwise. -func unquote(s string) string { - if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { - return string(enc.Unquote(s)) - } - return s -} - -// irFloatKind returns the IR floating-point kind corresponding to the given AST -// floating-point kind. -func irFloatKind(kind ast.FloatKind) types.FloatKind { - text := kind.Text() - switch text { - case "half": - return types.FloatKindHalf - case "float": - return types.FloatKindFloat - case "double": - return types.FloatKindDouble - case "x86_fp80": - return types.FloatKindX86FP80 - case "fp128": - return types.FloatKindFP128 - case "ppc_fp128": - return types.FloatKindPPCFP128 - default: - panic(fmt.Errorf("support for floating-point kind %q not yet implemented", text)) - } -} - -// irOptVariadic returns the variadic boolean corresponding to the given AST -// ellipsis. -func irOptVariadic(n *ast.Ellipsis) bool { - // TODO: check why Variadic is non-nil for `Variadic=Ellipsisopt`, regardless - // of whether the input is (...) or (). - // - // It seems that the Variadic.Text simply returns empty string when - // Ellipsisopt reduces to \empty. - // - // Using `n.Text() == "..."` for now, would like to use `n != nil`. - return n.Text() == "..." -} - -// irIntTypeBitSize returns the integer type bit size corresponding to the given -// AST integer type. -func irIntTypeBitSize(n *ast.IntType) int64 { - text := n.Text() - const prefix = "i" - if !strings.HasPrefix(text, prefix) { - // NOTE: Panic instead of returning error as this case should not be - // possible given the grammar. - panic(fmt.Errorf("invalid integer type %q; missing '%s' prefix", text, prefix)) - } - text = text[len(prefix):] - x, err := strconv.ParseInt(text, 10, 64) - if err != nil { - // NOTE: Panic instead of returning error as this case should not be - // possible given the grammar. - panic(fmt.Errorf("unable to parse integer type bit size %q; %v", text, err)) - } - return x -} - -// irOptAddrSpace returns the IR address space corresponding to the given AST -// address space. -func irOptAddrSpace(n *ast.AddrSpace) types.AddrSpace { - // \empty is used when address space not present. - if n.Text() == "" { - return 0 - } - x := uintLit(n.N()) - return types.AddrSpace(x) -} diff --git a/asm/type.go b/asm/type.go new file mode 100644 index 00000000..0357b1c9 --- /dev/null +++ b/asm/type.go @@ -0,0 +1,461 @@ +package asm + +import ( + "fmt" + "sort" + "strconv" + "strings" + + "github.com/llir/l/ir/types" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" + "github.com/pkg/errors" +) + +// resolveTypeDefs resolves the type definitions of the given module. The +// returned value maps from type name (without '%' prefix) to the underlying +// type. +func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type, error) { + // index maps from type name to underlying AST type. + index := make(map[string]ast.LlvmNode) + // Record order of type definitions. + added := make(map[string]bool) + var order []string + // Index named AST types. + for _, entity := range module.TopLevelEntities() { + switch entity := entity.(type) { + case *ast.TypeDef: + alias := local(entity.Alias()) + if !added[alias] { + // Only record the first type definition of each type name. + // + // Type definitions of opaque types may contain several type + // definitions with the same type name. + order = append(order, alias) + } + added[alias] = true + typ := entity.Typ() + switch typ.(type) { + case *ast.OpaqueType: + case ast.Type: + default: + panic(fmt.Errorf("support for type %T not yet implemented", typ)) + } + if prev, ok := index[alias]; ok { + if _, ok := prev.(*ast.OpaqueType); !ok { + return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) + } + } + index[alias] = typ + } + } + + // Create corresponding named IR types (without bodies). + gen.ts = make(map[string]types.Type) + for alias, typ := range index { + // track is used to identify self-referential named types. + track := make(map[string]bool) + t, err := newIRType(alias, typ, index, track) + if err != nil { + return nil, errors.WithStack(err) + } + if prev, ok := gen.ts[alias]; ok { + return nil, errors.Errorf("IR type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Def(), t.Def()) + } + gen.ts[alias] = t + } + + // Translate type defintions (including bodies). + for alias, typ := range index { + t := gen.ts[alias] + _, err := gen.translateType(t, typ) + if err != nil { + return nil, errors.WithStack(err) + } + } + + // Add type definitions to IR module in order of occurrence in input. + for _, key := range order { + t := gen.ts[key] + gen.m.TypeDefs = append(gen.m.TypeDefs, t) + } + return gen.ts, nil +} + +// newIRType returns a new IR type (without body) based on the given AST type. +// Named types are resolved to their underlying type through lookup in index. An +// error is returned for (potentially recursive) self-referential name types. +// +// For instance, the following is disallowed. +// +// ; self-referential named type. +// %a = type %a +// +// ; recursively self-referential named types. +// %b = type %c +// %c = type %b +// +// The following is allowed, however. +// +// ; struct type containing pointer to itself. +// %d = type { %d* } +func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, track map[string]bool) (types.Type, error) { + switch typ := typ.(type) { + case *ast.OpaqueType: + return &types.StructType{Alias: alias, Opaque: true}, nil + case *ast.ArrayType: + return &types.ArrayType{Alias: alias}, nil + case *ast.FloatType: + return &types.FloatType{Alias: alias}, nil + case *ast.FuncType: + return &types.FuncType{Alias: alias}, nil + case *ast.IntType: + return &types.IntType{Alias: alias}, nil + case *ast.LabelType: + return &types.LabelType{Alias: alias}, nil + case *ast.MMXType: + return &types.MMXType{Alias: alias}, nil + case *ast.MetadataType: + return &types.MetadataType{Alias: alias}, nil + case *ast.NamedType: + if track[alias] { + var names []string + for name := range track { + names = append(names, enc.Local(name)) + } + sort.Strings(names) + return nil, errors.Errorf("invalid named type; self-referential with type name(s) %s", strings.Join(names, ", ")) + } + track[alias] = true + newAlias := local(typ.Name()) + newTyp := index[newAlias] + return newIRType(newAlias, newTyp, index, track) + case *ast.PointerType: + return &types.PointerType{Alias: alias}, nil + case *ast.StructType: + return &types.StructType{Alias: alias}, nil + case *ast.TokenType: + return &types.TokenType{Alias: alias}, nil + case *ast.VectorType: + return &types.VectorType{Alias: alias}, nil + case *ast.VoidType: + return &types.VoidType{Alias: alias}, nil + default: + panic(fmt.Errorf("support for type %T not yet implemented", typ)) + } +} + +// === [ Types ] =============================================================== + +// translateType translates the AST type into an equivalent IR type. A new IR +// type correspoding to the AST type is created if t is nil, otherwise the body +// of t is populated. Named types are resolved through ts. +func (gen *generator) translateType(t types.Type, old ast.LlvmNode) (types.Type, error) { + switch old := old.(type) { + case *ast.OpaqueType: + return gen.translateOpaqueType(t, old) + case *ast.ArrayType: + return gen.translateArrayType(t, old) + case *ast.FloatType: + return gen.translateFloatType(t, old) + case *ast.FuncType: + return gen.translateFuncType(t, old) + case *ast.IntType: + return gen.translateIntType(t, old) + case *ast.LabelType: + return gen.translateLabelType(t, old) + case *ast.MMXType: + return gen.translateMMXType(t, old) + case *ast.MetadataType: + return gen.translateMetadataType(t, old) + case *ast.NamedType: + return gen.translateNamedType(t, old) + case *ast.PointerType: + return gen.translatePointerType(t, old) + case *ast.StructType: + return gen.translateStructType(t, old) + case *ast.TokenType: + return gen.translateTokenType(t, old) + case *ast.VectorType: + return gen.translateVectorType(t, old) + case *ast.VoidType: + return gen.translateVoidType(t, old) + default: + panic(fmt.Errorf("support for type %T not yet implemented", old)) + } +} + +// --- [ Void Types ] ---------------------------------------------------------- + +func (gen *generator) translateVoidType(t types.Type, old *ast.VoidType) (types.Type, error) { + typ, ok := t.(*types.VoidType) + if t == nil { + typ = &types.VoidType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST void type; expected *types.VoidType, got %T", t)) + } + // nothing to do. + return typ, nil +} + +// --- [ Function Types ] ------------------------------------------------------ + +func (gen *generator) translateFuncType(t types.Type, old *ast.FuncType) (types.Type, error) { + typ, ok := t.(*types.FuncType) + if t == nil { + typ = &types.FuncType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST function type; expected *types.FuncType, got %T", t)) + } + // Return type. + retType, err := gen.translateType(nil, old.RetType()) + if err != nil { + return nil, errors.WithStack(err) + } + typ.RetType = retType + // Function parameters. + ps := old.Params() + for _, p := range ps.Params() { + param, err := gen.translateType(nil, p.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + typ.Params = append(typ.Params, param) + } + // Variadic. + typ.Variadic = irVariadic(ps.Variadic()) + return typ, nil +} + +// --- [ Integer Types ] ------------------------------------------------------- + +func (gen *generator) translateIntType(t types.Type, old *ast.IntType) (types.Type, error) { + typ, ok := t.(*types.IntType) + if t == nil { + typ = &types.IntType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST integer type; expected *types.IntType, got %T", t)) + } + // Bit size. + typ.BitSize = irIntTypeBitSize(old) + return typ, nil +} + +// irIntTypeBitSize returns the integer type bit size corresponding to the given +// AST integer type. +func irIntTypeBitSize(n *ast.IntType) int64 { + text := n.Text() + const prefix = "i" + if !strings.HasPrefix(text, prefix) { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid integer type %q; missing '%s' prefix", text, prefix)) + } + text = text[len(prefix):] + x, err := strconv.ParseInt(text, 10, 64) + if err != nil { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("unable to parse integer type bit size %q; %v", text, err)) + } + return x +} + +// --- [ Floating-point Types ] ------------------------------------------------ + +func (gen *generator) translateFloatType(t types.Type, old *ast.FloatType) (types.Type, error) { + typ, ok := t.(*types.FloatType) + if t == nil { + typ = &types.FloatType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST floating-point type; expected *types.FloatType, got %T", t)) + } + // Floating-point kind. + typ.Kind = irFloatKind(old.FloatKind()) + return typ, nil +} + +// irFloatKind returns the IR floating-point kind corresponding to the given AST +// floating-point kind. +func irFloatKind(kind ast.FloatKind) types.FloatKind { + text := kind.Text() + switch text { + case "half": + return types.FloatKindHalf + case "float": + return types.FloatKindFloat + case "double": + return types.FloatKindDouble + case "x86_fp80": + return types.FloatKindX86FP80 + case "fp128": + return types.FloatKindFP128 + case "ppc_fp128": + return types.FloatKindPPCFP128 + default: + panic(fmt.Errorf("support for floating-point kind %q not yet implemented", text)) + } +} + +// --- [ MMX Types ] ----------------------------------------------------------- + +func (gen *generator) translateMMXType(t types.Type, old *ast.MMXType) (types.Type, error) { + typ, ok := t.(*types.MMXType) + if t == nil { + typ = &types.MMXType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST MMX type; expected *types.MMXType, got %T", t)) + } + // nothing to do. + return typ, nil +} + +// --- [ Pointer Types ] ------------------------------------------------------- + +func (gen *generator) translatePointerType(t types.Type, old *ast.PointerType) (types.Type, error) { + typ, ok := t.(*types.PointerType) + if t == nil { + typ = &types.PointerType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST pointer type; expected *types.PointerType, got %T", t)) + } + // Element type. + elemType, err := gen.translateType(nil, old.Elem()) + if err != nil { + return nil, errors.WithStack(err) + } + typ.ElemType = elemType + // Address space. + typ.AddrSpace = irAddrSpace(old.AddrSpace()) + return typ, nil +} + +// --- [ Vector Types ] -------------------------------------------------------- + +func (gen *generator) translateVectorType(t types.Type, old *ast.VectorType) (types.Type, error) { + typ, ok := t.(*types.VectorType) + if t == nil { + typ = &types.VectorType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST vector type; expected *types.VectorType, got %T", t)) + } + // Vector length. + len := uintLit(old.Len()) + typ.Len = int64(len) + // Element type. + elem, err := gen.translateType(nil, old.Elem()) + if err != nil { + return nil, errors.WithStack(err) + } + typ.ElemType = elem + return typ, nil +} + +// --- [ Label Types ] --------------------------------------------------------- + +func (gen *generator) translateLabelType(t types.Type, old *ast.LabelType) (types.Type, error) { + typ, ok := t.(*types.LabelType) + if t == nil { + typ = &types.LabelType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST label type; expected *types.LabelType, got %T", t)) + } + // nothing to do. + return typ, nil +} + +// --- [ Token Types ] --------------------------------------------------------- + +func (gen *generator) translateTokenType(t types.Type, old *ast.TokenType) (types.Type, error) { + typ, ok := t.(*types.TokenType) + if t == nil { + typ = &types.TokenType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST token type; expected *types.TokenType, got %T", t)) + } + // nothing to do. + return typ, nil +} + +// --- [ Metadata Types ] ------------------------------------------------------ + +func (gen *generator) translateMetadataType(t types.Type, old *ast.MetadataType) (types.Type, error) { + typ, ok := t.(*types.MetadataType) + if t == nil { + typ = &types.MetadataType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST metadata type; expected *types.MetadataType, got %T", t)) + } + // nothing to do. + return typ, nil +} + +// --- [ Array Types ] --------------------------------------------------------- + +func (gen *generator) translateArrayType(t types.Type, old *ast.ArrayType) (types.Type, error) { + typ, ok := t.(*types.ArrayType) + if t == nil { + typ = &types.ArrayType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST array type; expected *types.ArrayType, got %T", t)) + } + // Array length. + len := uintLit(old.Len()) + typ.Len = int64(len) + // Element type. + elem, err := gen.translateType(nil, old.Elem()) + if err != nil { + return nil, errors.WithStack(err) + } + typ.ElemType = elem + return typ, nil +} + +// --- [ Structure Types ] ----------------------------------------------------- + +func (gen *generator) translateOpaqueType(t types.Type, old *ast.OpaqueType) (types.Type, error) { + typ, ok := t.(*types.StructType) + if t == nil { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic("invalid use of opaque type; only allowed in type definitions") + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST opaque type; expected *types.StructType, got %T", t)) + } + // nothing to do. + return typ, nil +} + +func (gen *generator) translateStructType(t types.Type, old *ast.StructType) (types.Type, error) { + typ, ok := t.(*types.StructType) + if t == nil { + typ = &types.StructType{} + } else if !ok { + panic(fmt.Errorf("invalid IR type for AST struct type; expected *types.StructType, got %T", t)) + } + // Packed. + // TODO: Figure out how to represent packed in grammar. + // Fields. + for _, f := range old.Fields() { + field, err := gen.translateType(nil, f) + if err != nil { + return nil, errors.WithStack(err) + } + typ.Fields = append(typ.Fields, field) + } + // struct body now present. + typ.Opaque = false + return typ, nil +} + +// --- [ Named Types ] --------------------------------------------------------- + +func (gen *generator) translateNamedType(t types.Type, old *ast.NamedType) (types.Type, error) { + // Resolve named type. + alias := local(old.Name()) + typ, ok := gen.ts[alias] + if !ok { + return nil, errors.Errorf("unable to locate type definition of named type %q", enc.Local(alias)) + } + return typ, nil +} diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index 649c96b4..3fd30531 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -6,6 +6,7 @@ import ( "log" "time" + "github.com/kr/pretty" "github.com/mewmew/l-tm/asm" ) @@ -28,7 +29,7 @@ func main() { log.Fatalf("%q: %+v", llPath, err) } _ = m - //pretty.Println(m) + pretty.Println(m) fmt.Printf("total time for file %q: %v\n", llPath, time.Since(fileStart)) } } From 4d21d160be863096b0719af1449bb318027d3752 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 13:09:46 +0200 Subject: [PATCH 11/70] asm: add preliminary implementation of global resolution --- asm/global.go | 192 +++++++++++++++++++++++++++++++++++++++++++++++ asm/helper.go | 77 ++++++++++++++----- asm/translate.go | 19 ++++- asm/type.go | 43 ++++++++--- cmd/l-tm/main.go | 1 + 5 files changed, 302 insertions(+), 30 deletions(-) create mode 100644 asm/global.go diff --git a/asm/global.go b/asm/global.go new file mode 100644 index 00000000..6ea82a77 --- /dev/null +++ b/asm/global.go @@ -0,0 +1,192 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/llir/l/ir/value" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" + "github.com/pkg/errors" +) + +// resolveGlobals resolves the global variable and function declarations and +// defintions of the given module. The returned value maps from global +// identifier (without '@' prefix) to the corresponding IR value. +func (gen *generator) resolveGlobals(module *ast.Module) (map[string]value.Value, error) { + // index maps from global identifier to underlying AST value. + index := make(map[string]ast.LlvmNode) // TODO: see if we can make the type stronger. ast.Value, ast.Constant? + // Record order of global variable and function declarations and definitions. + var globalOrder, funcOrder []string + // Index global variable and function declarations and definitions. + for _, entity := range module.TopLevelEntities() { + switch entity := entity.(type) { + case *ast.GlobalDecl: + name := global(entity.Name()) + globalOrder = append(globalOrder, name) + if prev, ok := index[name]; ok { + // TODO: don't report error if prev is a declaration (of same type)? + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + } + index[name] = entity + case *ast.GlobalDef: + name := global(entity.Name()) + globalOrder = append(globalOrder, name) + if prev, ok := index[name]; ok { + // TODO: don't report error if prev is a declaration (of same type)? + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + } + index[name] = entity + case *ast.FuncDecl: + name := global(entity.Header().Name()) + funcOrder = append(funcOrder, name) + if prev, ok := index[name]; ok { + // TODO: don't report error if prev is a declaration (of same type)? + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + } + index[name] = entity + case *ast.FuncDef: + name := global(entity.Header().Name()) + funcOrder = append(funcOrder, name) + if prev, ok := index[name]; ok { + // TODO: don't report error if prev is a declaration (of same type)? + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + } + index[name] = entity + // TODO: handle alias definitions and IFuncs. + //case *ast.AliasDef: + //case *ast.IFuncDef: + } + } + + // Create corresponding IR global variables and functions (without bodies). + gen.gs = make(map[string]value.Value) + for name, old := range index { + g, err := gen.newGlobal(name, old) + if err != nil { + return nil, errors.WithStack(err) + } + gen.gs[name] = g + } + + // Translate global variables and functions (including bodies). + for name, old := range index { + g := gen.gs[name] + _, err := gen.translateGlobal(g, old) + if err != nil { + return nil, errors.WithStack(err) + } + } + + // Add global variable declarations and definitions to IR module in order of + // occurrence in input. + for _, key := range globalOrder { + g, ok := gen.gs[key].(*ir.Global) + if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR type for AST global variable declaration or definition; expected *ir.Global, got %T", g)) + } + gen.m.Globals = append(gen.m.Globals, g) + } + + // Add function declarations and definitions to IR module in order of + // occurrence in input. + for _, key := range funcOrder { + f, ok := gen.gs[key].(*ir.Function) + if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR type for AST function declaration or definition; expected *ir.Function, got %T", f)) + } + gen.m.Funcs = append(gen.m.Funcs, f) + } + + return gen.gs, nil +} + +// newGlobal returns a new IR value (without body but with a type) based on the +// given AST global variable or function. +func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, error) { + switch old := old.(type) { + case *ast.GlobalDecl: + // TODO: Add type. + return &ir.Global{GlobalName: name}, nil + case *ast.GlobalDef: + // TODO: Add type. + return &ir.Global{GlobalName: name}, nil + case *ast.FuncDecl: + // TODO: Add type. + return &ir.Function{FuncName: name}, nil + case *ast.FuncDef: + // TODO: Add type. + return &ir.Function{FuncName: name}, nil + default: + panic(fmt.Errorf("support for global variable or function %T not yet implemented", old)) + } +} + +// translateGlobal translates the AST global variable or function into an +// equivalent IR value. +func (gen *generator) translateGlobal(g value.Value, old ast.LlvmNode) (value.Value, error) { + switch old := old.(type) { + case *ast.GlobalDecl: + return gen.translateGlobalDecl(g, old) + case *ast.GlobalDef: + return gen.translateGlobalDef(g, old) + case *ast.FuncDecl: + return gen.translateFuncDecl(g, old) + case *ast.FuncDef: + return gen.translateFuncDef(g, old) + default: + panic(fmt.Errorf("support for type %T not yet implemented", old)) + } +} + +// ~~~ [ Global Variable Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) translateGlobalDecl(g value.Value, old *ast.GlobalDecl) (value.Value, error) { + global, ok := g.(*ir.Global) + if !ok { + panic(fmt.Errorf("invalid IR type for AST global declaration; expected *ir.Global, got %T", g)) + } + // TODO: implement + return global, nil +} + +// ~~~ [ Global Variable Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) translateGlobalDef(g value.Value, old *ast.GlobalDef) (value.Value, error) { + global, ok := g.(*ir.Global) + if !ok { + panic(fmt.Errorf("invalid IR type for AST global definition; expected *ir.Global, got %T", g)) + } + // TODO: implement + return global, nil +} + +// ~~~ [ Indirect Symbol Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// TODO: add alias definition and IFuncs. + +// ~~~ [ Function Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) translateFuncDecl(g value.Value, old *ast.FuncDecl) (value.Value, error) { + f, ok := g.(*ir.Function) + if !ok { + panic(fmt.Errorf("invalid IR type for AST function declaration; expected *ir.Function, got %T", g)) + } + // TODO: implement + return f, nil +} + +// ~~~ [ Function Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) translateFuncDef(g value.Value, old *ast.FuncDef) (value.Value, error) { + f, ok := g.(*ir.Function) + if !ok { + panic(fmt.Errorf("invalid IR type for AST function definition; expected *ir.Function, got %T", g)) + } + // TODO: implement + return f, nil +} diff --git a/asm/helper.go b/asm/helper.go index aa7bffcf..d89fdbd1 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -10,20 +10,28 @@ import ( "github.com/mewmew/l-tm/internal/enc" ) -// irAddrSpace returns the IR address space corresponding to the given optional -// AST address space. -func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { - // \empty is used when address space not present. - if n.Text() == "" { - return 0 +// === [ Identifiers ] ========================================================= + +// --- [ Global Identifiers ] -------------------------------------------------- + +// global returns the name (without '@' prefix) of the given global identifier. +func global(n ast.GlobalIdent) string { + text := n.Text() + const prefix = "@" + if !strings.HasPrefix(text, prefix) { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid global identifier %q; missing '%s' prefix", text, prefix)) } - x := uintLit(n.N()) - return types.AddrSpace(x) + text = text[len(prefix):] + return unquote(text) } +// --- [ Local Identifiers ] --------------------------------------------------- + // local returns the name (without '%' prefix) of the given local identifier. -func local(l ast.LocalIdent) string { - text := l.Text() +func local(n ast.LocalIdent) string { + text := n.Text() const prefix = "%" if !strings.HasPrefix(text, prefix) { // NOTE: Panic instead of returning error as this case should not be @@ -34,10 +42,22 @@ func local(l ast.LocalIdent) string { return unquote(text) } +// --- [ Label Identifiers ] --------------------------------------------------- + +// --- [ Attribute Group Identifiers ] ----------------------------------------- + +// --- [ Comdat Identifiers ] -------------------------------------------------- + +// --- [ Metadata Identifiers ] ------------------------------------------------ + +// === [ Literals ] ============================================================ + +// --- [ Integer literals ] ---------------------------------------------------- + // uintLit returns the unsigned integer value corresponding to the given // unsigned integer literal. -func uintLit(l ast.UintLit) uint64 { - text := l.Text() +func uintLit(n ast.UintLit) uint64 { + text := n.Text() x, err := strconv.ParseUint(text, 10, 64) if err != nil { // NOTE: Panic instead of returning error as this case should not be @@ -50,13 +70,23 @@ func uintLit(l ast.UintLit) uint64 { return x } -// unquote returns the unquoted version of s if quoted, and the original string -// otherwise. -func unquote(s string) string { - if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { - return string(enc.Unquote(s)) +// --- [ Floating-point literals ] --------------------------------------------- + +// --- [ String literals ] ----------------------------------------------------- + +// --- [ Null literals ] ------------------------------------------------------- + +// ___ [ Helpers ] _____________________________________________________________ + +// irAddrSpace returns the IR address space corresponding to the given optional +// AST address space. +func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { + // \empty is used when address space not present. + if n.Text() == "" { + return 0 } - return s + x := uintLit(n.N()) + return types.AddrSpace(x) } // irVariadic returns the variadic boolean corresponding to the given optional @@ -71,3 +101,14 @@ func irVariadic(n *ast.Ellipsis) bool { // Using `n.Text() == "..."` for now, would like to use `n != nil`. return n.Text() == "..." } + +// ### [ Helpers ] ############################################################# + +// unquote returns the unquoted version of s if quoted, and the original string +// otherwise. +func unquote(s string) string { + if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) { + return string(enc.Unquote(s)) + } + return s +} diff --git a/asm/translate.go b/asm/translate.go index 3b10ce0a..50f1533e 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -6,6 +6,7 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" + "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/pkg/errors" ) @@ -14,6 +15,9 @@ import ( var ( // DoTypeResolution enables type resolution of type defintions. DoTypeResolution = true + // DoGlobalResolution enables global resolution of global variable and + // function delcarations and defintions. + DoGlobalResolution = true ) // Translate translates the AST of the given module to an equivalent LLVM IR @@ -29,6 +33,15 @@ func Translate(module *ast.Module) (*ir.Module, error) { fmt.Println("type resolution of type definitions took:", time.Since(typeResolutionStart)) fmt.Println() } + if DoGlobalResolution { + globalResolutionStart := time.Now() + _, err := gen.resolveGlobals(module) + if err != nil { + return nil, errors.WithStack(err) + } + fmt.Println("global resolution of global variable and function declarations and definitions took:", time.Since(globalResolutionStart)) + fmt.Println() + } return gen.m, nil } @@ -38,8 +51,12 @@ type generator struct { // LLVM IR module being generated. m *ir.Module - // ts maps from type name to underlying IR type. + // ts maps from type name (without '%' prefix) to underlying IR type. ts map[string]types.Type + + // gs maps from global identifier (without '@' prefix) to corresponding + // IR value. + gs map[string]value.Value } // newGenerator returns a new generator for translating an LLVM IR module from diff --git a/asm/type.go b/asm/type.go index 0357b1c9..571c3f8f 100644 --- a/asm/type.go +++ b/asm/type.go @@ -52,23 +52,20 @@ func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type // Create corresponding named IR types (without bodies). gen.ts = make(map[string]types.Type) - for alias, typ := range index { + for alias, old := range index { // track is used to identify self-referential named types. track := make(map[string]bool) - t, err := newIRType(alias, typ, index, track) + t, err := newIRType(alias, old, index, track) if err != nil { return nil, errors.WithStack(err) } - if prev, ok := gen.ts[alias]; ok { - return nil, errors.Errorf("IR type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Def(), t.Def()) - } gen.ts[alias] = t } // Translate type defintions (including bodies). - for alias, typ := range index { + for alias, old := range index { t := gen.ts[alias] - _, err := gen.translateType(t, typ) + _, err := gen.translateType(t, old) if err != nil { return nil, errors.WithStack(err) } @@ -99,8 +96,8 @@ func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type // // ; struct type containing pointer to itself. // %d = type { %d* } -func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, track map[string]bool) (types.Type, error) { - switch typ := typ.(type) { +func newIRType(alias string, old ast.LlvmNode, index map[string]ast.LlvmNode, track map[string]bool) (types.Type, error) { + switch old := old.(type) { case *ast.OpaqueType: return &types.StructType{Alias: alias, Opaque: true}, nil case *ast.ArrayType: @@ -127,7 +124,7 @@ func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, tr return nil, errors.Errorf("invalid named type; self-referential with type name(s) %s", strings.Join(names, ", ")) } track[alias] = true - newAlias := local(typ.Name()) + newAlias := local(old.Name()) newTyp := index[newAlias] return newIRType(newAlias, newTyp, index, track) case *ast.PointerType: @@ -141,7 +138,7 @@ func newIRType(alias string, typ ast.LlvmNode, index map[string]ast.LlvmNode, tr case *ast.VoidType: return &types.VoidType{Alias: alias}, nil default: - panic(fmt.Errorf("support for type %T not yet implemented", typ)) + panic(fmt.Errorf("support for type %T not yet implemented", old)) } } @@ -192,6 +189,8 @@ func (gen *generator) translateVoidType(t types.Type, old *ast.VoidType) (types. if t == nil { typ = &types.VoidType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST void type; expected *types.VoidType, got %T", t)) } // nothing to do. @@ -205,6 +204,8 @@ func (gen *generator) translateFuncType(t types.Type, old *ast.FuncType) (types. if t == nil { typ = &types.FuncType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST function type; expected *types.FuncType, got %T", t)) } // Return type. @@ -234,6 +235,8 @@ func (gen *generator) translateIntType(t types.Type, old *ast.IntType) (types.Ty if t == nil { typ = &types.IntType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST integer type; expected *types.IntType, got %T", t)) } // Bit size. @@ -304,6 +307,8 @@ func (gen *generator) translateMMXType(t types.Type, old *ast.MMXType) (types.Ty if t == nil { typ = &types.MMXType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST MMX type; expected *types.MMXType, got %T", t)) } // nothing to do. @@ -317,6 +322,8 @@ func (gen *generator) translatePointerType(t types.Type, old *ast.PointerType) ( if t == nil { typ = &types.PointerType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST pointer type; expected *types.PointerType, got %T", t)) } // Element type. @@ -337,6 +344,8 @@ func (gen *generator) translateVectorType(t types.Type, old *ast.VectorType) (ty if t == nil { typ = &types.VectorType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST vector type; expected *types.VectorType, got %T", t)) } // Vector length. @@ -358,6 +367,8 @@ func (gen *generator) translateLabelType(t types.Type, old *ast.LabelType) (type if t == nil { typ = &types.LabelType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST label type; expected *types.LabelType, got %T", t)) } // nothing to do. @@ -371,6 +382,8 @@ func (gen *generator) translateTokenType(t types.Type, old *ast.TokenType) (type if t == nil { typ = &types.TokenType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST token type; expected *types.TokenType, got %T", t)) } // nothing to do. @@ -384,6 +397,8 @@ func (gen *generator) translateMetadataType(t types.Type, old *ast.MetadataType) if t == nil { typ = &types.MetadataType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST metadata type; expected *types.MetadataType, got %T", t)) } // nothing to do. @@ -397,6 +412,8 @@ func (gen *generator) translateArrayType(t types.Type, old *ast.ArrayType) (type if t == nil { typ = &types.ArrayType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST array type; expected *types.ArrayType, got %T", t)) } // Array length. @@ -420,6 +437,8 @@ func (gen *generator) translateOpaqueType(t types.Type, old *ast.OpaqueType) (ty // possible given the grammar. panic("invalid use of opaque type; only allowed in type definitions") } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST opaque type; expected *types.StructType, got %T", t)) } // nothing to do. @@ -431,6 +450,8 @@ func (gen *generator) translateStructType(t types.Type, old *ast.StructType) (ty if t == nil { typ = &types.StructType{} } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST struct type; expected *types.StructType, got %T", t)) } // Packed. diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index 3fd30531..72d6afd6 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -12,6 +12,7 @@ import ( func main() { flag.BoolVar(&asm.DoTypeResolution, "types", true, "enable type resolution of type definitions") + flag.BoolVar(&asm.DoGlobalResolution, "globals", true, "enable global resolution of global variable and function declarations and definitions") flag.Parse() for _, llPath := range flag.Args() { fmt.Printf("=== [ %v ] =======================\n", llPath) From 94322468a20e9aada4548780a35db6729bff5722 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 13:34:21 +0200 Subject: [PATCH 12/70] asm: translate types of global variables and functions --- asm/global.go | 69 +++++++++++++++++++++++++++++++++++++++++++++------ asm/type.go | 19 +++++++++----- 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/asm/global.go b/asm/global.go index 6ea82a77..604e0d8d 100644 --- a/asm/global.go +++ b/asm/global.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/llir/l/ir" + "github.com/llir/l/ir/types" "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" @@ -110,17 +111,69 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]value.Value func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, error) { switch old := old.(type) { case *ast.GlobalDecl: - // TODO: Add type. - return &ir.Global{GlobalName: name}, nil + g := &ir.Global{GlobalName: name} + // Content type. + typ, err := gen.irType(old.ContentType()) + if err != nil { + return nil, errors.WithStack(err) + } + g.ContentType = typ + return g, nil case *ast.GlobalDef: - // TODO: Add type. - return &ir.Global{GlobalName: name}, nil + g := &ir.Global{GlobalName: name} + // Content type. + typ, err := gen.irType(old.ContentType()) + if err != nil { + return nil, errors.WithStack(err) + } + g.ContentType = typ + return g, nil case *ast.FuncDecl: - // TODO: Add type. - return &ir.Function{FuncName: name}, nil + f := &ir.Function{FuncName: name} + hdr := old.Header() + sig := &types.FuncType{} + // Return type. + retType, err := gen.irType(hdr.RetType()) + if err != nil { + return nil, errors.WithStack(err) + } + sig.RetType = retType + // Function parameters. + ps := hdr.Params() + for _, p := range ps.Params() { + param, err := gen.irType(p.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + sig.Params = append(sig.Params, param) + } + // Variadic. + sig.Variadic = irVariadic(ps.Variadic()) + f.Sig = sig + return f, nil case *ast.FuncDef: - // TODO: Add type. - return &ir.Function{FuncName: name}, nil + f := &ir.Function{FuncName: name} + sig := &types.FuncType{} + hdr := old.Header() + // Return type. + retType, err := gen.irType(hdr.RetType()) + if err != nil { + return nil, errors.WithStack(err) + } + sig.RetType = retType + // Function parameters. + ps := hdr.Params() + for _, p := range ps.Params() { + param, err := gen.irType(p.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + sig.Params = append(sig.Params, param) + } + // Variadic. + sig.Variadic = irVariadic(ps.Variadic()) + f.Sig = sig + return f, nil default: panic(fmt.Errorf("support for global variable or function %T not yet implemented", old)) } diff --git a/asm/type.go b/asm/type.go index 571c3f8f..e73e8f9e 100644 --- a/asm/type.go +++ b/asm/type.go @@ -209,7 +209,7 @@ func (gen *generator) translateFuncType(t types.Type, old *ast.FuncType) (types. panic(fmt.Errorf("invalid IR type for AST function type; expected *types.FuncType, got %T", t)) } // Return type. - retType, err := gen.translateType(nil, old.RetType()) + retType, err := gen.irType(old.RetType()) if err != nil { return nil, errors.WithStack(err) } @@ -217,7 +217,7 @@ func (gen *generator) translateFuncType(t types.Type, old *ast.FuncType) (types. // Function parameters. ps := old.Params() for _, p := range ps.Params() { - param, err := gen.translateType(nil, p.Typ()) + param, err := gen.irType(p.Typ()) if err != nil { return nil, errors.WithStack(err) } @@ -327,7 +327,7 @@ func (gen *generator) translatePointerType(t types.Type, old *ast.PointerType) ( panic(fmt.Errorf("invalid IR type for AST pointer type; expected *types.PointerType, got %T", t)) } // Element type. - elemType, err := gen.translateType(nil, old.Elem()) + elemType, err := gen.irType(old.Elem()) if err != nil { return nil, errors.WithStack(err) } @@ -352,7 +352,7 @@ func (gen *generator) translateVectorType(t types.Type, old *ast.VectorType) (ty len := uintLit(old.Len()) typ.Len = int64(len) // Element type. - elem, err := gen.translateType(nil, old.Elem()) + elem, err := gen.irType(old.Elem()) if err != nil { return nil, errors.WithStack(err) } @@ -420,7 +420,7 @@ func (gen *generator) translateArrayType(t types.Type, old *ast.ArrayType) (type len := uintLit(old.Len()) typ.Len = int64(len) // Element type. - elem, err := gen.translateType(nil, old.Elem()) + elem, err := gen.irType(old.Elem()) if err != nil { return nil, errors.WithStack(err) } @@ -458,7 +458,7 @@ func (gen *generator) translateStructType(t types.Type, old *ast.StructType) (ty // TODO: Figure out how to represent packed in grammar. // Fields. for _, f := range old.Fields() { - field, err := gen.translateType(nil, f) + field, err := gen.irType(f) if err != nil { return nil, errors.WithStack(err) } @@ -480,3 +480,10 @@ func (gen *generator) translateNamedType(t types.Type, old *ast.NamedType) (type } return typ, nil } + +// ### [ Helpers ] ############################################################# + +// irType returns the IR type corresponding to the given AST type. +func (gen *generator) irType(old ast.LlvmNode) (types.Type, error) { + return gen.translateType(nil, old) +} From 961b4cfa1c01e3a2abeefdfd6e03de9c84781231 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 13:37:47 +0200 Subject: [PATCH 13/70] asm: remove TODO about index type bound for globals --- asm/global.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asm/global.go b/asm/global.go index 604e0d8d..a92b2a7c 100644 --- a/asm/global.go +++ b/asm/global.go @@ -16,7 +16,7 @@ import ( // identifier (without '@' prefix) to the corresponding IR value. func (gen *generator) resolveGlobals(module *ast.Module) (map[string]value.Value, error) { // index maps from global identifier to underlying AST value. - index := make(map[string]ast.LlvmNode) // TODO: see if we can make the type stronger. ast.Value, ast.Constant? + index := make(map[string]ast.LlvmNode) // Record order of global variable and function declarations and definitions. var globalOrder, funcOrder []string // Index global variable and function declarations and definitions. From 021f132851ee7af3fa4683f484eb775709af0f1f Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 19:39:36 +0200 Subject: [PATCH 14/70] grammar: rename PreemptionSpecifier to Preemption to match IR package --- asm/helper.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ asm/ll/ll.tm | 17 ++++++++----- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index d89fdbd1..0c351342 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "github.com/llir/l/ir/ll" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" @@ -89,6 +90,75 @@ func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { return types.AddrSpace(x) } +// irDLLStorageClass returns the IR DLL storage class corresponding to the given +// optional AST DLL storage class. +func irDLLStorageClass(n *ast.DLLStorageClass) ll.DLLStorageClass { + text := n.Text() + switch text { + case "": + // \empty is used when DLL storage class not present. + return ll.DLLStorageClassNone + case "dllexport": + return ll.DLLStorageClassDLLExport + case "dllimport": + return ll.DLLStorageClassDLLImport + default: + panic(fmt.Errorf("support for DLL storage class %q not yet implemented", text)) + } +} + +// irLinkage returns the IR linkage corresponding to the given optional AST +// linkage. +func irLinkage(n *ast.Linkage) ll.Linkage { + text := n.Text() + switch text { + case "": + // \empty is used when linkage not present. + return ll.LinkageNone + case "appending": + return ll.LinkageAppending + case "available_externally": + return ll.LinkageAvailableExternally + case "common": + return ll.LinkageCommon + case "internal": + return ll.LinkageInternal + case "linkonce": + return ll.LinkageLinkOnce + case "linkonce_odr": + return ll.LinkageLinkOnceODR + case "private": + return ll.LinkagePrivate + case "weak": + return ll.LinkageWeak + case "weak_odr": + return ll.LinkageWeakODR + case "external": + return ll.LinkageExternal + case "extern_weak": + return ll.LinkageExternWeak + default: + panic(fmt.Errorf("support for linkage %q not yet implemented", text)) + } +} + +// irPreemption returns the IR preemption corresponding to the given optional +// AST preemption. +func irPreemption(n *ast.Preemption) ll.Preemption { + text := n.Text() + switch text { + case "": + // \empty is used when preemption not present. + return ll.PreemptionNone + case "dso_local": + return ll.PreemptionDSOLocal + case "dso_preemptable": + return ll.PreemptionDSOPreemptable + default: + panic(fmt.Errorf("support for preemption %q not yet implemented", text)) + } +} + // irVariadic returns the variadic boolean corresponding to the given optional // AST ellipsis. func irVariadic(n *ast.Ellipsis) bool { diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index a8c37d2b..6787c5ac 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -809,13 +809,13 @@ SelectionKind -> SelectionKind # Const OptionalAttrs GlobalDecl -> GlobalDecl - : Name=GlobalIdent '=' ExternLinkage PreemptionSpecifieropt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt AddrSpaceopt ExternallyInitializedopt Immutable ContentType=Type GlobalAttrs=(',' GlobalAttr)+? FuncAttrs=(',' FuncAttr)+? + : Name=GlobalIdent '=' ExternLinkage Preemptionopt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt AddrSpaceopt ExternallyInitializedopt Immutable ContentType=Type GlobalAttrs=(',' GlobalAttr)+? FuncAttrs=(',' FuncAttr)+? ; # ~~~ [ Global Variable Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GlobalDef -> GlobalDef - : Name=GlobalIdent '=' Linkageopt PreemptionSpecifieropt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt AddrSpaceopt ExternallyInitializedopt Immutable ContentType=Type Init=Constant GlobalAttrs=(',' GlobalAttr)+? FuncAttrs=(',' FuncAttr)+? + : Name=GlobalIdent '=' Linkageopt Preemptionopt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt AddrSpaceopt ExternallyInitializedopt Immutable ContentType=Type Init=Constant GlobalAttrs=(',' GlobalAttr)+? FuncAttrs=(',' FuncAttr)+? ; # TODO: Check if ExternallyInitialized can be inlined or handled in a cleaner way. ref: https://github.com/inspirer/textmapper/issues/14 @@ -859,11 +859,11 @@ IndirectSymbolDef -> IndirectSymbolDef ; AliasDef -> AliasDef - : Name=GlobalIdent '=' (ExternLinkage | Linkageopt) PreemptionSpecifieropt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt 'alias' Typ=Type ',' AliaseeType=Type Aliasee=Constant + : Name=GlobalIdent '=' (ExternLinkage | Linkageopt) Preemptionopt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt 'alias' Typ=Type ',' AliaseeType=Type Aliasee=Constant ; IFuncDef -> IFuncDef - : Name=GlobalIdent '=' (ExternLinkage | Linkageopt) PreemptionSpecifieropt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt 'ifunc' Typ=Type ',' ResolverType=Type Resolver=Constant + : Name=GlobalIdent '=' (ExternLinkage | Linkageopt) Preemptionopt Visibilityopt DLLStorageClassopt ThreadLocalopt UnnamedAddropt 'ifunc' Typ=Type ',' ResolverType=Type Resolver=Constant ; # ~~~ [ Function Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -901,7 +901,7 @@ FuncDef -> FuncDef # The shift/reduce conflict is present since FuncAttr also contains 'align'. FuncHeader -> FuncHeader - : (Linkage | ExternLinkage)? PreemptionSpecifieropt Visibilityopt DLLStorageClassopt CallingConvopt ReturnAttrs=ReturnAttr* RetType=Type Name=GlobalIdent '(' Params ')' UnnamedAddropt AddrSpaceopt FuncAttrs=FuncAttr* Sectionopt Comdatopt GCopt Prefixopt Prologueopt Personalityopt + : (Linkage | ExternLinkage)? Preemptionopt Visibilityopt DLLStorageClassopt CallingConvopt ReturnAttrs=ReturnAttr* RetType=Type Name=GlobalIdent '(' Params ')' UnnamedAddropt AddrSpaceopt FuncAttrs=FuncAttr* Sectionopt Comdatopt GCopt Prefixopt Prologueopt Personalityopt ; # TODO: Rename GCNode to GC when collision with token 'gc' has been resolved. @@ -4462,6 +4462,11 @@ FuncMetadata -> FuncMetadata : MetadataAttachments=MetadataAttachment* ; +# TODO: consider removing remove GlobalAttr in favour of using (',' Section)? +# (',' Comdat)? (',' Alignment)? (',' MetadataAttachment)* as was used in the +# LangRef spec of LLVM IR. Note that the LLVM C++ parser is implemented using +# GlobalAttr, and does not follow the LangRef spec. + %interface GlobalAttr; GlobalAttr -> GlobalAttr @@ -4623,7 +4628,7 @@ ParamAttribute -> ParamAttribute # ref: ParseOptionalDSOLocal -PreemptionSpecifier -> PreemptionSpecifier +Preemption -> Preemption : 'dso_local' | 'dso_preemptable' ; From 8da28aa4d861533fca27fbe276703458766419b1 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 16 Oct 2018 20:30:53 +0200 Subject: [PATCH 15/70] ast: translate most fields of GlobalDecl and GlobalDef --- asm/global.go | 51 ++++++++++++++++++++- asm/helper.go | 120 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 4 deletions(-) diff --git a/asm/global.go b/asm/global.go index a92b2a7c..d20ed8af 100644 --- a/asm/global.go +++ b/asm/global.go @@ -118,6 +118,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, err return nil, errors.WithStack(err) } g.ContentType = typ + g.Typ = types.NewPointer(g.ContentType) return g, nil case *ast.GlobalDef: g := &ir.Global{GlobalName: name} @@ -127,6 +128,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, err return nil, errors.WithStack(err) } g.ContentType = typ + g.Typ = types.NewPointer(g.ContentType) return g, nil case *ast.FuncDecl: f := &ir.Function{FuncName: name} @@ -150,6 +152,8 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, err // Variadic. sig.Variadic = irVariadic(ps.Variadic()) f.Sig = sig + // TODO: add Typ? + //f.Typ = types.NewPointer(f.Sig) return f, nil case *ast.FuncDef: f := &ir.Function{FuncName: name} @@ -173,6 +177,8 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, err // Variadic. sig.Variadic = irVariadic(ps.Variadic()) f.Sig = sig + // TODO: add Typ? + //f.Typ = types.NewPointer(f.Sig) return f, nil default: panic(fmt.Errorf("support for global variable or function %T not yet implemented", old)) @@ -203,7 +209,27 @@ func (gen *generator) translateGlobalDecl(g value.Value, old *ast.GlobalDecl) (v if !ok { panic(fmt.Errorf("invalid IR type for AST global declaration; expected *ir.Global, got %T", g)) } - // TODO: implement + // Linkage. + global.Linkage = irLinkage(old.ExternLinkage().Text()) + // Preemption. + global.Preemption = irPreemption(old.Preemption()) + // Visibility. + global.Visibility = irVisibility(old.Visibility()) + // DLL storage class. + global.DLLStorageClass = irDLLStorageClass(old.DLLStorageClass()) + // Thread local storage model. + global.TLSModel = irTLSModelFromThreadLocal(old.ThreadLocal()) + // Unnamed address. + global.UnnamedAddr = irUnnamedAddr(old.UnnamedAddr()) + // Address space. + global.Typ.AddrSpace = irAddrSpace(old.AddrSpace()) + // Externally initialized. + global.ExternallyInitialized = irExternallyInitialized(old.ExternallyInitialized()) + // Immutable (constant or global). + global.Immutable = irImmutable(old.Immutable()) + // Content type already stored during index. + // TODO: handle GlobalAttrs. + // TODO: handle FuncAttrs. return global, nil } @@ -214,7 +240,28 @@ func (gen *generator) translateGlobalDef(g value.Value, old *ast.GlobalDef) (val if !ok { panic(fmt.Errorf("invalid IR type for AST global definition; expected *ir.Global, got %T", g)) } - // TODO: implement + // Linkage. + global.Linkage = irLinkage(old.Linkage().Text()) + // Preemption. + global.Preemption = irPreemption(old.Preemption()) + // Visibility. + global.Visibility = irVisibility(old.Visibility()) + // DLL storage class. + global.DLLStorageClass = irDLLStorageClass(old.DLLStorageClass()) + // Thread local storage model. + global.TLSModel = irTLSModelFromThreadLocal(old.ThreadLocal()) + // Unnamed address. + global.UnnamedAddr = irUnnamedAddr(old.UnnamedAddr()) + // Address space. + global.Typ.AddrSpace = irAddrSpace(old.AddrSpace()) + // Externally initialized. + global.ExternallyInitialized = irExternallyInitialized(old.ExternallyInitialized()) + // Immutable (constant or global). + global.Immutable = irImmutable(old.Immutable()) + // Content type already stored during index. + // TODO: handle Init. + // TODO: handle GlobalAttrs. + // TODO: handle FuncAttrs. return global, nil } diff --git a/asm/helper.go b/asm/helper.go index 0c351342..cff59584 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -107,10 +107,35 @@ func irDLLStorageClass(n *ast.DLLStorageClass) ll.DLLStorageClass { } } +// irExternallyInitialized returns the externally initialized boolean +// corresponding to the given optional AST externally initialized. +func irExternallyInitialized(n *ast.ExternallyInitialized) bool { + // TODO: check why ExternallyInitialized is non-nil, when reduced as \empty. + return n.Text() == "externally_initialized" +} + +// irImmutable returns the immutable (constant or global) boolean corresponding +// to the given optional AST immutable. +func irImmutable(n ast.Immutable) bool { + // TODO: check why Immutable is non-nil, when reduced as \empty. + text := n.Text() + switch text { + case "constant": + return true + case "global": + return false + default: + panic(fmt.Errorf("support for immutable %q not yet implemented", text)) + } +} + // irLinkage returns the IR linkage corresponding to the given optional AST // linkage. -func irLinkage(n *ast.Linkage) ll.Linkage { - text := n.Text() +func irLinkage(text string) ll.Linkage { + // TODO: when ExternLinkage and Linkage are merged in grammar, update + // irLinkage to take `n *ast.Linkage` instead of `text string`. + + //text := n.Text() switch text { case "": // \empty is used when linkage not present. @@ -159,6 +184,78 @@ func irPreemption(n *ast.Preemption) ll.Preemption { } } +// irSelectionKind returns the IR Comdat selection kind corresponding to the +// given optional AST Comdat selection kind. +func irSelectionKind(n *ast.SelectionKind) ll.SelectionKind { + text := n.Text() + switch text { + case "any": + return ll.SelectionKindAny + case "exactmatch": + return ll.SelectionKindExactMatch + case "largest": + return ll.SelectionKindLargest + case "noduplicates": + return ll.SelectionKindNoDuplicates + case "samesize": + return ll.SelectionKindSameSize + default: + panic(fmt.Errorf("support for Comdat selection kind %q not yet implemented", text)) + } +} + +// irTLSModelFromThreadLocal returns the IR TLS model corresponding to the given +// optional AST thread local storage. +func irTLSModelFromThreadLocal(n *ast.ThreadLocal) ll.TLSModel { + if n.Text() != "" { + model := irTLSModel(n.Model()) + if model == ll.TLSModelNone { + // If no explicit model is given, the "general dynamic" model is used. + // thread_local + return ll.TLSModelGeneric + } + // e.g. thread_local(initialexec) + return model + } + return ll.TLSModelNone +} + +// irTLSModel returns the IR TLS model corresponding to the given optional AST +// TLS model. +func irTLSModel(n *ast.TLSModel) ll.TLSModel { + text := n.Text() + switch text { + case "": + // \empty is used when TLS model not present. + return ll.TLSModelNone + case "initialexec": + return ll.TLSModelInitialExec + case "localdynamic": + return ll.TLSModelLocalDynamic + case "localexec": + return ll.TLSModelLocalExec + default: + panic(fmt.Errorf("support for TLS model %q not yet implemented", text)) + } +} + +// irUnnamedAddr returns the IR unnamed address corresponding to the given +// optional AST unnamed address. +func irUnnamedAddr(n *ast.UnnamedAddr) ll.UnnamedAddr { + text := n.Text() + switch text { + case "": + // \empty is used when unnamed address not present. + return ll.UnnamedAddrNone + case "local_unnamed_addr": + return ll.UnnamedAddrLocalUnnamedAddr + case "unnamed_addr": + return ll.UnnamedAddrUnnamedAddr + default: + panic(fmt.Errorf("support for unnamed address %q not yet implemented", text)) + } +} + // irVariadic returns the variadic boolean corresponding to the given optional // AST ellipsis. func irVariadic(n *ast.Ellipsis) bool { @@ -172,6 +269,25 @@ func irVariadic(n *ast.Ellipsis) bool { return n.Text() == "..." } +// irVisibility returns the IR visibility kind corresponding to the given +// optional AST visibility kind. +func irVisibility(n *ast.Visibility) ll.Visibility { + text := n.Text() + switch text { + case "": + // \empty is used when visibility kind not present. + return ll.VisibilityNone + case "default": + return ll.VisibilityDefault + case "hidden": + return ll.VisibilityHidden + case "protected": + return ll.VisibilityProtected + default: + panic(fmt.Errorf("support for visibility kind %q not yet implemented", text)) + } +} + // ### [ Helpers ] ############################################################# // unquote returns the unquoted version of s if quoted, and the original string From 139bb4a14d7b888c322ee519deb4045a115e2900 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Wed, 17 Oct 2018 03:19:46 +0200 Subject: [PATCH 16/70] asm: add preliminary support for translating constants --- asm/const.go | 186 ++++++++++++++++++++++++ asm/const_expr.go | 359 ++++++++++++++++++++++++++++++++++++++++++++++ asm/global.go | 23 +-- asm/helper.go | 30 ++++ asm/translate.go | 3 +- 5 files changed, 589 insertions(+), 12 deletions(-) create mode 100644 asm/const.go create mode 100644 asm/const_expr.go diff --git a/asm/const.go b/asm/const.go new file mode 100644 index 00000000..7cf30d90 --- /dev/null +++ b/asm/const.go @@ -0,0 +1,186 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/llir/l/ir/types" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" + "github.com/pkg/errors" +) + +// === [ Constants ] =========================================================== + +func (gen *generator) irConstant(t types.Type, old ast.Constant) (ir.Constant, error) { + switch old := old.(type) { + case *ast.BoolConst: + return gen.irBoolConst(t, old) + case *ast.IntConst: + return gen.irIntConst(t, old) + case *ast.FloatConst: + return gen.irFloatConst(t, old) + case *ast.NullConst: + return gen.irNullConst(t, old) + case *ast.NoneConst: + return gen.irNoneConst(t, old) + case *ast.StructConst: + return gen.irStructConst(t, old) + case *ast.ArrayConst: + return gen.irArrayConst(t, old) + case *ast.CharArrayConst: + return gen.irCharArrayConst(t, old) + case *ast.VectorConst: + return gen.irVectorConst(t, old) + case *ast.ZeroInitializerConst: + return gen.irZeroInitializerConst(t, old) + case *ast.UndefConst: + return gen.irUndefConst(t, old) + case *ast.BlockAddressConst: + return gen.irBlockAddressConst(t, old) + case *ast.GlobalIdent: + name := global(*old) + g, ok := gen.gs[name] + if !ok { + return nil, errors.Errorf("unable to locate global identifier %q", enc.Global(name)) + } + return g, nil + case ast.ConstantExpr: + return gen.irConstantExpr(t, old) + default: + panic(fmt.Errorf("support for AST constant %T not yet implemented", old)) + } +} + +func (gen *generator) irTypeConst(old ast.TypeConst) (ir.Constant, error) { + typ, err := gen.irType(old.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return gen.irConstant(typ, old.Val()) +} + +// --- [ Boolean Constants ] --------------------------------------------------- + +func (gen *generator) irBoolConst(t types.Type, old *ast.BoolConst) (*ir.ConstInt, error) { + typ, ok := t.(*types.IntType) + if !ok { + return nil, errors.Errorf("invalid type of boolean constant; expected *types.IntType, got %T", t) + } + if typ.BitSize != 1 { + return nil, errors.Errorf("invalid integer type bit size of boolean constant; expected 1, got %d", typ.BitSize) + } + v := boolLit(old.BoolLit()) + if v { + return ir.True, nil + } + return ir.False, nil +} + +// --- [ Integer Constants ] --------------------------------------------------- + +func (gen *generator) irIntConst(t types.Type, old *ast.IntConst) (*ir.ConstInt, error) { + typ, ok := t.(*types.IntType) + if !ok { + return nil, errors.Errorf("invalid type of integer constant; expected *types.IntType, got %T", t) + } + s := old.IntLit().Text() + return ir.NewIntFromString(typ, s) +} + +// --- [ Floating-point Constants ] -------------------------------------------- + +func (gen *generator) irFloatConst(t types.Type, old *ast.FloatConst) (*ir.ConstFloat, error) { + typ, ok := t.(*types.FloatType) + if !ok { + return nil, errors.Errorf("invalid type of floating-point constant; expected *types.FloatType, got %T", t) + } + s := old.FloatLit().Text() + return ir.NewFloatFromString(typ, s) +} + +// --- [ Null Pointer Constants ] ---------------------------------------------- + +func (gen *generator) irNullConst(t types.Type, old *ast.NullConst) (*ir.ConstNull, error) { + typ, ok := t.(*types.PointerType) + if !ok { + return nil, errors.Errorf("invalid type of null constant; expected *types.PointerType, got %T", t) + } + return ir.NewNull(typ), nil +} + +// --- [ Token Constants ] ----------------------------------------------------- + +func (gen *generator) irNoneConst(t types.Type, old *ast.NoneConst) (*ir.ConstNone, error) { + panic("not yet implemented") +} + +// --- [ Structure Constants ] ------------------------------------------------- + +func (gen *generator) irStructConst(t types.Type, old *ast.StructConst) (*ir.ConstStruct, error) { + typ, ok := t.(*types.StructType) + if !ok { + return nil, errors.Errorf("invalid type of struct constant; expected *types.StructType, got %T", t) + } + var fields []ir.Constant + for _, f := range old.Fields() { + field, err := gen.irTypeConst(f) + if err != nil { + return nil, errors.WithStack(err) + } + fields = append(fields, field) + } + return ir.NewStruct(typ, fields...), nil +} + +// --- [ Array Constants ] ----------------------------------------------------- + +func (gen *generator) irArrayConst(t types.Type, old *ast.ArrayConst) (*ir.ConstArray, error) { + typ, ok := t.(*types.ArrayType) + if !ok { + return nil, errors.Errorf("invalid type of array constant; expected *types.ArrayType, got %T", t) + } + var elems []ir.Constant + for _, e := range old.Elems() { + elem, err := gen.irTypeConst(e) + if err != nil { + return nil, errors.WithStack(err) + } + elems = append(elems, elem) + } + return ir.NewArray(typ, elems...), nil +} + +func (gen *generator) irCharArrayConst(t types.Type, old *ast.CharArrayConst) (*ir.ConstCharArray, error) { + data := stringLitBytes(old.Val()) + // TODO: validate that t and type of newly created character array constant + // match. + + // TODO: also decide whether to update ir.NewCharArray to include a type as + // its first parameter, thus making it consistent with ir.NewArray. + return ir.NewCharArray(data), nil +} + +// --- [ Vector Constants ] ---------------------------------------------------- + +func (gen *generator) irVectorConst(t types.Type, old *ast.VectorConst) (*ir.ConstVector, error) { + panic("not yet implemented") +} + +// --- [ Zero Initialization Constants ] --------------------------------------- + +func (gen *generator) irZeroInitializerConst(t types.Type, old *ast.ZeroInitializerConst) (*ir.ConstZeroInitializer, error) { + return ir.NewZeroInitializer(t), nil +} + +// --- [ Undefined Values ] ---------------------------------------------------- + +func (gen *generator) irUndefConst(t types.Type, old *ast.UndefConst) (*ir.ConstUndef, error) { + panic("not yet implemented") +} + +// --- [ Addresses of Basic Blocks ] ------------------------------------------- + +func (gen *generator) irBlockAddressConst(t types.Type, old *ast.BlockAddressConst) (*ir.ConstBlockAddress, error) { + panic("not yet implemented") +} diff --git a/asm/const_expr.go b/asm/const_expr.go new file mode 100644 index 00000000..118f5efe --- /dev/null +++ b/asm/const_expr.go @@ -0,0 +1,359 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/llir/l/ir/types" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// === [ Constant expressions ] ================================================ + +func (gen *generator) irConstantExpr(t types.Type, old ast.ConstantExpr) (ir.Expression, error) { + switch old := old.(type) { + // Binary expressions + case ast.AddExpr: + return gen.irAddExpr(t, old) + case ast.FAddExpr: + return gen.irFAddExpr(t, old) + case ast.SubExpr: + return gen.irSubExpr(t, old) + case ast.FSubExpr: + return gen.irFSubExpr(t, old) + case ast.MulExpr: + return gen.irMulExpr(t, old) + case ast.FMulExpr: + return gen.irFMulExpr(t, old) + case ast.UDivExpr: + return gen.irUDivExpr(t, old) + case ast.SDivExpr: + return gen.irSDivExpr(t, old) + case ast.FDivExpr: + return gen.irFDivExpr(t, old) + case ast.URemExpr: + return gen.irURemExpr(t, old) + case ast.SRemExpr: + return gen.irSRemExpr(t, old) + case ast.FRemExpr: + return gen.irFRemExpr(t, old) + // Bitwise expressions + case ast.ShlExpr: + return gen.irShlExpr(t, old) + case ast.LShrExpr: + return gen.irLShrExpr(t, old) + case ast.AShrExpr: + return gen.irAShrExpr(t, old) + case ast.AndExpr: + return gen.irAndExpr(t, old) + case ast.OrExpr: + return gen.irOrExpr(t, old) + case ast.XorExpr: + return gen.irXorExpr(t, old) + // Vector expressions + case ast.ExtractElementExpr: + return gen.irExtractElementExpr(t, old) + case ast.InsertElementExpr: + return gen.irInsertElementExpr(t, old) + case ast.ShuffleVectorExpr: + return gen.irShuffleVectorExpr(t, old) + // Aggregate expressions + case ast.ExtractValueExpr: + return gen.irExtractValueExpr(t, old) + case ast.InsertValueExpr: + return gen.irInsertValueExpr(t, old) + // Memory expressions + case ast.GetElementPtrExpr: + return gen.irGetElementPtrExpr(t, old) + // Conversion expressions + case ast.TruncExpr: + return gen.irTruncExpr(t, old) + case ast.ZExtExpr: + return gen.irZExtExpr(t, old) + case ast.SExtExpr: + return gen.irSExtExpr(t, old) + case ast.FPTruncExpr: + return gen.irFPTruncExpr(t, old) + case ast.FPExtExpr: + return gen.irFPExtExpr(t, old) + case ast.FPToUIExpr: + return gen.irFPToUIExpr(t, old) + case ast.FPToSIExpr: + return gen.irFPToSIExpr(t, old) + case ast.UIToFPExpr: + return gen.irUIToFPExpr(t, old) + case ast.SIToFPExpr: + return gen.irSIToFPExpr(t, old) + case ast.PtrToIntExpr: + return gen.irPtrToIntExpr(t, old) + case ast.IntToPtrExpr: + return gen.irIntToPtrExpr(t, old) + case ast.BitCastExpr: + return gen.irBitCastExpr(t, old) + case ast.AddrSpaceCastExpr: + return gen.irAddrSpaceCastExpr(t, old) + // Other expressions + case ast.ICmpExpr: + return gen.irICmpExpr(t, old) + case ast.FCmpExpr: + return gen.irFCmpExpr(t, old) + case ast.SelectExpr: + return gen.irSelectExpr(t, old) + default: + panic(fmt.Errorf("support for AST constant expression %T not yet implemented", old)) + } +} + +// --- [ Binary expressions ] ------------------------------------------------- + +// ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irAddExpr(t types.Type, old ast.AddExpr) (*ir.ExprAdd, error) { + panic("not yet implemented") +} + +// ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFAddExpr(t types.Type, old ast.FAddExpr) (*ir.ExprFAdd, error) { + panic("not yet implemented") +} + +// ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irSubExpr(t types.Type, old ast.SubExpr) (*ir.ExprSub, error) { + panic("not yet implemented") +} + +// ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFSubExpr(t types.Type, old ast.FSubExpr) (*ir.ExprFSub, error) { + panic("not yet implemented") +} + +// ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irMulExpr(t types.Type, old ast.MulExpr) (*ir.ExprMul, error) { + panic("not yet implemented") +} + +// ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFMulExpr(t types.Type, old ast.FMulExpr) (*ir.ExprFMul, error) { + panic("not yet implemented") +} + +// ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irUDivExpr(t types.Type, old ast.UDivExpr) (*ir.ExprUDiv, error) { + panic("not yet implemented") +} + +// ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irSDivExpr(t types.Type, old ast.SDivExpr) (*ir.ExprSDiv, error) { + panic("not yet implemented") +} + +// ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFDivExpr(t types.Type, old ast.FDivExpr) (*ir.ExprFDiv, error) { + panic("not yet implemented") +} + +// ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irURemExpr(t types.Type, old ast.URemExpr) (*ir.ExprURem, error) { + panic("not yet implemented") +} + +// ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irSRemExpr(t types.Type, old ast.SRemExpr) (*ir.ExprSRem, error) { + panic("not yet implemented") +} + +// ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFRemExpr(t types.Type, old ast.FRemExpr) (*ir.ExprFRem, error) { + panic("not yet implemented") +} + +// --- [ Bitwise expressions ] ------------------------------------------------- + +// ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irShlExpr(t types.Type, old ast.ShlExpr) (*ir.ExprShl, error) { + panic("not yet implemented") +} + +// ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irLShrExpr(t types.Type, old ast.LShrExpr) (*ir.ExprLShr, error) { + panic("not yet implemented") +} + +// ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irAShrExpr(t types.Type, old ast.AShrExpr) (*ir.ExprAShr, error) { + panic("not yet implemented") +} + +// ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irAndExpr(t types.Type, old ast.AndExpr) (*ir.ExprAnd, error) { + panic("not yet implemented") +} + +// ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irOrExpr(t types.Type, old ast.OrExpr) (*ir.ExprOr, error) { + panic("not yet implemented") +} + +// ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irXorExpr(t types.Type, old ast.XorExpr) (*ir.ExprXor, error) { + panic("not yet implemented") +} + +// --- [ Vector expressions ] -------------------------------------------------- + +// ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irExtractElementExpr(t types.Type, old ast.ExtractElementExpr) (*ir.ExprExtractElement, error) { + panic("not yet implemented") +} + +// ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irInsertElementExpr(t types.Type, old ast.InsertElementExpr) (*ir.ExprInsertElement, error) { + panic("not yet implemented") +} + +// ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irShuffleVectorExpr(t types.Type, old ast.ShuffleVectorExpr) (*ir.ExprShuffleVector, error) { + panic("not yet implemented") +} + +// --- [ Aggregate expressions ] ----------------------------------------------- + +// ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irExtractValueExpr(t types.Type, old ast.ExtractValueExpr) (*ir.ExprExtractValue, error) { + panic("not yet implemented") +} + +// ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irInsertValueExpr(t types.Type, old ast.InsertValueExpr) (*ir.ExprInsertValue, error) { + panic("not yet implemented") +} + +// --- [ Memory expressions ] -------------------------------------------------- + +// ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irGetElementPtrExpr(t types.Type, old ast.GetElementPtrExpr) (*ir.ExprGetElementPtr, error) { + panic("not yet implemented") +} + +// --- [ Conversion expressions ] ---------------------------------------------- + +// ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irTruncExpr(t types.Type, old ast.TruncExpr) (*ir.ExprTrunc, error) { + panic("not yet implemented") +} + +// ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irZExtExpr(t types.Type, old ast.ZExtExpr) (*ir.ExprZExt, error) { + panic("not yet implemented") +} + +// ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irSExtExpr(t types.Type, old ast.SExtExpr) (*ir.ExprSExt, error) { + panic("not yet implemented") +} + +// ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFPTruncExpr(t types.Type, old ast.FPTruncExpr) (*ir.ExprFPTrunc, error) { + panic("not yet implemented") +} + +// ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFPExtExpr(t types.Type, old ast.FPExtExpr) (*ir.ExprFPExt, error) { + panic("not yet implemented") +} + +// ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFPToUIExpr(t types.Type, old ast.FPToUIExpr) (*ir.ExprFPToUI, error) { + panic("not yet implemented") +} + +// ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFPToSIExpr(t types.Type, old ast.FPToSIExpr) (*ir.ExprFPToSI, error) { + panic("not yet implemented") +} + +// ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irUIToFPExpr(t types.Type, old ast.UIToFPExpr) (*ir.ExprUIToFP, error) { + panic("not yet implemented") +} + +// ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irSIToFPExpr(t types.Type, old ast.SIToFPExpr) (*ir.ExprSIToFP, error) { + panic("not yet implemented") +} + +// ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irPtrToIntExpr(t types.Type, old ast.PtrToIntExpr) (*ir.ExprPtrToInt, error) { + panic("not yet implemented") +} + +// ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irIntToPtrExpr(t types.Type, old ast.IntToPtrExpr) (*ir.ExprIntToPtr, error) { + panic("not yet implemented") +} + +// ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irBitCastExpr(t types.Type, old ast.BitCastExpr) (*ir.ExprBitCast, error) { + panic("not yet implemented") +} + +// ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irAddrSpaceCastExpr(t types.Type, old ast.AddrSpaceCastExpr) (*ir.ExprAddrSpaceCast, error) { + panic("not yet implemented") +} + +// --- [ Other expressions ] --------------------------------------------------- + +// ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irICmpExpr(t types.Type, old ast.ICmpExpr) (*ir.ExprICmp, error) { + panic("not yet implemented") +} + +// ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irFCmpExpr(t types.Type, old ast.FCmpExpr) (*ir.ExprFCmp, error) { + panic("not yet implemented") +} + +// ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (gen *generator) irSelectExpr(t types.Type, old ast.SelectExpr) (*ir.ExprSelect, error) { + panic("not yet implemented") +} diff --git a/asm/global.go b/asm/global.go index d20ed8af..d5b8f676 100644 --- a/asm/global.go +++ b/asm/global.go @@ -5,7 +5,6 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" - "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" @@ -14,7 +13,7 @@ import ( // resolveGlobals resolves the global variable and function declarations and // defintions of the given module. The returned value maps from global // identifier (without '@' prefix) to the corresponding IR value. -func (gen *generator) resolveGlobals(module *ast.Module) (map[string]value.Value, error) { +func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant, error) { // index maps from global identifier to underlying AST value. index := make(map[string]ast.LlvmNode) // Record order of global variable and function declarations and definitions. @@ -61,7 +60,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]value.Value } // Create corresponding IR global variables and functions (without bodies). - gen.gs = make(map[string]value.Value) + gen.gs = make(map[string]ir.Constant) for name, old := range index { g, err := gen.newGlobal(name, old) if err != nil { @@ -108,7 +107,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]value.Value // newGlobal returns a new IR value (without body but with a type) based on the // given AST global variable or function. -func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, error) { +func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, error) { switch old := old.(type) { case *ast.GlobalDecl: g := &ir.Global{GlobalName: name} @@ -187,7 +186,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (value.Value, err // translateGlobal translates the AST global variable or function into an // equivalent IR value. -func (gen *generator) translateGlobal(g value.Value, old ast.LlvmNode) (value.Value, error) { +func (gen *generator) translateGlobal(g ir.Constant, old ast.LlvmNode) (ir.Constant, error) { switch old := old.(type) { case *ast.GlobalDecl: return gen.translateGlobalDecl(g, old) @@ -204,7 +203,7 @@ func (gen *generator) translateGlobal(g value.Value, old ast.LlvmNode) (value.Va // ~~~ [ Global Variable Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateGlobalDecl(g value.Value, old *ast.GlobalDecl) (value.Value, error) { +func (gen *generator) translateGlobalDecl(g ir.Constant, old *ast.GlobalDecl) (ir.Constant, error) { global, ok := g.(*ir.Global) if !ok { panic(fmt.Errorf("invalid IR type for AST global declaration; expected *ir.Global, got %T", g)) @@ -235,7 +234,7 @@ func (gen *generator) translateGlobalDecl(g value.Value, old *ast.GlobalDecl) (v // ~~~ [ Global Variable Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateGlobalDef(g value.Value, old *ast.GlobalDef) (value.Value, error) { +func (gen *generator) translateGlobalDef(g ir.Constant, old *ast.GlobalDef) (ir.Constant, error) { global, ok := g.(*ir.Global) if !ok { panic(fmt.Errorf("invalid IR type for AST global definition; expected *ir.Global, got %T", g)) @@ -259,7 +258,11 @@ func (gen *generator) translateGlobalDef(g value.Value, old *ast.GlobalDef) (val // Immutable (constant or global). global.Immutable = irImmutable(old.Immutable()) // Content type already stored during index. - // TODO: handle Init. + init, err := gen.irConstant(global.ContentType, old.Init()) + if err != nil { + return nil, errors.WithStack(err) + } + global.Init = init // TODO: handle GlobalAttrs. // TODO: handle FuncAttrs. return global, nil @@ -271,7 +274,7 @@ func (gen *generator) translateGlobalDef(g value.Value, old *ast.GlobalDef) (val // ~~~ [ Function Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateFuncDecl(g value.Value, old *ast.FuncDecl) (value.Value, error) { +func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Constant, error) { f, ok := g.(*ir.Function) if !ok { panic(fmt.Errorf("invalid IR type for AST function declaration; expected *ir.Function, got %T", g)) @@ -282,7 +285,7 @@ func (gen *generator) translateFuncDecl(g value.Value, old *ast.FuncDecl) (value // ~~~ [ Function Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateFuncDef(g value.Value, old *ast.FuncDef) (value.Value, error) { +func (gen *generator) translateFuncDef(g ir.Constant, old *ast.FuncDef) (ir.Constant, error) { f, ok := g.(*ir.Function) if !ok { panic(fmt.Errorf("invalid IR type for AST function definition; expected *ir.Function, got %T", g)) diff --git a/asm/helper.go b/asm/helper.go index cff59584..9b8f5f1d 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -55,6 +55,21 @@ func local(n ast.LocalIdent) string { // --- [ Integer literals ] ---------------------------------------------------- +// boolLit returns the boolean value corresponding to the given boolean literal. +func boolLit(n ast.BoolLit) bool { + text := n.Text() + switch text { + case "true": + return true + case "false": + return false + default: + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid boolean literal; expected `true` or `false`, got `%v`", text)) + } +} + // uintLit returns the unsigned integer value corresponding to the given // unsigned integer literal. func uintLit(n ast.UintLit) uint64 { @@ -75,6 +90,21 @@ func uintLit(n ast.UintLit) uint64 { // --- [ String literals ] ----------------------------------------------------- +// stringLit returns the string corresponding to the given string literal. +func stringLit(n ast.StringLit) string { + text := n.Text() + s := enc.Unquote(text) + return string(s) +} + +// TODO: remove stringLitBytes if not used. + +// stringLitBytes returns the byte slice corresponding to the given string literal. +func stringLitBytes(n ast.StringLit) []byte { + text := n.Text() + return enc.Unquote(text) +} + // --- [ Null literals ] ------------------------------------------------------- // ___ [ Helpers ] _____________________________________________________________ diff --git a/asm/translate.go b/asm/translate.go index 50f1533e..f9bd6d06 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -6,7 +6,6 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" - "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/pkg/errors" ) @@ -56,7 +55,7 @@ type generator struct { // gs maps from global identifier (without '@' prefix) to corresponding // IR value. - gs map[string]value.Value + gs map[string]ir.Constant } // newGenerator returns a new generator for translating an LLVM IR module from From 509dc507b1c338b4c8c474e2ee2e367feb1e67c4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 00:28:53 +0200 Subject: [PATCH 17/70] grammar: rename Inrange to InRange to match IR package --- asm/ll/ll.tm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 6787c5ac..4ac5eef8 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1643,10 +1643,10 @@ GetElementPtrExpr -> GetElementPtrExpr # ::= [inrange] TypeAndValue (',' [inrange] TypeAndValue)* GEPIndex -> GEPIndex - : Inrangeopt Index=TypeConst + : InRangeopt Index=TypeConst ; -Inrange -> Inrange +InRange -> InRange : 'inrange' ; From afcef08585d706ae802e7d7d244e152a3d3a12fe Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 00:33:49 +0200 Subject: [PATCH 18/70] asm: translate getelementptr expressions --- asm/const_expr.go | 197 +++++++++++++++++++++++++++------------------- asm/helper.go | 15 +++- 2 files changed, 130 insertions(+), 82 deletions(-) diff --git a/asm/const_expr.go b/asm/const_expr.go index 118f5efe..a79234fd 100644 --- a/asm/const_expr.go +++ b/asm/const_expr.go @@ -6,6 +6,7 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" ) // === [ Constant expressions ] ================================================ @@ -13,91 +14,91 @@ import ( func (gen *generator) irConstantExpr(t types.Type, old ast.ConstantExpr) (ir.Expression, error) { switch old := old.(type) { // Binary expressions - case ast.AddExpr: + case *ast.AddExpr: return gen.irAddExpr(t, old) - case ast.FAddExpr: + case *ast.FAddExpr: return gen.irFAddExpr(t, old) - case ast.SubExpr: + case *ast.SubExpr: return gen.irSubExpr(t, old) - case ast.FSubExpr: + case *ast.FSubExpr: return gen.irFSubExpr(t, old) - case ast.MulExpr: + case *ast.MulExpr: return gen.irMulExpr(t, old) - case ast.FMulExpr: + case *ast.FMulExpr: return gen.irFMulExpr(t, old) - case ast.UDivExpr: + case *ast.UDivExpr: return gen.irUDivExpr(t, old) - case ast.SDivExpr: + case *ast.SDivExpr: return gen.irSDivExpr(t, old) - case ast.FDivExpr: + case *ast.FDivExpr: return gen.irFDivExpr(t, old) - case ast.URemExpr: + case *ast.URemExpr: return gen.irURemExpr(t, old) - case ast.SRemExpr: + case *ast.SRemExpr: return gen.irSRemExpr(t, old) - case ast.FRemExpr: + case *ast.FRemExpr: return gen.irFRemExpr(t, old) // Bitwise expressions - case ast.ShlExpr: + case *ast.ShlExpr: return gen.irShlExpr(t, old) - case ast.LShrExpr: + case *ast.LShrExpr: return gen.irLShrExpr(t, old) - case ast.AShrExpr: + case *ast.AShrExpr: return gen.irAShrExpr(t, old) - case ast.AndExpr: + case *ast.AndExpr: return gen.irAndExpr(t, old) - case ast.OrExpr: + case *ast.OrExpr: return gen.irOrExpr(t, old) - case ast.XorExpr: + case *ast.XorExpr: return gen.irXorExpr(t, old) // Vector expressions - case ast.ExtractElementExpr: + case *ast.ExtractElementExpr: return gen.irExtractElementExpr(t, old) - case ast.InsertElementExpr: + case *ast.InsertElementExpr: return gen.irInsertElementExpr(t, old) - case ast.ShuffleVectorExpr: + case *ast.ShuffleVectorExpr: return gen.irShuffleVectorExpr(t, old) // Aggregate expressions - case ast.ExtractValueExpr: + case *ast.ExtractValueExpr: return gen.irExtractValueExpr(t, old) - case ast.InsertValueExpr: + case *ast.InsertValueExpr: return gen.irInsertValueExpr(t, old) // Memory expressions - case ast.GetElementPtrExpr: + case *ast.GetElementPtrExpr: return gen.irGetElementPtrExpr(t, old) // Conversion expressions - case ast.TruncExpr: + case *ast.TruncExpr: return gen.irTruncExpr(t, old) - case ast.ZExtExpr: + case *ast.ZExtExpr: return gen.irZExtExpr(t, old) - case ast.SExtExpr: + case *ast.SExtExpr: return gen.irSExtExpr(t, old) - case ast.FPTruncExpr: + case *ast.FPTruncExpr: return gen.irFPTruncExpr(t, old) - case ast.FPExtExpr: + case *ast.FPExtExpr: return gen.irFPExtExpr(t, old) - case ast.FPToUIExpr: + case *ast.FPToUIExpr: return gen.irFPToUIExpr(t, old) - case ast.FPToSIExpr: + case *ast.FPToSIExpr: return gen.irFPToSIExpr(t, old) - case ast.UIToFPExpr: + case *ast.UIToFPExpr: return gen.irUIToFPExpr(t, old) - case ast.SIToFPExpr: + case *ast.SIToFPExpr: return gen.irSIToFPExpr(t, old) - case ast.PtrToIntExpr: + case *ast.PtrToIntExpr: return gen.irPtrToIntExpr(t, old) - case ast.IntToPtrExpr: + case *ast.IntToPtrExpr: return gen.irIntToPtrExpr(t, old) - case ast.BitCastExpr: + case *ast.BitCastExpr: return gen.irBitCastExpr(t, old) - case ast.AddrSpaceCastExpr: + case *ast.AddrSpaceCastExpr: return gen.irAddrSpaceCastExpr(t, old) // Other expressions - case ast.ICmpExpr: + case *ast.ICmpExpr: return gen.irICmpExpr(t, old) - case ast.FCmpExpr: + case *ast.FCmpExpr: return gen.irFCmpExpr(t, old) - case ast.SelectExpr: + case *ast.SelectExpr: return gen.irSelectExpr(t, old) default: panic(fmt.Errorf("support for AST constant expression %T not yet implemented", old)) @@ -108,73 +109,73 @@ func (gen *generator) irConstantExpr(t types.Type, old ast.ConstantExpr) (ir.Exp // ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irAddExpr(t types.Type, old ast.AddExpr) (*ir.ExprAdd, error) { +func (gen *generator) irAddExpr(t types.Type, old *ast.AddExpr) (*ir.ExprAdd, error) { panic("not yet implemented") } // ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFAddExpr(t types.Type, old ast.FAddExpr) (*ir.ExprFAdd, error) { +func (gen *generator) irFAddExpr(t types.Type, old *ast.FAddExpr) (*ir.ExprFAdd, error) { panic("not yet implemented") } // ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irSubExpr(t types.Type, old ast.SubExpr) (*ir.ExprSub, error) { +func (gen *generator) irSubExpr(t types.Type, old *ast.SubExpr) (*ir.ExprSub, error) { panic("not yet implemented") } // ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFSubExpr(t types.Type, old ast.FSubExpr) (*ir.ExprFSub, error) { +func (gen *generator) irFSubExpr(t types.Type, old *ast.FSubExpr) (*ir.ExprFSub, error) { panic("not yet implemented") } // ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irMulExpr(t types.Type, old ast.MulExpr) (*ir.ExprMul, error) { +func (gen *generator) irMulExpr(t types.Type, old *ast.MulExpr) (*ir.ExprMul, error) { panic("not yet implemented") } // ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFMulExpr(t types.Type, old ast.FMulExpr) (*ir.ExprFMul, error) { +func (gen *generator) irFMulExpr(t types.Type, old *ast.FMulExpr) (*ir.ExprFMul, error) { panic("not yet implemented") } // ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irUDivExpr(t types.Type, old ast.UDivExpr) (*ir.ExprUDiv, error) { +func (gen *generator) irUDivExpr(t types.Type, old *ast.UDivExpr) (*ir.ExprUDiv, error) { panic("not yet implemented") } // ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irSDivExpr(t types.Type, old ast.SDivExpr) (*ir.ExprSDiv, error) { +func (gen *generator) irSDivExpr(t types.Type, old *ast.SDivExpr) (*ir.ExprSDiv, error) { panic("not yet implemented") } // ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFDivExpr(t types.Type, old ast.FDivExpr) (*ir.ExprFDiv, error) { +func (gen *generator) irFDivExpr(t types.Type, old *ast.FDivExpr) (*ir.ExprFDiv, error) { panic("not yet implemented") } // ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irURemExpr(t types.Type, old ast.URemExpr) (*ir.ExprURem, error) { +func (gen *generator) irURemExpr(t types.Type, old *ast.URemExpr) (*ir.ExprURem, error) { panic("not yet implemented") } // ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irSRemExpr(t types.Type, old ast.SRemExpr) (*ir.ExprSRem, error) { +func (gen *generator) irSRemExpr(t types.Type, old *ast.SRemExpr) (*ir.ExprSRem, error) { panic("not yet implemented") } // ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFRemExpr(t types.Type, old ast.FRemExpr) (*ir.ExprFRem, error) { +func (gen *generator) irFRemExpr(t types.Type, old *ast.FRemExpr) (*ir.ExprFRem, error) { panic("not yet implemented") } @@ -182,37 +183,37 @@ func (gen *generator) irFRemExpr(t types.Type, old ast.FRemExpr) (*ir.ExprFRem, // ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irShlExpr(t types.Type, old ast.ShlExpr) (*ir.ExprShl, error) { +func (gen *generator) irShlExpr(t types.Type, old *ast.ShlExpr) (*ir.ExprShl, error) { panic("not yet implemented") } // ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irLShrExpr(t types.Type, old ast.LShrExpr) (*ir.ExprLShr, error) { +func (gen *generator) irLShrExpr(t types.Type, old *ast.LShrExpr) (*ir.ExprLShr, error) { panic("not yet implemented") } // ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irAShrExpr(t types.Type, old ast.AShrExpr) (*ir.ExprAShr, error) { +func (gen *generator) irAShrExpr(t types.Type, old *ast.AShrExpr) (*ir.ExprAShr, error) { panic("not yet implemented") } // ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irAndExpr(t types.Type, old ast.AndExpr) (*ir.ExprAnd, error) { +func (gen *generator) irAndExpr(t types.Type, old *ast.AndExpr) (*ir.ExprAnd, error) { panic("not yet implemented") } // ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irOrExpr(t types.Type, old ast.OrExpr) (*ir.ExprOr, error) { +func (gen *generator) irOrExpr(t types.Type, old *ast.OrExpr) (*ir.ExprOr, error) { panic("not yet implemented") } // ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irXorExpr(t types.Type, old ast.XorExpr) (*ir.ExprXor, error) { +func (gen *generator) irXorExpr(t types.Type, old *ast.XorExpr) (*ir.ExprXor, error) { panic("not yet implemented") } @@ -220,19 +221,19 @@ func (gen *generator) irXorExpr(t types.Type, old ast.XorExpr) (*ir.ExprXor, err // ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irExtractElementExpr(t types.Type, old ast.ExtractElementExpr) (*ir.ExprExtractElement, error) { +func (gen *generator) irExtractElementExpr(t types.Type, old *ast.ExtractElementExpr) (*ir.ExprExtractElement, error) { panic("not yet implemented") } // ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irInsertElementExpr(t types.Type, old ast.InsertElementExpr) (*ir.ExprInsertElement, error) { +func (gen *generator) irInsertElementExpr(t types.Type, old *ast.InsertElementExpr) (*ir.ExprInsertElement, error) { panic("not yet implemented") } // ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irShuffleVectorExpr(t types.Type, old ast.ShuffleVectorExpr) (*ir.ExprShuffleVector, error) { +func (gen *generator) irShuffleVectorExpr(t types.Type, old *ast.ShuffleVectorExpr) (*ir.ExprShuffleVector, error) { panic("not yet implemented") } @@ -240,13 +241,13 @@ func (gen *generator) irShuffleVectorExpr(t types.Type, old ast.ShuffleVectorExp // ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irExtractValueExpr(t types.Type, old ast.ExtractValueExpr) (*ir.ExprExtractValue, error) { +func (gen *generator) irExtractValueExpr(t types.Type, old *ast.ExtractValueExpr) (*ir.ExprExtractValue, error) { panic("not yet implemented") } // ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irInsertValueExpr(t types.Type, old ast.InsertValueExpr) (*ir.ExprInsertValue, error) { +func (gen *generator) irInsertValueExpr(t types.Type, old *ast.InsertValueExpr) (*ir.ExprInsertValue, error) { panic("not yet implemented") } @@ -254,87 +255,121 @@ func (gen *generator) irInsertValueExpr(t types.Type, old ast.InsertValueExpr) ( // ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irGetElementPtrExpr(t types.Type, old ast.GetElementPtrExpr) (*ir.ExprGetElementPtr, error) { - panic("not yet implemented") +func (gen *generator) irGetElementPtrExpr(t types.Type, old *ast.GetElementPtrExpr) (*ir.ExprGetElementPtr, error) { + // Element type. + elemType, err := gen.irType(old.ElemType()) + if err != nil { + return nil, errors.WithStack(err) + } + // Source. + src, err := gen.irTypeConst(old.Src()) + if err != nil { + return nil, errors.WithStack(err) + } + // Indices. + var indices []*ir.Index + for _, idx := range old.Indices() { + index, err := gen.irGEPIndex(idx) + if err != nil { + return nil, errors.WithStack(err) + } + indices = append(indices, index) + } + expr := ir.NewGetElementPtrExpr(elemType, src, indices...) + // TODO: validate type t against expr.Typ. + // In-bounds. + expr.InBounds = irInBounds(old.InBounds()) + return expr, nil +} + +func (gen *generator) irGEPIndex(old ast.GEPIndex) (*ir.Index, error) { + // Index. + idx, err := gen.irTypeConst(old.Index()) + if err != nil { + return nil, errors.WithStack(err) + } + index := ir.NewIndex(idx) + index.InRange = irInRange(old.InRange()) + return index, nil } // --- [ Conversion expressions ] ---------------------------------------------- // ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irTruncExpr(t types.Type, old ast.TruncExpr) (*ir.ExprTrunc, error) { +func (gen *generator) irTruncExpr(t types.Type, old *ast.TruncExpr) (*ir.ExprTrunc, error) { panic("not yet implemented") } // ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irZExtExpr(t types.Type, old ast.ZExtExpr) (*ir.ExprZExt, error) { +func (gen *generator) irZExtExpr(t types.Type, old *ast.ZExtExpr) (*ir.ExprZExt, error) { panic("not yet implemented") } // ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irSExtExpr(t types.Type, old ast.SExtExpr) (*ir.ExprSExt, error) { +func (gen *generator) irSExtExpr(t types.Type, old *ast.SExtExpr) (*ir.ExprSExt, error) { panic("not yet implemented") } // ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFPTruncExpr(t types.Type, old ast.FPTruncExpr) (*ir.ExprFPTrunc, error) { +func (gen *generator) irFPTruncExpr(t types.Type, old *ast.FPTruncExpr) (*ir.ExprFPTrunc, error) { panic("not yet implemented") } // ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFPExtExpr(t types.Type, old ast.FPExtExpr) (*ir.ExprFPExt, error) { +func (gen *generator) irFPExtExpr(t types.Type, old *ast.FPExtExpr) (*ir.ExprFPExt, error) { panic("not yet implemented") } // ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFPToUIExpr(t types.Type, old ast.FPToUIExpr) (*ir.ExprFPToUI, error) { +func (gen *generator) irFPToUIExpr(t types.Type, old *ast.FPToUIExpr) (*ir.ExprFPToUI, error) { panic("not yet implemented") } // ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFPToSIExpr(t types.Type, old ast.FPToSIExpr) (*ir.ExprFPToSI, error) { +func (gen *generator) irFPToSIExpr(t types.Type, old *ast.FPToSIExpr) (*ir.ExprFPToSI, error) { panic("not yet implemented") } // ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irUIToFPExpr(t types.Type, old ast.UIToFPExpr) (*ir.ExprUIToFP, error) { +func (gen *generator) irUIToFPExpr(t types.Type, old *ast.UIToFPExpr) (*ir.ExprUIToFP, error) { panic("not yet implemented") } // ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irSIToFPExpr(t types.Type, old ast.SIToFPExpr) (*ir.ExprSIToFP, error) { +func (gen *generator) irSIToFPExpr(t types.Type, old *ast.SIToFPExpr) (*ir.ExprSIToFP, error) { panic("not yet implemented") } // ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irPtrToIntExpr(t types.Type, old ast.PtrToIntExpr) (*ir.ExprPtrToInt, error) { +func (gen *generator) irPtrToIntExpr(t types.Type, old *ast.PtrToIntExpr) (*ir.ExprPtrToInt, error) { panic("not yet implemented") } // ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irIntToPtrExpr(t types.Type, old ast.IntToPtrExpr) (*ir.ExprIntToPtr, error) { +func (gen *generator) irIntToPtrExpr(t types.Type, old *ast.IntToPtrExpr) (*ir.ExprIntToPtr, error) { panic("not yet implemented") } // ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irBitCastExpr(t types.Type, old ast.BitCastExpr) (*ir.ExprBitCast, error) { +func (gen *generator) irBitCastExpr(t types.Type, old *ast.BitCastExpr) (*ir.ExprBitCast, error) { panic("not yet implemented") } // ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irAddrSpaceCastExpr(t types.Type, old ast.AddrSpaceCastExpr) (*ir.ExprAddrSpaceCast, error) { +func (gen *generator) irAddrSpaceCastExpr(t types.Type, old *ast.AddrSpaceCastExpr) (*ir.ExprAddrSpaceCast, error) { panic("not yet implemented") } @@ -342,18 +377,18 @@ func (gen *generator) irAddrSpaceCastExpr(t types.Type, old ast.AddrSpaceCastExp // ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irICmpExpr(t types.Type, old ast.ICmpExpr) (*ir.ExprICmp, error) { +func (gen *generator) irICmpExpr(t types.Type, old *ast.ICmpExpr) (*ir.ExprICmp, error) { panic("not yet implemented") } // ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irFCmpExpr(t types.Type, old ast.FCmpExpr) (*ir.ExprFCmp, error) { +func (gen *generator) irFCmpExpr(t types.Type, old *ast.FCmpExpr) (*ir.ExprFCmp, error) { panic("not yet implemented") } // ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) irSelectExpr(t types.Type, old ast.SelectExpr) (*ir.ExprSelect, error) { +func (gen *generator) irSelectExpr(t types.Type, old *ast.SelectExpr) (*ir.ExprSelect, error) { panic("not yet implemented") } diff --git a/asm/helper.go b/asm/helper.go index 9b8f5f1d..531afc84 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -147,7 +147,6 @@ func irExternallyInitialized(n *ast.ExternallyInitialized) bool { // irImmutable returns the immutable (constant or global) boolean corresponding // to the given optional AST immutable. func irImmutable(n ast.Immutable) bool { - // TODO: check why Immutable is non-nil, when reduced as \empty. text := n.Text() switch text { case "constant": @@ -159,6 +158,13 @@ func irImmutable(n ast.Immutable) bool { } } +// irInBounds returns the in-bounds boolean corresponding to the given optional +// AST in-bounds. +func irInBounds(n *ast.InBounds) bool { + // TODO: check why InBounds is non-nil, when reduced as \empty. + return n.Text() == "inbounds" +} + // irLinkage returns the IR linkage corresponding to the given optional AST // linkage. func irLinkage(text string) ll.Linkage { @@ -214,6 +220,13 @@ func irPreemption(n *ast.Preemption) ll.Preemption { } } +// irInRange returns the in-range boolean corresponding to the given optional +// AST in-range. +func irInRange(n *ast.InRange) bool { + // TODO: check why InRange is non-nil, when reduced as \empty. + return n.Text() == "inrange" +} + // irSelectionKind returns the IR Comdat selection kind corresponding to the // given optional AST Comdat selection kind. func irSelectionKind(n *ast.SelectionKind) ll.SelectionKind { From 7ed134243d814a5028c0c5d1479a66f819b9c5ae Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 00:42:39 +0200 Subject: [PATCH 19/70] asm: translate constant conversion expressions --- asm/const_expr.go | 182 ++++++++++++++++++++++++++++++++++++++++++---- cmd/l-tm/main.go | 3 +- 2 files changed, 170 insertions(+), 15 deletions(-) diff --git a/asm/const_expr.go b/asm/const_expr.go index a79234fd..e54db33d 100644 --- a/asm/const_expr.go +++ b/asm/const_expr.go @@ -298,79 +298,235 @@ func (gen *generator) irGEPIndex(old ast.GEPIndex) (*ir.Index, error) { // ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irTruncExpr(t types.Type, old *ast.TruncExpr) (*ir.ExprTrunc, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewTruncExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irZExtExpr(t types.Type, old *ast.ZExtExpr) (*ir.ExprZExt, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewZExtExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irSExtExpr(t types.Type, old *ast.SExtExpr) (*ir.ExprSExt, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewSExtExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irFPTruncExpr(t types.Type, old *ast.FPTruncExpr) (*ir.ExprFPTrunc, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewFPTruncExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irFPExtExpr(t types.Type, old *ast.FPExtExpr) (*ir.ExprFPExt, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewFPExtExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irFPToUIExpr(t types.Type, old *ast.FPToUIExpr) (*ir.ExprFPToUI, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewFPToUIExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irFPToSIExpr(t types.Type, old *ast.FPToSIExpr) (*ir.ExprFPToSI, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewFPToSIExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irUIToFPExpr(t types.Type, old *ast.UIToFPExpr) (*ir.ExprUIToFP, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewUIToFPExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irSIToFPExpr(t types.Type, old *ast.SIToFPExpr) (*ir.ExprSIToFP, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewSIToFPExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irPtrToIntExpr(t types.Type, old *ast.PtrToIntExpr) (*ir.ExprPtrToInt, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewPtrToIntExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irIntToPtrExpr(t types.Type, old *ast.IntToPtrExpr) (*ir.ExprIntToPtr, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewIntToPtrExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irBitCastExpr(t types.Type, old *ast.BitCastExpr) (*ir.ExprBitCast, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewBitCastExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ func (gen *generator) irAddrSpaceCastExpr(t types.Type, old *ast.AddrSpaceCastExpr) (*ir.ExprAddrSpaceCast, error) { - panic("not yet implemented") + // From. + from, err := gen.irTypeConst(old.From()) + if err != nil { + return nil, errors.WithStack(err) + } + // To. + to, err := gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + expr := ir.NewAddrSpaceCastExpr(from, to) + // TODO: validate type t against expr.Typ. + return expr, nil } // --- [ Other expressions ] --------------------------------------------------- diff --git a/cmd/l-tm/main.go b/cmd/l-tm/main.go index 72d6afd6..44b33611 100644 --- a/cmd/l-tm/main.go +++ b/cmd/l-tm/main.go @@ -6,7 +6,6 @@ import ( "log" "time" - "github.com/kr/pretty" "github.com/mewmew/l-tm/asm" ) @@ -30,7 +29,7 @@ func main() { log.Fatalf("%q: %+v", llPath, err) } _ = m - pretty.Println(m) + //pretty.Println(m) fmt.Printf("total time for file %q: %v\n", llPath, time.Since(fileStart)) } } From 2c65084855ca5037543b2a66274d10f7d83a24c4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 01:12:07 +0200 Subject: [PATCH 20/70] asm: translate undef constant --- asm/const.go | 59 ++++++++++++++++++++++++++++++++++++------------ asm/global.go | 18 +++++++-------- asm/translate.go | 26 +++++++++++++++++++++ 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/asm/const.go b/asm/const.go index 7cf30d90..47d8d83e 100644 --- a/asm/const.go +++ b/asm/const.go @@ -6,7 +6,6 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" - "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" ) @@ -40,11 +39,11 @@ func (gen *generator) irConstant(t types.Type, old ast.Constant) (ir.Constant, e return gen.irBlockAddressConst(t, old) case *ast.GlobalIdent: name := global(*old) - g, ok := gen.gs[name] + v, ok := gen.gs[name] if !ok { - return nil, errors.Errorf("unable to locate global identifier %q", enc.Global(name)) + return nil, errors.Errorf("unable to locate global identifier %q", name) } - return g, nil + return v, nil case ast.ConstantExpr: return gen.irConstantExpr(t, old) default: @@ -53,10 +52,12 @@ func (gen *generator) irConstant(t types.Type, old ast.Constant) (ir.Constant, e } func (gen *generator) irTypeConst(old ast.TypeConst) (ir.Constant, error) { + // Type. typ, err := gen.irType(old.Typ()) if err != nil { return nil, errors.WithStack(err) } + // Constant. return gen.irConstant(typ, old.Val()) } @@ -112,7 +113,8 @@ func (gen *generator) irNullConst(t types.Type, old *ast.NullConst) (*ir.ConstNu // --- [ Token Constants ] ----------------------------------------------------- func (gen *generator) irNoneConst(t types.Type, old *ast.NoneConst) (*ir.ConstNone, error) { - panic("not yet implemented") + // TODO: validate type t. + return ir.None, nil } // --- [ Structure Constants ] ------------------------------------------------- @@ -153,18 +155,29 @@ func (gen *generator) irArrayConst(t types.Type, old *ast.ArrayConst) (*ir.Const func (gen *generator) irCharArrayConst(t types.Type, old *ast.CharArrayConst) (*ir.ConstCharArray, error) { data := stringLitBytes(old.Val()) - // TODO: validate that t and type of newly created character array constant - // match. - - // TODO: also decide whether to update ir.NewCharArray to include a type as - // its first parameter, thus making it consistent with ir.NewArray. - return ir.NewCharArray(data), nil + // TODO: decide whether to update ir.NewCharArray to include a type as its + // first parameter, thus making it consistent with ir.NewArray. + expr := ir.NewCharArray(data) + // TODO: validate t against expr.Typ. + return expr, nil } // --- [ Vector Constants ] ---------------------------------------------------- func (gen *generator) irVectorConst(t types.Type, old *ast.VectorConst) (*ir.ConstVector, error) { - panic("not yet implemented") + typ, ok := t.(*types.VectorType) + if !ok { + return nil, errors.Errorf("invalid type of vector constant; expected *types.VectorType, got %T", t) + } + var elems []ir.Constant + for _, e := range old.Elems() { + elem, err := gen.irTypeConst(e) + if err != nil { + return nil, errors.WithStack(err) + } + elems = append(elems, elem) + } + return ir.NewVector(typ, elems...), nil } // --- [ Zero Initialization Constants ] --------------------------------------- @@ -176,11 +189,29 @@ func (gen *generator) irZeroInitializerConst(t types.Type, old *ast.ZeroInitiali // --- [ Undefined Values ] ---------------------------------------------------- func (gen *generator) irUndefConst(t types.Type, old *ast.UndefConst) (*ir.ConstUndef, error) { - panic("not yet implemented") + return ir.NewUndef(t), nil } // --- [ Addresses of Basic Blocks ] ------------------------------------------- func (gen *generator) irBlockAddressConst(t types.Type, old *ast.BlockAddressConst) (*ir.ConstBlockAddress, error) { - panic("not yet implemented") + panic("not yet implemented. ensure that irBlockAddressConst is invoked only after function bodies have been populated, and local identifiers have been assigned names. In this sense, irBlockAddressConst is different from all other constants.") + // Function. + funcName := global(old.Func()) + f, err := gen.function(funcName) + if err != nil { + return nil, errors.WithStack(err) + } + // Basic block. + blockName := local(old.Block()) + // TODO: assign block IDs; or rather, place call to irBlockAddressConst after + // the IDs have been assigned already. + for _, block := range f.Blocks { + if block.LocalName == blockName { + expr := ir.NewBlockAddress(f, block) + // TODO: validate type t against expr.Typ. + return expr, nil + } + } + return nil, errors.Errorf("unable to locate basic block %q in function %q", blockName, funcName) } diff --git a/asm/global.go b/asm/global.go index d5b8f676..93ca250b 100644 --- a/asm/global.go +++ b/asm/global.go @@ -81,11 +81,10 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant // Add global variable declarations and definitions to IR module in order of // occurrence in input. for _, key := range globalOrder { - g, ok := gen.gs[key].(*ir.Global) - if !ok { - // NOTE: Panic instead of returning error as this case should not be - // possible, and would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR type for AST global variable declaration or definition; expected *ir.Global, got %T", g)) + g, err := gen.global(key) + if err != nil { + // NOTE: panic since this would indicate a bug in the implementation. + panic(err) } gen.m.Globals = append(gen.m.Globals, g) } @@ -93,11 +92,10 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant // Add function declarations and definitions to IR module in order of // occurrence in input. for _, key := range funcOrder { - f, ok := gen.gs[key].(*ir.Function) - if !ok { - // NOTE: Panic instead of returning error as this case should not be - // possible, and would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR type for AST function declaration or definition; expected *ir.Function, got %T", f)) + f, err := gen.function(key) + if err != nil { + // NOTE: panic since this would indicate a bug in the implementation. + panic(err) } gen.m.Funcs = append(gen.m.Funcs, f) } diff --git a/asm/translate.go b/asm/translate.go index f9bd6d06..30207de5 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -65,3 +65,29 @@ func newGenerator() *generator { m: &ir.Module{}, } } + +// global returns the IR global variable of the given name. +func (gen *generator) global(name string) (*ir.Global, error) { + v, ok := gen.gs[name] + if !ok { + return nil, errors.Errorf("unable to locate global variable %q", name) + } + g, ok := v.(*ir.Global) + if !ok { + return nil, errors.Errorf("invalid global variable type of %q; expected *ir.Global, got %T", name, v) + } + return g, nil +} + +// function returns the IR function of the given name. +func (gen *generator) function(name string) (*ir.Function, error) { + v, ok := gen.gs[name] + if !ok { + return nil, errors.Errorf("unable to locate function %q", name) + } + f, ok := v.(*ir.Function) + if !ok { + return nil, errors.Errorf("invalid function type of %q; expected *ir.Function, got %T", name, v) + } + return f, nil +} From dd5992f787b5088154b67e5b3434d02181aab197 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 08:18:26 +0200 Subject: [PATCH 21/70] asm: fix translation of blockaddress ref: https://github.com/mewmew/l/issues/6#issuecomment-430160271 Translate blockaddress to `&ir.ConstBlockAddress{Func: f, Block: &ir.BasicBlock{LocalName: local(old.Name())}}`, the point being that we create a dummy IR basic block, that will record the basic block name used in the blockaddress constant. Then, once function bodies have been translated, run `f.AssignIDs()` to assign local IDs to unnamed instruction results, basic blocks and function parameters. As far as I can tell, this would solve the dependency relationship mentioned above. Updates #6. --- asm/const.go | 25 +++++++++++++++++++------ asm/translate.go | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/asm/const.go b/asm/const.go index 47d8d83e..bd7c7e08 100644 --- a/asm/const.go +++ b/asm/const.go @@ -204,14 +204,27 @@ func (gen *generator) irBlockAddressConst(t types.Type, old *ast.BlockAddressCon } // Basic block. blockName := local(old.Block()) - // TODO: assign block IDs; or rather, place call to irBlockAddressConst after - // the IDs have been assigned already. + // Add dummy basic block to track the name recorded by the AST. Resolve the + // proper basic block after translation of function bodies and assignment of + // local IDs. + block := &ir.BasicBlock{ + LocalName: blockName, + } + expr := ir.NewBlockAddress(f, block) + gen.todo = append(gen.todo, expr) + // TODO: validate type t against expr.Typ. Store t in todo? + return expr, nil +} + +// Pre-condition: translate function body and assign local IDs of c.Func. +func fixBlockAddressConst(c *ir.ConstBlockAddress) error { + f := c.Func + blockName := c.Block.LocalName for _, block := range f.Blocks { if block.LocalName == blockName { - expr := ir.NewBlockAddress(f, block) - // TODO: validate type t against expr.Typ. - return expr, nil + c.Block = block + return nil } } - return nil, errors.Errorf("unable to locate basic block %q in function %q", blockName, funcName) + return errors.Errorf("unable to locate basic block %q in function %q", blockName, f.FuncName) } diff --git a/asm/translate.go b/asm/translate.go index 30207de5..d9c00865 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -23,6 +23,7 @@ var ( // module. func Translate(module *ast.Module) (*ir.Module, error) { gen := newGenerator() + // Resolve types. if DoTypeResolution { typeResolutionStart := time.Now() _, err := gen.resolveTypeDefs(module) @@ -32,6 +33,7 @@ func Translate(module *ast.Module) (*ir.Module, error) { fmt.Println("type resolution of type definitions took:", time.Since(typeResolutionStart)) fmt.Println() } + // Resolve globals. if DoGlobalResolution { globalResolutionStart := time.Now() _, err := gen.resolveGlobals(module) @@ -41,6 +43,14 @@ func Translate(module *ast.Module) (*ir.Module, error) { fmt.Println("global resolution of global variable and function declarations and definitions took:", time.Since(globalResolutionStart)) fmt.Println() } + // Resolve functions. + // TODO: implement. + // Fix dummy values. + for _, c := range gen.todo { + if err := fixBlockAddressConst(c); err != nil { + return nil, errors.WithStack(err) + } + } return gen.m, nil } @@ -56,6 +66,10 @@ type generator struct { // gs maps from global identifier (without '@' prefix) to corresponding // IR value. gs map[string]ir.Constant + + // Fix dummy basic blocks after translation of function bodies and assignment + // of local IDs. + todo []*ir.ConstBlockAddress } // newGenerator returns a new generator for translating an LLVM IR module from From cd2d356d9b979b3e43f2dd14323c94f3800554d8 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 09:04:02 +0200 Subject: [PATCH 22/70] asm: translate function declarations --- asm/global.go | 55 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/asm/global.go b/asm/global.go index 93ca250b..b3780e7e 100644 --- a/asm/global.go +++ b/asm/global.go @@ -59,7 +59,8 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant } } - // Create corresponding IR global variables and functions (without bodies). + // Create corresponding IR global variables and functions (without bodies but + // with a type). gen.gs = make(map[string]ir.Constant) for name, old := range index { g, err := gen.newGlobal(name, old) @@ -110,21 +111,21 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err case *ast.GlobalDecl: g := &ir.Global{GlobalName: name} // Content type. - typ, err := gen.irType(old.ContentType()) + contentType, err := gen.irType(old.ContentType()) if err != nil { return nil, errors.WithStack(err) } - g.ContentType = typ + g.ContentType = contentType g.Typ = types.NewPointer(g.ContentType) return g, nil case *ast.GlobalDef: g := &ir.Global{GlobalName: name} // Content type. - typ, err := gen.irType(old.ContentType()) + contentType, err := gen.irType(old.ContentType()) if err != nil { return nil, errors.WithStack(err) } - g.ContentType = typ + g.ContentType = contentType g.Typ = types.NewPointer(g.ContentType) return g, nil case *ast.FuncDecl: @@ -149,8 +150,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err // Variadic. sig.Variadic = irVariadic(ps.Variadic()) f.Sig = sig - // TODO: add Typ? - //f.Typ = types.NewPointer(f.Sig) + f.Typ = types.NewPointer(f.Sig) return f, nil case *ast.FuncDef: f := &ir.Function{FuncName: name} @@ -174,8 +174,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err // Variadic. sig.Variadic = irVariadic(ps.Variadic()) f.Sig = sig - // TODO: add Typ? - //f.Typ = types.NewPointer(f.Sig) + f.Typ = types.NewPointer(f.Sig) return f, nil default: panic(fmt.Errorf("support for global variable or function %T not yet implemented", old)) @@ -277,7 +276,43 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co if !ok { panic(fmt.Errorf("invalid IR type for AST function declaration; expected *ir.Function, got %T", g)) } - // TODO: implement + hdr := old.Header() + // Linkage. + // TODO: Handle ExternLinkage. + f.Linkage = irLinkage(hdr.Linkage().Text()) + // Preemption. + f.Preemption = irPreemption(hdr.Preemption()) + // Visibility. + f.Visibility = irVisibility(hdr.Visibility()) + // DLL storage class. + f.DLLStorageClass = irDLLStorageClass(hdr.DLLStorageClass()) + // Calling convention. + // TODO: translate CallingConv. + // Return attributes. + // TODO: handle ReturnAttrs. + // Return type; already handled. + // Function name; already handled. + // Function parameters. + // TODO: handle Params. + // Unnamed address. + f.UnnamedAddr = irUnnamedAddr(hdr.UnnamedAddr()) + // Address space. + f.Typ.AddrSpace = irAddrSpace(hdr.AddrSpace()) + // Function attributes. + // TODO: handle FuncAttrs. + // Section. + // TODO: handle Section. + // Comdat. + // TODO: handle Comdat. + // GC. + // TODO: handle GC. + // Prefix. + // TODO: handle Prefix. + // Prologue. + // TODO: handle Prologue. + // Personality. + // TODO: handle Personality. + // TODO: assign local IDs. return f, nil } From a1d2d11f243c1d5fa191e93f5066e1bd73fa75a4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 09:50:13 +0200 Subject: [PATCH 23/70] asm: translate function parameters --- asm/global.go | 19 ++++++++++++++++--- asm/helper.go | 8 ++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/asm/global.go b/asm/global.go index b3780e7e..0b729e6d 100644 --- a/asm/global.go +++ b/asm/global.go @@ -278,8 +278,7 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co } hdr := old.Header() // Linkage. - // TODO: Handle ExternLinkage. - f.Linkage = irLinkage(hdr.Linkage().Text()) + f.Linkage = irLinkage(hdr.ExternLinkage().Text()) // Preemption. f.Preemption = irPreemption(hdr.Preemption()) // Visibility. @@ -293,7 +292,21 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co // Return type; already handled. // Function name; already handled. // Function parameters. - // TODO: handle Params. + var params []*ir.Param + ps := hdr.Params() + for _, p := range ps.Params() { + // Type. + typ, err := gen.irType(p.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + // Parameter attributes. + // TODO: handle Attrs. + name := local(*p.Name()) + param := ir.NewParam(typ, name) + params = append(params, param) + } + // Unnamed address. f.UnnamedAddr = irUnnamedAddr(hdr.UnnamedAddr()) // Address space. diff --git a/asm/helper.go b/asm/helper.go index 531afc84..0e333b22 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -18,6 +18,10 @@ import ( // global returns the name (without '@' prefix) of the given global identifier. func global(n ast.GlobalIdent) string { text := n.Text() + if text == "" { + // \empty is used when global identifier not present. + return "" + } const prefix = "@" if !strings.HasPrefix(text, prefix) { // NOTE: Panic instead of returning error as this case should not be @@ -33,6 +37,10 @@ func global(n ast.GlobalIdent) string { // local returns the name (without '%' prefix) of the given local identifier. func local(n ast.LocalIdent) string { text := n.Text() + if text == "" { + // \empty is used when local identifier not present. + return "" + } const prefix = "%" if !strings.HasPrefix(text, prefix) { // NOTE: Panic instead of returning error as this case should not be From 081425cc79c3a7a3006ed1cdc51efd1b11aa8cf4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 09:51:21 +0200 Subject: [PATCH 24/70] asm: remove panic for blockaddress, now implemented --- asm/const.go | 1 - 1 file changed, 1 deletion(-) diff --git a/asm/const.go b/asm/const.go index bd7c7e08..60a30013 100644 --- a/asm/const.go +++ b/asm/const.go @@ -195,7 +195,6 @@ func (gen *generator) irUndefConst(t types.Type, old *ast.UndefConst) (*ir.Const // --- [ Addresses of Basic Blocks ] ------------------------------------------- func (gen *generator) irBlockAddressConst(t types.Type, old *ast.BlockAddressConst) (*ir.ConstBlockAddress, error) { - panic("not yet implemented. ensure that irBlockAddressConst is invoked only after function bodies have been populated, and local identifiers have been assigned names. In this sense, irBlockAddressConst is different from all other constants.") // Function. funcName := global(old.Func()) f, err := gen.function(funcName) From 7cd08190482147fe39aa4e77411fb28b3101fb22 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 18 Oct 2018 09:58:20 +0200 Subject: [PATCH 25/70] asm: translate function header in FuncDef --- asm/global.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/asm/global.go b/asm/global.go index 0b729e6d..745470e8 100644 --- a/asm/global.go +++ b/asm/global.go @@ -276,7 +276,15 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co if !ok { panic(fmt.Errorf("invalid IR type for AST function declaration; expected *ir.Function, got %T", g)) } - hdr := old.Header() + if err := gen.translateFuncHeader(f, old.Header()); err != nil { + return nil, errors.WithStack(err) + } + // Metadata. + // TODO: translate function metadata. + return f, nil +} + +func (gen *generator) translateFuncHeader(f *ir.Function, hdr ast.FuncHeader) error { // Linkage. f.Linkage = irLinkage(hdr.ExternLinkage().Text()) // Preemption. @@ -298,7 +306,7 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co // Type. typ, err := gen.irType(p.Typ()) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } // Parameter attributes. // TODO: handle Attrs. @@ -326,7 +334,7 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co // Personality. // TODO: handle Personality. // TODO: assign local IDs. - return f, nil + return nil } // ~~~ [ Function Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -336,6 +344,11 @@ func (gen *generator) translateFuncDef(g ir.Constant, old *ast.FuncDef) (ir.Cons if !ok { panic(fmt.Errorf("invalid IR type for AST function definition; expected *ir.Function, got %T", g)) } + if err := gen.translateFuncHeader(f, old.Header()); err != nil { + return nil, errors.WithStack(err) + } + // Metadata. + // TODO: translate function metadata. // TODO: implement return f, nil } From e9a54973dbabf51821d5fa52fefd7ae497ea6b3a Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 19 Oct 2018 00:24:38 +0200 Subject: [PATCH 26/70] grammar: rename RetType to Typ in CallInst This is to closer match its behaviour, as it may either hold the return type or the function signature of the callee. --- asm/ll/ll.tm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 4ac5eef8..d91e2241 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -2514,7 +2514,7 @@ SelectInst -> SelectInst # OptionalAttrs Type Value ParameterList OptionalAttrs CallInst -> CallInst - : Tailopt 'call' FastMathFlags=FastMathFlag* CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt RetType=Type Callee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles InstMetadata + : Tailopt 'call' FastMathFlags=FastMathFlag* CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Typ=Type Callee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles InstMetadata ; Tail -> Tail From 238d17f47f273146f7acbd8ecf147e46bb79ea3e Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 19 Oct 2018 00:55:56 +0200 Subject: [PATCH 27/70] asm: initial attempt at resolving local identifiers --- asm/global.go | 17 ++- asm/helper.go | 17 +++ asm/local.go | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+), 6 deletions(-) create mode 100644 asm/local.go diff --git a/asm/global.go b/asm/global.go index 745470e8..ddbfdfe7 100644 --- a/asm/global.go +++ b/asm/global.go @@ -276,11 +276,11 @@ func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Co if !ok { panic(fmt.Errorf("invalid IR type for AST function declaration; expected *ir.Function, got %T", g)) } + // Metadata. + // TODO: translate function metadata. if err := gen.translateFuncHeader(f, old.Header()); err != nil { return nil, errors.WithStack(err) } - // Metadata. - // TODO: translate function metadata. return f, nil } @@ -300,7 +300,6 @@ func (gen *generator) translateFuncHeader(f *ir.Function, hdr ast.FuncHeader) er // Return type; already handled. // Function name; already handled. // Function parameters. - var params []*ir.Param ps := hdr.Params() for _, p := range ps.Params() { // Type. @@ -312,7 +311,7 @@ func (gen *generator) translateFuncHeader(f *ir.Function, hdr ast.FuncHeader) er // TODO: handle Attrs. name := local(*p.Name()) param := ir.NewParam(typ, name) - params = append(params, param) + f.Params = append(f.Params, param) } // Unnamed address. @@ -333,7 +332,6 @@ func (gen *generator) translateFuncHeader(f *ir.Function, hdr ast.FuncHeader) er // TODO: handle Prologue. // Personality. // TODO: handle Personality. - // TODO: assign local IDs. return nil } @@ -349,6 +347,13 @@ func (gen *generator) translateFuncDef(g ir.Constant, old *ast.FuncDef) (ir.Cons } // Metadata. // TODO: translate function metadata. - // TODO: implement + // Basic blocks. + fgen := newFuncGen(gen, f) + _, err := fgen.resolveLocals(old.Body()) + if err != nil { + return nil, errors.WithStack(err) + } + // Use list orders. + // TODO: translate use list orders. return f, nil } diff --git a/asm/helper.go b/asm/helper.go index 0e333b22..4605c8f9 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -53,6 +53,23 @@ func local(n ast.LocalIdent) string { // --- [ Label Identifiers ] --------------------------------------------------- +// label returns the name (without ':' suffix) of the given label identifier. +func label(n ast.LabelIdent) string { + text := n.Text() + if text == "" { + // \empty is used when label identifier not present. + return "" + } + const suffix = ":" + if !strings.HasSuffix(text, suffix) { + // NOTE: Panic instead of returning error as this case should not be + // possible given the grammar. + panic(fmt.Errorf("invalid label identifier %q; missing '%s' suffix", text, suffix)) + } + text = text[:len(text)-len(suffix)] + return unquote(text) +} + // --- [ Attribute Group Identifiers ] ----------------------------------------- // --- [ Comdat Identifiers ] -------------------------------------------------- diff --git a/asm/local.go b/asm/local.go new file mode 100644 index 00000000..10ce520b --- /dev/null +++ b/asm/local.go @@ -0,0 +1,358 @@ +// TODO: make concurrent :) + +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/llir/l/ir/value" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +type funcGen struct { + // Module generator. + *generator + + // LLVM IR function being generated. + f *ir.Function + + // ls maps from local identifier (without '%' prefix) to corresponding IR + // value. + ls map[string]value.Value +} + +func newFuncGen(gen *generator, f *ir.Function) *funcGen { + return &funcGen{ + generator: gen, + f: f, + ls: make(map[string]value.Value), + } +} + +// resolveLocals resolves the local variables, basic blocks and function +// parameters of the given function body. The returned value maps from local +// identifier (without '%' prefix) to the corresponding IR value. +func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, error) { + // Create instructions (without bodies), in preparation for index. + f := fgen.f + bbs := body.Blocks() + for _, b := range bbs { + blockName := label(*b.Name()) + block := ir.NewBlock(blockName) + for _, i := range b.Insts() { + inst, err := fgen.newIRInst(i) + if err != nil { + return nil, errors.WithStack(err) + } + block.Insts = append(block.Insts, inst) + } + f.Blocks = append(f.Blocks, block) + } + // Assign local IDs. + if err := f.AssignIDs(); err != nil { + return nil, errors.WithStack(err) + } + // Index local identifiers. + // TODO: index local identifiers. + + // Translate instructions. + for i, block := range f.Blocks { + insts := bbs[i].Insts() + for j, inst := range block.Insts { + old := insts[j] + if _, err := fgen.translateInst(inst, old); err != nil { + return nil, errors.WithStack(err) + } + } + } + // TODO: implement. + panic("not yet implemented") + // Translate terminators. + // TODO: implement. +} + +// newIRInst returns a new IR instruction (without body) based on the given AST +// instruction. +func (fgen *funcGen) newIRInst(old ast.Instruction) (ir.Instruction, error) { + switch old := old.(type) { + // Value instruction. + case *ast.LocalDef: + name := local(old.Name()) + return fgen.newIRValueInst(name, old.Inst()) + case ast.ValueInstruction: + return fgen.newIRValueInst("", old) + // Non-value instructions. + case *ast.StoreInst: + return &ir.InstStore{}, nil + case *ast.FenceInst: + return &ir.InstFence{}, nil + case *ast.CmpXchgInst: + return &ir.InstCmpXchg{}, nil + case *ast.AtomicRMWInst: + return &ir.InstAtomicRMW{}, nil + default: + panic(fmt.Errorf("support for AST instruction type %T not yet implemented", old)) + } +} + +// newIRValueInst returns a new IR value instruction (without body) based on the +// given AST value instruction. +func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.Instruction, error) { + switch old := old.(type) { + // Binary instructions + case *ast.AddInst: + return &ir.InstAdd{LocalName: name}, nil + case *ast.FAddInst: + return &ir.InstFAdd{LocalName: name}, nil + case *ast.SubInst: + return &ir.InstSub{LocalName: name}, nil + case *ast.FSubInst: + return &ir.InstFSub{LocalName: name}, nil + case *ast.MulInst: + return &ir.InstMul{LocalName: name}, nil + case *ast.FMulInst: + return &ir.InstFMul{LocalName: name}, nil + case *ast.UDivInst: + return &ir.InstUDiv{LocalName: name}, nil + case *ast.SDivInst: + return &ir.InstSDiv{LocalName: name}, nil + case *ast.FDivInst: + return &ir.InstFDiv{LocalName: name}, nil + case *ast.URemInst: + return &ir.InstURem{LocalName: name}, nil + case *ast.SRemInst: + return &ir.InstSRem{LocalName: name}, nil + case *ast.FRemInst: + return &ir.InstFRem{LocalName: name}, nil + // Bitwise instructions + case *ast.ShlInst: + return &ir.InstShl{LocalName: name}, nil + case *ast.LShrInst: + return &ir.InstLShr{LocalName: name}, nil + case *ast.AShrInst: + return &ir.InstAShr{LocalName: name}, nil + case *ast.AndInst: + return &ir.InstAnd{LocalName: name}, nil + case *ast.OrInst: + return &ir.InstOr{LocalName: name}, nil + case *ast.XorInst: + return &ir.InstXor{LocalName: name}, nil + // Vector instructions + case *ast.ExtractElementInst: + return &ir.InstExtractElement{LocalName: name}, nil + case *ast.InsertElementInst: + return &ir.InstInsertElement{LocalName: name}, nil + case *ast.ShuffleVectorInst: + return &ir.InstShuffleVector{LocalName: name}, nil + // Aggregate instructions + case *ast.ExtractValueInst: + return &ir.InstExtractValue{LocalName: name}, nil + case *ast.InsertValueInst: + return &ir.InstInsertValue{LocalName: name}, nil + // Memory instructions + case *ast.AllocaInst: + return &ir.InstAlloca{LocalName: name}, nil + case *ast.LoadInst: + return &ir.InstLoad{LocalName: name}, nil + case *ast.GetElementPtrInst: + return &ir.InstGetElementPtr{LocalName: name}, nil + // Conversion instructions + case *ast.TruncInst: + return &ir.InstTrunc{LocalName: name}, nil + case *ast.ZExtInst: + return &ir.InstZExt{LocalName: name}, nil + case *ast.SExtInst: + return &ir.InstSExt{LocalName: name}, nil + case *ast.FPTruncInst: + return &ir.InstFPTrunc{LocalName: name}, nil + case *ast.FPExtInst: + return &ir.InstFPExt{LocalName: name}, nil + case *ast.FPToUIInst: + return &ir.InstFPToUI{LocalName: name}, nil + case *ast.FPToSIInst: + return &ir.InstFPToSI{LocalName: name}, nil + case *ast.UIToFPInst: + return &ir.InstUIToFP{LocalName: name}, nil + case *ast.SIToFPInst: + return &ir.InstSIToFP{LocalName: name}, nil + case *ast.PtrToIntInst: + return &ir.InstPtrToInt{LocalName: name}, nil + case *ast.IntToPtrInst: + return &ir.InstIntToPtr{LocalName: name}, nil + case *ast.BitCastInst: + return &ir.InstBitCast{LocalName: name}, nil + case *ast.AddrSpaceCastInst: + return &ir.InstAddrSpaceCast{LocalName: name}, nil + // Other instructions + case *ast.ICmpInst: + return &ir.InstICmp{LocalName: name}, nil + case *ast.FCmpInst: + return &ir.InstFCmp{LocalName: name}, nil + case *ast.PhiInst: + return &ir.InstPhi{LocalName: name}, nil + case *ast.SelectInst: + return &ir.InstSelect{LocalName: name}, nil + case *ast.CallInst: + // NOTE: We need to store the type of call instructions before invoking + // f.AssignIDs, since call instructions may be value instructions or + // non-value instructions based on return type. + typ, err := fgen.irType(old.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstCall{LocalName: name, Typ: typ}, nil + case *ast.VAArgInst: + return &ir.InstVAArg{LocalName: name}, nil + case *ast.LandingPadInst: + return &ir.InstLandingPad{LocalName: name}, nil + case *ast.CatchPadInst: + return &ir.InstCatchPad{LocalName: name}, nil + case *ast.CleanupPadInst: + return &ir.InstCleanupPad{LocalName: name}, nil + default: + panic(fmt.Errorf("support for AST value instruction type %T not yet implemented", old)) + } +} + +// === [ Instructions ] ======================================================== + +// translateInst translates the AST instruction into an equivalent IR +// instruction. +func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir.Instruction, error) { + switch old := old.(type) { + case *ast.AddInst: + return fgen.translateAddInst(inst, old) + default: + panic(fmt.Errorf("support for instruction type %T not yet implemented", old)) + } +} + +// --- [ Binary instructions ] ------------------------------------------------- + +// ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { + i, ok := inst.(*ir.InstAdd) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAdd, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ Bitwise instructions ] ------------------------------------------------ + +// ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ Vector instructions ] ------------------------------------------------- + +// ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ Aggregate instructions ] ---------------------------------------------- + +// ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ Memory instructions ] ------------------------------------------------- + +// ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ Conversion instructions ] --------------------------------------------- + +// ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ Other instructions ] -------------------------------------------------- + +// ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// --- [ catchpad ] ------------------------------------------------------------ + +// --- [ cleanuppad ] ---------------------------------------------------------- From 042e797c412a05ee350912d964cb2302b0fc2a9f Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 19 Oct 2018 12:29:49 +0200 Subject: [PATCH 28/70] asm: add notes about problems to solve in locals.go --- asm/local.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/asm/local.go b/asm/local.go index 10ce520b..6eb1bf56 100644 --- a/asm/local.go +++ b/asm/local.go @@ -1,3 +1,20 @@ +// Problems to solve. +// +// phi instructions can reference local variables defined in basic blocks not +// yet visited when translating basic blocks in linear order. +// +// Terminator instructions can reference basic blocks not yet visited when +// translating basic blocks in linear order. +// +// The function parameters, basic blocks and local variables (produced by the +// result of instructions) of a function may be unnamed. They are assigned the +// first unused local ID (e.g. %42) when traversing the body of the function in +// linear order; where function parameters are assigned first, then for each +// basic block, assign an ID to the basic block and then to the result of its +// instructions. Note, instructions that produce void results are ignored. +// Non-value instructions (e.g. store) are always ignored. Notably, the call +// instruction may be ignored if the callee has a void return. + // TODO: make concurrent :) package asm From 55287d71d5ba6af411af0474e5aa4c11644fb83c Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 01:12:41 +0200 Subject: [PATCH 29/70] asm: index local variables --- asm/local.go | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/asm/local.go b/asm/local.go index 6eb1bf56..38419da0 100644 --- a/asm/local.go +++ b/asm/local.go @@ -24,13 +24,14 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/value" + "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/pkg/errors" ) type funcGen struct { // Module generator. - *generator + gen *generator // LLVM IR function being generated. f *ir.Function @@ -42,9 +43,9 @@ type funcGen struct { func newFuncGen(gen *generator, f *ir.Function) *funcGen { return &funcGen{ - generator: gen, - f: f, - ls: make(map[string]value.Value), + gen: gen, + f: f, + ls: make(map[string]value.Value), } } @@ -72,8 +73,24 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e return nil, errors.WithStack(err) } // Index local identifiers. - // TODO: index local identifiers. - + for _, param := range f.Params { + fgen.ls[param.ParamName] = param + } + for _, block := range f.Blocks { + // TODO: Rename block.LocalName to block.BlockName? + fgen.ls[block.LocalName] = block + for _, inst := range block.Insts { + if n, ok := inst.(value.Named); ok { + // Skip call instruction if callee has void return type. + if n, ok := n.(*ir.InstCall); ok { + if n.Type().Equal(types.Void) { + continue + } + } + fgen.ls[n.Name()] = n + } + } + } // Translate instructions. for i, block := range f.Blocks { insts := bbs[i].Insts() @@ -215,7 +232,7 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I // NOTE: We need to store the type of call instructions before invoking // f.AssignIDs, since call instructions may be value instructions or // non-value instructions based on return type. - typ, err := fgen.irType(old.Typ()) + typ, err := fgen.gen.irType(old.Typ()) if err != nil { return nil, errors.WithStack(err) } @@ -250,6 +267,9 @@ func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir // ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// TODO: implement astToIRValue(old ast.Value) value.Value +//func (fgen *funcGen) astToIRValue(old ast.Node) value.Value + func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { i, ok := inst.(*ir.InstAdd) if !ok { From dd019f24aba303ceac6007d614963384be6934ce Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 02:34:23 +0200 Subject: [PATCH 30/70] asm: implement translation of add instructions --- asm/ll/ll.tm | 4 ++-- asm/local.go | 31 ++++++++++++++++++++++++------- asm/value.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 asm/value.go diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index d91e2241..8c746ea6 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -2570,7 +2570,7 @@ FilterClause -> FilterClause : 'filter' Typ=Type Val=ArrayConst ; -# --- [ catchpad ] ------------------------------------------------------------- +# ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ref: ParseCatchPad # @@ -2580,7 +2580,7 @@ CatchPadInst -> CatchPadInst : 'catchpad' 'within' Scope=LocalIdent '[' Args=(ExceptionArg separator ',')* ']' InstMetadata ; -# --- [ cleanuppad ] ----------------------------------------------------------- +# ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ref: ParseCleanupPad # diff --git a/asm/local.go b/asm/local.go index 38419da0..bb48cbdb 100644 --- a/asm/local.go +++ b/asm/local.go @@ -23,8 +23,8 @@ import ( "fmt" "github.com/llir/l/ir" - "github.com/llir/l/ir/value" "github.com/llir/l/ir/types" + "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/pkg/errors" ) @@ -256,6 +256,17 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I // instruction. func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir.Instruction, error) { switch old := old.(type) { + case *ast.LocalDef: + name := local(old.Name()) + v, ok := fgen.ls[name] + if !ok { + return nil, errors.Errorf("unable to locate local variable %q", name) + } + i, ok := v.(ir.Instruction) + if !ok { + return nil, errors.Errorf("invalid instruction type of %q; expected ir.Instruction, got %T", name, v) + } + return fgen.translateInst(i, old.Inst().(ast.Instruction)) case *ast.AddInst: return fgen.translateAddInst(inst, old) default: @@ -267,16 +278,22 @@ func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir // ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// TODO: implement astToIRValue(old ast.Value) value.Value -//func (fgen *funcGen) astToIRValue(old ast.Node) value.Value - func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { i, ok := inst.(*ir.InstAdd) if !ok { // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAdd, got %T", inst)) } - // TODO: implement + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + y, err := fgen.astToIRValue(x.Type(), old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + i.Y = y return i, nil } @@ -390,6 +407,6 @@ func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*i // ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// --- [ catchpad ] ------------------------------------------------------------ +// ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// --- [ cleanuppad ] ---------------------------------------------------------- +// ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/asm/value.go b/asm/value.go new file mode 100644 index 00000000..49457e68 --- /dev/null +++ b/asm/value.go @@ -0,0 +1,46 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir/types" + "github.com/llir/l/ir/value" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +func (fgen *funcGen) astToIRValue(typ types.Type, old ast.Value) (value.Value, error) { + switch old := old.(type) { + case *ast.GlobalIdent: + name := global(*old) + v, ok := fgen.gen.gs[name] + if !ok { + return nil, errors.Errorf("unable to locate global identifier %q", name) + } + return v, nil + case *ast.LocalIdent: + name := local(*old) + v, ok := fgen.ls[name] + if !ok { + return nil, errors.Errorf("unable to locate local identifier %q", name) + } + return v, nil + case *ast.InlineAsm: + // TODO: implement + panic("not yet implemented") + case ast.Constant: + return fgen.gen.irConstant(typ, old) + default: + panic(fmt.Errorf("support for AST value %T not yet implemented", old)) + } +} + +func (fgen *funcGen) astToIRTypeValue(old ast.TypeValue) (value.Value, error) { + // Type. + typ, err := fgen.gen.irType(old.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + // Value. + return fgen.astToIRValue(typ, old.Val()) +} From a32b6565809d5b1b6f7802316cfce12a6e22555f Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 03:08:07 +0200 Subject: [PATCH 31/70] asm: add scaffolding for translating instructions --- asm/local.go | 646 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 644 insertions(+), 2 deletions(-) diff --git a/asm/local.go b/asm/local.go index bb48cbdb..3ee1058f 100644 --- a/asm/local.go +++ b/asm/local.go @@ -26,6 +26,7 @@ import ( "github.com/llir/l/ir/types" "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" ) @@ -74,9 +75,15 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e } // Index local identifiers. for _, param := range f.Params { + if prev, ok := fgen.ls[param.ParamName]; ok { + return nil, errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(param.ParamName), prev, param) + } fgen.ls[param.ParamName] = param } for _, block := range f.Blocks { + if prev, ok := fgen.ls[block.LocalName]; ok { + return nil, errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(block.LocalName), prev, block) + } // TODO: Rename block.LocalName to block.BlockName? fgen.ls[block.LocalName] = block for _, inst := range block.Insts { @@ -87,6 +94,9 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e continue } } + if prev, ok := fgen.ls[n.Name()]; ok { + return nil, errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(n.Name()), prev, n) + } fgen.ls[n.Name()] = n } } @@ -256,6 +266,7 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I // instruction. func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir.Instruction, error) { switch old := old.(type) { + // Value instruction. case *ast.LocalDef: name := local(old.Name()) v, ok := fgen.ls[name] @@ -266,11 +277,132 @@ func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir if !ok { return nil, errors.Errorf("invalid instruction type of %q; expected ir.Instruction, got %T", name, v) } - return fgen.translateInst(i, old.Inst().(ast.Instruction)) + return fgen.translateValueInst(i, old.Inst()) + case ast.ValueInstruction: + return fgen.translateValueInst(inst, old) + // Non-value instructions. + case *ast.StoreInst: + return fgen.translateStoreInst(inst, old) + case *ast.FenceInst: + return fgen.translateFenceInst(inst, old) + case *ast.CmpXchgInst: + return fgen.translateCmpXchgInst(inst, old) + case *ast.AtomicRMWInst: + return fgen.translateAtomicRMWInst(inst, old) + default: + panic(fmt.Errorf("support for instruction type %T not yet implemented", old)) + } +} + +// translateValueInst translates the AST value instruction into an equivalent IR +// value instruction. +func (fgen *funcGen) translateValueInst(inst ir.Instruction, old ast.ValueInstruction) (ir.Instruction, error) { + switch old := old.(type) { + // Binary instructions case *ast.AddInst: return fgen.translateAddInst(inst, old) + case *ast.FAddInst: + return fgen.translateFAddInst(inst, old) + case *ast.SubInst: + return fgen.translateSubInst(inst, old) + case *ast.FSubInst: + return fgen.translateFSubInst(inst, old) + case *ast.MulInst: + return fgen.translateMulInst(inst, old) + case *ast.FMulInst: + return fgen.translateFMulInst(inst, old) + case *ast.UDivInst: + return fgen.translateUDivInst(inst, old) + case *ast.SDivInst: + return fgen.translateSDivInst(inst, old) + case *ast.FDivInst: + return fgen.translateFDivInst(inst, old) + case *ast.URemInst: + return fgen.translateURemInst(inst, old) + case *ast.SRemInst: + return fgen.translateSRemInst(inst, old) + case *ast.FRemInst: + return fgen.translateFRemInst(inst, old) + // Bitwise instructions + case *ast.ShlInst: + return fgen.translateShlInst(inst, old) + case *ast.LShrInst: + return fgen.translateLShrInst(inst, old) + case *ast.AShrInst: + return fgen.translateAShrInst(inst, old) + case *ast.AndInst: + return fgen.translateAndInst(inst, old) + case *ast.OrInst: + return fgen.translateOrInst(inst, old) + case *ast.XorInst: + return fgen.translateXorInst(inst, old) + // Vector instructions + case *ast.ExtractElementInst: + return fgen.translateExtractElementInst(inst, old) + case *ast.InsertElementInst: + return fgen.translateInsertElementInst(inst, old) + case *ast.ShuffleVectorInst: + return fgen.translateShuffleVectorInst(inst, old) + // Aggregate instructions + case *ast.ExtractValueInst: + return fgen.translateExtractValueInst(inst, old) + case *ast.InsertValueInst: + return fgen.translateInsertValueInst(inst, old) + // Memory instructions + case *ast.AllocaInst: + return fgen.translateAllocaInst(inst, old) + case *ast.LoadInst: + return fgen.translateLoadInst(inst, old) + case *ast.GetElementPtrInst: + return fgen.translateGetElementPtrInst(inst, old) + // Conversion instructions + case *ast.TruncInst: + return fgen.translateTruncInst(inst, old) + case *ast.ZExtInst: + return fgen.translateZExtInst(inst, old) + case *ast.SExtInst: + return fgen.translateSExtInst(inst, old) + case *ast.FPTruncInst: + return fgen.translateFPTruncInst(inst, old) + case *ast.FPExtInst: + return fgen.translateFPExtInst(inst, old) + case *ast.FPToUIInst: + return fgen.translateFPToUIInst(inst, old) + case *ast.FPToSIInst: + return fgen.translateFPToSIInst(inst, old) + case *ast.UIToFPInst: + return fgen.translateUIToFPInst(inst, old) + case *ast.SIToFPInst: + return fgen.translateSIToFPInst(inst, old) + case *ast.PtrToIntInst: + return fgen.translatePtrToIntInst(inst, old) + case *ast.IntToPtrInst: + return fgen.translateIntToPtrInst(inst, old) + case *ast.BitCastInst: + return fgen.translateBitCastInst(inst, old) + case *ast.AddrSpaceCastInst: + return fgen.translateAddrSpaceCastInst(inst, old) + // Other instructions + case *ast.ICmpInst: + return fgen.translateICmpInst(inst, old) + case *ast.FCmpInst: + return fgen.translateFCmpInst(inst, old) + case *ast.PhiInst: + return fgen.translatePhiInst(inst, old) + case *ast.SelectInst: + return fgen.translateSelectInst(inst, old) + case *ast.CallInst: + return fgen.translateCallInst(inst, old) + case *ast.VAArgInst: + return fgen.translateVAArgInst(inst, old) + case *ast.LandingPadInst: + return fgen.translateLandingPadInst(inst, old) + case *ast.CatchPadInst: + return fgen.translateCatchPadInst(inst, old) + case *ast.CleanupPadInst: + return fgen.translateCleanupPadInst(inst, old) default: - panic(fmt.Errorf("support for instruction type %T not yet implemented", old)) + panic(fmt.Errorf("support for value instruction type %T not yet implemented", old)) } } @@ -299,114 +431,624 @@ func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*i // ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFAddInst(inst ir.Instruction, old *ast.FAddInst) (*ir.InstFAdd, error) { + i, ok := inst.(*ir.InstFAdd) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFAdd, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateSubInst(inst ir.Instruction, old *ast.SubInst) (*ir.InstSub, error) { + i, ok := inst.(*ir.InstSub) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSub, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFSubInst(inst ir.Instruction, old *ast.FSubInst) (*ir.InstFSub, error) { + i, ok := inst.(*ir.InstFSub) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFSub, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateMulInst(inst ir.Instruction, old *ast.MulInst) (*ir.InstMul, error) { + i, ok := inst.(*ir.InstMul) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstMul, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFMulInst(inst ir.Instruction, old *ast.FMulInst) (*ir.InstFMul, error) { + i, ok := inst.(*ir.InstFMul) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFMul, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateUDivInst(inst ir.Instruction, old *ast.UDivInst) (*ir.InstUDiv, error) { + i, ok := inst.(*ir.InstUDiv) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUDiv, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateSDivInst(inst ir.Instruction, old *ast.SDivInst) (*ir.InstSDiv, error) { + i, ok := inst.(*ir.InstSDiv) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSDiv, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFDivInst(inst ir.Instruction, old *ast.FDivInst) (*ir.InstFDiv, error) { + i, ok := inst.(*ir.InstFDiv) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFDiv, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateURemInst(inst ir.Instruction, old *ast.URemInst) (*ir.InstURem, error) { + i, ok := inst.(*ir.InstURem) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstURem, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateSRemInst(inst ir.Instruction, old *ast.SRemInst) (*ir.InstSRem, error) { + i, ok := inst.(*ir.InstSRem) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSRem, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFRemInst(inst ir.Instruction, old *ast.FRemInst) (*ir.InstFRem, error) { + i, ok := inst.(*ir.InstFRem) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFRem, got %T", inst)) + } + // TODO: implement + return i, nil +} + // --- [ Bitwise instructions ] ------------------------------------------------ // ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateShlInst(inst ir.Instruction, old *ast.ShlInst) (*ir.InstShl, error) { + i, ok := inst.(*ir.InstShl) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShl, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateLShrInst(inst ir.Instruction, old *ast.LShrInst) (*ir.InstLShr, error) { + i, ok := inst.(*ir.InstLShr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLShr, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateAShrInst(inst ir.Instruction, old *ast.AShrInst) (*ir.InstAShr, error) { + i, ok := inst.(*ir.InstAShr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAShr, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateAndInst(inst ir.Instruction, old *ast.AndInst) (*ir.InstAnd, error) { + i, ok := inst.(*ir.InstAnd) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAnd, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateOrInst(inst ir.Instruction, old *ast.OrInst) (*ir.InstOr, error) { + i, ok := inst.(*ir.InstOr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstOr, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateXorInst(inst ir.Instruction, old *ast.XorInst) (*ir.InstXor, error) { + i, ok := inst.(*ir.InstXor) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstXor, got %T", inst)) + } + // TODO: implement + return i, nil +} + // --- [ Vector instructions ] ------------------------------------------------- // ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateExtractElementInst(inst ir.Instruction, old *ast.ExtractElementInst) (*ir.InstExtractElement, error) { + i, ok := inst.(*ir.InstExtractElement) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstExtractElement, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateInsertElementInst(inst ir.Instruction, old *ast.InsertElementInst) (*ir.InstInsertElement, error) { + i, ok := inst.(*ir.InstInsertElement) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstInsertElement, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateShuffleVectorInst(inst ir.Instruction, old *ast.ShuffleVectorInst) (*ir.InstShuffleVector, error) { + i, ok := inst.(*ir.InstShuffleVector) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShuffleVector, got %T", inst)) + } + // TODO: implement + return i, nil +} + // --- [ Aggregate instructions ] ---------------------------------------------- // ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateExtractValueInst(inst ir.Instruction, old *ast.ExtractValueInst) (*ir.InstExtractValue, error) { + i, ok := inst.(*ir.InstExtractValue) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstExtractValue, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateInsertValueInst(inst ir.Instruction, old *ast.InsertValueInst) (*ir.InstInsertValue, error) { + i, ok := inst.(*ir.InstInsertValue) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstInsertValue, got %T", inst)) + } + // TODO: implement + return i, nil +} + // --- [ Memory instructions ] ------------------------------------------------- // ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateAllocaInst(inst ir.Instruction, old *ast.AllocaInst) (*ir.InstAlloca, error) { + i, ok := inst.(*ir.InstAlloca) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAlloca, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateLoadInst(inst ir.Instruction, old *ast.LoadInst) (*ir.InstLoad, error) { + i, ok := inst.(*ir.InstLoad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLoad, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateStoreInst(inst ir.Instruction, old *ast.StoreInst) (*ir.InstStore, error) { + i, ok := inst.(*ir.InstStore) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstStore, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFenceInst(inst ir.Instruction, old *ast.FenceInst) (*ir.InstFence, error) { + i, ok := inst.(*ir.InstFence) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFence, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateCmpXchgInst(inst ir.Instruction, old *ast.CmpXchgInst) (*ir.InstCmpXchg, error) { + i, ok := inst.(*ir.InstCmpXchg) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCmpXchg, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateAtomicRMWInst(inst ir.Instruction, old *ast.AtomicRMWInst) (*ir.InstAtomicRMW, error) { + i, ok := inst.(*ir.InstAtomicRMW) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAtomicRMW, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateGetElementPtrInst(inst ir.Instruction, old *ast.GetElementPtrInst) (*ir.InstGetElementPtr, error) { + i, ok := inst.(*ir.InstGetElementPtr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstGetElementPtr, got %T", inst)) + } + // TODO: implement + return i, nil +} + // --- [ Conversion instructions ] --------------------------------------------- // ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateTruncInst(inst ir.Instruction, old *ast.TruncInst) (*ir.InstTrunc, error) { + i, ok := inst.(*ir.InstTrunc) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstTrunc, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateZExtInst(inst ir.Instruction, old *ast.ZExtInst) (*ir.InstZExt, error) { + i, ok := inst.(*ir.InstZExt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstZExt, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateSExtInst(inst ir.Instruction, old *ast.SExtInst) (*ir.InstSExt, error) { + i, ok := inst.(*ir.InstSExt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSExt, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFPTruncInst(inst ir.Instruction, old *ast.FPTruncInst) (*ir.InstFPTrunc, error) { + i, ok := inst.(*ir.InstFPTrunc) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPTrunc, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFPExtInst(inst ir.Instruction, old *ast.FPExtInst) (*ir.InstFPExt, error) { + i, ok := inst.(*ir.InstFPExt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPExt, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFPToUIInst(inst ir.Instruction, old *ast.FPToUIInst) (*ir.InstFPToUI, error) { + i, ok := inst.(*ir.InstFPToUI) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPToUI, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFPToSIInst(inst ir.Instruction, old *ast.FPToSIInst) (*ir.InstFPToSI, error) { + i, ok := inst.(*ir.InstFPToSI) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPToSI, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateUIToFPInst(inst ir.Instruction, old *ast.UIToFPInst) (*ir.InstUIToFP, error) { + i, ok := inst.(*ir.InstUIToFP) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUIToFP, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateSIToFPInst(inst ir.Instruction, old *ast.SIToFPInst) (*ir.InstSIToFP, error) { + i, ok := inst.(*ir.InstSIToFP) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSIToFP, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translatePtrToIntInst(inst ir.Instruction, old *ast.PtrToIntInst) (*ir.InstPtrToInt, error) { + i, ok := inst.(*ir.InstPtrToInt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPtrToInt, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateIntToPtrInst(inst ir.Instruction, old *ast.IntToPtrInst) (*ir.InstIntToPtr, error) { + i, ok := inst.(*ir.InstIntToPtr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstIntToPtr, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateBitCastInst(inst ir.Instruction, old *ast.BitCastInst) (*ir.InstBitCast, error) { + i, ok := inst.(*ir.InstBitCast) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstBitCast, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateAddrSpaceCastInst(inst ir.Instruction, old *ast.AddrSpaceCastInst) (*ir.InstAddrSpaceCast, error) { + i, ok := inst.(*ir.InstAddrSpaceCast) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAddrSpaceCast, got %T", inst)) + } + // TODO: implement + return i, nil +} + // --- [ Other instructions ] -------------------------------------------------- // ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateICmpInst(inst ir.Instruction, old *ast.ICmpInst) (*ir.InstICmp, error) { + i, ok := inst.(*ir.InstICmp) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstICmp, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateFCmpInst(inst ir.Instruction, old *ast.FCmpInst) (*ir.InstFCmp, error) { + i, ok := inst.(*ir.InstFCmp) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFCmp, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translatePhiInst(inst ir.Instruction, old *ast.PhiInst) (*ir.InstPhi, error) { + i, ok := inst.(*ir.InstPhi) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPhi, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateSelectInst(inst ir.Instruction, old *ast.SelectInst) (*ir.InstSelect, error) { + i, ok := inst.(*ir.InstSelect) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSelect, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateCallInst(inst ir.Instruction, old *ast.CallInst) (*ir.InstCall, error) { + i, ok := inst.(*ir.InstCall) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCall, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateVAArgInst(inst ir.Instruction, old *ast.VAArgInst) (*ir.InstVAArg, error) { + i, ok := inst.(*ir.InstVAArg) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstVAArg, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateLandingPadInst(inst ir.Instruction, old *ast.LandingPadInst) (*ir.InstLandingPad, error) { + i, ok := inst.(*ir.InstLandingPad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLandingPad, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +func (fgen *funcGen) translateCatchPadInst(inst ir.Instruction, old *ast.CatchPadInst) (*ir.InstCatchPad, error) { + i, ok := inst.(*ir.InstCatchPad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCatchPad, got %T", inst)) + } + // TODO: implement + return i, nil +} + // ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) translateCleanupPadInst(inst ir.Instruction, old *ast.CleanupPadInst) (*ir.InstCleanupPad, error) { + i, ok := inst.(*ir.InstCleanupPad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCleanupPad, got %T", inst)) + } + // TODO: implement + return i, nil +} From 4a8c09b31644c883fb00181f63560c5a542917c4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 03:09:01 +0200 Subject: [PATCH 32/70] asm: add TODO to rename translateFoo to astToIRFoo --- asm/local.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/asm/local.go b/asm/local.go index 3ee1058f..692eeb7b 100644 --- a/asm/local.go +++ b/asm/local.go @@ -1,3 +1,5 @@ +// TODO: rename from translateFoo to astToIRFoo. + // Problems to solve. // // phi instructions can reference local variables defined in basic blocks not From 1c27983fc9f97fe184e04cba04333cee14017793 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 03:23:51 +0200 Subject: [PATCH 33/70] asm: add scaffolding for translating terminators --- asm/local.go | 136 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/asm/local.go b/asm/local.go index 692eeb7b..ca26dcdf 100644 --- a/asm/local.go +++ b/asm/local.go @@ -113,10 +113,16 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e } } } - // TODO: implement. - panic("not yet implemented") // Translate terminators. - // TODO: implement. + for i, block := range f.Blocks { + old := bbs[i].Term() + term, err := fgen.translateTerm(old) + if err != nil { + return nil, errors.WithStack(err) + } + block.Term = term + } + return fgen.ls, nil } // newIRInst returns a new IR instruction (without body) based on the given AST @@ -237,7 +243,11 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I case *ast.FCmpInst: return &ir.InstFCmp{LocalName: name}, nil case *ast.PhiInst: - return &ir.InstPhi{LocalName: name}, nil + typ, err := fgen.gen.irType(old.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstPhi{LocalName: name, Typ: typ}, nil case *ast.SelectInst: return &ir.InstSelect{LocalName: name}, nil case *ast.CallInst: @@ -1054,3 +1064,121 @@ func (fgen *funcGen) translateCleanupPadInst(inst ir.Instruction, old *ast.Clean // TODO: implement return i, nil } + +// === [ Terminators ] ========================================================= + +// translateTerm translates the AST terminator into an equivalent IR terminator. +func (fgen *funcGen) translateTerm(old ast.Terminator) (ir.Terminator, error) { + switch old := old.(type) { + case *ast.RetTerm: + return fgen.translateRetTerm(old) + case *ast.BrTerm: + return fgen.translateBrTerm(old) + case *ast.CondBrTerm: + return fgen.translateCondBrTerm(old) + case *ast.SwitchTerm: + return fgen.translateSwitchTerm(old) + case *ast.IndirectBrTerm: + return fgen.translateIndirectBrTerm(old) + case *ast.InvokeTerm: + return fgen.translateInvokeTerm(old) + case *ast.ResumeTerm: + return fgen.translateResumeTerm(old) + case *ast.CatchSwitchTerm: + return fgen.translateCatchSwitchTerm(old) + case *ast.CatchRetTerm: + return fgen.translateCatchRetTerm(old) + case *ast.CleanupRetTerm: + return fgen.translateCleanupRetTerm(old) + case *ast.UnreachableTerm: + return fgen.translateUnreachableTerm(old) + default: + panic(fmt.Errorf("support for AST terminator type %T not yet implemented", old)) + } +} + +// --- [ ret ] ----------------------------------------------------------------- + +func (fgen *funcGen) translateRetTerm(old *ast.RetTerm) (*ir.TermRet, error) { + term := &ir.TermRet{} + // TODO: implement + return term, nil +} + +// --- [ br ] ------------------------------------------------------------------ + +func (fgen *funcGen) translateBrTerm(old *ast.BrTerm) (*ir.TermBr, error) { + term := &ir.TermBr{} + // TODO: implement + return term, nil +} + +func (fgen *funcGen) translateCondBrTerm(old *ast.CondBrTerm) (*ir.TermCondBr, error) { + term := &ir.TermCondBr{} + // TODO: implement + return term, nil +} + +// --- [ switch ] -------------------------------------------------------------- + +func (fgen *funcGen) translateSwitchTerm(old *ast.SwitchTerm) (*ir.TermSwitch, error) { + term := &ir.TermSwitch{} + // TODO: implement + return term, nil +} + +// --- [ indirectbr ] ---------------------------------------------------------- + +func (fgen *funcGen) translateIndirectBrTerm(old *ast.IndirectBrTerm) (*ir.TermIndirectBr, error) { + term := &ir.TermIndirectBr{} + // TODO: implement + return term, nil +} + +// --- [ invoke ] -------------------------------------------------------------- + +func (fgen *funcGen) translateInvokeTerm(old *ast.InvokeTerm) (*ir.TermInvoke, error) { + term := &ir.TermInvoke{} + // TODO: implement + return term, nil +} + +// --- [ resume ] -------------------------------------------------------------- + +func (fgen *funcGen) translateResumeTerm(old *ast.ResumeTerm) (*ir.TermResume, error) { + term := &ir.TermResume{} + // TODO: implement + return term, nil +} + +// --- [ catchswitch ] --------------------------------------------------------- + +func (fgen *funcGen) translateCatchSwitchTerm(old *ast.CatchSwitchTerm) (*ir.TermCatchSwitch, error) { + term := &ir.TermCatchSwitch{} + // TODO: implement + return term, nil +} + +// --- [ catchret ] ------------------------------------------------------------ + +func (fgen *funcGen) translateCatchRetTerm(old *ast.CatchRetTerm) (*ir.TermCatchRet, error) { + term := &ir.TermCatchRet{} + // TODO: implement + return term, nil +} + +// --- [ cleanupret ] ---------------------------------------------------------- + +func (fgen *funcGen) translateCleanupRetTerm(old *ast.CleanupRetTerm) (*ir.TermCleanupRet, error) { + term := &ir.TermCleanupRet{} + // TODO: implement + return term, nil +} + +// --- [ unreachable ] --------------------------------------------------------- + +func (fgen *funcGen) translateUnreachableTerm(old *ast.UnreachableTerm) (*ir.TermUnreachable, error) { + term := &ir.TermUnreachable{} + // TODO: implement + return term, nil +} From d88034cea2ed9212b99e30abad8b77f61c8aad64 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 19:53:44 +0200 Subject: [PATCH 34/70] asm: handle packed struct types --- asm/ll/ll.tm | 4 +--- asm/type.go | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 8c746ea6..fb543691 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1157,11 +1157,9 @@ ArrayType -> ArrayType # ::= '<' '{' '}' '>' # ::= '<' '{' Type (',' Type)* '}' '>' -# TODO: Figure out how to represent packed; ref: https://github.com/inspirer/textmapper/issues/14 - StructType -> StructType : '{' Fields=(Type separator ',')+? '}' - | '<' '{' Fields=(Type separator ',')+? '}' '>' + | '<' '{' Fields=(Type separator ',')+? '}' '>' -> PackedStructType ; OpaqueType -> OpaqueType diff --git a/asm/type.go b/asm/type.go index e73e8f9e..67804140 100644 --- a/asm/type.go +++ b/asm/type.go @@ -99,7 +99,7 @@ func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type func newIRType(alias string, old ast.LlvmNode, index map[string]ast.LlvmNode, track map[string]bool) (types.Type, error) { switch old := old.(type) { case *ast.OpaqueType: - return &types.StructType{Alias: alias, Opaque: true}, nil + return &types.StructType{Alias: alias}, nil case *ast.ArrayType: return &types.ArrayType{Alias: alias}, nil case *ast.FloatType: @@ -131,6 +131,8 @@ func newIRType(alias string, old ast.LlvmNode, index map[string]ast.LlvmNode, tr return &types.PointerType{Alias: alias}, nil case *ast.StructType: return &types.StructType{Alias: alias}, nil + case *ast.PackedStructType: + return &types.StructType{Alias: alias}, nil case *ast.TokenType: return &types.TokenType{Alias: alias}, nil case *ast.VectorType: @@ -171,6 +173,8 @@ func (gen *generator) translateType(t types.Type, old ast.LlvmNode) (types.Type, return gen.translatePointerType(t, old) case *ast.StructType: return gen.translateStructType(t, old) + case *ast.PackedStructType: + return gen.translatePackedStructType(t, old) case *ast.TokenType: return gen.translateTokenType(t, old) case *ast.VectorType: @@ -441,7 +445,8 @@ func (gen *generator) translateOpaqueType(t types.Type, old *ast.OpaqueType) (ty // possible, and would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR type for AST opaque type; expected *types.StructType, got %T", t)) } - // nothing to do. + // Opaque. + typ.Opaque = true return typ, nil } @@ -455,7 +460,30 @@ func (gen *generator) translateStructType(t types.Type, old *ast.StructType) (ty panic(fmt.Errorf("invalid IR type for AST struct type; expected *types.StructType, got %T", t)) } // Packed. - // TODO: Figure out how to represent packed in grammar. + // Fields. + for _, f := range old.Fields() { + field, err := gen.irType(f) + if err != nil { + return nil, errors.WithStack(err) + } + typ.Fields = append(typ.Fields, field) + } + // struct body now present. + typ.Opaque = false + return typ, nil +} + +func (gen *generator) translatePackedStructType(t types.Type, old *ast.PackedStructType) (types.Type, error) { + typ, ok := t.(*types.StructType) + if t == nil { + typ = &types.StructType{} + } else if !ok { + // NOTE: Panic instead of returning error as this case should not be + // possible, and would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR type for AST struct type; expected *types.StructType, got %T", t)) + } + // Packed. + typ.Packed = true // Fields. for _, f := range old.Fields() { field, err := gen.irType(f) From 9e56b44875bb40ece77538a461d96b1844781a81 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 20 Oct 2018 20:09:32 +0200 Subject: [PATCH 35/70] asm: merge production rules for ArrayConst and CharArrayConst The AST still looks the same, through the use of arrow notation --- asm/ll/ll.tm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index fb543691..090a3c73 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1230,7 +1230,6 @@ Constant -> Constant | NoneConst | StructConst | ArrayConst - | CharArrayConst | VectorConst | ZeroInitializerConst # @42 @@ -1315,11 +1314,9 @@ StructConst -> StructConst ArrayConst -> ArrayConst : '[' Elems=(TypeConst separator ',')* ']' + | 'c' Val=StringLit -> CharArrayConst ; -CharArrayConst -> CharArrayConst - : 'c' Val=StringLit -; # --- [ Vector Constants ] ----------------------------------------------------- From e233ae1628c5be4054fb5e0173f5b3b42ae1a699 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sun, 21 Oct 2018 01:38:26 +0200 Subject: [PATCH 36/70] asm: translate binary and bitwise instructions --- asm/local.go | 299 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 280 insertions(+), 19 deletions(-) diff --git a/asm/local.go b/asm/local.go index ca26dcdf..cf418c7f 100644 --- a/asm/local.go +++ b/asm/local.go @@ -428,15 +428,21 @@ func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAdd, got %T", inst)) } - x, err := fgen.astToIRTypeValue(old.X()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { return nil, errors.WithStack(err) } - y, err := fgen.astToIRValue(x.Type(), old.Y()) + x, err := fgen.astToIRTypeValue(old.X()) if err != nil { return nil, errors.WithStack(err) } i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } i.Y = y return i, nil } @@ -449,7 +455,22 @@ func (fgen *funcGen) translateFAddInst(inst ir.Instruction, old *ast.FAddInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFAdd, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -461,7 +482,22 @@ func (fgen *funcGen) translateSubInst(inst ir.Instruction, old *ast.SubInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSub, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -473,7 +509,22 @@ func (fgen *funcGen) translateFSubInst(inst ir.Instruction, old *ast.FSubInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFSub, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -485,7 +536,22 @@ func (fgen *funcGen) translateMulInst(inst ir.Instruction, old *ast.MulInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstMul, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -497,7 +563,22 @@ func (fgen *funcGen) translateFMulInst(inst ir.Instruction, old *ast.FMulInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFMul, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -509,7 +590,22 @@ func (fgen *funcGen) translateUDivInst(inst ir.Instruction, old *ast.UDivInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUDiv, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -521,7 +617,22 @@ func (fgen *funcGen) translateSDivInst(inst ir.Instruction, old *ast.SDivInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSDiv, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -533,7 +644,22 @@ func (fgen *funcGen) translateFDivInst(inst ir.Instruction, old *ast.FDivInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFDiv, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -545,7 +671,22 @@ func (fgen *funcGen) translateURemInst(inst ir.Instruction, old *ast.URemInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstURem, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -557,7 +698,22 @@ func (fgen *funcGen) translateSRemInst(inst ir.Instruction, old *ast.SRemInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSRem, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -569,7 +725,22 @@ func (fgen *funcGen) translateFRemInst(inst ir.Instruction, old *ast.FRemInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFRem, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -583,7 +754,22 @@ func (fgen *funcGen) translateShlInst(inst ir.Instruction, old *ast.ShlInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShl, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -595,7 +781,22 @@ func (fgen *funcGen) translateLShrInst(inst ir.Instruction, old *ast.LShrInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLShr, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -607,7 +808,22 @@ func (fgen *funcGen) translateAShrInst(inst ir.Instruction, old *ast.AShrInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAShr, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -619,7 +835,22 @@ func (fgen *funcGen) translateAndInst(inst ir.Instruction, old *ast.AndInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAnd, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -631,7 +862,22 @@ func (fgen *funcGen) translateOrInst(inst ir.Instruction, old *ast.OrInst) (*ir. // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstOr, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } @@ -643,7 +889,22 @@ func (fgen *funcGen) translateXorInst(inst ir.Instruction, old *ast.XorInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstXor, got %T", inst)) } - // TODO: implement + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y return i, nil } From 3172f552c54466c32b84dd79d8d2fb915e8b919d Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sun, 21 Oct 2018 02:00:09 +0200 Subject: [PATCH 37/70] grammar: add OverflowFlag production rule --- asm/ll/ll.tm | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 090a3c73..da984f2f 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1429,7 +1429,7 @@ ConstantExpr -> ConstantExpr # ref: ParseValID AddExpr -> AddExpr - : 'add' OverflowFlags '(' X=TypeConst ',' Y=TypeConst ')' + : 'add' OverflowFlags=OverflowFlag* '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1445,7 +1445,7 @@ FAddExpr -> FAddExpr # ref: ParseValID SubExpr -> SubExpr - : 'sub' OverflowFlags '(' X=TypeConst ',' Y=TypeConst ')' + : 'sub' OverflowFlags=OverflowFlag* '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1461,7 +1461,7 @@ FSubExpr -> FSubExpr # ref: ParseValID MulExpr -> MulExpr - : 'mul' OverflowFlags '(' X=TypeConst ',' Y=TypeConst ')' + : 'mul' OverflowFlags=OverflowFlag* '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1529,7 +1529,7 @@ FRemExpr -> FRemExpr # ref: ParseValID ShlExpr -> ShlExpr - : 'shl' OverflowFlags '(' X=TypeConst ',' Y=TypeConst ')' + : 'shl' OverflowFlags=OverflowFlag* '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1885,7 +1885,7 @@ ValueInstruction -> ValueInstruction # ::= ArithmeticOps TypeAndValue ',' Value AddInst -> AddInst - : 'add' OverflowFlags X=TypeValue ',' Y=Value InstMetadata + : 'add' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1909,7 +1909,7 @@ FAddInst -> FAddInst # ::= ArithmeticOps TypeAndValue ',' Value SubInst -> SubInst - : 'sub' OverflowFlags X=TypeValue ',' Y=Value InstMetadata + : 'sub' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1933,7 +1933,7 @@ FSubInst -> FSubInst # ::= ArithmeticOps TypeAndValue ',' Value MulInst -> MulInst - : 'mul' OverflowFlags X=TypeValue ',' Y=Value InstMetadata + : 'mul' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2031,7 +2031,7 @@ FRemInst -> FRemInst # ::= ArithmeticOps TypeAndValue ',' Value ShlInst -> ShlInst - : 'shl' OverflowFlags X=TypeValue ',' Y=Value InstMetadata + : 'shl' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -4558,8 +4558,9 @@ OperandBundle -> OperandBundle : Tag=StringLit '(' Inputs=(TypeValue separator ',')* ')' ; -OverflowFlags -> OverflowFlags - : ('nsw' | 'nuw')* +OverflowFlag -> OverflowFlag + : 'nsw' + | 'nuw' ; # ref: ParseArgumentList From 3d9492e85cfac912d2b38229a5f4ad7cb55272fc Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sun, 21 Oct 2018 02:18:38 +0200 Subject: [PATCH 38/70] asm: translate overflow flags and fast math flags --- asm/helper.go | 77 +++++++++++++++++++++++++++++++++++++++++++++------ asm/local.go | 23 +++++++++++++++ 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index 4605c8f9..8983b713 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -169,6 +169,43 @@ func irExternallyInitialized(n *ast.ExternallyInitialized) bool { return n.Text() == "externally_initialized" } +// irFastMathFlags returns the IR fast math flags corresponding to the given +// optional AST fast math flags. +func irFastMathFlags(ns []ast.FastMathFlag) []ll.FastMathFlag { + var flags []ll.FastMathFlag + for _, n := range ns { + flag := irFastMathFlag(n) + flags = append(flags, flag) + } + return flags +} + +// irFastMathFlag returns the IR fast math flag corresponding to the given +// optional AST fast math flag. +func irFastMathFlag(n ast.FastMathFlag) ll.FastMathFlag { + text := n.Text() + switch text { + case "afn": + return ll.FastMathFlagAFn + case "arcp": + return ll.FastMathFlagARcp + case "contract": + return ll.FastMathFlagContract + case "fast": + return ll.FastMathFlagFast + case "ninf": + return ll.FastMathFlagNInf + case "nnan": + return ll.FastMathFlagNNaN + case "nsz": + return ll.FastMathFlagNSZ + case "reassoc": + return ll.FastMathFlagReassoc + default: + panic(fmt.Errorf("support for fast math flag %q not yet implemented", text)) + } +} + // irImmutable returns the immutable (constant or global) boolean corresponding // to the given optional AST immutable. func irImmutable(n ast.Immutable) bool { @@ -190,12 +227,18 @@ func irInBounds(n *ast.InBounds) bool { return n.Text() == "inbounds" } +// irInRange returns the in-range boolean corresponding to the given optional +// AST in-range. +func irInRange(n *ast.InRange) bool { + // TODO: check why InRange is non-nil, when reduced as \empty. + return n.Text() == "inrange" +} + // irLinkage returns the IR linkage corresponding to the given optional AST // linkage. func irLinkage(text string) ll.Linkage { // TODO: when ExternLinkage and Linkage are merged in grammar, update // irLinkage to take `n *ast.Linkage` instead of `text string`. - //text := n.Text() switch text { case "": @@ -228,6 +271,31 @@ func irLinkage(text string) ll.Linkage { } } +// irOverflowFlags returns the IR overflow flags corresponding to the given +// optional AST overflow flags. +func irOverflowFlags(ns []ast.OverflowFlag) []ll.OverflowFlag { + var flags []ll.OverflowFlag + for _, n := range ns { + flag := irOverflowFlag(n) + flags = append(flags, flag) + } + return flags +} + +// irOverflowFlag returns the IR overflow flag corresponding to the given +// optional AST overflow flag. +func irOverflowFlag(n ast.OverflowFlag) ll.OverflowFlag { + text := n.Text() + switch text { + case "nsw": + return ll.OverflowFlagNSW + case "nuw": + return ll.OverflowFlagNUW + default: + panic(fmt.Errorf("support for overflow flag %q not yet implemented", text)) + } +} + // irPreemption returns the IR preemption corresponding to the given optional // AST preemption. func irPreemption(n *ast.Preemption) ll.Preemption { @@ -245,13 +313,6 @@ func irPreemption(n *ast.Preemption) ll.Preemption { } } -// irInRange returns the in-range boolean corresponding to the given optional -// AST in-range. -func irInRange(n *ast.InRange) bool { - // TODO: check why InRange is non-nil, when reduced as \empty. - return n.Text() == "inrange" -} - // irSelectionKind returns the IR Comdat selection kind corresponding to the // given optional AST Comdat selection kind. func irSelectionKind(n *ast.SelectionKind) ll.SelectionKind { diff --git a/asm/local.go b/asm/local.go index cf418c7f..d15a90a6 100644 --- a/asm/local.go +++ b/asm/local.go @@ -428,7 +428,10 @@ func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAdd, got %T", inst)) } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) // X operand. + // TODO: remove xType if types are added during indexing; then use x.Type() instead. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { return nil, errors.WithStack(err) @@ -455,6 +458,8 @@ func (fgen *funcGen) translateFAddInst(inst ir.Instruction, old *ast.FAddInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFAdd, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -482,6 +487,8 @@ func (fgen *funcGen) translateSubInst(inst ir.Instruction, old *ast.SubInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSub, got %T", inst)) } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -509,6 +516,8 @@ func (fgen *funcGen) translateFSubInst(inst ir.Instruction, old *ast.FSubInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFSub, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -536,6 +545,8 @@ func (fgen *funcGen) translateMulInst(inst ir.Instruction, old *ast.MulInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstMul, got %T", inst)) } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -563,6 +574,8 @@ func (fgen *funcGen) translateFMulInst(inst ir.Instruction, old *ast.FMulInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFMul, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -644,6 +657,8 @@ func (fgen *funcGen) translateFDivInst(inst ir.Instruction, old *ast.FDivInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFDiv, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -725,6 +740,8 @@ func (fgen *funcGen) translateFRemInst(inst ir.Instruction, old *ast.FRemInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFRem, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -754,6 +771,8 @@ func (fgen *funcGen) translateShlInst(inst ir.Instruction, old *ast.ShlInst) (*i // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShl, got %T", inst)) } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) // X operand. xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { @@ -1238,6 +1257,8 @@ func (fgen *funcGen) translateFCmpInst(inst ir.Instruction, old *ast.FCmpInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFCmp, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // TODO: implement return i, nil } @@ -1274,6 +1295,8 @@ func (fgen *funcGen) translateCallInst(inst ir.Instruction, old *ast.CallInst) ( // NOTE: panic since this would indicate a bug in the implementation. panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCall, got %T", inst)) } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // TODO: implement return i, nil } From afa3abd1aaf5d0ca22cbab2f8b55ffa5b452e99a Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sun, 21 Oct 2018 16:44:01 +0200 Subject: [PATCH 39/70] grammar: cmpxchg and atomicrmw are both value instructions --- asm/ll/ll.tm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index da984f2f..06eb2981 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1803,8 +1803,6 @@ Instruction -> Instruction # Instructions not producing values. : StoreInst | FenceInst - | CmpXchgInst - | AtomicRMWInst # Instructions producing values. | LocalDef | ValueInstruction @@ -1847,6 +1845,8 @@ ValueInstruction -> ValueInstruction # Memory instructions | AllocaInst | LoadInst + | CmpXchgInst + | AtomicRMWInst | GetElementPtrInst # Conversion instructions | TruncInst From 75544e93c2af35ec223f2813d622e93e4c72d43e Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 01:12:14 +0200 Subject: [PATCH 40/70] asm: make cmpxchg and atomicrmw value instructions --- asm/local.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/asm/local.go b/asm/local.go index d15a90a6..9c9c9fd5 100644 --- a/asm/local.go +++ b/asm/local.go @@ -140,10 +140,6 @@ func (fgen *funcGen) newIRInst(old ast.Instruction) (ir.Instruction, error) { return &ir.InstStore{}, nil case *ast.FenceInst: return &ir.InstFence{}, nil - case *ast.CmpXchgInst: - return &ir.InstCmpXchg{}, nil - case *ast.AtomicRMWInst: - return &ir.InstAtomicRMW{}, nil default: panic(fmt.Errorf("support for AST instruction type %T not yet implemented", old)) } @@ -208,6 +204,10 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I return &ir.InstAlloca{LocalName: name}, nil case *ast.LoadInst: return &ir.InstLoad{LocalName: name}, nil + case *ast.CmpXchgInst: + return &ir.InstCmpXchg{LocalName: name}, nil + case *ast.AtomicRMWInst: + return &ir.InstAtomicRMW{LocalName: name}, nil case *ast.GetElementPtrInst: return &ir.InstGetElementPtr{LocalName: name}, nil // Conversion instructions @@ -297,10 +297,6 @@ func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir return fgen.translateStoreInst(inst, old) case *ast.FenceInst: return fgen.translateFenceInst(inst, old) - case *ast.CmpXchgInst: - return fgen.translateCmpXchgInst(inst, old) - case *ast.AtomicRMWInst: - return fgen.translateAtomicRMWInst(inst, old) default: panic(fmt.Errorf("support for instruction type %T not yet implemented", old)) } @@ -365,6 +361,10 @@ func (fgen *funcGen) translateValueInst(inst ir.Instruction, old ast.ValueInstru return fgen.translateAllocaInst(inst, old) case *ast.LoadInst: return fgen.translateLoadInst(inst, old) + case *ast.CmpXchgInst: + return fgen.translateCmpXchgInst(inst, old) + case *ast.AtomicRMWInst: + return fgen.translateAtomicRMWInst(inst, old) case *ast.GetElementPtrInst: return fgen.translateGetElementPtrInst(inst, old) // Conversion instructions From 675d5e6a8a1f52bb910cb9c1fb127f0cccc5134d Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 01:18:33 +0200 Subject: [PATCH 41/70] asm: add type to binary instructions during local index --- asm/global.go | 4 +- asm/local.go | 116 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/asm/global.go b/asm/global.go index ddbfdfe7..da9eef5d 100644 --- a/asm/global.go +++ b/asm/global.go @@ -60,7 +60,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant } // Create corresponding IR global variables and functions (without bodies but - // with a type). + // with type). gen.gs = make(map[string]ir.Constant) for name, old := range index { g, err := gen.newGlobal(name, old) @@ -104,7 +104,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant return gen.gs, nil } -// newGlobal returns a new IR value (without body but with a type) based on the +// newGlobal returns a new IR value (without body but with type) based on the // given AST global variable or function. func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, error) { switch old := old.(type) { diff --git a/asm/local.go b/asm/local.go index 9c9c9fd5..0dedb5c4 100644 --- a/asm/local.go +++ b/asm/local.go @@ -125,8 +125,8 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e return fgen.ls, nil } -// newIRInst returns a new IR instruction (without body) based on the given AST -// instruction. +// newIRInst returns a new IR instruction (without body but with type) based on +// the given AST instruction. func (fgen *funcGen) newIRInst(old ast.Instruction) (ir.Instruction, error) { switch old := old.(type) { // Value instruction. @@ -145,48 +145,120 @@ func (fgen *funcGen) newIRInst(old ast.Instruction) (ir.Instruction, error) { } } -// newIRValueInst returns a new IR value instruction (without body) based on the -// given AST value instruction. +// newIRValueInst returns a new IR value instruction (without body but with +// type) based on the given AST value instruction. func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.Instruction, error) { switch old := old.(type) { // Binary instructions case *ast.AddInst: - return &ir.InstAdd{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstAdd{LocalName: name, Typ: typ}, nil case *ast.FAddInst: - return &ir.InstFAdd{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFAdd{LocalName: name, Typ: typ}, nil case *ast.SubInst: - return &ir.InstSub{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstSub{LocalName: name, Typ: typ}, nil case *ast.FSubInst: - return &ir.InstFSub{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFSub{LocalName: name, Typ: typ}, nil case *ast.MulInst: - return &ir.InstMul{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstMul{LocalName: name, Typ: typ}, nil case *ast.FMulInst: - return &ir.InstFMul{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFMul{LocalName: name, Typ: typ}, nil case *ast.UDivInst: - return &ir.InstUDiv{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstUDiv{LocalName: name, Typ: typ}, nil case *ast.SDivInst: - return &ir.InstSDiv{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstSDiv{LocalName: name, Typ: typ}, nil case *ast.FDivInst: - return &ir.InstFDiv{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFDiv{LocalName: name, Typ: typ}, nil case *ast.URemInst: - return &ir.InstURem{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstURem{LocalName: name, Typ: typ}, nil case *ast.SRemInst: - return &ir.InstSRem{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstSRem{LocalName: name, Typ: typ}, nil case *ast.FRemInst: - return &ir.InstFRem{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFRem{LocalName: name, Typ: typ}, nil // Bitwise instructions case *ast.ShlInst: - return &ir.InstShl{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstShl{LocalName: name, Typ: typ}, nil case *ast.LShrInst: - return &ir.InstLShr{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstLShr{LocalName: name, Typ: typ}, nil case *ast.AShrInst: - return &ir.InstAShr{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstAShr{LocalName: name, Typ: typ}, nil case *ast.AndInst: - return &ir.InstAnd{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstAnd{LocalName: name, Typ: typ}, nil case *ast.OrInst: - return &ir.InstOr{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstOr{LocalName: name, Typ: typ}, nil case *ast.XorInst: - return &ir.InstXor{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstXor{LocalName: name, Typ: typ}, nil // Vector instructions case *ast.ExtractElementInst: return &ir.InstExtractElement{LocalName: name}, nil From 7000db12b63b3dcbce2dc655899e724070a5e7e7 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 02:02:03 +0200 Subject: [PATCH 42/70] asm: store type of alloca, load and cmpxchg in newIRValueInst --- asm/local.go | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/asm/local.go b/asm/local.go index 0dedb5c4..4057f0f1 100644 --- a/asm/local.go +++ b/asm/local.go @@ -273,11 +273,24 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I return &ir.InstInsertValue{LocalName: name}, nil // Memory instructions case *ast.AllocaInst: - return &ir.InstAlloca{LocalName: name}, nil + elemType, err := fgen.gen.irType(old.ElemType()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstAlloca{LocalName: name, ElemType: elemType}, nil case *ast.LoadInst: - return &ir.InstLoad{LocalName: name}, nil + elemType, err := fgen.gen.irType(old.ElemType()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstLoad{LocalName: name, Typ: elemType}, nil case *ast.CmpXchgInst: - return &ir.InstCmpXchg{LocalName: name}, nil + oldType, err := fgen.gen.irType(old.New().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + typ := types.NewStruct(oldType, types.I8) + return &ir.InstCmpXchg{LocalName: name, Typ: typ}, nil case *ast.AtomicRMWInst: return &ir.InstAtomicRMW{LocalName: name}, nil case *ast.GetElementPtrInst: @@ -503,18 +516,13 @@ func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*i // Overflow flags. i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) // X operand. - // TODO: remove xType if types are added during indexing; then use x.Type() instead. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } x, err := fgen.astToIRTypeValue(old.X()) if err != nil { return nil, errors.WithStack(err) } i.X = x // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) + y, err := fgen.astToIRValue(x.Type(), old.Y()) if err != nil { return nil, errors.WithStack(err) } @@ -533,6 +541,7 @@ func (fgen *funcGen) translateFAddInst(inst ir.Instruction, old *ast.FAddInst) ( // Fast math flags. i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // X operand. + // TODO: remove xType in favour of x.Type(). xType, err := fgen.gen.irType(old.X().Typ()) if err != nil { return nil, errors.WithStack(err) From e7d0e76bc4dc043c3a32ab66e23b66dd8a87bfbd Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 11:15:47 +0200 Subject: [PATCH 43/70] asm: update to use ir/enum --- asm/helper.go | 124 +++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index 8983b713..6e7909dd 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - "github.com/llir/l/ir/ll" + "github.com/llir/l/ir/enum" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" @@ -147,16 +147,16 @@ func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { // irDLLStorageClass returns the IR DLL storage class corresponding to the given // optional AST DLL storage class. -func irDLLStorageClass(n *ast.DLLStorageClass) ll.DLLStorageClass { +func irDLLStorageClass(n *ast.DLLStorageClass) enum.DLLStorageClass { text := n.Text() switch text { case "": // \empty is used when DLL storage class not present. - return ll.DLLStorageClassNone + return enum.DLLStorageClassNone case "dllexport": - return ll.DLLStorageClassDLLExport + return enum.DLLStorageClassDLLExport case "dllimport": - return ll.DLLStorageClassDLLImport + return enum.DLLStorageClassDLLImport default: panic(fmt.Errorf("support for DLL storage class %q not yet implemented", text)) } @@ -171,8 +171,8 @@ func irExternallyInitialized(n *ast.ExternallyInitialized) bool { // irFastMathFlags returns the IR fast math flags corresponding to the given // optional AST fast math flags. -func irFastMathFlags(ns []ast.FastMathFlag) []ll.FastMathFlag { - var flags []ll.FastMathFlag +func irFastMathFlags(ns []ast.FastMathFlag) []enum.FastMathFlag { + var flags []enum.FastMathFlag for _, n := range ns { flag := irFastMathFlag(n) flags = append(flags, flag) @@ -182,25 +182,25 @@ func irFastMathFlags(ns []ast.FastMathFlag) []ll.FastMathFlag { // irFastMathFlag returns the IR fast math flag corresponding to the given // optional AST fast math flag. -func irFastMathFlag(n ast.FastMathFlag) ll.FastMathFlag { +func irFastMathFlag(n ast.FastMathFlag) enum.FastMathFlag { text := n.Text() switch text { case "afn": - return ll.FastMathFlagAFn + return enum.FastMathFlagAFn case "arcp": - return ll.FastMathFlagARcp + return enum.FastMathFlagARcp case "contract": - return ll.FastMathFlagContract + return enum.FastMathFlagContract case "fast": - return ll.FastMathFlagFast + return enum.FastMathFlagFast case "ninf": - return ll.FastMathFlagNInf + return enum.FastMathFlagNInf case "nnan": - return ll.FastMathFlagNNaN + return enum.FastMathFlagNNaN case "nsz": - return ll.FastMathFlagNSZ + return enum.FastMathFlagNSZ case "reassoc": - return ll.FastMathFlagReassoc + return enum.FastMathFlagReassoc default: panic(fmt.Errorf("support for fast math flag %q not yet implemented", text)) } @@ -236,36 +236,36 @@ func irInRange(n *ast.InRange) bool { // irLinkage returns the IR linkage corresponding to the given optional AST // linkage. -func irLinkage(text string) ll.Linkage { +func irLinkage(text string) enum.Linkage { // TODO: when ExternLinkage and Linkage are merged in grammar, update // irLinkage to take `n *ast.Linkage` instead of `text string`. //text := n.Text() switch text { case "": // \empty is used when linkage not present. - return ll.LinkageNone + return enum.LinkageNone case "appending": - return ll.LinkageAppending + return enum.LinkageAppending case "available_externally": - return ll.LinkageAvailableExternally + return enum.LinkageAvailableExternally case "common": - return ll.LinkageCommon + return enum.LinkageCommon case "internal": - return ll.LinkageInternal + return enum.LinkageInternal case "linkonce": - return ll.LinkageLinkOnce + return enum.LinkageLinkOnce case "linkonce_odr": - return ll.LinkageLinkOnceODR + return enum.LinkageLinkOnceODR case "private": - return ll.LinkagePrivate + return enum.LinkagePrivate case "weak": - return ll.LinkageWeak + return enum.LinkageWeak case "weak_odr": - return ll.LinkageWeakODR + return enum.LinkageWeakODR case "external": - return ll.LinkageExternal + return enum.LinkageExternal case "extern_weak": - return ll.LinkageExternWeak + return enum.LinkageExternWeak default: panic(fmt.Errorf("support for linkage %q not yet implemented", text)) } @@ -273,8 +273,8 @@ func irLinkage(text string) ll.Linkage { // irOverflowFlags returns the IR overflow flags corresponding to the given // optional AST overflow flags. -func irOverflowFlags(ns []ast.OverflowFlag) []ll.OverflowFlag { - var flags []ll.OverflowFlag +func irOverflowFlags(ns []ast.OverflowFlag) []enum.OverflowFlag { + var flags []enum.OverflowFlag for _, n := range ns { flag := irOverflowFlag(n) flags = append(flags, flag) @@ -284,13 +284,13 @@ func irOverflowFlags(ns []ast.OverflowFlag) []ll.OverflowFlag { // irOverflowFlag returns the IR overflow flag corresponding to the given // optional AST overflow flag. -func irOverflowFlag(n ast.OverflowFlag) ll.OverflowFlag { +func irOverflowFlag(n ast.OverflowFlag) enum.OverflowFlag { text := n.Text() switch text { case "nsw": - return ll.OverflowFlagNSW + return enum.OverflowFlagNSW case "nuw": - return ll.OverflowFlagNUW + return enum.OverflowFlagNUW default: panic(fmt.Errorf("support for overflow flag %q not yet implemented", text)) } @@ -298,16 +298,16 @@ func irOverflowFlag(n ast.OverflowFlag) ll.OverflowFlag { // irPreemption returns the IR preemption corresponding to the given optional // AST preemption. -func irPreemption(n *ast.Preemption) ll.Preemption { +func irPreemption(n *ast.Preemption) enum.Preemption { text := n.Text() switch text { case "": // \empty is used when preemption not present. - return ll.PreemptionNone + return enum.PreemptionNone case "dso_local": - return ll.PreemptionDSOLocal + return enum.PreemptionDSOLocal case "dso_preemptable": - return ll.PreemptionDSOPreemptable + return enum.PreemptionDSOPreemptable default: panic(fmt.Errorf("support for preemption %q not yet implemented", text)) } @@ -315,19 +315,19 @@ func irPreemption(n *ast.Preemption) ll.Preemption { // irSelectionKind returns the IR Comdat selection kind corresponding to the // given optional AST Comdat selection kind. -func irSelectionKind(n *ast.SelectionKind) ll.SelectionKind { +func irSelectionKind(n *ast.SelectionKind) enum.SelectionKind { text := n.Text() switch text { case "any": - return ll.SelectionKindAny + return enum.SelectionKindAny case "exactmatch": - return ll.SelectionKindExactMatch + return enum.SelectionKindExactMatch case "largest": - return ll.SelectionKindLargest + return enum.SelectionKindLargest case "noduplicates": - return ll.SelectionKindNoDuplicates + return enum.SelectionKindNoDuplicates case "samesize": - return ll.SelectionKindSameSize + return enum.SelectionKindSameSize default: panic(fmt.Errorf("support for Comdat selection kind %q not yet implemented", text)) } @@ -335,34 +335,34 @@ func irSelectionKind(n *ast.SelectionKind) ll.SelectionKind { // irTLSModelFromThreadLocal returns the IR TLS model corresponding to the given // optional AST thread local storage. -func irTLSModelFromThreadLocal(n *ast.ThreadLocal) ll.TLSModel { +func irTLSModelFromThreadLocal(n *ast.ThreadLocal) enum.TLSModel { if n.Text() != "" { model := irTLSModel(n.Model()) - if model == ll.TLSModelNone { + if model == enum.TLSModelNone { // If no explicit model is given, the "general dynamic" model is used. // thread_local - return ll.TLSModelGeneric + return enum.TLSModelGeneric } // e.g. thread_local(initialexec) return model } - return ll.TLSModelNone + return enum.TLSModelNone } // irTLSModel returns the IR TLS model corresponding to the given optional AST // TLS model. -func irTLSModel(n *ast.TLSModel) ll.TLSModel { +func irTLSModel(n *ast.TLSModel) enum.TLSModel { text := n.Text() switch text { case "": // \empty is used when TLS model not present. - return ll.TLSModelNone + return enum.TLSModelNone case "initialexec": - return ll.TLSModelInitialExec + return enum.TLSModelInitialExec case "localdynamic": - return ll.TLSModelLocalDynamic + return enum.TLSModelLocalDynamic case "localexec": - return ll.TLSModelLocalExec + return enum.TLSModelLocalExec default: panic(fmt.Errorf("support for TLS model %q not yet implemented", text)) } @@ -370,16 +370,16 @@ func irTLSModel(n *ast.TLSModel) ll.TLSModel { // irUnnamedAddr returns the IR unnamed address corresponding to the given // optional AST unnamed address. -func irUnnamedAddr(n *ast.UnnamedAddr) ll.UnnamedAddr { +func irUnnamedAddr(n *ast.UnnamedAddr) enum.UnnamedAddr { text := n.Text() switch text { case "": // \empty is used when unnamed address not present. - return ll.UnnamedAddrNone + return enum.UnnamedAddrNone case "local_unnamed_addr": - return ll.UnnamedAddrLocalUnnamedAddr + return enum.UnnamedAddrLocalUnnamedAddr case "unnamed_addr": - return ll.UnnamedAddrUnnamedAddr + return enum.UnnamedAddrUnnamedAddr default: panic(fmt.Errorf("support for unnamed address %q not yet implemented", text)) } @@ -400,18 +400,18 @@ func irVariadic(n *ast.Ellipsis) bool { // irVisibility returns the IR visibility kind corresponding to the given // optional AST visibility kind. -func irVisibility(n *ast.Visibility) ll.Visibility { +func irVisibility(n *ast.Visibility) enum.Visibility { text := n.Text() switch text { case "": // \empty is used when visibility kind not present. - return ll.VisibilityNone + return enum.VisibilityNone case "default": - return ll.VisibilityDefault + return enum.VisibilityDefault case "hidden": - return ll.VisibilityHidden + return enum.VisibilityHidden case "protected": - return ll.VisibilityProtected + return enum.VisibilityProtected default: panic(fmt.Errorf("support for visibility kind %q not yet implemented", text)) } From 244c7fef4993955617b8e0916be8cd5cfaeaeba1 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 17:55:14 +0200 Subject: [PATCH 44/70] grammar: recognize atomic in instructions --- asm/ll/ll.tm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 06eb2981..6c223f2a 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -2195,7 +2195,7 @@ LoadInst -> LoadInst # Load. : 'load' Volatileopt ElemType=Type ',' Src=TypeValue (',' Alignment)? InstMetadata # Atomic load. - | 'load' 'atomic' Volatileopt ElemType=Type ',' Src=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? InstMetadata + | 'load' Atomic Volatileopt ElemType=Type ',' Src=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? InstMetadata ; # ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2210,7 +2210,7 @@ LoadInst -> LoadInst StoreInst -> StoreInst : 'store' Volatileopt Src=TypeValue ',' Dst=TypeValue (',' Alignment)? InstMetadata - | 'store' 'atomic' Volatileopt Src=TypeValue ',' Dst=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? InstMetadata + | 'store' Atomic Volatileopt Src=TypeValue ',' Dst=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? InstMetadata ; # ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2252,10 +2252,10 @@ Weak -> Weak # 'singlethread'? AtomicOrdering AtomicRMWInst -> AtomicRMWInst - : 'atomicrmw' Volatileopt Op=BinOp Ptr=TypeValue ',' X=TypeValue SyncScopeopt AtomicOrdering InstMetadata + : 'atomicrmw' Volatileopt Op=AtomicOp Dst=TypeValue ',' X=TypeValue SyncScopeopt AtomicOrdering InstMetadata ; -BinOp -> BinOp +AtomicOp -> AtomicOp : 'add' | 'and' | 'max' @@ -4184,6 +4184,10 @@ Arg -> Arg | Typ=MetadataType Val=Metadata ; +Atomic -> Atomic + : 'atomic' +; + # ref: ParseOrdering # # ::= AtomicOrdering From 7d3cfbf763fef8773498e41a3dd8084052977c95 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 18:03:10 +0200 Subject: [PATCH 45/70] grammar: rename IPred and FPred to ICond and FCond to match IR lalr: 0.333s, text: 0.657s, parser: 2164 states, 186KB --- asm/ll/ll.tm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 6c223f2a..e326e9f8 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1762,7 +1762,7 @@ AddrSpaceCastExpr -> AddrSpaceCastExpr # ref: ParseValID ICmpExpr -> ICmpExpr - : 'icmp' Pred=IPred '(' X=TypeConst ',' Y=TypeConst ')' + : 'icmp' Cond=ICond '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1770,7 +1770,7 @@ ICmpExpr -> ICmpExpr # ref: ParseValID FCmpExpr -> FCmpExpr - : 'fcmp' Pred=FPred '(' X=TypeConst ',' Y=TypeConst ')' + : 'fcmp' Cond=FCond '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2450,7 +2450,7 @@ AddrSpaceCastInst -> AddrSpaceCastInst # ::= 'icmp' IPredicates TypeAndValue ',' Value ICmpInst -> ICmpInst - : 'icmp' Pred=IPred X=TypeValue ',' Y=Value InstMetadata + : 'icmp' Cond=ICond X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2462,7 +2462,7 @@ ICmpInst -> ICmpInst # ::= 'fcmp' FPredicates TypeAndValue ',' Value FCmpInst -> FCmpInst - : 'fcmp' FastMathFlags=FastMathFlag* Pred=FPred X=TypeValue ',' Y=Value InstMetadata + : 'fcmp' FastMathFlags=FastMathFlag* Cond=FCond X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -4362,7 +4362,7 @@ FastMathFlag -> FastMathFlag # ref: ParseCmpPredicate -FPred -> FPred +FCond -> FCond : 'false' | 'oeq' | 'oge' @@ -4490,7 +4490,7 @@ InstMetadata -> InstMetadata # ref: ParseCmpPredicate -IPred -> IPred +ICond -> ICond : 'eq' | 'ne' | 'sge' From 3d103c2e97de08645f16c36feacaddf8a707d05b Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 22 Oct 2018 18:18:55 +0200 Subject: [PATCH 46/70] Revert "grammar: rename IPred and FPred to ICond and FCond to match IR" This reverts commit 7d3cfbf763fef8773498e41a3dd8084052977c95. --- asm/ll/ll.tm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index e326e9f8..6c223f2a 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1762,7 +1762,7 @@ AddrSpaceCastExpr -> AddrSpaceCastExpr # ref: ParseValID ICmpExpr -> ICmpExpr - : 'icmp' Cond=ICond '(' X=TypeConst ',' Y=TypeConst ')' + : 'icmp' Pred=IPred '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1770,7 +1770,7 @@ ICmpExpr -> ICmpExpr # ref: ParseValID FCmpExpr -> FCmpExpr - : 'fcmp' Cond=FCond '(' X=TypeConst ',' Y=TypeConst ')' + : 'fcmp' Pred=FPred '(' X=TypeConst ',' Y=TypeConst ')' ; # ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2450,7 +2450,7 @@ AddrSpaceCastInst -> AddrSpaceCastInst # ::= 'icmp' IPredicates TypeAndValue ',' Value ICmpInst -> ICmpInst - : 'icmp' Cond=ICond X=TypeValue ',' Y=Value InstMetadata + : 'icmp' Pred=IPred X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2462,7 +2462,7 @@ ICmpInst -> ICmpInst # ::= 'fcmp' FPredicates TypeAndValue ',' Value FCmpInst -> FCmpInst - : 'fcmp' FastMathFlags=FastMathFlag* Cond=FCond X=TypeValue ',' Y=Value InstMetadata + : 'fcmp' FastMathFlags=FastMathFlag* Pred=FPred X=TypeValue ',' Y=Value InstMetadata ; # ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -4362,7 +4362,7 @@ FastMathFlag -> FastMathFlag # ref: ParseCmpPredicate -FCond -> FCond +FPred -> FPred : 'false' | 'oeq' | 'oge' @@ -4490,7 +4490,7 @@ InstMetadata -> InstMetadata # ref: ParseCmpPredicate -ICond -> ICond +IPred -> IPred : 'eq' | 'ne' | 'sge' From cbdd9c47aa96349590cc6f939382f2169a5451d2 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 23 Oct 2018 20:01:31 +0200 Subject: [PATCH 47/70] grammar: update TypeValue and TypeConst to require FirstClassType lalr: 0.265s, text: 0.573s, parser: 2163 states, 185KB --- asm/ll/ll.tm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 6c223f2a..4f0c3cec 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -4703,11 +4703,11 @@ TLSModel -> TLSModel ; TypeConst -> TypeConst - : Typ=Type Val=Constant + : Typ=FirstClassType Val=Constant ; TypeValue -> TypeValue - : Typ=Type Val=Value + : Typ=FirstClassType Val=Value ; # ref: ParseOptionalUnnamedAddr From 3c6c88d648be5c999a03278d90f2d64b199ff617 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Wed, 24 Oct 2018 09:45:47 +0200 Subject: [PATCH 48/70] asm: add type to new IR conversion instruction (without body) --- asm/local.go | 78 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/asm/local.go b/asm/local.go index 4057f0f1..85f30ff7 100644 --- a/asm/local.go +++ b/asm/local.go @@ -297,31 +297,83 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I return &ir.InstGetElementPtr{LocalName: name}, nil // Conversion instructions case *ast.TruncInst: - return &ir.InstTrunc{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstTrunc{LocalName: name, To: to}, nil case *ast.ZExtInst: - return &ir.InstZExt{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstZExt{LocalName: name, To: to}, nil case *ast.SExtInst: - return &ir.InstSExt{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstSExt{LocalName: name, To: to}, nil case *ast.FPTruncInst: - return &ir.InstFPTrunc{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFPTrunc{LocalName: name, To: to}, nil case *ast.FPExtInst: - return &ir.InstFPExt{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFPExt{LocalName: name, To: to}, nil case *ast.FPToUIInst: - return &ir.InstFPToUI{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFPToUI{LocalName: name, To: to}, nil case *ast.FPToSIInst: - return &ir.InstFPToSI{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstFPToSI{LocalName: name, To: to}, nil case *ast.UIToFPInst: - return &ir.InstUIToFP{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstUIToFP{LocalName: name, To: to}, nil case *ast.SIToFPInst: - return &ir.InstSIToFP{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstSIToFP{LocalName: name, To: to}, nil case *ast.PtrToIntInst: - return &ir.InstPtrToInt{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstPtrToInt{LocalName: name, To: to}, nil case *ast.IntToPtrInst: - return &ir.InstIntToPtr{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstIntToPtr{LocalName: name, To: to}, nil case *ast.BitCastInst: - return &ir.InstBitCast{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstBitCast{LocalName: name, To: to}, nil case *ast.AddrSpaceCastInst: - return &ir.InstAddrSpaceCast{LocalName: name}, nil + to, err := fgen.gen.irType(old.To()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstAddrSpaceCast{LocalName: name, To: to}, nil // Other instructions case *ast.ICmpInst: return &ir.InstICmp{LocalName: name}, nil From 8aaa9a171f25eefb654bc64e3503d23c8b0c18e0 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Wed, 24 Oct 2018 10:03:04 +0200 Subject: [PATCH 49/70] asm: add type to new IR vector and aggregate instructions --- asm/helper.go | 11 +++++++ asm/local.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index 6e7909dd..b304c513 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -111,6 +111,17 @@ func uintLit(n ast.UintLit) uint64 { return x } +// uintSlice returns the slice of unsigned integer value corresponding to the given +// unsigned integer slice. +func uintSlice(ns []ast.UintLit) []uint64 { + var xs []uint64 + for _, n := range ns { + x := uintLit(n) + xs = append(xs, x) + } + return xs +} + // --- [ Floating-point literals ] --------------------------------------------- // --- [ String literals ] ----------------------------------------------------- diff --git a/asm/local.go b/asm/local.go index 85f30ff7..3a4482a2 100644 --- a/asm/local.go +++ b/asm/local.go @@ -261,16 +261,59 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I return &ir.InstXor{LocalName: name, Typ: typ}, nil // Vector instructions case *ast.ExtractElementInst: - return &ir.InstExtractElement{LocalName: name}, nil + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + t, ok := xType.(*types.VectorType) + if !ok { + panic(fmt.Errorf("invalid vector type; expected *types.VectorType, got %T", xType)) + } + return &ir.InstExtractElement{LocalName: name, Typ: t.ElemType}, nil case *ast.InsertElementInst: - return &ir.InstInsertElement{LocalName: name}, nil + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + t, ok := xType.(*types.VectorType) + if !ok { + panic(fmt.Errorf("invalid vector type; expected *types.VectorType, got %T", xType)) + } + return &ir.InstInsertElement{LocalName: name, Typ: t}, nil case *ast.ShuffleVectorInst: - return &ir.InstShuffleVector{LocalName: name}, nil + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + xt, ok := xType.(*types.VectorType) + if !ok { + panic(fmt.Errorf("invalid vector type; expected *types.VectorType, got %T", xType)) + } + maskType, err := fgen.gen.irType(old.Mask().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + mt, ok := maskType.(*types.VectorType) + if !ok { + panic(fmt.Errorf("invalid vector type; expected *types.VectorType, got %T", maskType)) + } + typ := types.NewVector(mt.Len, xt.ElemType) + return &ir.InstShuffleVector{LocalName: name, Typ: typ}, nil // Aggregate instructions case *ast.ExtractValueInst: - return &ir.InstExtractValue{LocalName: name}, nil + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + indices := uintSlice(old.Indices()) + typ := aggregateElemType(xType, indices) + return &ir.InstExtractValue{LocalName: name, Typ: typ}, nil case *ast.InsertValueInst: - return &ir.InstInsertValue{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstInsertValue{LocalName: name, Typ: typ}, nil // Memory instructions case *ast.AllocaInst: elemType, err := fgen.gen.irType(old.ElemType()) @@ -386,7 +429,11 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I } return &ir.InstPhi{LocalName: name, Typ: typ}, nil case *ast.SelectInst: - return &ir.InstSelect{LocalName: name}, nil + typ, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.InstSelect{LocalName: name, Typ: typ}, nil case *ast.CallInst: // NOTE: We need to store the type of call instructions before invoking // f.AssignIDs, since call instructions may be value instructions or @@ -1599,3 +1646,25 @@ func (fgen *funcGen) translateUnreachableTerm(old *ast.UnreachableTerm) (*ir.Ter // TODO: implement return term, nil } + +// ### [ Helper functions ] #################################################### + +// NOTE: aggregateElemType is copied from llir/l/ir/inst_aggregate.go and the +// type of indicies is updated from []int64 to []uint64 + +// aggregateElemType returns the element type at the position in the aggregate +// type specified by the given indices. +func aggregateElemType(t types.Type, indices []uint64) types.Type { + // Base case. + if len(indices) == 0 { + return t + } + switch t := t.(type) { + case *types.ArrayType: + return aggregateElemType(t.ElemType, indices[1:]) + case *types.StructType: + return aggregateElemType(t.Fields[indices[0]], indices[1:]) + default: + panic(fmt.Errorf("support for aggregate type %T not yet implemented", t)) + } +} From 809d87a39acbe09404ab7db27787b6dad6707aa4 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 25 Oct 2018 22:59:37 +0200 Subject: [PATCH 50/70] grammar: keep using GCNode Updates inspirer/textmapper#18. --- asm/ll/ll.tm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 4f0c3cec..60e2c695 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -904,10 +904,11 @@ FuncHeader -> FuncHeader : (Linkage | ExternLinkage)? Preemptionopt Visibilityopt DLLStorageClassopt CallingConvopt ReturnAttrs=ReturnAttr* RetType=Type Name=GlobalIdent '(' Params ')' UnnamedAddropt AddrSpaceopt FuncAttrs=FuncAttr* Sectionopt Comdatopt GCopt Prefixopt Prologueopt Personalityopt ; -# TODO: Rename GCNode to GC when collision with token 'gc' has been resolved. -# Both define an identifier GC, the former in listener.go and the latter in token.go. - -# TODO: Create issue in Textmapper to track this upstream. +# NODE: Named GCNode instead of GC to avoid collisions with 'gc' token. Both +# define an identifier GC, the former in listener.go and the latter in +# token.go. +# +# Upstream issue https://github.com/inspirer/textmapper/issues/18 GC -> GCNode : 'gc' Name=StringLit From 26de777212db3fd07ffa528551fe3814144a4a52 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 25 Oct 2018 23:32:57 +0200 Subject: [PATCH 51/70] asm: rename from translateFoo to astToIRFoo Based on feedback from @pwaller. --- asm/global.go | 28 ++--- asm/local.go | 276 +++++++++++++++++++++++++------------------------- asm/type.go | 68 ++++++------- 3 files changed, 185 insertions(+), 187 deletions(-) diff --git a/asm/global.go b/asm/global.go index da9eef5d..b6c25e36 100644 --- a/asm/global.go +++ b/asm/global.go @@ -73,7 +73,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant // Translate global variables and functions (including bodies). for name, old := range index { g := gen.gs[name] - _, err := gen.translateGlobal(g, old) + _, err := gen.astToIRGlobal(g, old) if err != nil { return nil, errors.WithStack(err) } @@ -181,18 +181,18 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err } } -// translateGlobal translates the AST global variable or function into an +// astToIRGlobal translates the AST global variable or function into an // equivalent IR value. -func (gen *generator) translateGlobal(g ir.Constant, old ast.LlvmNode) (ir.Constant, error) { +func (gen *generator) astToIRGlobal(g ir.Constant, old ast.LlvmNode) (ir.Constant, error) { switch old := old.(type) { case *ast.GlobalDecl: - return gen.translateGlobalDecl(g, old) + return gen.astToIRGlobalDecl(g, old) case *ast.GlobalDef: - return gen.translateGlobalDef(g, old) + return gen.astToIRGlobalDef(g, old) case *ast.FuncDecl: - return gen.translateFuncDecl(g, old) + return gen.astToIRFuncDecl(g, old) case *ast.FuncDef: - return gen.translateFuncDef(g, old) + return gen.astToIRFuncDef(g, old) default: panic(fmt.Errorf("support for type %T not yet implemented", old)) } @@ -200,7 +200,7 @@ func (gen *generator) translateGlobal(g ir.Constant, old ast.LlvmNode) (ir.Const // ~~~ [ Global Variable Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateGlobalDecl(g ir.Constant, old *ast.GlobalDecl) (ir.Constant, error) { +func (gen *generator) astToIRGlobalDecl(g ir.Constant, old *ast.GlobalDecl) (*ir.Global, error) { global, ok := g.(*ir.Global) if !ok { panic(fmt.Errorf("invalid IR type for AST global declaration; expected *ir.Global, got %T", g)) @@ -231,7 +231,7 @@ func (gen *generator) translateGlobalDecl(g ir.Constant, old *ast.GlobalDecl) (i // ~~~ [ Global Variable Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateGlobalDef(g ir.Constant, old *ast.GlobalDef) (ir.Constant, error) { +func (gen *generator) astToIRGlobalDef(g ir.Constant, old *ast.GlobalDef) (*ir.Global, error) { global, ok := g.(*ir.Global) if !ok { panic(fmt.Errorf("invalid IR type for AST global definition; expected *ir.Global, got %T", g)) @@ -271,20 +271,20 @@ func (gen *generator) translateGlobalDef(g ir.Constant, old *ast.GlobalDef) (ir. // ~~~ [ Function Declaration ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateFuncDecl(g ir.Constant, old *ast.FuncDecl) (ir.Constant, error) { +func (gen *generator) astToIRFuncDecl(g ir.Constant, old *ast.FuncDecl) (*ir.Function, error) { f, ok := g.(*ir.Function) if !ok { panic(fmt.Errorf("invalid IR type for AST function declaration; expected *ir.Function, got %T", g)) } // Metadata. // TODO: translate function metadata. - if err := gen.translateFuncHeader(f, old.Header()); err != nil { + if err := gen.astToIRFuncHeader(f, old.Header()); err != nil { return nil, errors.WithStack(err) } return f, nil } -func (gen *generator) translateFuncHeader(f *ir.Function, hdr ast.FuncHeader) error { +func (gen *generator) astToIRFuncHeader(f *ir.Function, hdr ast.FuncHeader) error { // Linkage. f.Linkage = irLinkage(hdr.ExternLinkage().Text()) // Preemption. @@ -337,12 +337,12 @@ func (gen *generator) translateFuncHeader(f *ir.Function, hdr ast.FuncHeader) er // ~~~ [ Function Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (gen *generator) translateFuncDef(g ir.Constant, old *ast.FuncDef) (ir.Constant, error) { +func (gen *generator) astToIRFuncDef(g ir.Constant, old *ast.FuncDef) (*ir.Function, error) { f, ok := g.(*ir.Function) if !ok { panic(fmt.Errorf("invalid IR type for AST function definition; expected *ir.Function, got %T", g)) } - if err := gen.translateFuncHeader(f, old.Header()); err != nil { + if err := gen.astToIRFuncHeader(f, old.Header()); err != nil { return nil, errors.WithStack(err) } // Metadata. diff --git a/asm/local.go b/asm/local.go index 3a4482a2..4385b120 100644 --- a/asm/local.go +++ b/asm/local.go @@ -1,5 +1,3 @@ -// TODO: rename from translateFoo to astToIRFoo. - // Problems to solve. // // phi instructions can reference local variables defined in basic blocks not @@ -102,13 +100,14 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e fgen.ls[n.Name()] = n } } + // TODO: Index terminators. } // Translate instructions. for i, block := range f.Blocks { insts := bbs[i].Insts() for j, inst := range block.Insts { old := insts[j] - if _, err := fgen.translateInst(inst, old); err != nil { + if _, err := fgen.astToIRInst(inst, old); err != nil { return nil, errors.WithStack(err) } } @@ -116,7 +115,7 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e // Translate terminators. for i, block := range f.Blocks { old := bbs[i].Term() - term, err := fgen.translateTerm(old) + term, err := fgen.astToIRTerm(old) if err != nil { return nil, errors.WithStack(err) } @@ -458,9 +457,8 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I // === [ Instructions ] ======================================================== -// translateInst translates the AST instruction into an equivalent IR -// instruction. -func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir.Instruction, error) { +// astToIRInst translates the AST instruction into an equivalent IR instruction. +func (fgen *funcGen) astToIRInst(inst ir.Instruction, old ast.Instruction) (ir.Instruction, error) { switch old := old.(type) { // Value instruction. case *ast.LocalDef: @@ -473,130 +471,130 @@ func (fgen *funcGen) translateInst(inst ir.Instruction, old ast.Instruction) (ir if !ok { return nil, errors.Errorf("invalid instruction type of %q; expected ir.Instruction, got %T", name, v) } - return fgen.translateValueInst(i, old.Inst()) + return fgen.astToIRInstValue(i, old.Inst()) case ast.ValueInstruction: - return fgen.translateValueInst(inst, old) + return fgen.astToIRInstValue(inst, old) // Non-value instructions. case *ast.StoreInst: - return fgen.translateStoreInst(inst, old) + return fgen.astToIRInstStore(inst, old) case *ast.FenceInst: - return fgen.translateFenceInst(inst, old) + return fgen.astToIRInstFence(inst, old) default: panic(fmt.Errorf("support for instruction type %T not yet implemented", old)) } } -// translateValueInst translates the AST value instruction into an equivalent IR +// astToIRValueInst translates the AST value instruction into an equivalent IR // value instruction. -func (fgen *funcGen) translateValueInst(inst ir.Instruction, old ast.ValueInstruction) (ir.Instruction, error) { +func (fgen *funcGen) astToIRInstValue(inst ir.Instruction, old ast.ValueInstruction) (ir.Instruction, error) { switch old := old.(type) { // Binary instructions case *ast.AddInst: - return fgen.translateAddInst(inst, old) + return fgen.astToIRInstAdd(inst, old) case *ast.FAddInst: - return fgen.translateFAddInst(inst, old) + return fgen.astToIRInstFAdd(inst, old) case *ast.SubInst: - return fgen.translateSubInst(inst, old) + return fgen.astToIRInstSub(inst, old) case *ast.FSubInst: - return fgen.translateFSubInst(inst, old) + return fgen.astToIRInstFSub(inst, old) case *ast.MulInst: - return fgen.translateMulInst(inst, old) + return fgen.astToIRInstMul(inst, old) case *ast.FMulInst: - return fgen.translateFMulInst(inst, old) + return fgen.astToIRInstFMul(inst, old) case *ast.UDivInst: - return fgen.translateUDivInst(inst, old) + return fgen.astToIRInstUDiv(inst, old) case *ast.SDivInst: - return fgen.translateSDivInst(inst, old) + return fgen.astToIRInstSDiv(inst, old) case *ast.FDivInst: - return fgen.translateFDivInst(inst, old) + return fgen.astToIRInstFDiv(inst, old) case *ast.URemInst: - return fgen.translateURemInst(inst, old) + return fgen.astToIRInstURem(inst, old) case *ast.SRemInst: - return fgen.translateSRemInst(inst, old) + return fgen.astToIRInstSRem(inst, old) case *ast.FRemInst: - return fgen.translateFRemInst(inst, old) + return fgen.astToIRInstFRem(inst, old) // Bitwise instructions case *ast.ShlInst: - return fgen.translateShlInst(inst, old) + return fgen.astToIRInstShl(inst, old) case *ast.LShrInst: - return fgen.translateLShrInst(inst, old) + return fgen.astToIRInstLShr(inst, old) case *ast.AShrInst: - return fgen.translateAShrInst(inst, old) + return fgen.astToIRInstAShr(inst, old) case *ast.AndInst: - return fgen.translateAndInst(inst, old) + return fgen.astToIRInstAnd(inst, old) case *ast.OrInst: - return fgen.translateOrInst(inst, old) + return fgen.astToIRInstOr(inst, old) case *ast.XorInst: - return fgen.translateXorInst(inst, old) + return fgen.astToIRInstXor(inst, old) // Vector instructions case *ast.ExtractElementInst: - return fgen.translateExtractElementInst(inst, old) + return fgen.astToIRInstExtractElement(inst, old) case *ast.InsertElementInst: - return fgen.translateInsertElementInst(inst, old) + return fgen.astToIRInstInsertElement(inst, old) case *ast.ShuffleVectorInst: - return fgen.translateShuffleVectorInst(inst, old) + return fgen.astToIRInstShuffleVector(inst, old) // Aggregate instructions case *ast.ExtractValueInst: - return fgen.translateExtractValueInst(inst, old) + return fgen.astToIRInstExtractValue(inst, old) case *ast.InsertValueInst: - return fgen.translateInsertValueInst(inst, old) + return fgen.astToIRInstInsertValue(inst, old) // Memory instructions case *ast.AllocaInst: - return fgen.translateAllocaInst(inst, old) + return fgen.astToIRInstAlloca(inst, old) case *ast.LoadInst: - return fgen.translateLoadInst(inst, old) + return fgen.astToIRInstLoad(inst, old) case *ast.CmpXchgInst: - return fgen.translateCmpXchgInst(inst, old) + return fgen.astToIRInstCmpXchg(inst, old) case *ast.AtomicRMWInst: - return fgen.translateAtomicRMWInst(inst, old) + return fgen.astToIRInstAtomicRMW(inst, old) case *ast.GetElementPtrInst: - return fgen.translateGetElementPtrInst(inst, old) + return fgen.astToIRInstGetElementPtr(inst, old) // Conversion instructions case *ast.TruncInst: - return fgen.translateTruncInst(inst, old) + return fgen.astToIRInstTrunc(inst, old) case *ast.ZExtInst: - return fgen.translateZExtInst(inst, old) + return fgen.astToIRInstZExt(inst, old) case *ast.SExtInst: - return fgen.translateSExtInst(inst, old) + return fgen.astToIRInstSExt(inst, old) case *ast.FPTruncInst: - return fgen.translateFPTruncInst(inst, old) + return fgen.astToIRInstFPTrunc(inst, old) case *ast.FPExtInst: - return fgen.translateFPExtInst(inst, old) + return fgen.astToIRInstFPExt(inst, old) case *ast.FPToUIInst: - return fgen.translateFPToUIInst(inst, old) + return fgen.astToIRInstFPToUI(inst, old) case *ast.FPToSIInst: - return fgen.translateFPToSIInst(inst, old) + return fgen.astToIRInstFPToSI(inst, old) case *ast.UIToFPInst: - return fgen.translateUIToFPInst(inst, old) + return fgen.astToIRInstUIToFP(inst, old) case *ast.SIToFPInst: - return fgen.translateSIToFPInst(inst, old) + return fgen.astToIRInstSIToFP(inst, old) case *ast.PtrToIntInst: - return fgen.translatePtrToIntInst(inst, old) + return fgen.astToIRInstPtrToInt(inst, old) case *ast.IntToPtrInst: - return fgen.translateIntToPtrInst(inst, old) + return fgen.astToIRInstIntToPtr(inst, old) case *ast.BitCastInst: - return fgen.translateBitCastInst(inst, old) + return fgen.astToIRInstBitCast(inst, old) case *ast.AddrSpaceCastInst: - return fgen.translateAddrSpaceCastInst(inst, old) + return fgen.astToIRInstAddrSpaceCast(inst, old) // Other instructions case *ast.ICmpInst: - return fgen.translateICmpInst(inst, old) + return fgen.astToIRInstICmp(inst, old) case *ast.FCmpInst: - return fgen.translateFCmpInst(inst, old) + return fgen.astToIRInstFCmp(inst, old) case *ast.PhiInst: - return fgen.translatePhiInst(inst, old) + return fgen.astToIRInstPhi(inst, old) case *ast.SelectInst: - return fgen.translateSelectInst(inst, old) + return fgen.astToIRInstSelect(inst, old) case *ast.CallInst: - return fgen.translateCallInst(inst, old) + return fgen.astToIRInstCall(inst, old) case *ast.VAArgInst: - return fgen.translateVAArgInst(inst, old) + return fgen.astToIRInstVAArg(inst, old) case *ast.LandingPadInst: - return fgen.translateLandingPadInst(inst, old) + return fgen.astToIRInstLandingPad(inst, old) case *ast.CatchPadInst: - return fgen.translateCatchPadInst(inst, old) + return fgen.astToIRInstCatchPad(inst, old) case *ast.CleanupPadInst: - return fgen.translateCleanupPadInst(inst, old) + return fgen.astToIRInstCleanupPad(inst, old) default: panic(fmt.Errorf("support for value instruction type %T not yet implemented", old)) } @@ -606,7 +604,7 @@ func (fgen *funcGen) translateValueInst(inst ir.Instruction, old ast.ValueInstru // ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { +func (fgen *funcGen) astToIRInstAdd(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { i, ok := inst.(*ir.InstAdd) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -631,7 +629,7 @@ func (fgen *funcGen) translateAddInst(inst ir.Instruction, old *ast.AddInst) (*i // ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFAddInst(inst ir.Instruction, old *ast.FAddInst) (*ir.InstFAdd, error) { +func (fgen *funcGen) astToIRInstFAdd(inst ir.Instruction, old *ast.FAddInst) (*ir.InstFAdd, error) { i, ok := inst.(*ir.InstFAdd) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -661,7 +659,7 @@ func (fgen *funcGen) translateFAddInst(inst ir.Instruction, old *ast.FAddInst) ( // ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateSubInst(inst ir.Instruction, old *ast.SubInst) (*ir.InstSub, error) { +func (fgen *funcGen) astToIRInstSub(inst ir.Instruction, old *ast.SubInst) (*ir.InstSub, error) { i, ok := inst.(*ir.InstSub) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -690,7 +688,7 @@ func (fgen *funcGen) translateSubInst(inst ir.Instruction, old *ast.SubInst) (*i // ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFSubInst(inst ir.Instruction, old *ast.FSubInst) (*ir.InstFSub, error) { +func (fgen *funcGen) astToIRInstFSub(inst ir.Instruction, old *ast.FSubInst) (*ir.InstFSub, error) { i, ok := inst.(*ir.InstFSub) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -719,7 +717,7 @@ func (fgen *funcGen) translateFSubInst(inst ir.Instruction, old *ast.FSubInst) ( // ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateMulInst(inst ir.Instruction, old *ast.MulInst) (*ir.InstMul, error) { +func (fgen *funcGen) astToIRInstMul(inst ir.Instruction, old *ast.MulInst) (*ir.InstMul, error) { i, ok := inst.(*ir.InstMul) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -748,7 +746,7 @@ func (fgen *funcGen) translateMulInst(inst ir.Instruction, old *ast.MulInst) (*i // ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFMulInst(inst ir.Instruction, old *ast.FMulInst) (*ir.InstFMul, error) { +func (fgen *funcGen) astToIRInstFMul(inst ir.Instruction, old *ast.FMulInst) (*ir.InstFMul, error) { i, ok := inst.(*ir.InstFMul) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -777,7 +775,7 @@ func (fgen *funcGen) translateFMulInst(inst ir.Instruction, old *ast.FMulInst) ( // ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateUDivInst(inst ir.Instruction, old *ast.UDivInst) (*ir.InstUDiv, error) { +func (fgen *funcGen) astToIRInstUDiv(inst ir.Instruction, old *ast.UDivInst) (*ir.InstUDiv, error) { i, ok := inst.(*ir.InstUDiv) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -804,7 +802,7 @@ func (fgen *funcGen) translateUDivInst(inst ir.Instruction, old *ast.UDivInst) ( // ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateSDivInst(inst ir.Instruction, old *ast.SDivInst) (*ir.InstSDiv, error) { +func (fgen *funcGen) astToIRInstSDiv(inst ir.Instruction, old *ast.SDivInst) (*ir.InstSDiv, error) { i, ok := inst.(*ir.InstSDiv) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -831,7 +829,7 @@ func (fgen *funcGen) translateSDivInst(inst ir.Instruction, old *ast.SDivInst) ( // ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFDivInst(inst ir.Instruction, old *ast.FDivInst) (*ir.InstFDiv, error) { +func (fgen *funcGen) astToIRInstFDiv(inst ir.Instruction, old *ast.FDivInst) (*ir.InstFDiv, error) { i, ok := inst.(*ir.InstFDiv) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -860,7 +858,7 @@ func (fgen *funcGen) translateFDivInst(inst ir.Instruction, old *ast.FDivInst) ( // ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateURemInst(inst ir.Instruction, old *ast.URemInst) (*ir.InstURem, error) { +func (fgen *funcGen) astToIRInstURem(inst ir.Instruction, old *ast.URemInst) (*ir.InstURem, error) { i, ok := inst.(*ir.InstURem) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -887,7 +885,7 @@ func (fgen *funcGen) translateURemInst(inst ir.Instruction, old *ast.URemInst) ( // ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateSRemInst(inst ir.Instruction, old *ast.SRemInst) (*ir.InstSRem, error) { +func (fgen *funcGen) astToIRInstSRem(inst ir.Instruction, old *ast.SRemInst) (*ir.InstSRem, error) { i, ok := inst.(*ir.InstSRem) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -914,7 +912,7 @@ func (fgen *funcGen) translateSRemInst(inst ir.Instruction, old *ast.SRemInst) ( // ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFRemInst(inst ir.Instruction, old *ast.FRemInst) (*ir.InstFRem, error) { +func (fgen *funcGen) astToIRInstFRem(inst ir.Instruction, old *ast.FRemInst) (*ir.InstFRem, error) { i, ok := inst.(*ir.InstFRem) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -945,7 +943,7 @@ func (fgen *funcGen) translateFRemInst(inst ir.Instruction, old *ast.FRemInst) ( // ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateShlInst(inst ir.Instruction, old *ast.ShlInst) (*ir.InstShl, error) { +func (fgen *funcGen) astToIRInstShl(inst ir.Instruction, old *ast.ShlInst) (*ir.InstShl, error) { i, ok := inst.(*ir.InstShl) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -974,7 +972,7 @@ func (fgen *funcGen) translateShlInst(inst ir.Instruction, old *ast.ShlInst) (*i // ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateLShrInst(inst ir.Instruction, old *ast.LShrInst) (*ir.InstLShr, error) { +func (fgen *funcGen) astToIRInstLShr(inst ir.Instruction, old *ast.LShrInst) (*ir.InstLShr, error) { i, ok := inst.(*ir.InstLShr) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1001,7 +999,7 @@ func (fgen *funcGen) translateLShrInst(inst ir.Instruction, old *ast.LShrInst) ( // ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateAShrInst(inst ir.Instruction, old *ast.AShrInst) (*ir.InstAShr, error) { +func (fgen *funcGen) astToIRInstAShr(inst ir.Instruction, old *ast.AShrInst) (*ir.InstAShr, error) { i, ok := inst.(*ir.InstAShr) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1028,7 +1026,7 @@ func (fgen *funcGen) translateAShrInst(inst ir.Instruction, old *ast.AShrInst) ( // ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateAndInst(inst ir.Instruction, old *ast.AndInst) (*ir.InstAnd, error) { +func (fgen *funcGen) astToIRInstAnd(inst ir.Instruction, old *ast.AndInst) (*ir.InstAnd, error) { i, ok := inst.(*ir.InstAnd) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1055,7 +1053,7 @@ func (fgen *funcGen) translateAndInst(inst ir.Instruction, old *ast.AndInst) (*i // ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateOrInst(inst ir.Instruction, old *ast.OrInst) (*ir.InstOr, error) { +func (fgen *funcGen) astToIRInstOr(inst ir.Instruction, old *ast.OrInst) (*ir.InstOr, error) { i, ok := inst.(*ir.InstOr) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1082,7 +1080,7 @@ func (fgen *funcGen) translateOrInst(inst ir.Instruction, old *ast.OrInst) (*ir. // ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateXorInst(inst ir.Instruction, old *ast.XorInst) (*ir.InstXor, error) { +func (fgen *funcGen) astToIRInstXor(inst ir.Instruction, old *ast.XorInst) (*ir.InstXor, error) { i, ok := inst.(*ir.InstXor) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1111,7 +1109,7 @@ func (fgen *funcGen) translateXorInst(inst ir.Instruction, old *ast.XorInst) (*i // ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateExtractElementInst(inst ir.Instruction, old *ast.ExtractElementInst) (*ir.InstExtractElement, error) { +func (fgen *funcGen) astToIRInstExtractElement(inst ir.Instruction, old *ast.ExtractElementInst) (*ir.InstExtractElement, error) { i, ok := inst.(*ir.InstExtractElement) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1123,7 +1121,7 @@ func (fgen *funcGen) translateExtractElementInst(inst ir.Instruction, old *ast.E // ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateInsertElementInst(inst ir.Instruction, old *ast.InsertElementInst) (*ir.InstInsertElement, error) { +func (fgen *funcGen) astToIRInstInsertElement(inst ir.Instruction, old *ast.InsertElementInst) (*ir.InstInsertElement, error) { i, ok := inst.(*ir.InstInsertElement) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1135,7 +1133,7 @@ func (fgen *funcGen) translateInsertElementInst(inst ir.Instruction, old *ast.In // ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateShuffleVectorInst(inst ir.Instruction, old *ast.ShuffleVectorInst) (*ir.InstShuffleVector, error) { +func (fgen *funcGen) astToIRInstShuffleVector(inst ir.Instruction, old *ast.ShuffleVectorInst) (*ir.InstShuffleVector, error) { i, ok := inst.(*ir.InstShuffleVector) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1149,7 +1147,7 @@ func (fgen *funcGen) translateShuffleVectorInst(inst ir.Instruction, old *ast.Sh // ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateExtractValueInst(inst ir.Instruction, old *ast.ExtractValueInst) (*ir.InstExtractValue, error) { +func (fgen *funcGen) astToIRInstExtractValue(inst ir.Instruction, old *ast.ExtractValueInst) (*ir.InstExtractValue, error) { i, ok := inst.(*ir.InstExtractValue) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1161,7 +1159,7 @@ func (fgen *funcGen) translateExtractValueInst(inst ir.Instruction, old *ast.Ext // ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateInsertValueInst(inst ir.Instruction, old *ast.InsertValueInst) (*ir.InstInsertValue, error) { +func (fgen *funcGen) astToIRInstInsertValue(inst ir.Instruction, old *ast.InsertValueInst) (*ir.InstInsertValue, error) { i, ok := inst.(*ir.InstInsertValue) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1175,7 +1173,7 @@ func (fgen *funcGen) translateInsertValueInst(inst ir.Instruction, old *ast.Inse // ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateAllocaInst(inst ir.Instruction, old *ast.AllocaInst) (*ir.InstAlloca, error) { +func (fgen *funcGen) astToIRInstAlloca(inst ir.Instruction, old *ast.AllocaInst) (*ir.InstAlloca, error) { i, ok := inst.(*ir.InstAlloca) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1187,7 +1185,7 @@ func (fgen *funcGen) translateAllocaInst(inst ir.Instruction, old *ast.AllocaIns // ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateLoadInst(inst ir.Instruction, old *ast.LoadInst) (*ir.InstLoad, error) { +func (fgen *funcGen) astToIRInstLoad(inst ir.Instruction, old *ast.LoadInst) (*ir.InstLoad, error) { i, ok := inst.(*ir.InstLoad) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1199,7 +1197,7 @@ func (fgen *funcGen) translateLoadInst(inst ir.Instruction, old *ast.LoadInst) ( // ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateStoreInst(inst ir.Instruction, old *ast.StoreInst) (*ir.InstStore, error) { +func (fgen *funcGen) astToIRInstStore(inst ir.Instruction, old *ast.StoreInst) (*ir.InstStore, error) { i, ok := inst.(*ir.InstStore) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1211,7 +1209,7 @@ func (fgen *funcGen) translateStoreInst(inst ir.Instruction, old *ast.StoreInst) // ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFenceInst(inst ir.Instruction, old *ast.FenceInst) (*ir.InstFence, error) { +func (fgen *funcGen) astToIRInstFence(inst ir.Instruction, old *ast.FenceInst) (*ir.InstFence, error) { i, ok := inst.(*ir.InstFence) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1223,7 +1221,7 @@ func (fgen *funcGen) translateFenceInst(inst ir.Instruction, old *ast.FenceInst) // ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateCmpXchgInst(inst ir.Instruction, old *ast.CmpXchgInst) (*ir.InstCmpXchg, error) { +func (fgen *funcGen) astToIRInstCmpXchg(inst ir.Instruction, old *ast.CmpXchgInst) (*ir.InstCmpXchg, error) { i, ok := inst.(*ir.InstCmpXchg) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1235,7 +1233,7 @@ func (fgen *funcGen) translateCmpXchgInst(inst ir.Instruction, old *ast.CmpXchgI // ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateAtomicRMWInst(inst ir.Instruction, old *ast.AtomicRMWInst) (*ir.InstAtomicRMW, error) { +func (fgen *funcGen) astToIRInstAtomicRMW(inst ir.Instruction, old *ast.AtomicRMWInst) (*ir.InstAtomicRMW, error) { i, ok := inst.(*ir.InstAtomicRMW) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1247,7 +1245,7 @@ func (fgen *funcGen) translateAtomicRMWInst(inst ir.Instruction, old *ast.Atomic // ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateGetElementPtrInst(inst ir.Instruction, old *ast.GetElementPtrInst) (*ir.InstGetElementPtr, error) { +func (fgen *funcGen) astToIRInstGetElementPtr(inst ir.Instruction, old *ast.GetElementPtrInst) (*ir.InstGetElementPtr, error) { i, ok := inst.(*ir.InstGetElementPtr) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1261,7 +1259,7 @@ func (fgen *funcGen) translateGetElementPtrInst(inst ir.Instruction, old *ast.Ge // ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateTruncInst(inst ir.Instruction, old *ast.TruncInst) (*ir.InstTrunc, error) { +func (fgen *funcGen) astToIRInstTrunc(inst ir.Instruction, old *ast.TruncInst) (*ir.InstTrunc, error) { i, ok := inst.(*ir.InstTrunc) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1273,7 +1271,7 @@ func (fgen *funcGen) translateTruncInst(inst ir.Instruction, old *ast.TruncInst) // ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateZExtInst(inst ir.Instruction, old *ast.ZExtInst) (*ir.InstZExt, error) { +func (fgen *funcGen) astToIRInstZExt(inst ir.Instruction, old *ast.ZExtInst) (*ir.InstZExt, error) { i, ok := inst.(*ir.InstZExt) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1285,7 +1283,7 @@ func (fgen *funcGen) translateZExtInst(inst ir.Instruction, old *ast.ZExtInst) ( // ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateSExtInst(inst ir.Instruction, old *ast.SExtInst) (*ir.InstSExt, error) { +func (fgen *funcGen) astToIRInstSExt(inst ir.Instruction, old *ast.SExtInst) (*ir.InstSExt, error) { i, ok := inst.(*ir.InstSExt) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1297,7 +1295,7 @@ func (fgen *funcGen) translateSExtInst(inst ir.Instruction, old *ast.SExtInst) ( // ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFPTruncInst(inst ir.Instruction, old *ast.FPTruncInst) (*ir.InstFPTrunc, error) { +func (fgen *funcGen) astToIRInstFPTrunc(inst ir.Instruction, old *ast.FPTruncInst) (*ir.InstFPTrunc, error) { i, ok := inst.(*ir.InstFPTrunc) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1309,7 +1307,7 @@ func (fgen *funcGen) translateFPTruncInst(inst ir.Instruction, old *ast.FPTruncI // ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFPExtInst(inst ir.Instruction, old *ast.FPExtInst) (*ir.InstFPExt, error) { +func (fgen *funcGen) astToIRInstFPExt(inst ir.Instruction, old *ast.FPExtInst) (*ir.InstFPExt, error) { i, ok := inst.(*ir.InstFPExt) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1321,7 +1319,7 @@ func (fgen *funcGen) translateFPExtInst(inst ir.Instruction, old *ast.FPExtInst) // ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFPToUIInst(inst ir.Instruction, old *ast.FPToUIInst) (*ir.InstFPToUI, error) { +func (fgen *funcGen) astToIRInstFPToUI(inst ir.Instruction, old *ast.FPToUIInst) (*ir.InstFPToUI, error) { i, ok := inst.(*ir.InstFPToUI) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1333,7 +1331,7 @@ func (fgen *funcGen) translateFPToUIInst(inst ir.Instruction, old *ast.FPToUIIns // ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFPToSIInst(inst ir.Instruction, old *ast.FPToSIInst) (*ir.InstFPToSI, error) { +func (fgen *funcGen) astToIRInstFPToSI(inst ir.Instruction, old *ast.FPToSIInst) (*ir.InstFPToSI, error) { i, ok := inst.(*ir.InstFPToSI) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1345,7 +1343,7 @@ func (fgen *funcGen) translateFPToSIInst(inst ir.Instruction, old *ast.FPToSIIns // ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateUIToFPInst(inst ir.Instruction, old *ast.UIToFPInst) (*ir.InstUIToFP, error) { +func (fgen *funcGen) astToIRInstUIToFP(inst ir.Instruction, old *ast.UIToFPInst) (*ir.InstUIToFP, error) { i, ok := inst.(*ir.InstUIToFP) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1357,7 +1355,7 @@ func (fgen *funcGen) translateUIToFPInst(inst ir.Instruction, old *ast.UIToFPIns // ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateSIToFPInst(inst ir.Instruction, old *ast.SIToFPInst) (*ir.InstSIToFP, error) { +func (fgen *funcGen) astToIRInstSIToFP(inst ir.Instruction, old *ast.SIToFPInst) (*ir.InstSIToFP, error) { i, ok := inst.(*ir.InstSIToFP) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1369,7 +1367,7 @@ func (fgen *funcGen) translateSIToFPInst(inst ir.Instruction, old *ast.SIToFPIns // ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translatePtrToIntInst(inst ir.Instruction, old *ast.PtrToIntInst) (*ir.InstPtrToInt, error) { +func (fgen *funcGen) astToIRInstPtrToInt(inst ir.Instruction, old *ast.PtrToIntInst) (*ir.InstPtrToInt, error) { i, ok := inst.(*ir.InstPtrToInt) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1381,7 +1379,7 @@ func (fgen *funcGen) translatePtrToIntInst(inst ir.Instruction, old *ast.PtrToIn // ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateIntToPtrInst(inst ir.Instruction, old *ast.IntToPtrInst) (*ir.InstIntToPtr, error) { +func (fgen *funcGen) astToIRInstIntToPtr(inst ir.Instruction, old *ast.IntToPtrInst) (*ir.InstIntToPtr, error) { i, ok := inst.(*ir.InstIntToPtr) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1393,7 +1391,7 @@ func (fgen *funcGen) translateIntToPtrInst(inst ir.Instruction, old *ast.IntToPt // ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateBitCastInst(inst ir.Instruction, old *ast.BitCastInst) (*ir.InstBitCast, error) { +func (fgen *funcGen) astToIRInstBitCast(inst ir.Instruction, old *ast.BitCastInst) (*ir.InstBitCast, error) { i, ok := inst.(*ir.InstBitCast) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1405,7 +1403,7 @@ func (fgen *funcGen) translateBitCastInst(inst ir.Instruction, old *ast.BitCastI // ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateAddrSpaceCastInst(inst ir.Instruction, old *ast.AddrSpaceCastInst) (*ir.InstAddrSpaceCast, error) { +func (fgen *funcGen) astToIRInstAddrSpaceCast(inst ir.Instruction, old *ast.AddrSpaceCastInst) (*ir.InstAddrSpaceCast, error) { i, ok := inst.(*ir.InstAddrSpaceCast) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1419,7 +1417,7 @@ func (fgen *funcGen) translateAddrSpaceCastInst(inst ir.Instruction, old *ast.Ad // ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateICmpInst(inst ir.Instruction, old *ast.ICmpInst) (*ir.InstICmp, error) { +func (fgen *funcGen) astToIRInstICmp(inst ir.Instruction, old *ast.ICmpInst) (*ir.InstICmp, error) { i, ok := inst.(*ir.InstICmp) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1431,7 +1429,7 @@ func (fgen *funcGen) translateICmpInst(inst ir.Instruction, old *ast.ICmpInst) ( // ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateFCmpInst(inst ir.Instruction, old *ast.FCmpInst) (*ir.InstFCmp, error) { +func (fgen *funcGen) astToIRInstFCmp(inst ir.Instruction, old *ast.FCmpInst) (*ir.InstFCmp, error) { i, ok := inst.(*ir.InstFCmp) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1445,7 +1443,7 @@ func (fgen *funcGen) translateFCmpInst(inst ir.Instruction, old *ast.FCmpInst) ( // ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translatePhiInst(inst ir.Instruction, old *ast.PhiInst) (*ir.InstPhi, error) { +func (fgen *funcGen) astToIRInstPhi(inst ir.Instruction, old *ast.PhiInst) (*ir.InstPhi, error) { i, ok := inst.(*ir.InstPhi) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1457,7 +1455,7 @@ func (fgen *funcGen) translatePhiInst(inst ir.Instruction, old *ast.PhiInst) (*i // ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateSelectInst(inst ir.Instruction, old *ast.SelectInst) (*ir.InstSelect, error) { +func (fgen *funcGen) astToIRInstSelect(inst ir.Instruction, old *ast.SelectInst) (*ir.InstSelect, error) { i, ok := inst.(*ir.InstSelect) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1469,7 +1467,7 @@ func (fgen *funcGen) translateSelectInst(inst ir.Instruction, old *ast.SelectIns // ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateCallInst(inst ir.Instruction, old *ast.CallInst) (*ir.InstCall, error) { +func (fgen *funcGen) astToIRInstCall(inst ir.Instruction, old *ast.CallInst) (*ir.InstCall, error) { i, ok := inst.(*ir.InstCall) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1483,7 +1481,7 @@ func (fgen *funcGen) translateCallInst(inst ir.Instruction, old *ast.CallInst) ( // ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateVAArgInst(inst ir.Instruction, old *ast.VAArgInst) (*ir.InstVAArg, error) { +func (fgen *funcGen) astToIRInstVAArg(inst ir.Instruction, old *ast.VAArgInst) (*ir.InstVAArg, error) { i, ok := inst.(*ir.InstVAArg) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1495,7 +1493,7 @@ func (fgen *funcGen) translateVAArgInst(inst ir.Instruction, old *ast.VAArgInst) // ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateLandingPadInst(inst ir.Instruction, old *ast.LandingPadInst) (*ir.InstLandingPad, error) { +func (fgen *funcGen) astToIRInstLandingPad(inst ir.Instruction, old *ast.LandingPadInst) (*ir.InstLandingPad, error) { i, ok := inst.(*ir.InstLandingPad) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1507,7 +1505,7 @@ func (fgen *funcGen) translateLandingPadInst(inst ir.Instruction, old *ast.Landi // ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateCatchPadInst(inst ir.Instruction, old *ast.CatchPadInst) (*ir.InstCatchPad, error) { +func (fgen *funcGen) astToIRInstCatchPad(inst ir.Instruction, old *ast.CatchPadInst) (*ir.InstCatchPad, error) { i, ok := inst.(*ir.InstCatchPad) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1519,7 +1517,7 @@ func (fgen *funcGen) translateCatchPadInst(inst ir.Instruction, old *ast.CatchPa // ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -func (fgen *funcGen) translateCleanupPadInst(inst ir.Instruction, old *ast.CleanupPadInst) (*ir.InstCleanupPad, error) { +func (fgen *funcGen) astToIRInstCleanupPad(inst ir.Instruction, old *ast.CleanupPadInst) (*ir.InstCleanupPad, error) { i, ok := inst.(*ir.InstCleanupPad) if !ok { // NOTE: panic since this would indicate a bug in the implementation. @@ -1531,31 +1529,31 @@ func (fgen *funcGen) translateCleanupPadInst(inst ir.Instruction, old *ast.Clean // === [ Terminators ] ========================================================= -// translateTerm translates the AST terminator into an equivalent IR terminator. -func (fgen *funcGen) translateTerm(old ast.Terminator) (ir.Terminator, error) { +// astToIRTerm translates the AST terminator into an equivalent IR terminator. +func (fgen *funcGen) astToIRTerm(old ast.Terminator) (ir.Terminator, error) { switch old := old.(type) { case *ast.RetTerm: - return fgen.translateRetTerm(old) + return fgen.astToIRTermRet(old) case *ast.BrTerm: - return fgen.translateBrTerm(old) + return fgen.astToIRTermBr(old) case *ast.CondBrTerm: - return fgen.translateCondBrTerm(old) + return fgen.astToIRTermCondBr(old) case *ast.SwitchTerm: - return fgen.translateSwitchTerm(old) + return fgen.astToIRTermSwitch(old) case *ast.IndirectBrTerm: - return fgen.translateIndirectBrTerm(old) + return fgen.astToIRTermIndirectBr(old) case *ast.InvokeTerm: - return fgen.translateInvokeTerm(old) + return fgen.astToIRTermInvoke(old) case *ast.ResumeTerm: - return fgen.translateResumeTerm(old) + return fgen.astToIRTermResume(old) case *ast.CatchSwitchTerm: - return fgen.translateCatchSwitchTerm(old) + return fgen.astToIRTermCatchSwitch(old) case *ast.CatchRetTerm: - return fgen.translateCatchRetTerm(old) + return fgen.astToIRTermCatchRet(old) case *ast.CleanupRetTerm: - return fgen.translateCleanupRetTerm(old) + return fgen.astToIRTermCleanupRet(old) case *ast.UnreachableTerm: - return fgen.translateUnreachableTerm(old) + return fgen.astToIRTermUnreachable(old) default: panic(fmt.Errorf("support for AST terminator type %T not yet implemented", old)) } @@ -1563,7 +1561,7 @@ func (fgen *funcGen) translateTerm(old ast.Terminator) (ir.Terminator, error) { // --- [ ret ] ----------------------------------------------------------------- -func (fgen *funcGen) translateRetTerm(old *ast.RetTerm) (*ir.TermRet, error) { +func (fgen *funcGen) astToIRTermRet(old *ast.RetTerm) (*ir.TermRet, error) { term := &ir.TermRet{} // TODO: implement return term, nil @@ -1571,13 +1569,13 @@ func (fgen *funcGen) translateRetTerm(old *ast.RetTerm) (*ir.TermRet, error) { // --- [ br ] ------------------------------------------------------------------ -func (fgen *funcGen) translateBrTerm(old *ast.BrTerm) (*ir.TermBr, error) { +func (fgen *funcGen) astToIRTermBr(old *ast.BrTerm) (*ir.TermBr, error) { term := &ir.TermBr{} // TODO: implement return term, nil } -func (fgen *funcGen) translateCondBrTerm(old *ast.CondBrTerm) (*ir.TermCondBr, error) { +func (fgen *funcGen) astToIRTermCondBr(old *ast.CondBrTerm) (*ir.TermCondBr, error) { term := &ir.TermCondBr{} // TODO: implement return term, nil @@ -1585,7 +1583,7 @@ func (fgen *funcGen) translateCondBrTerm(old *ast.CondBrTerm) (*ir.TermCondBr, e // --- [ switch ] -------------------------------------------------------------- -func (fgen *funcGen) translateSwitchTerm(old *ast.SwitchTerm) (*ir.TermSwitch, error) { +func (fgen *funcGen) astToIRTermSwitch(old *ast.SwitchTerm) (*ir.TermSwitch, error) { term := &ir.TermSwitch{} // TODO: implement return term, nil @@ -1593,7 +1591,7 @@ func (fgen *funcGen) translateSwitchTerm(old *ast.SwitchTerm) (*ir.TermSwitch, e // --- [ indirectbr ] ---------------------------------------------------------- -func (fgen *funcGen) translateIndirectBrTerm(old *ast.IndirectBrTerm) (*ir.TermIndirectBr, error) { +func (fgen *funcGen) astToIRTermIndirectBr(old *ast.IndirectBrTerm) (*ir.TermIndirectBr, error) { term := &ir.TermIndirectBr{} // TODO: implement return term, nil @@ -1601,7 +1599,7 @@ func (fgen *funcGen) translateIndirectBrTerm(old *ast.IndirectBrTerm) (*ir.TermI // --- [ invoke ] -------------------------------------------------------------- -func (fgen *funcGen) translateInvokeTerm(old *ast.InvokeTerm) (*ir.TermInvoke, error) { +func (fgen *funcGen) astToIRTermInvoke(old *ast.InvokeTerm) (*ir.TermInvoke, error) { term := &ir.TermInvoke{} // TODO: implement return term, nil @@ -1609,7 +1607,7 @@ func (fgen *funcGen) translateInvokeTerm(old *ast.InvokeTerm) (*ir.TermInvoke, e // --- [ resume ] -------------------------------------------------------------- -func (fgen *funcGen) translateResumeTerm(old *ast.ResumeTerm) (*ir.TermResume, error) { +func (fgen *funcGen) astToIRTermResume(old *ast.ResumeTerm) (*ir.TermResume, error) { term := &ir.TermResume{} // TODO: implement return term, nil @@ -1617,7 +1615,7 @@ func (fgen *funcGen) translateResumeTerm(old *ast.ResumeTerm) (*ir.TermResume, e // --- [ catchswitch ] --------------------------------------------------------- -func (fgen *funcGen) translateCatchSwitchTerm(old *ast.CatchSwitchTerm) (*ir.TermCatchSwitch, error) { +func (fgen *funcGen) astToIRTermCatchSwitch(old *ast.CatchSwitchTerm) (*ir.TermCatchSwitch, error) { term := &ir.TermCatchSwitch{} // TODO: implement return term, nil @@ -1625,7 +1623,7 @@ func (fgen *funcGen) translateCatchSwitchTerm(old *ast.CatchSwitchTerm) (*ir.Ter // --- [ catchret ] ------------------------------------------------------------ -func (fgen *funcGen) translateCatchRetTerm(old *ast.CatchRetTerm) (*ir.TermCatchRet, error) { +func (fgen *funcGen) astToIRTermCatchRet(old *ast.CatchRetTerm) (*ir.TermCatchRet, error) { term := &ir.TermCatchRet{} // TODO: implement return term, nil @@ -1633,7 +1631,7 @@ func (fgen *funcGen) translateCatchRetTerm(old *ast.CatchRetTerm) (*ir.TermCatch // --- [ cleanupret ] ---------------------------------------------------------- -func (fgen *funcGen) translateCleanupRetTerm(old *ast.CleanupRetTerm) (*ir.TermCleanupRet, error) { +func (fgen *funcGen) astToIRTermCleanupRet(old *ast.CleanupRetTerm) (*ir.TermCleanupRet, error) { term := &ir.TermCleanupRet{} // TODO: implement return term, nil @@ -1641,7 +1639,7 @@ func (fgen *funcGen) translateCleanupRetTerm(old *ast.CleanupRetTerm) (*ir.TermC // --- [ unreachable ] --------------------------------------------------------- -func (fgen *funcGen) translateUnreachableTerm(old *ast.UnreachableTerm) (*ir.TermUnreachable, error) { +func (fgen *funcGen) astToIRTermUnreachable(old *ast.UnreachableTerm) (*ir.TermUnreachable, error) { term := &ir.TermUnreachable{} // TODO: implement return term, nil diff --git a/asm/type.go b/asm/type.go index 67804140..e83faf2f 100644 --- a/asm/type.go +++ b/asm/type.go @@ -65,7 +65,7 @@ func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type // Translate type defintions (including bodies). for alias, old := range index { t := gen.ts[alias] - _, err := gen.translateType(t, old) + _, err := gen.astToIRTypeDef(t, old) if err != nil { return nil, errors.WithStack(err) } @@ -146,41 +146,41 @@ func newIRType(alias string, old ast.LlvmNode, index map[string]ast.LlvmNode, tr // === [ Types ] =============================================================== -// translateType translates the AST type into an equivalent IR type. A new IR +// astToIRTypeDef translates the AST type into an equivalent IR type. A new IR // type correspoding to the AST type is created if t is nil, otherwise the body // of t is populated. Named types are resolved through ts. -func (gen *generator) translateType(t types.Type, old ast.LlvmNode) (types.Type, error) { +func (gen *generator) astToIRTypeDef(t types.Type, old ast.LlvmNode) (types.Type, error) { switch old := old.(type) { case *ast.OpaqueType: - return gen.translateOpaqueType(t, old) + return gen.astToIROpaqueType(t, old) case *ast.ArrayType: - return gen.translateArrayType(t, old) + return gen.astToIRArrayType(t, old) case *ast.FloatType: - return gen.translateFloatType(t, old) + return gen.astToIRFloatType(t, old) case *ast.FuncType: - return gen.translateFuncType(t, old) + return gen.astToIRFuncType(t, old) case *ast.IntType: - return gen.translateIntType(t, old) + return gen.astToIRIntType(t, old) case *ast.LabelType: - return gen.translateLabelType(t, old) + return gen.astToIRLabelType(t, old) case *ast.MMXType: - return gen.translateMMXType(t, old) + return gen.astToIRMMXType(t, old) case *ast.MetadataType: - return gen.translateMetadataType(t, old) + return gen.astToIRMetadataType(t, old) case *ast.NamedType: - return gen.translateNamedType(t, old) + return gen.astToIRNamedType(t, old) case *ast.PointerType: - return gen.translatePointerType(t, old) + return gen.astToIRPointerType(t, old) case *ast.StructType: - return gen.translateStructType(t, old) + return gen.astToIRStructType(t, old) case *ast.PackedStructType: - return gen.translatePackedStructType(t, old) + return gen.astToIRPackedStructType(t, old) case *ast.TokenType: - return gen.translateTokenType(t, old) + return gen.astToIRTokenType(t, old) case *ast.VectorType: - return gen.translateVectorType(t, old) + return gen.astToIRVectorType(t, old) case *ast.VoidType: - return gen.translateVoidType(t, old) + return gen.astToIRVoidType(t, old) default: panic(fmt.Errorf("support for type %T not yet implemented", old)) } @@ -188,7 +188,7 @@ func (gen *generator) translateType(t types.Type, old ast.LlvmNode) (types.Type, // --- [ Void Types ] ---------------------------------------------------------- -func (gen *generator) translateVoidType(t types.Type, old *ast.VoidType) (types.Type, error) { +func (gen *generator) astToIRVoidType(t types.Type, old *ast.VoidType) (types.Type, error) { typ, ok := t.(*types.VoidType) if t == nil { typ = &types.VoidType{} @@ -203,7 +203,7 @@ func (gen *generator) translateVoidType(t types.Type, old *ast.VoidType) (types. // --- [ Function Types ] ------------------------------------------------------ -func (gen *generator) translateFuncType(t types.Type, old *ast.FuncType) (types.Type, error) { +func (gen *generator) astToIRFuncType(t types.Type, old *ast.FuncType) (types.Type, error) { typ, ok := t.(*types.FuncType) if t == nil { typ = &types.FuncType{} @@ -234,7 +234,7 @@ func (gen *generator) translateFuncType(t types.Type, old *ast.FuncType) (types. // --- [ Integer Types ] ------------------------------------------------------- -func (gen *generator) translateIntType(t types.Type, old *ast.IntType) (types.Type, error) { +func (gen *generator) astToIRIntType(t types.Type, old *ast.IntType) (types.Type, error) { typ, ok := t.(*types.IntType) if t == nil { typ = &types.IntType{} @@ -270,7 +270,7 @@ func irIntTypeBitSize(n *ast.IntType) int64 { // --- [ Floating-point Types ] ------------------------------------------------ -func (gen *generator) translateFloatType(t types.Type, old *ast.FloatType) (types.Type, error) { +func (gen *generator) astToIRFloatType(t types.Type, old *ast.FloatType) (types.Type, error) { typ, ok := t.(*types.FloatType) if t == nil { typ = &types.FloatType{} @@ -306,7 +306,7 @@ func irFloatKind(kind ast.FloatKind) types.FloatKind { // --- [ MMX Types ] ----------------------------------------------------------- -func (gen *generator) translateMMXType(t types.Type, old *ast.MMXType) (types.Type, error) { +func (gen *generator) astToIRMMXType(t types.Type, old *ast.MMXType) (types.Type, error) { typ, ok := t.(*types.MMXType) if t == nil { typ = &types.MMXType{} @@ -321,7 +321,7 @@ func (gen *generator) translateMMXType(t types.Type, old *ast.MMXType) (types.Ty // --- [ Pointer Types ] ------------------------------------------------------- -func (gen *generator) translatePointerType(t types.Type, old *ast.PointerType) (types.Type, error) { +func (gen *generator) astToIRPointerType(t types.Type, old *ast.PointerType) (types.Type, error) { typ, ok := t.(*types.PointerType) if t == nil { typ = &types.PointerType{} @@ -343,7 +343,7 @@ func (gen *generator) translatePointerType(t types.Type, old *ast.PointerType) ( // --- [ Vector Types ] -------------------------------------------------------- -func (gen *generator) translateVectorType(t types.Type, old *ast.VectorType) (types.Type, error) { +func (gen *generator) astToIRVectorType(t types.Type, old *ast.VectorType) (types.Type, error) { typ, ok := t.(*types.VectorType) if t == nil { typ = &types.VectorType{} @@ -366,7 +366,7 @@ func (gen *generator) translateVectorType(t types.Type, old *ast.VectorType) (ty // --- [ Label Types ] --------------------------------------------------------- -func (gen *generator) translateLabelType(t types.Type, old *ast.LabelType) (types.Type, error) { +func (gen *generator) astToIRLabelType(t types.Type, old *ast.LabelType) (types.Type, error) { typ, ok := t.(*types.LabelType) if t == nil { typ = &types.LabelType{} @@ -381,7 +381,7 @@ func (gen *generator) translateLabelType(t types.Type, old *ast.LabelType) (type // --- [ Token Types ] --------------------------------------------------------- -func (gen *generator) translateTokenType(t types.Type, old *ast.TokenType) (types.Type, error) { +func (gen *generator) astToIRTokenType(t types.Type, old *ast.TokenType) (types.Type, error) { typ, ok := t.(*types.TokenType) if t == nil { typ = &types.TokenType{} @@ -396,7 +396,7 @@ func (gen *generator) translateTokenType(t types.Type, old *ast.TokenType) (type // --- [ Metadata Types ] ------------------------------------------------------ -func (gen *generator) translateMetadataType(t types.Type, old *ast.MetadataType) (types.Type, error) { +func (gen *generator) astToIRMetadataType(t types.Type, old *ast.MetadataType) (types.Type, error) { typ, ok := t.(*types.MetadataType) if t == nil { typ = &types.MetadataType{} @@ -411,7 +411,7 @@ func (gen *generator) translateMetadataType(t types.Type, old *ast.MetadataType) // --- [ Array Types ] --------------------------------------------------------- -func (gen *generator) translateArrayType(t types.Type, old *ast.ArrayType) (types.Type, error) { +func (gen *generator) astToIRArrayType(t types.Type, old *ast.ArrayType) (types.Type, error) { typ, ok := t.(*types.ArrayType) if t == nil { typ = &types.ArrayType{} @@ -434,7 +434,7 @@ func (gen *generator) translateArrayType(t types.Type, old *ast.ArrayType) (type // --- [ Structure Types ] ----------------------------------------------------- -func (gen *generator) translateOpaqueType(t types.Type, old *ast.OpaqueType) (types.Type, error) { +func (gen *generator) astToIROpaqueType(t types.Type, old *ast.OpaqueType) (types.Type, error) { typ, ok := t.(*types.StructType) if t == nil { // NOTE: Panic instead of returning error as this case should not be @@ -450,7 +450,7 @@ func (gen *generator) translateOpaqueType(t types.Type, old *ast.OpaqueType) (ty return typ, nil } -func (gen *generator) translateStructType(t types.Type, old *ast.StructType) (types.Type, error) { +func (gen *generator) astToIRStructType(t types.Type, old *ast.StructType) (types.Type, error) { typ, ok := t.(*types.StructType) if t == nil { typ = &types.StructType{} @@ -473,7 +473,7 @@ func (gen *generator) translateStructType(t types.Type, old *ast.StructType) (ty return typ, nil } -func (gen *generator) translatePackedStructType(t types.Type, old *ast.PackedStructType) (types.Type, error) { +func (gen *generator) astToIRPackedStructType(t types.Type, old *ast.PackedStructType) (types.Type, error) { typ, ok := t.(*types.StructType) if t == nil { typ = &types.StructType{} @@ -499,7 +499,7 @@ func (gen *generator) translatePackedStructType(t types.Type, old *ast.PackedStr // --- [ Named Types ] --------------------------------------------------------- -func (gen *generator) translateNamedType(t types.Type, old *ast.NamedType) (types.Type, error) { +func (gen *generator) astToIRNamedType(t types.Type, old *ast.NamedType) (types.Type, error) { // Resolve named type. alias := local(old.Name()) typ, ok := gen.ts[alias] @@ -513,5 +513,5 @@ func (gen *generator) translateNamedType(t types.Type, old *ast.NamedType) (type // irType returns the IR type corresponding to the given AST type. func (gen *generator) irType(old ast.LlvmNode) (types.Type, error) { - return gen.translateType(nil, old) + return gen.astToIRTypeDef(nil, old) } From 4022f9a7a9a42c7724e2dbfadffbaa2bce12200f Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 25 Oct 2018 23:34:08 +0200 Subject: [PATCH 52/70] asm: add TODO to rename irType to astToIRType --- asm/type.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/asm/type.go b/asm/type.go index e83faf2f..47572271 100644 --- a/asm/type.go +++ b/asm/type.go @@ -511,6 +511,8 @@ func (gen *generator) astToIRNamedType(t types.Type, old *ast.NamedType) (types. // ### [ Helpers ] ############################################################# +// TODO: rename irType to astToIRType? + // irType returns the IR type corresponding to the given AST type. func (gen *generator) irType(old ast.LlvmNode) (types.Type, error) { return gen.astToIRTypeDef(nil, old) From 866c96b00cfc2ed5c70a0863e26a450f22bd1be8 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 25 Oct 2018 23:55:06 +0200 Subject: [PATCH 53/70] grammar: use Type Value instead of TypeValue in Invokee This is so that we may retrieve the type (before the body) when creating local variable skeletons. Also, the type may either be the return type of the invokee, or the function signature. In the former case, using TypeValue is confusing, as the type is not actually the type of the value. lalr: 0.2s, text: 0.556s, parser: 2164 states, 186KB --- asm/ll/ll.tm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 60e2c695..327000d3 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -2686,7 +2686,7 @@ IndirectBrTerm -> IndirectBrTerm # OptionalAttrs 'to' TypeAndValue 'unwind' TypeAndValue InvokeTerm -> InvokeTerm - : 'invoke' CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Invokee=TypeValue '(' Args ')' FuncAttrs=FuncAttr* OperandBundles 'to' Normal=Label 'unwind' Exception=Label InstMetadata + : 'invoke' CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Typ=Type Invokee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles 'to' Normal=Label 'unwind' Exception=Label InstMetadata ; # --- [ resume ] --------------------------------------------------------------- From 09e6e5443674404ad6334dbf16890f2171760d36 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 00:06:15 +0200 Subject: [PATCH 54/70] grammar: fix parsing of value terminators Prior to this commit, value terminators (i.e. invoke and catchswitch) was only supported by the grammar if unnamed. $ l-tm test/CodeGen/AArch64/GlobalISel/legalize-exceptions.ll "test/CodeGen/AArch64/GlobalISel/legalize-exceptions.ll": syntax error at line 27 Line 27: %1 = invoke i32 @foo(i32 42) to label %continue unwind label %cleanup --- asm/ll/ll.tm | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 327000d3..c30c8633 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -1805,11 +1805,11 @@ Instruction -> Instruction : StoreInst | FenceInst # Instructions producing values. - | LocalDef + | LocalDefInst | ValueInstruction ; -LocalDef -> LocalDef +LocalDefInst -> LocalDefInst : Name=LocalIdent '=' Inst=ValueInstruction ; @@ -2595,17 +2595,30 @@ CleanupPadInst -> CleanupPadInst %interface Terminator; Terminator -> Terminator + # Terminators not producing values. : RetTerm | BrTerm | CondBrTerm | SwitchTerm | IndirectBrTerm - | InvokeTerm | ResumeTerm - | CatchSwitchTerm | CatchRetTerm | CleanupRetTerm | UnreachableTerm + # Terminators producing values. + | LocalDefTerm + | ValueTerminator +; + +LocalDefTerm -> LocalDefTerm + : Name=LocalIdent '=' Term=ValueTerminator +; + +%interface ValueTerminator; + +ValueTerminator -> ValueTerminator + : InvokeTerm + | CatchSwitchTerm ; # --- [ ret ] ------------------------------------------------------------------ From d8b009d12df69ae9d76312eee4749ec9e412ef41 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 01:40:07 +0200 Subject: [PATCH 55/70] asm: handle terminator values (i.e. invoke and catchswitch) --- asm/const.go | 2 +- asm/global.go | 4 +- asm/index_global.go | 1 + asm/index_local.go | 99 ++++++++++++++++++ asm/local.go | 244 +++++++++++++++++++++++++------------------- asm/terminator.go | 60 +++++++++++ 6 files changed, 302 insertions(+), 108 deletions(-) create mode 100644 asm/index_global.go create mode 100644 asm/index_local.go create mode 100644 asm/terminator.go diff --git a/asm/const.go b/asm/const.go index 60a30013..0a27dce1 100644 --- a/asm/const.go +++ b/asm/const.go @@ -225,5 +225,5 @@ func fixBlockAddressConst(c *ir.ConstBlockAddress) error { return nil } } - return errors.Errorf("unable to locate basic block %q in function %q", blockName, f.FuncName) + return errors.Errorf("unable to locate basic block %q in function %q", blockName, f.GlobalName) } diff --git a/asm/global.go b/asm/global.go index b6c25e36..6dc94361 100644 --- a/asm/global.go +++ b/asm/global.go @@ -129,7 +129,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err g.Typ = types.NewPointer(g.ContentType) return g, nil case *ast.FuncDecl: - f := &ir.Function{FuncName: name} + f := &ir.Function{GlobalName: name} hdr := old.Header() sig := &types.FuncType{} // Return type. @@ -153,7 +153,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err f.Typ = types.NewPointer(f.Sig) return f, nil case *ast.FuncDef: - f := &ir.Function{FuncName: name} + f := &ir.Function{GlobalName: name} sig := &types.FuncType{} hdr := old.Header() // Return type. diff --git a/asm/index_global.go b/asm/index_global.go new file mode 100644 index 00000000..d9a29db2 --- /dev/null +++ b/asm/index_global.go @@ -0,0 +1 @@ +package asm diff --git a/asm/index_local.go b/asm/index_local.go new file mode 100644 index 00000000..eedb0392 --- /dev/null +++ b/asm/index_local.go @@ -0,0 +1,99 @@ +package asm + +import ( + "github.com/llir/l/ir" + "github.com/llir/l/ir/types" + "github.com/llir/l/ir/value" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +// indexLocals indexes the function parameters, basic blocks and local variables +// (produced by instructions and terminators) of the given function. +// +// Post-condition: fgen.ls maps from local identifier (without '%' prefix) to +// corresponding skeleton IR value. +func (fgen *funcGen) indexLocals(oldBlocks []ast.BasicBlock) error { + // Create local variable skeletons (with type and without body). + if err := fgen.newLocals(oldBlocks); err != nil { + return errors.WithStack(err) + } + // Assign local IDs. + // + // Note: We need to store the type of call instructions and invoke + // terminators before assigning local IDs, since they may be values or + // non-values based on return type. This is done in newLocals. + f := fgen.f + if err := f.AssignIDs(); err != nil { + return errors.WithStack(err) + } + // Index local identifiers. + for _, param := range f.Params { + if err := fgen.addLocal(param.LocalName, param); err != nil { + return errors.WithStack(err) + } + } + for _, block := range f.Blocks { + if err := fgen.addLocal(block.LocalName, block); err != nil { + return errors.WithStack(err) + } + for _, inst := range block.Insts { + if n, ok := inst.(value.Named); ok { + if isVoidValue(n) { + continue + } + if err := fgen.addLocal(n.Name(), n); err != nil { + return errors.WithStack(err) + } + } + } + if n, ok := block.Term.(value.Named); ok { + if isVoidValue(n) { + continue + } + if err := fgen.addLocal(n.Name(), n); err != nil { + return errors.WithStack(err) + } + } + } + return nil +} + +// newLocals creates IR skeletons (with type and without body) for corresponding +// AST basic blocks, instructions and terminators of the given function. +// +// Post-condition: fgen.f.Blocks is populated with IR skeletons. +func (fgen *funcGen) newLocals(oldBlocks []ast.BasicBlock) error { + // Note: Function parameters are already translated in astToIRFuncHeader. + f := fgen.f + for _, oldBlock := range oldBlocks { + blockName := label(*oldBlock.Name()) + block := ir.NewBlock(blockName) + for _, oldInst := range oldBlock.Insts() { + inst, err := fgen.newIRInst(oldInst) + if err != nil { + return errors.WithStack(err) + } + block.Insts = append(block.Insts, inst) + } + term, err := fgen.newIRTerm(oldBlock.Term()) + if err != nil { + return errors.WithStack(err) + } + block.Term = term + f.Blocks = append(f.Blocks, block) + } + return nil +} + +// ### [ Helper functions ] #################################################### + +// isVoidValue reports whether the given named value is a non-value (i.e. a call +// instruction or invoke terminator with void-return type). +func isVoidValue(n value.Named) bool { + switch n.(type) { + case *ir.InstCall, *ir.TermInvoke: + return n.Type().Equal(types.Void) + } + return false +} diff --git a/asm/local.go b/asm/local.go index 4385b120..ce2f30df 100644 --- a/asm/local.go +++ b/asm/local.go @@ -30,18 +30,18 @@ import ( "github.com/pkg/errors" ) +// funcGen is a generator for a given IR function. type funcGen struct { // Module generator. gen *generator - // LLVM IR function being generated. f *ir.Function - // ls maps from local identifier (without '%' prefix) to corresponding IR // value. ls map[string]value.Value } +// newFuncGen returns a new generator for the given IR function. func newFuncGen(gen *generator, f *ir.Function) *funcGen { return &funcGen{ gen: gen, @@ -50,61 +50,29 @@ func newFuncGen(gen *generator, f *ir.Function) *funcGen { } } +// addLocal adds the local variable with the given name to the map of local +// variables of the function. +func (fgen *funcGen) addLocal(name string, v value.Value) error { + if prev, ok := fgen.ls[name]; ok { + return errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(name), prev, v) + } + fgen.ls[name] = v + return nil +} + // resolveLocals resolves the local variables, basic blocks and function // parameters of the given function body. The returned value maps from local // identifier (without '%' prefix) to the corresponding IR value. func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, error) { // Create instructions (without bodies), in preparation for index. - f := fgen.f - bbs := body.Blocks() - for _, b := range bbs { - blockName := label(*b.Name()) - block := ir.NewBlock(blockName) - for _, i := range b.Insts() { - inst, err := fgen.newIRInst(i) - if err != nil { - return nil, errors.WithStack(err) - } - block.Insts = append(block.Insts, inst) - } - f.Blocks = append(f.Blocks, block) - } - // Assign local IDs. - if err := f.AssignIDs(); err != nil { + oldBlocks := body.Blocks() + if err := fgen.indexLocals(oldBlocks); err != nil { return nil, errors.WithStack(err) } - // Index local identifiers. - for _, param := range f.Params { - if prev, ok := fgen.ls[param.ParamName]; ok { - return nil, errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(param.ParamName), prev, param) - } - fgen.ls[param.ParamName] = param - } - for _, block := range f.Blocks { - if prev, ok := fgen.ls[block.LocalName]; ok { - return nil, errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(block.LocalName), prev, block) - } - // TODO: Rename block.LocalName to block.BlockName? - fgen.ls[block.LocalName] = block - for _, inst := range block.Insts { - if n, ok := inst.(value.Named); ok { - // Skip call instruction if callee has void return type. - if n, ok := n.(*ir.InstCall); ok { - if n.Type().Equal(types.Void) { - continue - } - } - if prev, ok := fgen.ls[n.Name()]; ok { - return nil, errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(n.Name()), prev, n) - } - fgen.ls[n.Name()] = n - } - } - // TODO: Index terminators. - } // Translate instructions. + f := fgen.f for i, block := range f.Blocks { - insts := bbs[i].Insts() + insts := oldBlocks[i].Insts() for j, inst := range block.Insts { old := insts[j] if _, err := fgen.astToIRInst(inst, old); err != nil { @@ -114,12 +82,10 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e } // Translate terminators. for i, block := range f.Blocks { - old := bbs[i].Term() - term, err := fgen.astToIRTerm(old) - if err != nil { + old := oldBlocks[i].Term() + if _, err := fgen.astToIRTerm(block.Term, old); err != nil { return nil, errors.WithStack(err) } - block.Term = term } return fgen.ls, nil } @@ -128,8 +94,8 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e // the given AST instruction. func (fgen *funcGen) newIRInst(old ast.Instruction) (ir.Instruction, error) { switch old := old.(type) { - // Value instruction. - case *ast.LocalDef: + // Value instructions. + case *ast.LocalDefInst: name := local(old.Name()) return fgen.newIRValueInst(name, old.Inst()) case ast.ValueInstruction: @@ -461,7 +427,7 @@ func (fgen *funcGen) newIRValueInst(name string, old ast.ValueInstruction) (ir.I func (fgen *funcGen) astToIRInst(inst ir.Instruction, old ast.Instruction) (ir.Instruction, error) { switch old := old.(type) { // Value instruction. - case *ast.LocalDef: + case *ast.LocalDefInst: name := local(old.Name()) v, ok := fgen.ls[name] if !ok { @@ -471,9 +437,9 @@ func (fgen *funcGen) astToIRInst(inst ir.Instruction, old ast.Instruction) (ir.I if !ok { return nil, errors.Errorf("invalid instruction type of %q; expected ir.Instruction, got %T", name, v) } - return fgen.astToIRInstValue(i, old.Inst()) + return fgen.astToIRValueInst(i, old.Inst()) case ast.ValueInstruction: - return fgen.astToIRInstValue(inst, old) + return fgen.astToIRValueInst(inst, old) // Non-value instructions. case *ast.StoreInst: return fgen.astToIRInstStore(inst, old) @@ -486,7 +452,7 @@ func (fgen *funcGen) astToIRInst(inst ir.Instruction, old ast.Instruction) (ir.I // astToIRValueInst translates the AST value instruction into an equivalent IR // value instruction. -func (fgen *funcGen) astToIRInstValue(inst ir.Instruction, old ast.ValueInstruction) (ir.Instruction, error) { +func (fgen *funcGen) astToIRValueInst(inst ir.Instruction, old ast.ValueInstruction) (ir.Instruction, error) { switch old := old.(type) { // Binary instructions case *ast.AddInst: @@ -1530,119 +1496,187 @@ func (fgen *funcGen) astToIRInstCleanupPad(inst ir.Instruction, old *ast.Cleanup // === [ Terminators ] ========================================================= // astToIRTerm translates the AST terminator into an equivalent IR terminator. -func (fgen *funcGen) astToIRTerm(old ast.Terminator) (ir.Terminator, error) { +func (fgen *funcGen) astToIRTerm(term ir.Terminator, old ast.Terminator) (ir.Terminator, error) { switch old := old.(type) { + // Value terminator. + case *ast.LocalDefTerm: + name := local(old.Name()) + v, ok := fgen.ls[name] + if !ok { + return nil, errors.Errorf("unable to locate local variable %q", name) + } + t, ok := v.(ir.Terminator) + if !ok { + return nil, errors.Errorf("invalid terminator type of %q; expected ir.Terminator, got %T", name, v) + } + return fgen.astToIRValueTerm(t, old.Term()) + case ast.ValueTerminator: + return fgen.astToIRValueTerm(term, old) + // Non-value terminators. case *ast.RetTerm: - return fgen.astToIRTermRet(old) + return fgen.astToIRTermRet(term, old) case *ast.BrTerm: - return fgen.astToIRTermBr(old) + return fgen.astToIRTermBr(term, old) case *ast.CondBrTerm: - return fgen.astToIRTermCondBr(old) + return fgen.astToIRTermCondBr(term, old) case *ast.SwitchTerm: - return fgen.astToIRTermSwitch(old) + return fgen.astToIRTermSwitch(term, old) case *ast.IndirectBrTerm: - return fgen.astToIRTermIndirectBr(old) - case *ast.InvokeTerm: - return fgen.astToIRTermInvoke(old) + return fgen.astToIRTermIndirectBr(term, old) case *ast.ResumeTerm: - return fgen.astToIRTermResume(old) - case *ast.CatchSwitchTerm: - return fgen.astToIRTermCatchSwitch(old) + return fgen.astToIRTermResume(term, old) case *ast.CatchRetTerm: - return fgen.astToIRTermCatchRet(old) + return fgen.astToIRTermCatchRet(term, old) case *ast.CleanupRetTerm: - return fgen.astToIRTermCleanupRet(old) + return fgen.astToIRTermCleanupRet(term, old) case *ast.UnreachableTerm: - return fgen.astToIRTermUnreachable(old) + return fgen.astToIRTermUnreachable(term, old) default: panic(fmt.Errorf("support for AST terminator type %T not yet implemented", old)) } } +// astToIRValueTerm translates the AST value terminator into an equivalent IR +// terminator. +func (fgen *funcGen) astToIRValueTerm(term ir.Terminator, old ast.ValueTerminator) (ir.Terminator, error) { + switch old := old.(type) { + case *ast.InvokeTerm: + return fgen.astToIRTermInvoke(term, old) + case *ast.CatchSwitchTerm: + return fgen.astToIRTermCatchSwitch(term, old) + default: + panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) + } +} + // --- [ ret ] ----------------------------------------------------------------- -func (fgen *funcGen) astToIRTermRet(old *ast.RetTerm) (*ir.TermRet, error) { - term := &ir.TermRet{} +func (fgen *funcGen) astToIRTermRet(term ir.Terminator, old *ast.RetTerm) (*ir.TermRet, error) { + t, ok := term.(*ir.TermRet) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermRet), got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ br ] ------------------------------------------------------------------ -func (fgen *funcGen) astToIRTermBr(old *ast.BrTerm) (*ir.TermBr, error) { - term := &ir.TermBr{} +func (fgen *funcGen) astToIRTermBr(term ir.Terminator, old *ast.BrTerm) (*ir.TermBr, error) { + t, ok := term.(*ir.TermBr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermBr, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } -func (fgen *funcGen) astToIRTermCondBr(old *ast.CondBrTerm) (*ir.TermCondBr, error) { - term := &ir.TermCondBr{} +func (fgen *funcGen) astToIRTermCondBr(term ir.Terminator, old *ast.CondBrTerm) (*ir.TermCondBr, error) { + t, ok := term.(*ir.TermCondBr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCondBr, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ switch ] -------------------------------------------------------------- -func (fgen *funcGen) astToIRTermSwitch(old *ast.SwitchTerm) (*ir.TermSwitch, error) { - term := &ir.TermSwitch{} +func (fgen *funcGen) astToIRTermSwitch(term ir.Terminator, old *ast.SwitchTerm) (*ir.TermSwitch, error) { + t, ok := term.(*ir.TermSwitch) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermSwitch, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ indirectbr ] ---------------------------------------------------------- -func (fgen *funcGen) astToIRTermIndirectBr(old *ast.IndirectBrTerm) (*ir.TermIndirectBr, error) { - term := &ir.TermIndirectBr{} +func (fgen *funcGen) astToIRTermIndirectBr(term ir.Terminator, old *ast.IndirectBrTerm) (*ir.TermIndirectBr, error) { + t, ok := term.(*ir.TermIndirectBr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermIndirectBr, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ invoke ] -------------------------------------------------------------- -func (fgen *funcGen) astToIRTermInvoke(old *ast.InvokeTerm) (*ir.TermInvoke, error) { - term := &ir.TermInvoke{} +func (fgen *funcGen) astToIRTermInvoke(term ir.Terminator, old *ast.InvokeTerm) (*ir.TermInvoke, error) { + t, ok := term.(*ir.TermInvoke) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermInvoke, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ resume ] -------------------------------------------------------------- -func (fgen *funcGen) astToIRTermResume(old *ast.ResumeTerm) (*ir.TermResume, error) { - term := &ir.TermResume{} +func (fgen *funcGen) astToIRTermResume(term ir.Terminator, old *ast.ResumeTerm) (*ir.TermResume, error) { + t, ok := term.(*ir.TermResume) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermResume, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ catchswitch ] --------------------------------------------------------- -func (fgen *funcGen) astToIRTermCatchSwitch(old *ast.CatchSwitchTerm) (*ir.TermCatchSwitch, error) { - term := &ir.TermCatchSwitch{} +func (fgen *funcGen) astToIRTermCatchSwitch(term ir.Terminator, old *ast.CatchSwitchTerm) (*ir.TermCatchSwitch, error) { + t, ok := term.(*ir.TermCatchSwitch) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchSwitch, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ catchret ] ------------------------------------------------------------ -func (fgen *funcGen) astToIRTermCatchRet(old *ast.CatchRetTerm) (*ir.TermCatchRet, error) { - term := &ir.TermCatchRet{} +func (fgen *funcGen) astToIRTermCatchRet(term ir.Terminator, old *ast.CatchRetTerm) (*ir.TermCatchRet, error) { + t, ok := term.(*ir.TermCatchRet) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchRet, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ cleanupret ] ---------------------------------------------------------- -func (fgen *funcGen) astToIRTermCleanupRet(old *ast.CleanupRetTerm) (*ir.TermCleanupRet, error) { - term := &ir.TermCleanupRet{} +func (fgen *funcGen) astToIRTermCleanupRet(term ir.Terminator, old *ast.CleanupRetTerm) (*ir.TermCleanupRet, error) { + t, ok := term.(*ir.TermCleanupRet) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCleanupRet, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // --- [ unreachable ] --------------------------------------------------------- -func (fgen *funcGen) astToIRTermUnreachable(old *ast.UnreachableTerm) (*ir.TermUnreachable, error) { - term := &ir.TermUnreachable{} +func (fgen *funcGen) astToIRTermUnreachable(term ir.Terminator, old *ast.UnreachableTerm) (*ir.TermUnreachable, error) { + t, ok := term.(*ir.TermUnreachable) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermUnreachable, got %T", term)) + } // TODO: implement - return term, nil + return t, nil } // ### [ Helper functions ] #################################################### diff --git a/asm/terminator.go b/asm/terminator.go new file mode 100644 index 00000000..65fd0ceb --- /dev/null +++ b/asm/terminator.go @@ -0,0 +1,60 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +// newIRTerm returns a new IR terminator (with type and without body) based on +// the given AST terminator. +func (fgen *funcGen) newIRTerm(old ast.Terminator) (ir.Terminator, error) { + switch old := old.(type) { + // Value terminators. + case *ast.LocalDefTerm: + name := local(old.Name()) + return fgen.newIRValueTerm(name, old.Term()) + case ast.ValueTerminator: + return fgen.newIRValueTerm("", old) + // Non-value instructions. + case *ast.RetTerm: + return &ir.TermRet{}, nil + case *ast.BrTerm: + return &ir.TermBr{}, nil + case *ast.CondBrTerm: + return &ir.TermCondBr{}, nil + case *ast.SwitchTerm: + return &ir.TermSwitch{}, nil + case *ast.IndirectBrTerm: + return &ir.TermIndirectBr{}, nil + case *ast.ResumeTerm: + return &ir.TermResume{}, nil + case *ast.CatchRetTerm: + return &ir.TermCatchRet{}, nil + case *ast.CleanupRetTerm: + return &ir.TermCleanupRet{}, nil + case *ast.UnreachableTerm: + return &ir.TermUnreachable{}, nil + default: + panic(fmt.Errorf("support for terminator %T not yet implemented", old)) + } +} + +// newIRValueTerm returns a new IR value terminator (with type and without body) +// based on the given AST value terminator. +func (fgen *funcGen) newIRValueTerm(name string, old ast.ValueTerminator) (ir.Terminator, error) { + switch old := old.(type) { + case *ast.InvokeTerm: + typ, err := fgen.gen.irType(old.Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + return &ir.TermInvoke{LocalName: name, Typ: typ}, nil + case *ast.CatchSwitchTerm: + return &ir.TermCatchSwitch{LocalName: name}, nil + default: + panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) + } +} From dfa765e186a00b8464fbcc265e858c687c99b6df Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 13:33:38 +0200 Subject: [PATCH 56/70] asm: move terminator translation from local.go to terminator.go --- asm/index_local.go | 11 +++ asm/local.go | 201 +---------------------------------------- asm/terminator.go | 219 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 231 insertions(+), 200 deletions(-) diff --git a/asm/index_local.go b/asm/index_local.go index eedb0392..ff7741f4 100644 --- a/asm/index_local.go +++ b/asm/index_local.go @@ -5,6 +5,7 @@ import ( "github.com/llir/l/ir/types" "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" ) @@ -88,6 +89,16 @@ func (fgen *funcGen) newLocals(oldBlocks []ast.BasicBlock) error { // ### [ Helper functions ] #################################################### +// addLocal adds the local variable with the given name to the map of local +// variables of the function. +func (fgen *funcGen) addLocal(name string, v value.Value) error { + if prev, ok := fgen.ls[name]; ok { + return errors.Errorf("local identifier %q already present; prev `%s`, new `%s`", enc.Local(name), prev, v) + } + fgen.ls[name] = v + return nil +} + // isVoidValue reports whether the given named value is a non-value (i.e. a call // instruction or invoke terminator with void-return type). func isVoidValue(n value.Named) bool { diff --git a/asm/local.go b/asm/local.go index ce2f30df..335298b3 100644 --- a/asm/local.go +++ b/asm/local.go @@ -26,7 +26,6 @@ import ( "github.com/llir/l/ir/types" "github.com/llir/l/ir/value" "github.com/mewmew/l-tm/asm/ll/ast" - "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" ) @@ -50,17 +49,7 @@ func newFuncGen(gen *generator, f *ir.Function) *funcGen { } } -// addLocal adds the local variable with the given name to the map of local -// variables of the function. -func (fgen *funcGen) addLocal(name string, v value.Value) error { - if prev, ok := fgen.ls[name]; ok { - return errors.Errorf("IR local identifier %q already present; prev `%s`, new `%s`", enc.Local(name), prev, v) - } - fgen.ls[name] = v - return nil -} - -// resolveLocals resolves the local variables, basic blocks and function +// resolveLocals resolves the local va1riables, basic blocks and function // parameters of the given function body. The returned value maps from local // identifier (without '%' prefix) to the corresponding IR value. func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, error) { @@ -83,7 +72,7 @@ func (fgen *funcGen) resolveLocals(body ast.FuncBody) (map[string]value.Value, e // Translate terminators. for i, block := range f.Blocks { old := oldBlocks[i].Term() - if _, err := fgen.astToIRTerm(block.Term, old); err != nil { + if err := fgen.astToIRTerm(block.Term, old); err != nil { return nil, errors.WithStack(err) } } @@ -1493,192 +1482,6 @@ func (fgen *funcGen) astToIRInstCleanupPad(inst ir.Instruction, old *ast.Cleanup return i, nil } -// === [ Terminators ] ========================================================= - -// astToIRTerm translates the AST terminator into an equivalent IR terminator. -func (fgen *funcGen) astToIRTerm(term ir.Terminator, old ast.Terminator) (ir.Terminator, error) { - switch old := old.(type) { - // Value terminator. - case *ast.LocalDefTerm: - name := local(old.Name()) - v, ok := fgen.ls[name] - if !ok { - return nil, errors.Errorf("unable to locate local variable %q", name) - } - t, ok := v.(ir.Terminator) - if !ok { - return nil, errors.Errorf("invalid terminator type of %q; expected ir.Terminator, got %T", name, v) - } - return fgen.astToIRValueTerm(t, old.Term()) - case ast.ValueTerminator: - return fgen.astToIRValueTerm(term, old) - // Non-value terminators. - case *ast.RetTerm: - return fgen.astToIRTermRet(term, old) - case *ast.BrTerm: - return fgen.astToIRTermBr(term, old) - case *ast.CondBrTerm: - return fgen.astToIRTermCondBr(term, old) - case *ast.SwitchTerm: - return fgen.astToIRTermSwitch(term, old) - case *ast.IndirectBrTerm: - return fgen.astToIRTermIndirectBr(term, old) - case *ast.ResumeTerm: - return fgen.astToIRTermResume(term, old) - case *ast.CatchRetTerm: - return fgen.astToIRTermCatchRet(term, old) - case *ast.CleanupRetTerm: - return fgen.astToIRTermCleanupRet(term, old) - case *ast.UnreachableTerm: - return fgen.astToIRTermUnreachable(term, old) - default: - panic(fmt.Errorf("support for AST terminator type %T not yet implemented", old)) - } -} - -// astToIRValueTerm translates the AST value terminator into an equivalent IR -// terminator. -func (fgen *funcGen) astToIRValueTerm(term ir.Terminator, old ast.ValueTerminator) (ir.Terminator, error) { - switch old := old.(type) { - case *ast.InvokeTerm: - return fgen.astToIRTermInvoke(term, old) - case *ast.CatchSwitchTerm: - return fgen.astToIRTermCatchSwitch(term, old) - default: - panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) - } -} - -// --- [ ret ] ----------------------------------------------------------------- - -func (fgen *funcGen) astToIRTermRet(term ir.Terminator, old *ast.RetTerm) (*ir.TermRet, error) { - t, ok := term.(*ir.TermRet) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermRet), got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ br ] ------------------------------------------------------------------ - -func (fgen *funcGen) astToIRTermBr(term ir.Terminator, old *ast.BrTerm) (*ir.TermBr, error) { - t, ok := term.(*ir.TermBr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermBr, got %T", term)) - } - // TODO: implement - return t, nil -} - -func (fgen *funcGen) astToIRTermCondBr(term ir.Terminator, old *ast.CondBrTerm) (*ir.TermCondBr, error) { - t, ok := term.(*ir.TermCondBr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCondBr, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ switch ] -------------------------------------------------------------- - -func (fgen *funcGen) astToIRTermSwitch(term ir.Terminator, old *ast.SwitchTerm) (*ir.TermSwitch, error) { - t, ok := term.(*ir.TermSwitch) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermSwitch, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ indirectbr ] ---------------------------------------------------------- - -func (fgen *funcGen) astToIRTermIndirectBr(term ir.Terminator, old *ast.IndirectBrTerm) (*ir.TermIndirectBr, error) { - t, ok := term.(*ir.TermIndirectBr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermIndirectBr, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ invoke ] -------------------------------------------------------------- - -func (fgen *funcGen) astToIRTermInvoke(term ir.Terminator, old *ast.InvokeTerm) (*ir.TermInvoke, error) { - t, ok := term.(*ir.TermInvoke) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermInvoke, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ resume ] -------------------------------------------------------------- - -func (fgen *funcGen) astToIRTermResume(term ir.Terminator, old *ast.ResumeTerm) (*ir.TermResume, error) { - t, ok := term.(*ir.TermResume) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermResume, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ catchswitch ] --------------------------------------------------------- - -func (fgen *funcGen) astToIRTermCatchSwitch(term ir.Terminator, old *ast.CatchSwitchTerm) (*ir.TermCatchSwitch, error) { - t, ok := term.(*ir.TermCatchSwitch) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchSwitch, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ catchret ] ------------------------------------------------------------ - -func (fgen *funcGen) astToIRTermCatchRet(term ir.Terminator, old *ast.CatchRetTerm) (*ir.TermCatchRet, error) { - t, ok := term.(*ir.TermCatchRet) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchRet, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ cleanupret ] ---------------------------------------------------------- - -func (fgen *funcGen) astToIRTermCleanupRet(term ir.Terminator, old *ast.CleanupRetTerm) (*ir.TermCleanupRet, error) { - t, ok := term.(*ir.TermCleanupRet) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCleanupRet, got %T", term)) - } - // TODO: implement - return t, nil -} - -// --- [ unreachable ] --------------------------------------------------------- - -func (fgen *funcGen) astToIRTermUnreachable(term ir.Terminator, old *ast.UnreachableTerm) (*ir.TermUnreachable, error) { - t, ok := term.(*ir.TermUnreachable) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermUnreachable, got %T", term)) - } - // TODO: implement - return t, nil -} - // ### [ Helper functions ] #################################################### // NOTE: aggregateElemType is copied from llir/l/ir/inst_aggregate.go and the diff --git a/asm/terminator.go b/asm/terminator.go index 65fd0ceb..f45f9131 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -5,9 +5,14 @@ import ( "github.com/llir/l/ir" "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" ) +// === [ Terminators ] ========================================================= + +// +++ [ Index ] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // newIRTerm returns a new IR terminator (with type and without body) based on // the given AST terminator. func (fgen *funcGen) newIRTerm(old ast.Terminator) (ir.Terminator, error) { @@ -18,7 +23,7 @@ func (fgen *funcGen) newIRTerm(old ast.Terminator) (ir.Terminator, error) { return fgen.newIRValueTerm(name, old.Term()) case ast.ValueTerminator: return fgen.newIRValueTerm("", old) - // Non-value instructions. + // Non-value terminators. case *ast.RetTerm: return &ir.TermRet{}, nil case *ast.BrTerm: @@ -47,6 +52,7 @@ func (fgen *funcGen) newIRTerm(old ast.Terminator) (ir.Terminator, error) { func (fgen *funcGen) newIRValueTerm(name string, old ast.ValueTerminator) (ir.Terminator, error) { switch old := old.(type) { case *ast.InvokeTerm: + // Invokee type. typ, err := fgen.gen.irType(old.Typ()) if err != nil { return nil, errors.WithStack(err) @@ -58,3 +64,214 @@ func (fgen *funcGen) newIRValueTerm(name string, old ast.ValueTerminator) (ir.Te panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) } } + +// +++ [ Translate ] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// astToIRTerm translates the given AST terminator into an equivalent IR +// terminator. +func (fgen *funcGen) astToIRTerm(term ir.Terminator, old ast.Terminator) error { + switch old := old.(type) { + // Value terminators. + case *ast.LocalDefTerm: + name := local(old.Name()) + v, ok := fgen.ls[name] + if !ok { + return errors.Errorf("unable to locate local variable %q", enc.Local(name)) + } + t, ok := v.(ir.Terminator) + if !ok { + return errors.Errorf("invalid terminator type of %q; expected ir.Terminator, got %T", enc.Local(name), v) + } + return fgen.astToIRValueTerm(t, old.Term()) + case ast.ValueTerminator: + return fgen.astToIRValueTerm(term, old) + // Non-value terminators. + case *ast.RetTerm: + return fgen.astToIRTermRet(term, old) + case *ast.BrTerm: + return fgen.astToIRTermBr(term, old) + case *ast.CondBrTerm: + return fgen.astToIRTermCondBr(term, old) + case *ast.SwitchTerm: + return fgen.astToIRTermSwitch(term, old) + case *ast.IndirectBrTerm: + return fgen.astToIRTermIndirectBr(term, old) + case *ast.ResumeTerm: + return fgen.astToIRTermResume(term, old) + case *ast.CatchRetTerm: + return fgen.astToIRTermCatchRet(term, old) + case *ast.CleanupRetTerm: + return fgen.astToIRTermCleanupRet(term, old) + case *ast.UnreachableTerm: + return fgen.astToIRTermUnreachable(term, old) + default: + panic(fmt.Errorf("support for terminator %T not yet implemented", old)) + } +} + +// astToIRValueTerm translates the given AST value terminator into an equivalent +// IR terminator. +func (fgen *funcGen) astToIRValueTerm(term ir.Terminator, old ast.ValueTerminator) error { + switch old := old.(type) { + case *ast.InvokeTerm: + return fgen.astToIRTermInvoke(term, old) + case *ast.CatchSwitchTerm: + return fgen.astToIRTermCatchSwitch(term, old) + default: + panic(fmt.Errorf("support for value terminator %T not yet implemented", old)) + } +} + +// --- [ ret ] ----------------------------------------------------------------- + +// astToIRTermRet translates the given AST ret terminator into an equivalent IR +// terminator. +func (fgen *funcGen) astToIRTermRet(term ir.Terminator, old *ast.RetTerm) error { + t, ok := term.(*ir.TermRet) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermRet, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ br ] ------------------------------------------------------------------ + +// astToIRTermBr translates the given AST br terminator into an equivalent IR +// terminator. +func (fgen *funcGen) astToIRTermBr(term ir.Terminator, old *ast.BrTerm) error { + t, ok := term.(*ir.TermBr) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermBr, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ condbr ] -------------------------------------------------------------- + +// astToIRTermCondBr translates the given AST condbr terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermCondBr(term ir.Terminator, old *ast.CondBrTerm) error { + t, ok := term.(*ir.TermCondBr) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCondBr, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ switch ] -------------------------------------------------------------- + +// astToIRTermSwitch translates the given AST switch terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermSwitch(term ir.Terminator, old *ast.SwitchTerm) error { + t, ok := term.(*ir.TermSwitch) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermSwitch, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ indirectbr ] ---------------------------------------------------------- + +// astToIRTermIndirectBr translates the given AST indirectbr terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermIndirectBr(term ir.Terminator, old *ast.IndirectBrTerm) error { + t, ok := term.(*ir.TermIndirectBr) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermIndirectBr, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ invoke ] -------------------------------------------------------------- + +// astToIRTermInvoke translates the given AST invoke terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermInvoke(term ir.Terminator, old *ast.InvokeTerm) error { + t, ok := term.(*ir.TermInvoke) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermInvoke, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ resume ] -------------------------------------------------------------- + +// astToIRTermResume translates the given AST resume terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermResume(term ir.Terminator, old *ast.ResumeTerm) error { + t, ok := term.(*ir.TermResume) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermResume, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ catchswitch ] --------------------------------------------------------- + +// astToIRTermCatchSwitch translates the given AST catchswitch terminator into +// an equivalent IR terminator. +func (fgen *funcGen) astToIRTermCatchSwitch(term ir.Terminator, old *ast.CatchSwitchTerm) error { + t, ok := term.(*ir.TermCatchSwitch) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchSwitch, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ catchret ] ------------------------------------------------------------ + +// astToIRTermCatchRet translates the given AST catchret terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermCatchRet(term ir.Terminator, old *ast.CatchRetTerm) error { + t, ok := term.(*ir.TermCatchRet) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCatchRet, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ cleanupret ] ---------------------------------------------------------- + +// astToIRTermCleanupRet translates the given AST cleanupret terminator into an +// equivalent IR terminator. +func (fgen *funcGen) astToIRTermCleanupRet(term ir.Terminator, old *ast.CleanupRetTerm) error { + t, ok := term.(*ir.TermCleanupRet) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCleanupRet, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} + +// --- [ unreachable ] --------------------------------------------------------- + +// astToIRTermUnreachable translates the given AST unreachable terminator into +// an equivalent IR terminator. +func (fgen *funcGen) astToIRTermUnreachable(term ir.Terminator, old *ast.UnreachableTerm) error { + t, ok := term.(*ir.TermUnreachable) + if !ok { + panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermUnreachable, got %T", term)) + } + // TODO: implement. + _ = t + return nil +} From 91dd9b7b09817d79adde057c53d1bd958b79bc5b Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 17:07:56 +0200 Subject: [PATCH 57/70] asm: translate ret terminators --- asm/terminator.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/asm/terminator.go b/asm/terminator.go index f45f9131..56e43644 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/llir/l/ir" + "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" @@ -131,8 +132,21 @@ func (fgen *funcGen) astToIRTermRet(term ir.Terminator, old *ast.RetTerm) error if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermRet, got %T", term)) } - // TODO: implement. - _ = t + // Return type. + typ, err := fgen.gen.irType(old.XTyp()) + if err != nil { + return errors.WithStack(err) + } + if typ.Equal(types.Void) { + // void return. + return nil + } + // Return value. + x, err := fgen.astToIRValue(typ, old.X()) + if err != nil { + return errors.WithStack(err) + } + t.X = x return nil } From 1dedce5ddebb5f57c62dd01d6347930f35eb3bbc Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 17:31:08 +0200 Subject: [PATCH 58/70] asm: translate br terminator --- asm/basic_block.go | 20 ++++++++++++++++++++ asm/terminator.go | 19 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 asm/basic_block.go diff --git a/asm/basic_block.go b/asm/basic_block.go new file mode 100644 index 00000000..914b8f42 --- /dev/null +++ b/asm/basic_block.go @@ -0,0 +1,20 @@ +package asm + +import ( + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +func (fgen *funcGen) irBasicBlock(old ast.Label) (*ir.BasicBlock, error) { + name := local(old.Name()) + v, ok := fgen.ls[name] + if !ok { + return nil, errors.Errorf("unable to locate local identifier %q", name) + } + block, ok := v.(*ir.BasicBlock) + if !ok { + return nil, errors.Errorf("invalid basic block type; expected *ir.BasicBlock, got %T", v) + } + return block, nil +} diff --git a/asm/terminator.go b/asm/terminator.go index 56e43644..3acbd3f4 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -147,6 +147,7 @@ func (fgen *funcGen) astToIRTermRet(term ir.Terminator, old *ast.RetTerm) error return errors.WithStack(err) } t.X = x + // TODO: handle metadata. return nil } @@ -159,8 +160,13 @@ func (fgen *funcGen) astToIRTermBr(term ir.Terminator, old *ast.BrTerm) error { if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermBr, got %T", term)) } - // TODO: implement. - _ = t + // Target. + target, err := fgen.irBasicBlock(old.Target()) + if err != nil { + return errors.WithStack(err) + } + t.Target = target + // TODO: handle metadata. return nil } @@ -175,6 +181,7 @@ func (fgen *funcGen) astToIRTermCondBr(term ir.Terminator, old *ast.CondBrTerm) } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -189,6 +196,7 @@ func (fgen *funcGen) astToIRTermSwitch(term ir.Terminator, old *ast.SwitchTerm) } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -203,6 +211,7 @@ func (fgen *funcGen) astToIRTermIndirectBr(term ir.Terminator, old *ast.Indirect } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -217,6 +226,7 @@ func (fgen *funcGen) astToIRTermInvoke(term ir.Terminator, old *ast.InvokeTerm) } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -231,6 +241,7 @@ func (fgen *funcGen) astToIRTermResume(term ir.Terminator, old *ast.ResumeTerm) } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -245,6 +256,7 @@ func (fgen *funcGen) astToIRTermCatchSwitch(term ir.Terminator, old *ast.CatchSw } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -259,6 +271,7 @@ func (fgen *funcGen) astToIRTermCatchRet(term ir.Terminator, old *ast.CatchRetTe } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -273,6 +286,7 @@ func (fgen *funcGen) astToIRTermCleanupRet(term ir.Terminator, old *ast.CleanupR } // TODO: implement. _ = t + // TODO: handle metadata. return nil } @@ -287,5 +301,6 @@ func (fgen *funcGen) astToIRTermUnreachable(term ir.Terminator, old *ast.Unreach } // TODO: implement. _ = t + // TODO: handle metadata. return nil } From 36c96d09fd1f3d17ac6608b78892e988b1b2092a Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 18:12:43 +0200 Subject: [PATCH 59/70] asm: translate conditional br terminator --- asm/terminator.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/asm/terminator.go b/asm/terminator.go index 3acbd3f4..506708d4 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -179,8 +179,29 @@ func (fgen *funcGen) astToIRTermCondBr(term ir.Terminator, old *ast.CondBrTerm) if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCondBr, got %T", term)) } - // TODO: implement. - _ = t + // Condition. + ct := old.CondTyp() + condType, err := fgen.gen.irType(&ct) + if err != nil { + return errors.WithStack(err) + } + cond, err := fgen.astToIRValue(condType, old.Cond()) + if err != nil { + return errors.WithStack(err) + } + t.Cond = cond + // Target true. + targetTrue, err := fgen.irBasicBlock(old.TargetTrue()) + if err != nil { + return errors.WithStack(err) + } + t.TargetTrue = targetTrue + // Target false. + targetFalse, err := fgen.irBasicBlock(old.TargetFalse()) + if err != nil { + return errors.WithStack(err) + } + t.TargetFalse = targetFalse // TODO: handle metadata. return nil } From e56b1016d281746cbf710bde3b5c6234a78ab25e Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 18:24:23 +0200 Subject: [PATCH 60/70] asm: translate switch terminator --- asm/helper.go | 15 +++++++++++++++ asm/terminator.go | 24 +++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index b304c513..6311c090 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -5,10 +5,12 @@ import ( "strconv" "strings" + "github.com/llir/l/ir" "github.com/llir/l/ir/enum" "github.com/llir/l/ir/types" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" + "github.com/pkg/errors" ) // === [ Identifiers ] ========================================================= @@ -156,6 +158,19 @@ func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { return types.AddrSpace(x) } +// irCase returns the IR switch case corresponding to the given AST switch case. +func (fgen *funcGen) irCase(old ast.Case) (*ir.Case, error) { + x, err := fgen.gen.irTypeConst(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + target, err := fgen.irBasicBlock(old.Target()) + if err != nil { + return nil, errors.WithStack(err) + } + return ir.NewCase(x, target), nil +} + // irDLLStorageClass returns the IR DLL storage class corresponding to the given // optional AST DLL storage class. func irDLLStorageClass(n *ast.DLLStorageClass) enum.DLLStorageClass { diff --git a/asm/terminator.go b/asm/terminator.go index 506708d4..a353ecff 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -179,7 +179,7 @@ func (fgen *funcGen) astToIRTermCondBr(term ir.Terminator, old *ast.CondBrTerm) if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermCondBr, got %T", term)) } - // Condition. + // Branching condition. ct := old.CondTyp() condType, err := fgen.gen.irType(&ct) if err != nil { @@ -215,8 +215,26 @@ func (fgen *funcGen) astToIRTermSwitch(term ir.Terminator, old *ast.SwitchTerm) if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermSwitch, got %T", term)) } - // TODO: implement. - _ = t + // Control variable. + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return errors.WithStack(err) + } + t.X = x + // Default target. + targetDefault, err := fgen.irBasicBlock(old.Default()) + if err != nil { + return errors.WithStack(err) + } + t.TargetDefault = targetDefault + // Switch cases. + for _, oldCase := range old.Cases() { + c, err := fgen.irCase(oldCase) + if err != nil { + return errors.WithStack(err) + } + t.Cases = append(t.Cases, c) + } // TODO: handle metadata. return nil } From e5db8cb9ff13090ab73125afdea85dabad883d8e Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 26 Oct 2018 18:52:56 +0200 Subject: [PATCH 61/70] asm: translate indirectbr terminator --- asm/ll/ll.tm | 2 +- asm/terminator.go | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index c30c8633..4365fa78 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -2686,7 +2686,7 @@ Case -> Case # ::= 'indirectbr' TypeAndValue ',' '[' LabelList ']' IndirectBrTerm -> IndirectBrTerm - : 'indirectbr' Addr=TypeValue ',' '[' Targets=(Label separator ',')+ ']' InstMetadata + : 'indirectbr' Addr=TypeValue ',' '[' ValidTargets=(Label separator ',')+ ']' InstMetadata ; # --- [ invoke ] --------------------------------------------------------------- diff --git a/asm/terminator.go b/asm/terminator.go index a353ecff..d2d892cc 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -248,8 +248,20 @@ func (fgen *funcGen) astToIRTermIndirectBr(term ir.Terminator, old *ast.Indirect if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermIndirectBr, got %T", term)) } - // TODO: implement. - _ = t + // Target address. + addr, err := fgen.astToIRTypeValue(old.Addr()) + if err != nil { + return errors.WithStack(err) + } + t.Addr = addr + // Valid targets. + for _, oldValidTarget := range old.ValidTargets() { + validTarget, err := fgen.irBasicBlock(oldValidTarget) + if err != nil { + return errors.WithStack(err) + } + t.ValidTargets = append(t.ValidTargets, validTarget) + } // TODO: handle metadata. return nil } From 97899a36b59d2e02d37941b95404f1e8828eca6c Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 27 Oct 2018 16:46:21 +0200 Subject: [PATCH 62/70] asm: implement opt calling convention using NoType Update inspirer/textmapper#19. --- asm/helper.go | 124 ++++++++++++++++++++++++++++++++++++++++++++++ asm/ll/ll.tm | 12 ++++- asm/local.go | 16 +++++- asm/terminator.go | 3 +- 4 files changed, 152 insertions(+), 3 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index 6311c090..19a4d557 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -171,6 +171,130 @@ func (fgen *funcGen) irCase(old ast.Case) (*ir.Case, error) { return ir.NewCase(x, target), nil } +// irCallingConv returns the IR calling convention corresponding to the given +// optional AST calling convention. +func irCallingConv(old ast.CallingConv) enum.CallingConv { + switch old := old.(type) { + case *ast.CallingConvEnum: + text := old.Text() + switch text { + case "": + // \empty is used when calling convention not present. + return enum.CallingConvNone + case "amdgpu_cs": + return enum.CallingConvAmdGPUCS + case "amdgpu_es": + return enum.CallingConvAmdGPUES + case "amdgpu_gs": + return enum.CallingConvAmdGPUGS + case "amdgpu_hs": + return enum.CallingConvAmdGPUHS + case "amdgpu_kernel": + return enum.CallingConvAmdGPUKernel + case "amdgpu_ls": + return enum.CallingConvAmdGPULS + case "amdgpu_ps": + return enum.CallingConvAmdGPUPS + case "amdgpu_vs": + return enum.CallingConvAmdGPUVS + case "anyregcc": + return enum.CallingConvAnyReg + case "arm_aapcs_vfpcc": + return enum.CallingConvARMAAPCSVFP + case "arm_aapcscc": + return enum.CallingConvARMAAPCS + case "arm_apcscc": + return enum.CallingConvARMAPCS + case "avr_intrcc": + return enum.CallingConvAVRIntr + case "avr_signalcc": + return enum.CallingConvAVRSignal + case "ccc": + return enum.CallingConvC + case "coldcc": + return enum.CallingConvCold + case "cxx_fast_tlscc": + return enum.CallingConvCXXFastTLS + case "fastcc": + return enum.CallingConvFast + case "ghccc": + return enum.CallingConvGHC + case "hhvm_ccc": + return enum.CallingConvHHVMC + case "hhvmcc": + return enum.CallingConvHHVM + case "intel_ocl_bicc": + return enum.CallingConvIntelOCLBI + case "msp430_intrcc": + return enum.CallingConvMSP430Intr + case "preserve_allcc": + return enum.CallingConvPreserveAll + case "preserve_mostcc": + return enum.CallingConvPreserveMost + case "ptx_device": + return enum.CallingConvPTXDevice + case "ptx_kernel": + return enum.CallingConvPTXKernel + case "spir_func": + return enum.CallingConvSPIRFunc + case "spir_kernel": + return enum.CallingConvSPIRKernel + case "swiftcc": + return enum.CallingConvSwift + case "webkit_jscc": + return enum.CallingConvWebKitJS + case "win64cc": + return enum.CallingConvWin64 + case "x86_64_sysvcc": + return enum.CallingConvX86_64SysV + case "x86_fastcallcc": + return enum.CallingConvX86FastCall + case "x86_intrcc": + return enum.CallingConvX86Intr + case "x86_regcallcc": + return enum.CallingConvX86RegCall + case "x86_stdcallcc": + return enum.CallingConvX86StdCall + case "x86_thiscallcc": + return enum.CallingConvX86ThisCall + case "x86_vectorcallcc": + return enum.CallingConvX86VectorCall + default: + panic(fmt.Errorf("support for calling convention %q not yet implemented", text)) + } + case *ast.CallingConvInt: + n := uintLit(old.UintLit()) + switch n { + case 11: + return enum.CallingConvHiPE + case 86: + return enum.CallingConvAVRBuiltin + case 87: + return enum.CallingConvAMDGPUVS + case 88: + return enum.CallingConvAMDGPUGS + case 89: + return enum.CallingConvAMDGPUPS + case 90: + return enum.CallingConvAMDGPUCS + case 91: + return enum.CallingConvAMDGPUKernel + case 93: + return enum.CallingConvAMDGPUHS + case 94: + return enum.CallingConvMSP430Builtin + case 95: + return enum.CallingConvAMDGPULS + case 96: + return enum.CallingConvAMDGPUES + default: + panic(fmt.Errorf("support for calling convention %d not yet implemented", n)) + } + default: + panic(fmt.Errorf("support for calling convention type %T not yet implemented", old)) + } +} + // irDLLStorageClass returns the IR DLL storage class corresponding to the given // optional AST DLL storage class. func irDLLStorageClass(n *ast.DLLStorageClass) enum.DLLStorageClass { diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 4365fa78..3e0a91c0 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -4267,7 +4267,14 @@ AttrString -> AttrString # ::= 'amdgpu_kernel' # ::= 'cc' UINT +%interface CallingConv; + CallingConv -> CallingConv + : CallingConvEnum + | CallingConvInt +; + +CallingConvEnum -> CallingConvEnum : 'aarch64_vector_pcs' | 'amdgpu_cs' | 'amdgpu_es' @@ -4308,7 +4315,10 @@ CallingConv -> CallingConv | 'x86_stdcallcc' | 'x86_thiscallcc' | 'x86_vectorcallcc' - | 'cc' UintLit # TODO: Check how the AST looks like for this case. +; + +CallingConvInt -> CallingConvInt + : 'cc' UintLit ; # ref: parseOptionalComdat diff --git a/asm/local.go b/asm/local.go index 335298b3..7a657eeb 100644 --- a/asm/local.go +++ b/asm/local.go @@ -25,7 +25,9 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" "github.com/llir/l/ir/value" + "github.com/mewmew/l-tm/asm/ll" "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/mewmew/l-tm/asm/ll/selector" "github.com/pkg/errors" ) @@ -1430,7 +1432,19 @@ func (fgen *funcGen) astToIRInstCall(inst ir.Instruction, old *ast.CallInst) (*i } // Fast math flags. i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // TODO: implement + // Calling convention. + // TODO: update when https://github.com/inspirer/textmapper/issues/19 is resolved. + // + // Note, I would like to write: + // i.CallingConv = irCallingConv(old.CallingConv()) + // + // Or, perhaps: + // if oldcc := old.CallingConv(); oldcc.IsValid() { + // i.CallingConv = irCallingConv(oldcc) + // } + if n := old.Child(selector.CallingConv); n.Type() != ll.NoType { + i.CallingConv = irCallingConv(ast.ToLlvmNode(n).(ast.CallingConv)) + } return i, nil } diff --git a/asm/terminator.go b/asm/terminator.go index d2d892cc..7f735524 100644 --- a/asm/terminator.go +++ b/asm/terminator.go @@ -275,7 +275,8 @@ func (fgen *funcGen) astToIRTermInvoke(term ir.Terminator, old *ast.InvokeTerm) if !ok { panic(fmt.Errorf("invalid IR terminator for AST terminator; expected *ir.TermInvoke, got %T", term)) } - // TODO: implement. + // Calling convention. + //t.CallingConv = irCallingConv(old.CallingConv()) _ = t // TODO: handle metadata. return nil From 17bcf2c854d00a426a43234bbdc1f5d2436b22fc Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 27 Oct 2018 18:53:34 +0200 Subject: [PATCH 63/70] asm: inline nullable nonterminals Note: Args is nullable, but only used inside of (), thus offset contained. Note: Params is nullable, but only used inside of (), thus offset contained. Inline InstMetadata and FuncMetadata. Inline OperandBundles for now. When declarative inlining is supported, revert back to the original. # ref: ParseOptionalOperandBundles # # ::= empty # ::= '[' OperandBundle [, OperandBundle ]* ']' # # OperandBundle # ::= bundle-tag '(' ')' # ::= bundle-tag '(' Type Value [, Type Value ]* ')' # # bundle-tag ::= String Constant OperandBundles inline : OperandBundles=('[' OperandBundles=(OperandBundle separator ',')+ ']')? ; Updates inspirer/textmapper#23. --- asm/ll/ll.tm | 222 +++++++++++++++++++++++++-------------------------- 1 file changed, 108 insertions(+), 114 deletions(-) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 3e0a91c0..78d7f356 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -875,7 +875,7 @@ IFuncDef -> IFuncDef # ::= 'declare' FunctionHeader FuncDecl -> FuncDecl - : 'declare' Metadata=FuncMetadata Header=FuncHeader + : 'declare' Metadata=MetadataAttachment* Header=FuncHeader ; # ~~~ [ Function Definition ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -886,8 +886,12 @@ FuncDecl -> FuncDecl # # ::= 'define' FunctionHeader (!dbg !56)* '{' ... +# ref: ParseOptionalFunctionMetadata +# +# ::= (!dbg !57)* + FuncDef -> FuncDef - : 'define' Header=FuncHeader Metadata=FuncMetadata Body=FuncBody + : 'define' Header=FuncHeader Metadata=MetadataAttachment* Body=FuncBody ; # ref: ParseFunctionHeader @@ -1318,7 +1322,6 @@ ArrayConst -> ArrayConst | 'c' Val=StringLit -> CharArrayConst ; - # --- [ Vector Constants ] ----------------------------------------------------- # https://llvm.org/docs/LangRef.html#complex-constants @@ -1789,7 +1792,7 @@ SelectExpr -> SelectExpr # ::= LabelStr? Instruction* BasicBlock -> BasicBlock - : Name=LabelIdent? Insts=Instruction* Term=Terminator + : Name=LabelIdentopt Insts=Instruction* Term=Terminator ; # === [ Instructions ] ========================================================= @@ -1801,12 +1804,12 @@ BasicBlock -> BasicBlock %interface Instruction; Instruction -> Instruction - # Instructions not producing values. - : StoreInst - | FenceInst # Instructions producing values. - | LocalDefInst + : LocalDefInst | ValueInstruction + # Instructions not producing values. + | StoreInst + | FenceInst ; LocalDefInst -> LocalDefInst @@ -1885,8 +1888,12 @@ ValueInstruction -> ValueInstruction # # ::= ArithmeticOps TypeAndValue ',' Value +# ref: ParseInstructionMetadata +# +# ::= !dbg !42 (',' !dbg !57)* + AddInst -> AddInst - : 'add' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata + : 'add' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1898,7 +1905,7 @@ AddInst -> AddInst # ::= ArithmeticOps TypeAndValue ',' Value FAddInst -> FAddInst - : 'fadd' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value InstMetadata + : 'fadd' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1910,7 +1917,7 @@ FAddInst -> FAddInst # ::= ArithmeticOps TypeAndValue ',' Value SubInst -> SubInst - : 'sub' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata + : 'sub' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1922,7 +1929,7 @@ SubInst -> SubInst # ::= ArithmeticOps TypeAndValue ',' Value FSubInst -> FSubInst - : 'fsub' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value InstMetadata + : 'fsub' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1934,7 +1941,7 @@ FSubInst -> FSubInst # ::= ArithmeticOps TypeAndValue ',' Value MulInst -> MulInst - : 'mul' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata + : 'mul' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1946,7 +1953,7 @@ MulInst -> MulInst # ::= ArithmeticOps TypeAndValue ',' Value FMulInst -> FMulInst - : 'fmul' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value InstMetadata + : 'fmul' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1958,7 +1965,7 @@ FMulInst -> FMulInst # ::= ArithmeticOps TypeAndValue ',' Value UDivInst -> UDivInst - : 'udiv' Exactopt X=TypeValue ',' Y=Value InstMetadata + : 'udiv' Exactopt X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1970,7 +1977,7 @@ UDivInst -> UDivInst # ::= ArithmeticOps TypeAndValue ',' Value SDivInst -> SDivInst - : 'sdiv' Exactopt X=TypeValue ',' Y=Value InstMetadata + : 'sdiv' Exactopt X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1982,7 +1989,7 @@ SDivInst -> SDivInst # ::= ArithmeticOps TypeAndValue ',' Value FDivInst -> FDivInst - : 'fdiv' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value InstMetadata + : 'fdiv' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1994,7 +2001,7 @@ FDivInst -> FDivInst # ::= ArithmeticOps TypeAndValue ',' Value URemInst -> URemInst - : 'urem' X=TypeValue ',' Y=Value InstMetadata + : 'urem' X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2006,7 +2013,7 @@ URemInst -> URemInst # ::= ArithmeticOps TypeAndValue ',' Value SRemInst -> SRemInst - : 'srem' X=TypeValue ',' Y=Value InstMetadata + : 'srem' X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2018,7 +2025,7 @@ SRemInst -> SRemInst # ::= ArithmeticOps TypeAndValue ',' Value FRemInst -> FRemInst - : 'frem' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value InstMetadata + : 'frem' FastMathFlags=FastMathFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # --- [ Bitwise instructions ] ------------------------------------------------- @@ -2032,7 +2039,7 @@ FRemInst -> FRemInst # ::= ArithmeticOps TypeAndValue ',' Value ShlInst -> ShlInst - : 'shl' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value InstMetadata + : 'shl' OverflowFlags=OverflowFlag* X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2044,7 +2051,7 @@ ShlInst -> ShlInst # ::= ArithmeticOps TypeAndValue ',' Value LShrInst -> LShrInst - : 'lshr' Exactopt X=TypeValue ',' Y=Value InstMetadata + : 'lshr' Exactopt X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2056,7 +2063,7 @@ LShrInst -> LShrInst # ::= ArithmeticOps TypeAndValue ',' Value AShrInst -> AShrInst - : 'ashr' Exactopt X=TypeValue ',' Y=Value InstMetadata + : 'ashr' Exactopt X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2068,7 +2075,7 @@ AShrInst -> AShrInst # ::= ArithmeticOps TypeAndValue ',' Value { AndInst -> AndInst - : 'and' X=TypeValue ',' Y=Value InstMetadata + : 'and' X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2080,7 +2087,7 @@ AndInst -> AndInst # ::= ArithmeticOps TypeAndValue ',' Value { OrInst -> OrInst - : 'or' X=TypeValue ',' Y=Value InstMetadata + : 'or' X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2092,7 +2099,7 @@ OrInst -> OrInst # ::= ArithmeticOps TypeAndValue ',' Value { XorInst -> XorInst - : 'xor' X=TypeValue ',' Y=Value InstMetadata + : 'xor' X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # --- [ Vector instructions ] -------------------------------------------------- @@ -2106,7 +2113,7 @@ XorInst -> XorInst # ::= 'extractelement' TypeAndValue ',' TypeAndValue ExtractElementInst -> ExtractElementInst - : 'extractelement' X=TypeValue ',' Index=TypeValue InstMetadata + : 'extractelement' X=TypeValue ',' Index=TypeValue Metadata=(',' MetadataAttachment)+? ; # ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2118,7 +2125,7 @@ ExtractElementInst -> ExtractElementInst # ::= 'insertelement' TypeAndValue ',' TypeAndValue ',' TypeAndValue InsertElementInst -> InsertElementInst - : 'insertelement' X=TypeValue ',' Elem=TypeValue ',' Index=TypeValue InstMetadata + : 'insertelement' X=TypeValue ',' Elem=TypeValue ',' Index=TypeValue Metadata=(',' MetadataAttachment)+? ; # ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2130,7 +2137,7 @@ InsertElementInst -> InsertElementInst # ::= 'shufflevector' TypeAndValue ',' TypeAndValue ',' TypeAndValue ShuffleVectorInst -> ShuffleVectorInst - : 'shufflevector' X=TypeValue ',' Y=TypeValue ',' Mask=TypeValue InstMetadata + : 'shufflevector' X=TypeValue ',' Y=TypeValue ',' Mask=TypeValue Metadata=(',' MetadataAttachment)+? ; # --- [ Aggregate instructions ] ----------------------------------------------- @@ -2144,7 +2151,7 @@ ShuffleVectorInst -> ShuffleVectorInst # ::= 'extractvalue' TypeAndValue (',' uint32)+ ExtractValueInst -> ExtractValueInst - : 'extractvalue' X=TypeValue Indices=(',' UintLit)+ InstMetadata + : 'extractvalue' X=TypeValue Indices=(',' UintLit)+ Metadata=(',' MetadataAttachment)+? ; # ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2156,7 +2163,7 @@ ExtractValueInst -> ExtractValueInst # ::= 'insertvalue' TypeAndValue ',' TypeAndValue (',' uint32)+ InsertValueInst -> InsertValueInst - : 'insertvalue' X=TypeValue ',' Elem=TypeValue Indices=(',' UintLit)+ InstMetadata + : 'insertvalue' X=TypeValue ',' Elem=TypeValue Indices=(',' UintLit)+ Metadata=(',' MetadataAttachment)+? ; # --- [ Memory instructions ] -------------------------------------------------- @@ -2171,7 +2178,7 @@ InsertValueInst -> InsertValueInst # (',' 'align' i32)? (',', 'addrspace(n))? AllocaInst -> AllocaInst - : 'alloca' InAllocaopt SwiftErroropt ElemType=Type NElems=(',' TypeValue)? (',' Alignment)? (',' AddrSpace)? InstMetadata + : 'alloca' InAllocaopt SwiftErroropt ElemType=Type NElems=(',' TypeValue)? (',' Alignment)? (',' AddrSpace)? Metadata=(',' MetadataAttachment)+? ; InAlloca -> InAlloca @@ -2194,9 +2201,9 @@ SwiftError -> SwiftError LoadInst -> LoadInst # Load. - : 'load' Volatileopt ElemType=Type ',' Src=TypeValue (',' Alignment)? InstMetadata + : 'load' Volatileopt ElemType=Type ',' Src=TypeValue (',' Alignment)? Metadata=(',' MetadataAttachment)+? # Atomic load. - | 'load' Atomic Volatileopt ElemType=Type ',' Src=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? InstMetadata + | 'load' Atomic Volatileopt ElemType=Type ',' Src=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? Metadata=(',' MetadataAttachment)+? ; # ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2210,8 +2217,8 @@ LoadInst -> LoadInst # 'singlethread'? AtomicOrdering (',' 'align' i32)? StoreInst -> StoreInst - : 'store' Volatileopt Src=TypeValue ',' Dst=TypeValue (',' Alignment)? InstMetadata - | 'store' Atomic Volatileopt Src=TypeValue ',' Dst=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? InstMetadata + : 'store' Volatileopt Src=TypeValue ',' Dst=TypeValue (',' Alignment)? Metadata=(',' MetadataAttachment)+? + | 'store' Atomic Volatileopt Src=TypeValue ',' Dst=TypeValue SyncScopeopt AtomicOrdering (',' Alignment)? Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2223,7 +2230,7 @@ StoreInst -> StoreInst # ::= 'fence' 'singlethread'? AtomicOrdering FenceInst -> FenceInst - : 'fence' SyncScopeopt AtomicOrdering InstMetadata + : 'fence' SyncScopeopt AtomicOrdering Metadata=(',' MetadataAttachment)+? ; # ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2236,7 +2243,7 @@ FenceInst -> FenceInst # TypeAndValue 'singlethread'? AtomicOrdering AtomicOrdering CmpXchgInst -> CmpXchgInst - : 'cmpxchg' Weakopt Volatileopt Ptr=TypeValue ',' Cmp=TypeValue ',' New=TypeValue SyncScopeopt Success=AtomicOrdering Failure=AtomicOrdering InstMetadata + : 'cmpxchg' Weakopt Volatileopt Ptr=TypeValue ',' Cmp=TypeValue ',' New=TypeValue SyncScopeopt Success=AtomicOrdering Failure=AtomicOrdering Metadata=(',' MetadataAttachment)+? ; Weak -> Weak @@ -2253,7 +2260,7 @@ Weak -> Weak # 'singlethread'? AtomicOrdering AtomicRMWInst -> AtomicRMWInst - : 'atomicrmw' Volatileopt Op=AtomicOp Dst=TypeValue ',' X=TypeValue SyncScopeopt AtomicOrdering InstMetadata + : 'atomicrmw' Volatileopt Op=AtomicOp Dst=TypeValue ',' X=TypeValue SyncScopeopt AtomicOrdering Metadata=(',' MetadataAttachment)+? ; AtomicOp -> AtomicOp @@ -2279,7 +2286,7 @@ AtomicOp -> AtomicOp # ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)* GetElementPtrInst -> GetElementPtrInst - : 'getelementptr' InBoundsopt ElemType=Type ',' Src=TypeValue Indices=(',' TypeValue)* InstMetadata + : 'getelementptr' InBoundsopt ElemType=Type ',' Src=TypeValue Indices=(',' TypeValue)* Metadata=(',' MetadataAttachment)+? ; # --- [ Conversion instructions ] ---------------------------------------------- @@ -2293,7 +2300,7 @@ GetElementPtrInst -> GetElementPtrInst # ::= CastOpc TypeAndValue 'to' Type TruncInst -> TruncInst - : 'trunc' From=TypeValue 'to' To=Type InstMetadata + : 'trunc' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2305,7 +2312,7 @@ TruncInst -> TruncInst # ::= CastOpc TypeAndValue 'to' Type ZExtInst -> ZExtInst - : 'zext' From=TypeValue 'to' To=Type InstMetadata + : 'zext' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2317,7 +2324,7 @@ ZExtInst -> ZExtInst # ::= CastOpc TypeAndValue 'to' Type SExtInst -> SExtInst - : 'sext' From=TypeValue 'to' To=Type InstMetadata + : 'sext' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2329,7 +2336,7 @@ SExtInst -> SExtInst # ::= CastOpc TypeAndValue 'to' Type FPTruncInst -> FPTruncInst - : 'fptrunc' From=TypeValue 'to' To=Type InstMetadata + : 'fptrunc' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2341,7 +2348,7 @@ FPTruncInst -> FPTruncInst # ::= CastOpc TypeAndValue 'to' Type FPExtInst -> FPExtInst - : 'fpext' From=TypeValue 'to' To=Type InstMetadata + : 'fpext' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2353,7 +2360,7 @@ FPExtInst -> FPExtInst # ::= CastOpc TypeAndValue 'to' Type FPToUIInst -> FPToUIInst - : 'fptoui' From=TypeValue 'to' To=Type InstMetadata + : 'fptoui' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2365,7 +2372,7 @@ FPToUIInst -> FPToUIInst # ::= CastOpc TypeAndValue 'to' Type FPToSIInst -> FPToSIInst - : 'fptosi' From=TypeValue 'to' To=Type InstMetadata + : 'fptosi' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2377,7 +2384,7 @@ FPToSIInst -> FPToSIInst # ::= CastOpc TypeAndValue 'to' Type UIToFPInst -> UIToFPInst - : 'uitofp' From=TypeValue 'to' To=Type InstMetadata + : 'uitofp' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2389,7 +2396,7 @@ UIToFPInst -> UIToFPInst # ::= CastOpc TypeAndValue 'to' Type SIToFPInst -> SIToFPInst - : 'sitofp' From=TypeValue 'to' To=Type InstMetadata + : 'sitofp' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2401,7 +2408,7 @@ SIToFPInst -> SIToFPInst # ::= CastOpc TypeAndValue 'to' Type PtrToIntInst -> PtrToIntInst - : 'ptrtoint' From=TypeValue 'to' To=Type InstMetadata + : 'ptrtoint' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2413,7 +2420,7 @@ PtrToIntInst -> PtrToIntInst # ::= CastOpc TypeAndValue 'to' Type IntToPtrInst -> IntToPtrInst - : 'inttoptr' From=TypeValue 'to' To=Type InstMetadata + : 'inttoptr' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2425,7 +2432,7 @@ IntToPtrInst -> IntToPtrInst # ::= CastOpc TypeAndValue 'to' Type BitCastInst -> BitCastInst - : 'bitcast' From=TypeValue 'to' To=Type InstMetadata + : 'bitcast' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2437,7 +2444,7 @@ BitCastInst -> BitCastInst # ::= CastOpc TypeAndValue 'to' Type AddrSpaceCastInst -> AddrSpaceCastInst - : 'addrspacecast' From=TypeValue 'to' To=Type InstMetadata + : 'addrspacecast' From=TypeValue 'to' To=Type Metadata=(',' MetadataAttachment)+? ; # --- [ Other instructions ] --------------------------------------------------- @@ -2451,7 +2458,7 @@ AddrSpaceCastInst -> AddrSpaceCastInst # ::= 'icmp' IPredicates TypeAndValue ',' Value ICmpInst -> ICmpInst - : 'icmp' Pred=IPred X=TypeValue ',' Y=Value InstMetadata + : 'icmp' Pred=IPred X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2463,7 +2470,7 @@ ICmpInst -> ICmpInst # ::= 'fcmp' FPredicates TypeAndValue ',' Value FCmpInst -> FCmpInst - : 'fcmp' FastMathFlags=FastMathFlag* Pred=FPred X=TypeValue ',' Y=Value InstMetadata + : 'fcmp' FastMathFlags=FastMathFlag* Pred=FPred X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+? ; # ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2475,7 +2482,7 @@ FCmpInst -> FCmpInst # ::= 'phi' Type '[' Value ',' Value ']' (',' '[' Value ',' Value ']')* PhiInst -> PhiInst - : 'phi' Typ=Type Incs=(Inc separator ',')+ InstMetadata + : 'phi' Typ=Type Incs=(Inc separator ',')+ Metadata=(',' MetadataAttachment)+? ; Inc -> Inc @@ -2491,7 +2498,7 @@ Inc -> Inc # ::= 'select' TypeAndValue ',' TypeAndValue ',' TypeAndValue SelectInst -> SelectInst - : 'select' Cond=TypeValue ',' X=TypeValue ',' Y=TypeValue InstMetadata + : 'select' Cond=TypeValue ',' X=TypeValue ',' Y=TypeValue Metadata=(',' MetadataAttachment)+? ; # ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2509,8 +2516,19 @@ SelectInst -> SelectInst # ::= 'notail' 'call' OptionalFastMathFlags OptionalCallingConv # OptionalAttrs Type Value ParameterList OptionalAttrs +# ref: ParseOptionalOperandBundles +# +# ::= empty +# ::= '[' OperandBundle [, OperandBundle ]* ']' +# +# OperandBundle +# ::= bundle-tag '(' ')' +# ::= bundle-tag '(' Type Value [, Type Value ]* ')' +# +# bundle-tag ::= String Constant + CallInst -> CallInst - : Tailopt 'call' FastMathFlags=FastMathFlag* CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Typ=Type Callee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles InstMetadata + : Tailopt 'call' FastMathFlags=FastMathFlag* CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Typ=Type Callee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles=('[' (OperandBundle separator ',')+ ']')? Metadata=(',' MetadataAttachment)+? ; Tail -> Tail @@ -2528,7 +2546,7 @@ Tail -> Tail # ::= 'va_arg' TypeAndValue ',' Type VAArgInst -> VAArgInst - : 'va_arg' ArgList=TypeValue ',' ArgType=Type InstMetadata + : 'va_arg' ArgList=TypeValue ',' ArgType=Type Metadata=(',' MetadataAttachment)+? ; # ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2544,7 +2562,7 @@ VAArgInst -> VAArgInst # ::= 'filter' TypeAndValue ( ',' TypeAndValue )* LandingPadInst -> LandingPadInst - : 'landingpad' Typ=Type Cleanupopt Clauses=Clause* InstMetadata + : 'landingpad' Typ=Type Cleanupopt Clauses=Clause* Metadata=(',' MetadataAttachment)+? ; Cleanup -> Cleanup @@ -2563,7 +2581,7 @@ CatchClause -> CatchClause ; FilterClause -> FilterClause - : 'filter' Typ=Type Val=ArrayConst + : 'filter' XTyp=Type X=ArrayConst ; # ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2573,7 +2591,7 @@ FilterClause -> FilterClause # ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue CatchPadInst -> CatchPadInst - : 'catchpad' 'within' Scope=LocalIdent '[' Args=(ExceptionArg separator ',')* ']' InstMetadata + : 'catchpad' 'within' Scope=LocalIdent '[' Args=(ExceptionArg separator ',')* ']' Metadata=(',' MetadataAttachment)+? ; # ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2583,7 +2601,7 @@ CatchPadInst -> CatchPadInst # ::= 'cleanuppad' within Parent ParamList CleanupPadInst -> CleanupPadInst - : 'cleanuppad' 'within' Scope=ExceptionScope '[' Args=(ExceptionArg separator ',')* ']' InstMetadata + : 'cleanuppad' 'within' Scope=ExceptionScope '[' Args=(ExceptionArg separator ',')* ']' Metadata=(',' MetadataAttachment)+? ; # === [ Terminators ] ========================================================== @@ -2595,8 +2613,11 @@ CleanupPadInst -> CleanupPadInst %interface Terminator; Terminator -> Terminator + # Terminators producing values. + : LocalDefTerm + | ValueTerminator # Terminators not producing values. - : RetTerm + | RetTerm | BrTerm | CondBrTerm | SwitchTerm @@ -2605,9 +2626,6 @@ Terminator -> Terminator | CatchRetTerm | CleanupRetTerm | UnreachableTerm - # Terminators producing values. - | LocalDefTerm - | ValueTerminator ; LocalDefTerm -> LocalDefTerm @@ -2632,9 +2650,9 @@ ValueTerminator -> ValueTerminator RetTerm -> RetTerm # Void return. - : 'ret' XTyp=VoidType InstMetadata + : 'ret' XTyp=VoidType Metadata=(',' MetadataAttachment)+? # Value return. - | 'ret' XTyp=ConcreteType X=Value InstMetadata + | 'ret' XTyp=ConcreteType X=Value Metadata=(',' MetadataAttachment)+? ; # --- [ br ] ------------------------------------------------------------------- @@ -2648,7 +2666,7 @@ RetTerm -> RetTerm # Unconditional branch. BrTerm -> BrTerm - : 'br' Target=Label InstMetadata + : 'br' Target=Label Metadata=(',' MetadataAttachment)+? ; # TODO: replace `IntType Value` with TypeValue when the parser generator @@ -2656,7 +2674,7 @@ BrTerm -> BrTerm # Conditional branch. CondBrTerm -> CondBrTerm - : 'br' CondTyp=IntType Cond=Value ',' TargetTrue=Label ',' TargetFalse=Label InstMetadata + : 'br' CondTyp=IntType Cond=Value ',' TargetTrue=Label ',' TargetFalse=Label Metadata=(',' MetadataAttachment)+? ; # --- [ switch ] --------------------------------------------------------------- @@ -2670,7 +2688,7 @@ CondBrTerm -> CondBrTerm # ::= (TypeAndValue ',' TypeAndValue)* SwitchTerm -> SwitchTerm - : 'switch' X=TypeValue ',' Default=Label '[' Cases=Case* ']' InstMetadata + : 'switch' X=TypeValue ',' Default=Label '[' Cases=Case* ']' Metadata=(',' MetadataAttachment)+? ; Case -> Case @@ -2686,7 +2704,7 @@ Case -> Case # ::= 'indirectbr' TypeAndValue ',' '[' LabelList ']' IndirectBrTerm -> IndirectBrTerm - : 'indirectbr' Addr=TypeValue ',' '[' ValidTargets=(Label separator ',')+ ']' InstMetadata + : 'indirectbr' Addr=TypeValue ',' '[' ValidTargets=(Label separator ',')+ ']' Metadata=(',' MetadataAttachment)+? ; # --- [ invoke ] --------------------------------------------------------------- @@ -2699,7 +2717,7 @@ IndirectBrTerm -> IndirectBrTerm # OptionalAttrs 'to' TypeAndValue 'unwind' TypeAndValue InvokeTerm -> InvokeTerm - : 'invoke' CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Typ=Type Invokee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles 'to' Normal=Label 'unwind' Exception=Label InstMetadata + : 'invoke' CallingConvopt ReturnAttrs=ReturnAttr* AddrSpaceopt Typ=Type Invokee=Value '(' Args ')' FuncAttrs=FuncAttr* OperandBundles=('[' (OperandBundle separator ',')+ ']')? 'to' Normal=Label 'unwind' Exception=Label Metadata=(',' MetadataAttachment)+? ; # --- [ resume ] --------------------------------------------------------------- @@ -2711,7 +2729,7 @@ InvokeTerm -> InvokeTerm # ::= 'resume' TypeAndValue ResumeTerm -> ResumeTerm - : 'resume' X=TypeValue InstMetadata + : 'resume' X=TypeValue Metadata=(',' MetadataAttachment)+? ; # --- [ catchswitch ] ---------------------------------------------------------- @@ -2723,7 +2741,7 @@ ResumeTerm -> ResumeTerm # ::= 'catchswitch' within Parent CatchSwitchTerm -> CatchSwitchTerm - : 'catchswitch' 'within' Scope=ExceptionScope '[' Handlers=(Label separator ',')+ ']' 'unwind' UnwindTarget InstMetadata + : 'catchswitch' 'within' Scope=ExceptionScope '[' Handlers=(Label separator ',')+ ']' 'unwind' UnwindTarget Metadata=(',' MetadataAttachment)+? ; # --- [ catchret ] ------------------------------------------------------------- @@ -2735,7 +2753,7 @@ CatchSwitchTerm -> CatchSwitchTerm # ::= 'catchret' from Parent Value 'to' TypeAndValue CatchRetTerm -> CatchRetTerm - : 'catchret' 'from' From=Value 'to' To=Label InstMetadata + : 'catchret' 'from' From=Value 'to' To=Label Metadata=(',' MetadataAttachment)+? ; # --- [ cleanupret ] ----------------------------------------------------------- @@ -2747,7 +2765,7 @@ CatchRetTerm -> CatchRetTerm # ::= 'cleanupret' from Value unwind ('to' 'caller' | TypeAndValue) CleanupRetTerm -> CleanupRetTerm - : 'cleanupret' 'from' From=Value 'unwind' UnwindTarget InstMetadata + : 'cleanupret' 'from' From=Value 'unwind' UnwindTarget Metadata=(',' MetadataAttachment)+? ; # --- [ unreachable ] ---------------------------------------------------------- @@ -2757,7 +2775,7 @@ CleanupRetTerm -> CleanupRetTerm # ref: ParseInstruction UnreachableTerm -> UnreachableTerm - : 'unreachable' InstMetadata + : 'unreachable' Metadata=(',' MetadataAttachment)+? ; # === [ Metadata Nodes and Metadata Strings ] ================================== @@ -4335,7 +4353,7 @@ Comdat -> Comdat Dereferenceable -> Dereferenceable : 'dereferenceable' '(' N=UintLit ')' - | 'dereferenceable_or_null' '(' N=UintLit ')' + | 'dereferenceable_or_null' '(' N=UintLit ')' # TODO: distinguish dereferenceable_or_null from dereferenceable during IR translation. ; # https://llvm.org/docs/LangRef.html#dll-storage-classes @@ -4427,6 +4445,7 @@ FuncAttr -> FuncAttr | AlignPair | AlignStackPair # used in functions. + # TODO: Figure out how to enable Alignment in FuncAttr again. #| Alignment # NOTE: removed to resolve reduce/reduce conflict, see above. | AllocSize | StackAlignment @@ -4477,14 +4496,6 @@ FuncAttribute -> FuncAttribute | 'writeonly' ; -# ref: ParseOptionalFunctionMetadata -# -# ::= (!dbg !57)* - -FuncMetadata -> FuncMetadata - : MetadataAttachments=MetadataAttachment* -; - # TODO: consider removing remove GlobalAttr in favour of using (',' Section)? # (',' Comdat)? (',' Alignment)? (',' MetadataAttachment)* as was used in the # LangRef spec of LLVM IR. Note that the LLVM C++ parser is implemented using @@ -4504,14 +4515,6 @@ InBounds -> InBounds : 'inbounds' ; -# ref: ParseInstructionMetadata -# -# ::= !dbg !42 (',' !dbg !57)* - -InstMetadata -> InstMetadata - : MetadataAttachments=(',' MetadataAttachment)+? -; - # ref: ParseCmpPredicate IPred -> IPred @@ -4548,6 +4551,10 @@ Label -> Label # ::= 'extern_weak' # ::= 'external' +# TODO: Check if it is possible to merge Linkage and ExternLinkage. Currently, +# this is not possible as it leads to shift/reduce conflicts. Perhaps when the +# parser generator is better capable at resolving conflicts. + Linkage -> Linkage : 'appending' | 'available_externally' @@ -4565,23 +4572,6 @@ ExternLinkage -> ExternLinkage | 'external' ; -# ref: ParseOptionalOperandBundles -# -# ::= empty -# ::= '[' OperandBundle [, OperandBundle ]* ']' -# -# OperandBundle -# ::= bundle-tag '(' ')' -# ::= bundle-tag '(' Type Value [, Type Value ]* ')' -# -# bundle-tag ::= String Constant - -# TODO: inline OperandBundles to avoid OperandBundles as a node in the AST? - -OperandBundles -> OperandBundles - : ('[' OperandBundles=(OperandBundle separator ',')+ ']')? -; - OperandBundle -> OperandBundle : Tag=StringLit '(' Inputs=(TypeValue separator ',')* ')' ; @@ -4685,7 +4675,7 @@ Section -> Section : 'section' Name=StringLit ; -# TODO: StackAlignment rename to AlignStack? +# TODO: rename StackAlignment to AlignStack? # ref: ParseOptionalStackAlignment # @@ -4741,6 +4731,10 @@ UnnamedAddr -> UnnamedAddr | 'unnamed_addr' ; +# TODO: Make UnwindTarget into an interface? The current issue is that +# catchswitch becomes ambiguous with the following error reported: +# `'Handlers' cannot be a list, since it precedes UnwindTarget` + UnwindTarget -> UnwindTarget : 'to' 'caller' | Label From 22cb1a62871def93e2e06f1a537aa4ec27e4938e Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 29 Oct 2018 20:45:00 +0100 Subject: [PATCH 64/70] asm/enum: generate string to enum conversions --- asm/enum/Makefile | 14 ++++++++++++++ asm/enum/callingconv_string.go | 22 ++++++++++++++++++++++ asm/enum/dllstorageclass_string.go | 22 ++++++++++++++++++++++ asm/enum/fastmathflag_string.go | 22 ++++++++++++++++++++++ asm/enum/fpred_string.go | 22 ++++++++++++++++++++++ asm/enum/ipred_string.go | 22 ++++++++++++++++++++++ asm/enum/linkage_string.go | 22 ++++++++++++++++++++++ asm/enum/overflowflag_string.go | 22 ++++++++++++++++++++++ asm/enum/preemption_string.go | 22 ++++++++++++++++++++++ asm/enum/selectionkind_string.go | 22 ++++++++++++++++++++++ asm/enum/tail_string.go | 22 ++++++++++++++++++++++ asm/enum/tlsmodel_string.go | 22 ++++++++++++++++++++++ asm/enum/unnamedaddr_string.go | 22 ++++++++++++++++++++++ asm/enum/visibility_string.go | 22 ++++++++++++++++++++++ 14 files changed, 300 insertions(+) create mode 100644 asm/enum/Makefile create mode 100644 asm/enum/callingconv_string.go create mode 100644 asm/enum/dllstorageclass_string.go create mode 100644 asm/enum/fastmathflag_string.go create mode 100644 asm/enum/fpred_string.go create mode 100644 asm/enum/ipred_string.go create mode 100644 asm/enum/linkage_string.go create mode 100644 asm/enum/overflowflag_string.go create mode 100644 asm/enum/preemption_string.go create mode 100644 asm/enum/selectionkind_string.go create mode 100644 asm/enum/tail_string.go create mode 100644 asm/enum/tlsmodel_string.go create mode 100644 asm/enum/unnamedaddr_string.go create mode 100644 asm/enum/visibility_string.go diff --git a/asm/enum/Makefile b/asm/enum/Makefile new file mode 100644 index 00000000..62a8aa73 --- /dev/null +++ b/asm/enum/Makefile @@ -0,0 +1,14 @@ +all: + string2enum -linecomment -type CallingConv /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type DLLStorageClass /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type FastMathFlag /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type FPred /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type IPred /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type Linkage /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type OverflowFlag /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type Preemption /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type SelectionKind /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type Tail /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type TLSModel /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type UnnamedAddr /home/u/Desktop/go/src/github.com/llir/l/ir/enum + string2enum -linecomment -type Visibility /home/u/Desktop/go/src/github.com/llir/l/ir/enum diff --git a/asm/enum/callingconv_string.go b/asm/enum/callingconv_string.go new file mode 100644 index 00000000..ba2551ce --- /dev/null +++ b/asm/enum/callingconv_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type CallingConv /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _CallingConv_name = "noneamdgpu_csamdgpu_esamdgpu_gsamdgpu_hsamdgpu_kernelamdgpu_lsamdgpu_psamdgpu_vsanyregccarm_aapcs_vfpccarm_aapcsccarm_apcsccavr_intrccavr_signalccccccoldcccxx_fast_tlsccfastccghccchhvm_ccchhvmccintel_ocl_biccmsp430_intrccpreserve_allccpreserve_mostccptx_deviceptx_kernelspir_funcspir_kernelswiftccwebkit_jsccwin64ccx86_64_sysvccx86_fastcallccx86_intrccx86_regcallccx86_stdcallccx86_thiscallccx86_vectorcallcccc 11cc 86cc 87cc 88cc 89cc 90cc 91cc 93cc 94cc 95cc 96" + +var _CallingConv_index = [...]uint16{0, 4, 13, 22, 31, 40, 53, 62, 71, 80, 88, 103, 114, 124, 134, 146, 149, 155, 169, 175, 180, 188, 194, 208, 221, 235, 250, 260, 270, 279, 290, 297, 308, 315, 328, 342, 352, 365, 378, 392, 408, 413, 418, 423, 428, 433, 438, 443, 448, 453, 458, 463} + +func CallingConvFromString(s string) enum.CallingConv { + if len(s) == 0 { + return 0 + } + for i := range _CallingConv_index[:len(_CallingConv_index)-1] { + if s == _CallingConv_name[_CallingConv_index[i]:_CallingConv_index[i+1]] { + return enum.CallingConv(i) + } + } + panic(fmt.Errorf("unable to locate CallingConv enum corresponding to %q", s)) +} diff --git a/asm/enum/dllstorageclass_string.go b/asm/enum/dllstorageclass_string.go new file mode 100644 index 00000000..af217d2d --- /dev/null +++ b/asm/enum/dllstorageclass_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type DLLStorageClass /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _DLLStorageClass_name = "nonedllexportdllimport" + +var _DLLStorageClass_index = [...]uint8{0, 4, 13, 22} + +func DLLStorageClassFromString(s string) enum.DLLStorageClass { + if len(s) == 0 { + return 0 + } + for i := range _DLLStorageClass_index[:len(_DLLStorageClass_index)-1] { + if s == _DLLStorageClass_name[_DLLStorageClass_index[i]:_DLLStorageClass_index[i+1]] { + return enum.DLLStorageClass(i) + } + } + panic(fmt.Errorf("unable to locate DLLStorageClass enum corresponding to %q", s)) +} diff --git a/asm/enum/fastmathflag_string.go b/asm/enum/fastmathflag_string.go new file mode 100644 index 00000000..231caab5 --- /dev/null +++ b/asm/enum/fastmathflag_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type FastMathFlag /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _FastMathFlag_name = "afnarcpcontractfastninfnnannszreassoc" + +var _FastMathFlag_index = [...]uint8{0, 3, 7, 15, 19, 23, 27, 30, 37} + +func FastMathFlagFromString(s string) enum.FastMathFlag { + if len(s) == 0 { + return 0 + } + for i := range _FastMathFlag_index[:len(_FastMathFlag_index)-1] { + if s == _FastMathFlag_name[_FastMathFlag_index[i]:_FastMathFlag_index[i+1]] { + return enum.FastMathFlag(i) + } + } + panic(fmt.Errorf("unable to locate FastMathFlag enum corresponding to %q", s)) +} diff --git a/asm/enum/fpred_string.go b/asm/enum/fpred_string.go new file mode 100644 index 00000000..3230d60a --- /dev/null +++ b/asm/enum/fpred_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type FPred /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _FPred_name = "falseoeqogeogtoleoltoneordtrueuequgeugtuleultuneuno" + +var _FPred_index = [...]uint8{0, 5, 8, 11, 14, 17, 20, 23, 26, 30, 33, 36, 39, 42, 45, 48, 51} + +func FPredFromString(s string) enum.FPred { + if len(s) == 0 { + return 0 + } + for i := range _FPred_index[:len(_FPred_index)-1] { + if s == _FPred_name[_FPred_index[i]:_FPred_index[i+1]] { + return enum.FPred(i) + } + } + panic(fmt.Errorf("unable to locate FPred enum corresponding to %q", s)) +} diff --git a/asm/enum/ipred_string.go b/asm/enum/ipred_string.go new file mode 100644 index 00000000..6fdfc29d --- /dev/null +++ b/asm/enum/ipred_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type IPred /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _IPred_name = "eqnesgesgtslesltugeugtuleult" + +var _IPred_index = [...]uint8{0, 2, 4, 7, 10, 13, 16, 19, 22, 25, 28} + +func IPredFromString(s string) enum.IPred { + if len(s) == 0 { + return 0 + } + for i := range _IPred_index[:len(_IPred_index)-1] { + if s == _IPred_name[_IPred_index[i]:_IPred_index[i+1]] { + return enum.IPred(i) + } + } + panic(fmt.Errorf("unable to locate IPred enum corresponding to %q", s)) +} diff --git a/asm/enum/linkage_string.go b/asm/enum/linkage_string.go new file mode 100644 index 00000000..5946630a --- /dev/null +++ b/asm/enum/linkage_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type Linkage /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _Linkage_name = "noneappendingavailable_externallycommoninternallinkoncelinkonce_odrprivateweakweak_odrexternalextern_weak" + +var _Linkage_index = [...]uint8{0, 4, 13, 33, 39, 47, 55, 67, 74, 78, 86, 94, 105} + +func LinkageFromString(s string) enum.Linkage { + if len(s) == 0 { + return 0 + } + for i := range _Linkage_index[:len(_Linkage_index)-1] { + if s == _Linkage_name[_Linkage_index[i]:_Linkage_index[i+1]] { + return enum.Linkage(i) + } + } + panic(fmt.Errorf("unable to locate Linkage enum corresponding to %q", s)) +} diff --git a/asm/enum/overflowflag_string.go b/asm/enum/overflowflag_string.go new file mode 100644 index 00000000..22db9642 --- /dev/null +++ b/asm/enum/overflowflag_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type OverflowFlag /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _OverflowFlag_name = "nswnuw" + +var _OverflowFlag_index = [...]uint8{0, 3, 6} + +func OverflowFlagFromString(s string) enum.OverflowFlag { + if len(s) == 0 { + return 0 + } + for i := range _OverflowFlag_index[:len(_OverflowFlag_index)-1] { + if s == _OverflowFlag_name[_OverflowFlag_index[i]:_OverflowFlag_index[i+1]] { + return enum.OverflowFlag(i) + } + } + panic(fmt.Errorf("unable to locate OverflowFlag enum corresponding to %q", s)) +} diff --git a/asm/enum/preemption_string.go b/asm/enum/preemption_string.go new file mode 100644 index 00000000..7eab8b99 --- /dev/null +++ b/asm/enum/preemption_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type Preemption /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _Preemption_name = "nonedso_localdso_preemptable" + +var _Preemption_index = [...]uint8{0, 4, 13, 28} + +func PreemptionFromString(s string) enum.Preemption { + if len(s) == 0 { + return 0 + } + for i := range _Preemption_index[:len(_Preemption_index)-1] { + if s == _Preemption_name[_Preemption_index[i]:_Preemption_index[i+1]] { + return enum.Preemption(i) + } + } + panic(fmt.Errorf("unable to locate Preemption enum corresponding to %q", s)) +} diff --git a/asm/enum/selectionkind_string.go b/asm/enum/selectionkind_string.go new file mode 100644 index 00000000..96821931 --- /dev/null +++ b/asm/enum/selectionkind_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type SelectionKind /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _SelectionKind_name = "anyexactmatchlargestnoduplicatessamesize" + +var _SelectionKind_index = [...]uint8{0, 3, 13, 20, 32, 40} + +func SelectionKindFromString(s string) enum.SelectionKind { + if len(s) == 0 { + return 0 + } + for i := range _SelectionKind_index[:len(_SelectionKind_index)-1] { + if s == _SelectionKind_name[_SelectionKind_index[i]:_SelectionKind_index[i+1]] { + return enum.SelectionKind(i) + } + } + panic(fmt.Errorf("unable to locate SelectionKind enum corresponding to %q", s)) +} diff --git a/asm/enum/tail_string.go b/asm/enum/tail_string.go new file mode 100644 index 00000000..3311ae66 --- /dev/null +++ b/asm/enum/tail_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type Tail /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _Tail_name = "nonemusttailnotailtail" + +var _Tail_index = [...]uint8{0, 4, 12, 18, 22} + +func TailFromString(s string) enum.Tail { + if len(s) == 0 { + return 0 + } + for i := range _Tail_index[:len(_Tail_index)-1] { + if s == _Tail_name[_Tail_index[i]:_Tail_index[i+1]] { + return enum.Tail(i) + } + } + panic(fmt.Errorf("unable to locate Tail enum corresponding to %q", s)) +} diff --git a/asm/enum/tlsmodel_string.go b/asm/enum/tlsmodel_string.go new file mode 100644 index 00000000..18f5acbe --- /dev/null +++ b/asm/enum/tlsmodel_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type TLSModel /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _TLSModel_name = "nonethread_localthread_local(initialexec)thread_local(localdynamic)thread_local(localexec)" + +var _TLSModel_index = [...]uint8{0, 4, 16, 41, 67, 90} + +func TLSModelFromString(s string) enum.TLSModel { + if len(s) == 0 { + return 0 + } + for i := range _TLSModel_index[:len(_TLSModel_index)-1] { + if s == _TLSModel_name[_TLSModel_index[i]:_TLSModel_index[i+1]] { + return enum.TLSModel(i) + } + } + panic(fmt.Errorf("unable to locate TLSModel enum corresponding to %q", s)) +} diff --git a/asm/enum/unnamedaddr_string.go b/asm/enum/unnamedaddr_string.go new file mode 100644 index 00000000..c341ac29 --- /dev/null +++ b/asm/enum/unnamedaddr_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type UnnamedAddr /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _UnnamedAddr_name = "nonelocal_unnamed_addrunnamed_addr" + +var _UnnamedAddr_index = [...]uint8{0, 4, 22, 34} + +func UnnamedAddrFromString(s string) enum.UnnamedAddr { + if len(s) == 0 { + return 0 + } + for i := range _UnnamedAddr_index[:len(_UnnamedAddr_index)-1] { + if s == _UnnamedAddr_name[_UnnamedAddr_index[i]:_UnnamedAddr_index[i+1]] { + return enum.UnnamedAddr(i) + } + } + panic(fmt.Errorf("unable to locate UnnamedAddr enum corresponding to %q", s)) +} diff --git a/asm/enum/visibility_string.go b/asm/enum/visibility_string.go new file mode 100644 index 00000000..7a760e14 --- /dev/null +++ b/asm/enum/visibility_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type Visibility /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _Visibility_name = "nonedefaulthiddenprotected" + +var _Visibility_index = [...]uint8{0, 4, 11, 17, 26} + +func VisibilityFromString(s string) enum.Visibility { + if len(s) == 0 { + return 0 + } + for i := range _Visibility_index[:len(_Visibility_index)-1] { + if s == _Visibility_name[_Visibility_index[i]:_Visibility_index[i+1]] { + return enum.Visibility(i) + } + } + panic(fmt.Errorf("unable to locate Visibility enum corresponding to %q", s)) +} From 47445a4f2b5f91a0a66294ee6ae9735f8ab2b47c Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 29 Oct 2018 21:45:02 +0100 Subject: [PATCH 65/70] asm: update to make use of TM 0.9.22 --- .gitignore | 2 + asm/const_expr.go | 4 +- asm/global.go | 68 ++++---- asm/helper.go | 411 +++++++++++---------------------------------- asm/index_local.go | 2 +- asm/ll/ll.tm | 1 + asm/local.go | 15 +- asm/parser.go | 85 +--------- asm/tree.go | 164 ------------------ asm/type.go | 6 +- 10 files changed, 156 insertions(+), 602 deletions(-) delete mode 100644 asm/tree.go diff --git a/.gitignore b/.gitignore index 37e24437..ef60d47c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ asm/ll/ast/ast.go asm/ll/ast/factory.go +asm/ll/ast/parser.go +asm/ll/ast/tree.go asm/ll/lexer.go asm/ll/lexer_tables.go asm/ll/listener.go diff --git a/asm/const_expr.go b/asm/const_expr.go index e54db33d..e8cbfc51 100644 --- a/asm/const_expr.go +++ b/asm/const_expr.go @@ -278,7 +278,7 @@ func (gen *generator) irGetElementPtrExpr(t types.Type, old *ast.GetElementPtrEx expr := ir.NewGetElementPtrExpr(elemType, src, indices...) // TODO: validate type t against expr.Typ. // In-bounds. - expr.InBounds = irInBounds(old.InBounds()) + expr.InBounds = irOptInBounds(old.InBounds()) return expr, nil } @@ -289,7 +289,7 @@ func (gen *generator) irGEPIndex(old ast.GEPIndex) (*ir.Index, error) { return nil, errors.WithStack(err) } index := ir.NewIndex(idx) - index.InRange = irInRange(old.InRange()) + index.InRange = irOptInRange(old.InRange()) return index, nil } diff --git a/asm/global.go b/asm/global.go index 6dc94361..c65f4855 100644 --- a/asm/global.go +++ b/asm/global.go @@ -26,7 +26,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant globalOrder = append(globalOrder, name) if prev, ok := index[name]; ok { // TODO: don't report error if prev is a declaration (of same type)? - return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), text(prev), text(entity)) } index[name] = entity case *ast.GlobalDef: @@ -34,7 +34,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant globalOrder = append(globalOrder, name) if prev, ok := index[name]; ok { // TODO: don't report error if prev is a declaration (of same type)? - return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), text(prev), text(entity)) } index[name] = entity case *ast.FuncDecl: @@ -42,7 +42,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant funcOrder = append(funcOrder, name) if prev, ok := index[name]; ok { // TODO: don't report error if prev is a declaration (of same type)? - return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), text(prev), text(entity)) } index[name] = entity case *ast.FuncDef: @@ -50,7 +50,7 @@ func (gen *generator) resolveGlobals(module *ast.Module) (map[string]ir.Constant funcOrder = append(funcOrder, name) if prev, ok := index[name]; ok { // TODO: don't report error if prev is a declaration (of same type)? - return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), prev.Text(), entity.Text()) + return nil, errors.Errorf("AST global identifier %q already present; prev `%s`, new `%s`", enc.Global(name), text(prev), text(entity)) } index[name] = entity // TODO: handle alias definitions and IFuncs. @@ -148,7 +148,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err sig.Params = append(sig.Params, param) } // Variadic. - sig.Variadic = irVariadic(ps.Variadic()) + sig.Variadic = irOptVariadic(ps.Variadic()) f.Sig = sig f.Typ = types.NewPointer(f.Sig) return f, nil @@ -172,7 +172,7 @@ func (gen *generator) newGlobal(name string, old ast.LlvmNode) (ir.Constant, err sig.Params = append(sig.Params, param) } // Variadic. - sig.Variadic = irVariadic(ps.Variadic()) + sig.Variadic = irOptVariadic(ps.Variadic()) f.Sig = sig f.Typ = types.NewPointer(f.Sig) return f, nil @@ -206,21 +206,21 @@ func (gen *generator) astToIRGlobalDecl(g ir.Constant, old *ast.GlobalDecl) (*ir panic(fmt.Errorf("invalid IR type for AST global declaration; expected *ir.Global, got %T", g)) } // Linkage. - global.Linkage = irLinkage(old.ExternLinkage().Text()) + global.Linkage = irOptLinkage(old.ExternLinkage()) // Preemption. - global.Preemption = irPreemption(old.Preemption()) + global.Preemption = irOptPreemption(old.Preemption()) // Visibility. - global.Visibility = irVisibility(old.Visibility()) + global.Visibility = irOptVisibility(old.Visibility()) // DLL storage class. - global.DLLStorageClass = irDLLStorageClass(old.DLLStorageClass()) + global.DLLStorageClass = irOptDLLStorageClass(old.DLLStorageClass()) // Thread local storage model. - global.TLSModel = irTLSModelFromThreadLocal(old.ThreadLocal()) + global.TLSModel = irOptTLSModelFromThreadLocal(old.ThreadLocal()) // Unnamed address. - global.UnnamedAddr = irUnnamedAddr(old.UnnamedAddr()) + global.UnnamedAddr = irOptUnnamedAddr(old.UnnamedAddr()) // Address space. - global.Typ.AddrSpace = irAddrSpace(old.AddrSpace()) + global.Typ.AddrSpace = irOptAddrSpace(old.AddrSpace()) // Externally initialized. - global.ExternallyInitialized = irExternallyInitialized(old.ExternallyInitialized()) + global.ExternallyInitialized = irOptExternallyInitialized(old.ExternallyInitialized()) // Immutable (constant or global). global.Immutable = irImmutable(old.Immutable()) // Content type already stored during index. @@ -237,21 +237,21 @@ func (gen *generator) astToIRGlobalDef(g ir.Constant, old *ast.GlobalDef) (*ir.G panic(fmt.Errorf("invalid IR type for AST global definition; expected *ir.Global, got %T", g)) } // Linkage. - global.Linkage = irLinkage(old.Linkage().Text()) + global.Linkage = irOptLinkage(old.Linkage()) // Preemption. - global.Preemption = irPreemption(old.Preemption()) + global.Preemption = irOptPreemption(old.Preemption()) // Visibility. - global.Visibility = irVisibility(old.Visibility()) + global.Visibility = irOptVisibility(old.Visibility()) // DLL storage class. - global.DLLStorageClass = irDLLStorageClass(old.DLLStorageClass()) + global.DLLStorageClass = irOptDLLStorageClass(old.DLLStorageClass()) // Thread local storage model. - global.TLSModel = irTLSModelFromThreadLocal(old.ThreadLocal()) + global.TLSModel = irOptTLSModelFromThreadLocal(old.ThreadLocal()) // Unnamed address. - global.UnnamedAddr = irUnnamedAddr(old.UnnamedAddr()) + global.UnnamedAddr = irOptUnnamedAddr(old.UnnamedAddr()) // Address space. - global.Typ.AddrSpace = irAddrSpace(old.AddrSpace()) + global.Typ.AddrSpace = irOptAddrSpace(old.AddrSpace()) // Externally initialized. - global.ExternallyInitialized = irExternallyInitialized(old.ExternallyInitialized()) + global.ExternallyInitialized = irOptExternallyInitialized(old.ExternallyInitialized()) // Immutable (constant or global). global.Immutable = irImmutable(old.Immutable()) // Content type already stored during index. @@ -286,13 +286,13 @@ func (gen *generator) astToIRFuncDecl(g ir.Constant, old *ast.FuncDecl) (*ir.Fun func (gen *generator) astToIRFuncHeader(f *ir.Function, hdr ast.FuncHeader) error { // Linkage. - f.Linkage = irLinkage(hdr.ExternLinkage().Text()) + f.Linkage = irOptLinkage(hdr.ExternLinkage()) // Preemption. - f.Preemption = irPreemption(hdr.Preemption()) + f.Preemption = irOptPreemption(hdr.Preemption()) // Visibility. - f.Visibility = irVisibility(hdr.Visibility()) + f.Visibility = irOptVisibility(hdr.Visibility()) // DLL storage class. - f.DLLStorageClass = irDLLStorageClass(hdr.DLLStorageClass()) + f.DLLStorageClass = irOptDLLStorageClass(hdr.DLLStorageClass()) // Calling convention. // TODO: translate CallingConv. // Return attributes. @@ -309,15 +309,15 @@ func (gen *generator) astToIRFuncHeader(f *ir.Function, hdr ast.FuncHeader) erro } // Parameter attributes. // TODO: handle Attrs. - name := local(*p.Name()) + name := optLocal(p.Name()) param := ir.NewParam(typ, name) f.Params = append(f.Params, param) } // Unnamed address. - f.UnnamedAddr = irUnnamedAddr(hdr.UnnamedAddr()) + f.UnnamedAddr = irOptUnnamedAddr(hdr.UnnamedAddr()) // Address space. - f.Typ.AddrSpace = irAddrSpace(hdr.AddrSpace()) + f.Typ.AddrSpace = irOptAddrSpace(hdr.AddrSpace()) // Function attributes. // TODO: handle FuncAttrs. // Section. @@ -357,3 +357,13 @@ func (gen *generator) astToIRFuncDef(g ir.Constant, old *ast.FuncDef) (*ir.Funct // TODO: translate use list orders. return f, nil } + +// ### [ Helper functions ] #################################################### + +// text returns the text of the given node. +func text(n ast.LlvmNode) string { + if n := n.LlvmNode(); n != nil { + return n.Text() + } + return "" +} diff --git a/asm/helper.go b/asm/helper.go index 19a4d557..7e6f3bd6 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -8,6 +8,7 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/enum" "github.com/llir/l/ir/types" + asmenum "github.com/mewmew/l-tm/asm/enum" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/mewmew/l-tm/internal/enc" "github.com/pkg/errors" @@ -20,10 +21,6 @@ import ( // global returns the name (without '@' prefix) of the given global identifier. func global(n ast.GlobalIdent) string { text := n.Text() - if text == "" { - // \empty is used when global identifier not present. - return "" - } const prefix = "@" if !strings.HasPrefix(text, prefix) { // NOTE: Panic instead of returning error as this case should not be @@ -39,10 +36,6 @@ func global(n ast.GlobalIdent) string { // local returns the name (without '%' prefix) of the given local identifier. func local(n ast.LocalIdent) string { text := n.Text() - if text == "" { - // \empty is used when local identifier not present. - return "" - } const prefix = "%" if !strings.HasPrefix(text, prefix) { // NOTE: Panic instead of returning error as this case should not be @@ -53,15 +46,20 @@ func local(n ast.LocalIdent) string { return unquote(text) } +// optLocal returns the name (without '%' prefix) of the given optional local +// identifier. +func optLocal(n *ast.LocalIdent) string { + if n == nil { + return "" + } + return local(*n) +} + // --- [ Label Identifiers ] --------------------------------------------------- // label returns the name (without ':' suffix) of the given label identifier. func label(n ast.LabelIdent) string { text := n.Text() - if text == "" { - // \empty is used when label identifier not present. - return "" - } const suffix = ":" if !strings.HasSuffix(text, suffix) { // NOTE: Panic instead of returning error as this case should not be @@ -72,6 +70,15 @@ func label(n ast.LabelIdent) string { return unquote(text) } +// optLabel returns the name (without ':' suffix) of the given optional label +// identifier. +func optLabel(n *ast.LabelIdent) string { + if n == nil { + return "" + } + return label(*n) +} + // --- [ Attribute Group Identifiers ] ----------------------------------------- // --- [ Comdat Identifiers ] -------------------------------------------------- @@ -147,11 +154,10 @@ func stringLitBytes(n ast.StringLit) []byte { // ___ [ Helpers ] _____________________________________________________________ -// irAddrSpace returns the IR address space corresponding to the given optional -// AST address space. -func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { - // \empty is used when address space not present. - if n.Text() == "" { +// irOptAddrSpace returns the IR address space corresponding to the given +// optional AST address space. +func irOptAddrSpace(n *ast.AddrSpace) types.AddrSpace { + if n == nil { return 0 } x := uintLit(n.N()) @@ -159,112 +165,30 @@ func irAddrSpace(n *ast.AddrSpace) types.AddrSpace { } // irCase returns the IR switch case corresponding to the given AST switch case. -func (fgen *funcGen) irCase(old ast.Case) (*ir.Case, error) { - x, err := fgen.gen.irTypeConst(old.X()) +func (fgen *funcGen) irCase(n ast.Case) (*ir.Case, error) { + x, err := fgen.gen.irTypeConst(n.X()) if err != nil { return nil, errors.WithStack(err) } - target, err := fgen.irBasicBlock(old.Target()) + target, err := fgen.irBasicBlock(n.Target()) if err != nil { return nil, errors.WithStack(err) } return ir.NewCase(x, target), nil } -// irCallingConv returns the IR calling convention corresponding to the given +// irOptCallingConv returns the IR calling convention corresponding to the given // optional AST calling convention. -func irCallingConv(old ast.CallingConv) enum.CallingConv { - switch old := old.(type) { +func irOptCallingConv(n ast.CallingConv) enum.CallingConv { + if n == nil { + return enum.CallingConvNone + } + switch n := n.(type) { case *ast.CallingConvEnum: - text := old.Text() - switch text { - case "": - // \empty is used when calling convention not present. - return enum.CallingConvNone - case "amdgpu_cs": - return enum.CallingConvAmdGPUCS - case "amdgpu_es": - return enum.CallingConvAmdGPUES - case "amdgpu_gs": - return enum.CallingConvAmdGPUGS - case "amdgpu_hs": - return enum.CallingConvAmdGPUHS - case "amdgpu_kernel": - return enum.CallingConvAmdGPUKernel - case "amdgpu_ls": - return enum.CallingConvAmdGPULS - case "amdgpu_ps": - return enum.CallingConvAmdGPUPS - case "amdgpu_vs": - return enum.CallingConvAmdGPUVS - case "anyregcc": - return enum.CallingConvAnyReg - case "arm_aapcs_vfpcc": - return enum.CallingConvARMAAPCSVFP - case "arm_aapcscc": - return enum.CallingConvARMAAPCS - case "arm_apcscc": - return enum.CallingConvARMAPCS - case "avr_intrcc": - return enum.CallingConvAVRIntr - case "avr_signalcc": - return enum.CallingConvAVRSignal - case "ccc": - return enum.CallingConvC - case "coldcc": - return enum.CallingConvCold - case "cxx_fast_tlscc": - return enum.CallingConvCXXFastTLS - case "fastcc": - return enum.CallingConvFast - case "ghccc": - return enum.CallingConvGHC - case "hhvm_ccc": - return enum.CallingConvHHVMC - case "hhvmcc": - return enum.CallingConvHHVM - case "intel_ocl_bicc": - return enum.CallingConvIntelOCLBI - case "msp430_intrcc": - return enum.CallingConvMSP430Intr - case "preserve_allcc": - return enum.CallingConvPreserveAll - case "preserve_mostcc": - return enum.CallingConvPreserveMost - case "ptx_device": - return enum.CallingConvPTXDevice - case "ptx_kernel": - return enum.CallingConvPTXKernel - case "spir_func": - return enum.CallingConvSPIRFunc - case "spir_kernel": - return enum.CallingConvSPIRKernel - case "swiftcc": - return enum.CallingConvSwift - case "webkit_jscc": - return enum.CallingConvWebKitJS - case "win64cc": - return enum.CallingConvWin64 - case "x86_64_sysvcc": - return enum.CallingConvX86_64SysV - case "x86_fastcallcc": - return enum.CallingConvX86FastCall - case "x86_intrcc": - return enum.CallingConvX86Intr - case "x86_regcallcc": - return enum.CallingConvX86RegCall - case "x86_stdcallcc": - return enum.CallingConvX86StdCall - case "x86_thiscallcc": - return enum.CallingConvX86ThisCall - case "x86_vectorcallcc": - return enum.CallingConvX86VectorCall - default: - panic(fmt.Errorf("support for calling convention %q not yet implemented", text)) - } + return asmenum.CallingConvFromString(n.Text()) case *ast.CallingConvInt: - n := uintLit(old.UintLit()) - switch n { + x := uintLit(n.UintLit()) + switch x { case 11: return enum.CallingConvHiPE case 86: @@ -288,74 +212,39 @@ func irCallingConv(old ast.CallingConv) enum.CallingConv { case 96: return enum.CallingConvAMDGPUES default: - panic(fmt.Errorf("support for calling convention %d not yet implemented", n)) + panic(fmt.Errorf("support for calling convention %d not yet implemented", x)) } default: - panic(fmt.Errorf("support for calling convention type %T not yet implemented", old)) + panic(fmt.Errorf("support for calling convention type %T not yet implemented", n)) } } -// irDLLStorageClass returns the IR DLL storage class corresponding to the given -// optional AST DLL storage class. -func irDLLStorageClass(n *ast.DLLStorageClass) enum.DLLStorageClass { - text := n.Text() - switch text { - case "": - // \empty is used when DLL storage class not present. +// irOptDLLStorageClass returns the IR DLL storage class corresponding to the +// given optional AST DLL storage class. +func irOptDLLStorageClass(n *ast.DLLStorageClass) enum.DLLStorageClass { + if n == nil { return enum.DLLStorageClassNone - case "dllexport": - return enum.DLLStorageClassDLLExport - case "dllimport": - return enum.DLLStorageClassDLLImport - default: - panic(fmt.Errorf("support for DLL storage class %q not yet implemented", text)) } + return asmenum.DLLStorageClassFromString(n.Text()) } -// irExternallyInitialized returns the externally initialized boolean +// irOptExternallyInitialized returns the externally initialized boolean // corresponding to the given optional AST externally initialized. -func irExternallyInitialized(n *ast.ExternallyInitialized) bool { - // TODO: check why ExternallyInitialized is non-nil, when reduced as \empty. - return n.Text() == "externally_initialized" +func irOptExternallyInitialized(n *ast.ExternallyInitialized) bool { + return n != nil } -// irFastMathFlags returns the IR fast math flags corresponding to the given -// optional AST fast math flags. +// irFastMathFlags returns the IR fast math flags corresponding to the given AST +// fast math flags. func irFastMathFlags(ns []ast.FastMathFlag) []enum.FastMathFlag { var flags []enum.FastMathFlag for _, n := range ns { - flag := irFastMathFlag(n) + flag := asmenum.FastMathFlagFromString(n.Text()) flags = append(flags, flag) } return flags } -// irFastMathFlag returns the IR fast math flag corresponding to the given -// optional AST fast math flag. -func irFastMathFlag(n ast.FastMathFlag) enum.FastMathFlag { - text := n.Text() - switch text { - case "afn": - return enum.FastMathFlagAFn - case "arcp": - return enum.FastMathFlagARcp - case "contract": - return enum.FastMathFlagContract - case "fast": - return enum.FastMathFlagFast - case "ninf": - return enum.FastMathFlagNInf - case "nnan": - return enum.FastMathFlagNNaN - case "nsz": - return enum.FastMathFlagNSZ - case "reassoc": - return enum.FastMathFlagReassoc - default: - panic(fmt.Errorf("support for fast math flag %q not yet implemented", text)) - } -} - // irImmutable returns the immutable (constant or global) boolean corresponding // to the given optional AST immutable. func irImmutable(n ast.Immutable) bool { @@ -370,201 +259,105 @@ func irImmutable(n ast.Immutable) bool { } } -// irInBounds returns the in-bounds boolean corresponding to the given optional -// AST in-bounds. -func irInBounds(n *ast.InBounds) bool { - // TODO: check why InBounds is non-nil, when reduced as \empty. - return n.Text() == "inbounds" +// irOptInBounds returns the in-bounds boolean corresponding to the given +// optional AST in-bounds. +func irOptInBounds(n *ast.InBounds) bool { + return n != nil } -// irInRange returns the in-range boolean corresponding to the given optional +// irOptInRange returns the in-range boolean corresponding to the given optional // AST in-range. -func irInRange(n *ast.InRange) bool { - // TODO: check why InRange is non-nil, when reduced as \empty. - return n.Text() == "inrange" +func irOptInRange(n *ast.InRange) bool { + return n != nil } -// irLinkage returns the IR linkage corresponding to the given optional AST +// irOptLinkage returns the IR linkage corresponding to the given optional AST // linkage. -func irLinkage(text string) enum.Linkage { - // TODO: when ExternLinkage and Linkage are merged in grammar, update - // irLinkage to take `n *ast.Linkage` instead of `text string`. - //text := n.Text() - switch text { - case "": - // \empty is used when linkage not present. +func irOptLinkage(n ast.LlvmNode) enum.Linkage { + // TODO: fix implementation of optlinkage. + return enum.LinkageNone + if n == nil { return enum.LinkageNone - case "appending": - return enum.LinkageAppending - case "available_externally": - return enum.LinkageAvailableExternally - case "common": - return enum.LinkageCommon - case "internal": - return enum.LinkageInternal - case "linkonce": - return enum.LinkageLinkOnce - case "linkonce_odr": - return enum.LinkageLinkOnceODR - case "private": - return enum.LinkagePrivate - case "weak": - return enum.LinkageWeak - case "weak_odr": - return enum.LinkageWeakODR - case "external": - return enum.LinkageExternal - case "extern_weak": - return enum.LinkageExternWeak - default: - panic(fmt.Errorf("support for linkage %q not yet implemented", text)) } + return asmenum.LinkageFromString(n.LlvmNode().Text()) } -// irOverflowFlags returns the IR overflow flags corresponding to the given -// optional AST overflow flags. +// irOverflowFlags returns the IR overflow flags corresponding to the given AST +// overflow flags. func irOverflowFlags(ns []ast.OverflowFlag) []enum.OverflowFlag { var flags []enum.OverflowFlag for _, n := range ns { - flag := irOverflowFlag(n) + flag := asmenum.OverflowFlagFromString(n.Text()) flags = append(flags, flag) } return flags } -// irOverflowFlag returns the IR overflow flag corresponding to the given -// optional AST overflow flag. -func irOverflowFlag(n ast.OverflowFlag) enum.OverflowFlag { - text := n.Text() - switch text { - case "nsw": - return enum.OverflowFlagNSW - case "nuw": - return enum.OverflowFlagNUW - default: - panic(fmt.Errorf("support for overflow flag %q not yet implemented", text)) - } -} - -// irPreemption returns the IR preemption corresponding to the given optional +// irOptPreemption returns the IR preemption corresponding to the given optional // AST preemption. -func irPreemption(n *ast.Preemption) enum.Preemption { - text := n.Text() - switch text { - case "": - // \empty is used when preemption not present. +func irOptPreemption(n *ast.Preemption) enum.Preemption { + if n == nil { return enum.PreemptionNone - case "dso_local": - return enum.PreemptionDSOLocal - case "dso_preemptable": - return enum.PreemptionDSOPreemptable - default: - panic(fmt.Errorf("support for preemption %q not yet implemented", text)) } + return asmenum.PreemptionFromString(n.Text()) } -// irSelectionKind returns the IR Comdat selection kind corresponding to the +// irOptSelectionKind returns the IR Comdat selection kind corresponding to the // given optional AST Comdat selection kind. -func irSelectionKind(n *ast.SelectionKind) enum.SelectionKind { - text := n.Text() - switch text { - case "any": +func irOptSelectionKind(n *ast.SelectionKind) enum.SelectionKind { + if n == nil { return enum.SelectionKindAny - case "exactmatch": - return enum.SelectionKindExactMatch - case "largest": - return enum.SelectionKindLargest - case "noduplicates": - return enum.SelectionKindNoDuplicates - case "samesize": - return enum.SelectionKindSameSize - default: - panic(fmt.Errorf("support for Comdat selection kind %q not yet implemented", text)) } + return asmenum.SelectionKindFromString(n.Text()) } -// irTLSModelFromThreadLocal returns the IR TLS model corresponding to the given -// optional AST thread local storage. -func irTLSModelFromThreadLocal(n *ast.ThreadLocal) enum.TLSModel { - if n.Text() != "" { - model := irTLSModel(n.Model()) - if model == enum.TLSModelNone { - // If no explicit model is given, the "general dynamic" model is used. - // thread_local - return enum.TLSModelGeneric - } - // e.g. thread_local(initialexec) - return model +// irOptTLSModelFromThreadLocal returns the IR TLS model corresponding to the +// given optional AST thread local storage. +func irOptTLSModelFromThreadLocal(n *ast.ThreadLocal) enum.TLSModel { + if n == nil { + return enum.TLSModelNone + } + model := irOptTLSModel(n.Model()) + if model == enum.TLSModelNone { + // If no explicit model is given, the "general dynamic" model is used. + // thread_local + return enum.TLSModelGeneric } - return enum.TLSModelNone + // e.g. thread_local(initialexec) + return model } -// irTLSModel returns the IR TLS model corresponding to the given optional AST -// TLS model. -func irTLSModel(n *ast.TLSModel) enum.TLSModel { - text := n.Text() - switch text { - case "": - // \empty is used when TLS model not present. +// irOptTLSModel returns the IR TLS model corresponding to the given optional +// AST TLS model. +func irOptTLSModel(n *ast.TLSModel) enum.TLSModel { + if n == nil { return enum.TLSModelNone - case "initialexec": - return enum.TLSModelInitialExec - case "localdynamic": - return enum.TLSModelLocalDynamic - case "localexec": - return enum.TLSModelLocalExec - default: - panic(fmt.Errorf("support for TLS model %q not yet implemented", text)) } + return asmenum.TLSModelFromString(n.Text()) } -// irUnnamedAddr returns the IR unnamed address corresponding to the given +// irOptUnnamedAddr returns the IR unnamed address corresponding to the given // optional AST unnamed address. -func irUnnamedAddr(n *ast.UnnamedAddr) enum.UnnamedAddr { - text := n.Text() - switch text { - case "": - // \empty is used when unnamed address not present. +func irOptUnnamedAddr(n *ast.UnnamedAddr) enum.UnnamedAddr { + if n == nil { return enum.UnnamedAddrNone - case "local_unnamed_addr": - return enum.UnnamedAddrLocalUnnamedAddr - case "unnamed_addr": - return enum.UnnamedAddrUnnamedAddr - default: - panic(fmt.Errorf("support for unnamed address %q not yet implemented", text)) } + return asmenum.UnnamedAddrFromString(n.Text()) } -// irVariadic returns the variadic boolean corresponding to the given optional -// AST ellipsis. -func irVariadic(n *ast.Ellipsis) bool { - // TODO: check why Variadic is non-nil for `Variadic=Ellipsisopt`, regardless - // of whether the input is (...) or (). - // - // It seems that the Variadic.Text simply returns empty string when - // Ellipsisopt reduces to \empty. - // - // Using `n.Text() == "..."` for now, would like to use `n != nil`. - return n.Text() == "..." +// irOptVariadic returns the variadic boolean corresponding to the given +// optional AST ellipsis. +func irOptVariadic(n *ast.Ellipsis) bool { + return n != nil } -// irVisibility returns the IR visibility kind corresponding to the given +// irOptVisibility returns the IR visibility kind corresponding to the given // optional AST visibility kind. -func irVisibility(n *ast.Visibility) enum.Visibility { - text := n.Text() - switch text { - case "": - // \empty is used when visibility kind not present. +func irOptVisibility(n *ast.Visibility) enum.Visibility { + if n == nil { return enum.VisibilityNone - case "default": - return enum.VisibilityDefault - case "hidden": - return enum.VisibilityHidden - case "protected": - return enum.VisibilityProtected - default: - panic(fmt.Errorf("support for visibility kind %q not yet implemented", text)) } + return asmenum.VisibilityFromString(n.Text()) } // ### [ Helpers ] ############################################################# diff --git a/asm/index_local.go b/asm/index_local.go index ff7741f4..73ad8589 100644 --- a/asm/index_local.go +++ b/asm/index_local.go @@ -68,7 +68,7 @@ func (fgen *funcGen) newLocals(oldBlocks []ast.BasicBlock) error { // Note: Function parameters are already translated in astToIRFuncHeader. f := fgen.f for _, oldBlock := range oldBlocks { - blockName := label(*oldBlock.Name()) + blockName := optLabel(oldBlock.Name()) block := ir.NewBlock(blockName) for _, oldInst := range oldBlock.Insts() { inst, err := fgen.newIRInst(oldInst) diff --git a/asm/ll/ll.tm b/asm/ll/ll.tm index 78d7f356..54fd6988 100644 --- a/asm/ll/ll.tm +++ b/asm/ll/ll.tm @@ -4,6 +4,7 @@ lang = "llvm" package = "github.com/mewmew/l-tm/asm/ll" eventBased = true eventFields = true +eventAST = true # TODO: check when to use Fooopt and when to use Foo? (as based on the AST # they produce) diff --git a/asm/local.go b/asm/local.go index 7a657eeb..ee366127 100644 --- a/asm/local.go +++ b/asm/local.go @@ -25,9 +25,7 @@ import ( "github.com/llir/l/ir" "github.com/llir/l/ir/types" "github.com/llir/l/ir/value" - "github.com/mewmew/l-tm/asm/ll" "github.com/mewmew/l-tm/asm/ll/ast" - "github.com/mewmew/l-tm/asm/ll/selector" "github.com/pkg/errors" ) @@ -1433,18 +1431,7 @@ func (fgen *funcGen) astToIRInstCall(inst ir.Instruction, old *ast.CallInst) (*i // Fast math flags. i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) // Calling convention. - // TODO: update when https://github.com/inspirer/textmapper/issues/19 is resolved. - // - // Note, I would like to write: - // i.CallingConv = irCallingConv(old.CallingConv()) - // - // Or, perhaps: - // if oldcc := old.CallingConv(); oldcc.IsValid() { - // i.CallingConv = irCallingConv(oldcc) - // } - if n := old.Child(selector.CallingConv); n.Type() != ll.NoType { - i.CallingConv = irCallingConv(ast.ToLlvmNode(n).(ast.CallingConv)) - } + i.CallingConv = irOptCallingConv(old.CallingConv()) return i, nil } diff --git a/asm/parser.go b/asm/parser.go index c0a049d0..ca658c88 100644 --- a/asm/parser.go +++ b/asm/parser.go @@ -4,8 +4,6 @@ package asm import ( "io/ioutil" - "github.com/inspirer/textmapper/tm-go/status" - "github.com/mewmew/l-tm/asm/ll" "github.com/mewmew/l-tm/asm/ll/ast" "github.com/pkg/errors" ) @@ -22,84 +20,11 @@ func ParseFile(path string) (*ast.Module, error) { // Parse parses the given LLVM IR assembly file into an LLVM IR module, reading // from content. -func Parse(filename, content string) (*ast.Module, error) { - var l ll.Lexer - l.Init(content) - var p ll.Parser - b := newBuilder(filename, content) - //p.Init(b.addError, b.addNode) - p.Init(b.addNode) - err := p.Parse(&l) +func Parse(path, content string) (*ast.Module, error) { + tree, err := ast.Parse(path, content) if err != nil { - return nil, err - } - if err := b.status.Err(); err != nil { - return nil, err - } - - b.file.parsed = b.chunks - x := ast.ToLlvmNode(b.file.root()) - return x.(*ast.Module), nil -} - -type builder struct { - file *file - chunks []chunk - stack []int - status status.Status -} - -func newBuilder(filename, content string) *builder { - return &builder{ - file: newFile(filename, content), - chunks: []chunk{{offset: -1}}, - stack: make([]int, 1, 512), - } -} - -func (b *builder) addError(se ll.SyntaxError) bool { - r := b.file.sourceRange(se.Offset, se.Endoffset) - b.status.Add(r, "syntax error") - return true -} - -func (b *builder) addNode(t ll.NodeType, offset, endoffset int) { - if t == ll.Module { - offset, endoffset = 0, len(b.file.content) - } - - index := len(b.chunks) - start := len(b.stack) - end := start - for o := b.chunks[b.stack[start-1]].offset; o >= offset; o = b.chunks[b.stack[start-1]].offset { - start-- - if o >= endoffset { - end-- - } - } - firstChild := 0 - if start < end { - firstChild = b.stack[start] - for _, i := range b.stack[start:end] { - b.chunks[i].parent = index - } - } - b.chunks[b.stack[start-1]].next = index - if end == len(b.stack) { - b.stack = append(b.stack[:start], index) - } else if start < end { - b.stack[start] = index - l := copy(b.stack[start+1:], b.stack[end:]) - b.stack = b.stack[:start+1+l] - } else { - b.stack = append(b.stack, 0) - copy(b.stack[start+1:], b.stack[start:]) - b.stack[start] = index + return nil, errors.WithStack(err) } - b.chunks = append(b.chunks, chunk{ - t: t, - offset: offset, - endoffset: endoffset, - firstChild: firstChild, - }) + root := ast.ToLlvmNode(tree.Root()) + return root.(*ast.Module), nil } diff --git a/asm/tree.go b/asm/tree.go deleted file mode 100644 index 2a791ba2..00000000 --- a/asm/tree.go +++ /dev/null @@ -1,164 +0,0 @@ -package asm - -import ( - "sort" - "strings" - - "github.com/inspirer/textmapper/tm-go/status" - "github.com/mewmew/l-tm/asm/ll" - "github.com/mewmew/l-tm/asm/ll/ast" - "github.com/mewmew/l-tm/asm/ll/selector" -) - -// file holds an AST of a single file and can covert offset ranges into status.SourceRange. -type file struct { - filename string - content string - lines []int - parsed []chunk -} - -func (f *file) root() ast.Node { - return node{f, len(f.parsed) - 1} -} - -type chunk struct { - t ll.NodeType - offset int - endoffset int - next int - firstChild int - parent int -} - -func newFile(filename, content string) *file { - return &file{ - filename: filename, - content: content, - lines: lineOffsets(content), - } -} - -func (f *file) sourceRange(offset, endoffset int) status.SourceRange { - line := sort.Search(len(f.lines), func(i int) bool { return f.lines[i] > offset }) - 1 - return status.SourceRange{ - Filename: f.filename, - Offset: offset, - EndOffset: endoffset, - Line: line + 1, - Column: offset - f.lines[line] + 1, - } -} - -func lineOffsets(str string) []int { - var lines = make([]int, 1, 128) - - var off int - for { - i := strings.IndexByte(str[off:], '\n') - if i == -1 { - break - } - off += i + 1 - lines = append(lines, off) - } - return lines -} - -type node struct { - file *file - index int -} - -// Type implements ast.Node -func (n node) Type() ll.NodeType { - if n.file == nil { - // TODO: introduce InvalidType - return ll.NodeType(0) - } - return n.file.parsed[n.index].t -} - -// Offset implements ast.Node -func (n node) Offset() int { - if n.file == nil { - return 0 - } - return n.file.parsed[n.index].offset -} - -// Endoffset implements ast.Node -func (n node) Endoffset() int { - if n.file == nil { - return 0 - } - return n.file.parsed[n.index].endoffset -} - -// Child implements ast.Node -func (n node) Child(sel selector.Selector) ast.Node { - if n.file == nil { - return node{} - } - for i := n.file.parsed[n.index].firstChild; i > 0; i = n.file.parsed[i].next { - if sel(n.file.parsed[i].t) { - return node{n.file, i} - } - } - return node{} -} - -// Children implements ast.Node -func (n node) Children(sel selector.Selector) []ast.Node { - if n.file == nil { - return nil - } - var ret []ast.Node - for i := n.file.parsed[n.index].firstChild; i > 0; i = n.file.parsed[i].next { - if sel(n.file.parsed[i].t) { - ret = append(ret, node{n.file, i}) - } - } - return ret -} - -// Next implements ast.Node -func (n node) Next(sel selector.Selector) ast.Node { - if n.file == nil { - return node{} - } - for i := n.file.parsed[n.index].next; i > 0; i = n.file.parsed[i].next { - if sel(n.file.parsed[i].t) { - return node{n.file, i} - } - } - return node{} -} - -// NextAll implements ast.Node -func (n node) NextAll(sel selector.Selector) []ast.Node { - if n.file == nil { - return nil - } - var ret []ast.Node - for i := n.file.parsed[n.index].next; i > 0; i = n.file.parsed[i].next { - if sel(n.file.parsed[i].t) { - ret = append(ret, node{n.file, i}) - } - } - return nil -} - -// Text implements ast.Node -func (n node) Text() string { - if n.file == nil { - return "" - } - start, end := n.file.parsed[n.index].offset, n.file.parsed[n.index].endoffset - return n.file.content[start:end] -} - -// SourceRange implements status.SourceNode -func (n node) SourceRange() status.SourceRange { - return n.file.sourceRange(n.file.parsed[n.index].offset, n.file.parsed[n.index].endoffset) -} diff --git a/asm/type.go b/asm/type.go index 47572271..b69770ce 100644 --- a/asm/type.go +++ b/asm/type.go @@ -43,7 +43,7 @@ func (gen *generator) resolveTypeDefs(module *ast.Module) (map[string]types.Type } if prev, ok := index[alias]; ok { if _, ok := prev.(*ast.OpaqueType); !ok { - return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), prev.Text(), typ.Text()) + return nil, errors.Errorf("AST type definition with alias %q already present; prev `%s`, new `%s`", enc.Local(alias), text(prev), text(typ)) } } index[alias] = typ @@ -228,7 +228,7 @@ func (gen *generator) astToIRFuncType(t types.Type, old *ast.FuncType) (types.Ty typ.Params = append(typ.Params, param) } // Variadic. - typ.Variadic = irVariadic(ps.Variadic()) + typ.Variadic = irOptVariadic(ps.Variadic()) return typ, nil } @@ -337,7 +337,7 @@ func (gen *generator) astToIRPointerType(t types.Type, old *ast.PointerType) (ty } typ.ElemType = elemType // Address space. - typ.AddrSpace = irAddrSpace(old.AddrSpace()) + typ.AddrSpace = irOptAddrSpace(old.AddrSpace()) return typ, nil } From 4be82a0bdb07aea44522b9abe0dc7b044941a3eb Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 29 Oct 2018 21:50:17 +0100 Subject: [PATCH 66/70] asm: implement irOptLinkage --- asm/helper.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/asm/helper.go b/asm/helper.go index 7e6f3bd6..e3761321 100644 --- a/asm/helper.go +++ b/asm/helper.go @@ -274,11 +274,19 @@ func irOptInRange(n *ast.InRange) bool { // irOptLinkage returns the IR linkage corresponding to the given optional AST // linkage. func irOptLinkage(n ast.LlvmNode) enum.Linkage { - // TODO: fix implementation of optlinkage. - return enum.LinkageNone if n == nil { return enum.LinkageNone } + switch n := n.(type) { + case *ast.ExternLinkage: + if n == nil { + return enum.LinkageNone + } + case *ast.Linkage: + if n == nil { + return enum.LinkageNone + } + } return asmenum.LinkageFromString(n.LlvmNode().Text()) } From 83d78705b7c8c98b3ce994fbd7b8c0591b1de0a9 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 2 Nov 2018 03:44:38 +0100 Subject: [PATCH 67/70] asm: add test cases for binary instructions --- asm/asm_test.go | 51 +++++++++++++++++++++++++++++++++++++ asm/testdata/inst_binary.ll | 15 +++++++++++ 2 files changed, 66 insertions(+) create mode 100644 asm/asm_test.go create mode 100644 asm/testdata/inst_binary.ll diff --git a/asm/asm_test.go b/asm/asm_test.go new file mode 100644 index 00000000..5c18ec1e --- /dev/null +++ b/asm/asm_test.go @@ -0,0 +1,51 @@ +package asm + +import ( + "io/ioutil" + "testing" +) + +func TestParseFile(t *testing.T) { + golden := []struct { + path string + }{ + {path: "testdata/inst_binary.ll"}, + } + for _, g := range golden { + _, err := ParseFile(g.path) + if err != nil { + t.Errorf("unable to parse %q into AST; %v", g.path, err) + continue + } + } +} + +func TestTranslate(t *testing.T) { + golden := []struct { + path string + }{ + {path: "testdata/inst_binary.ll"}, + } + for _, g := range golden { + m, err := ParseFile(g.path) + buf, err := ioutil.ReadFile(g.path) + if err != nil { + t.Errorf("unable to read %q; %v", g.path, err) + } + want := string(buf) + if err != nil { + t.Errorf("unable to parse %q into AST; %v", g.path, err) + continue + } + module, err := Translate(m) + if err != nil { + t.Errorf("unable to translate %q from AST to IR; %v", g.path, err) + continue + } + got := module.Def() + if want != got { + t.Errorf("module mismatch; expected `%s`, got `%s`", want, got) + continue + } + } +} diff --git a/asm/testdata/inst_binary.ll b/asm/testdata/inst_binary.ll new file mode 100644 index 00000000..5d22ce7c --- /dev/null +++ b/asm/testdata/inst_binary.ll @@ -0,0 +1,15 @@ +define void @f() { + add i32 1, 2 + fadd i32 3, 4 + sub i32 5, 6 + fsub i32 7, 8 + mul i32 9, 10 + fmul i32 11, 12 + udiv i32 13, 14 + sdiv i32 15, 16 + fdiv i32 17, 18 + urem i32 19, 20 + srem i32 21, 22 + frem i32 23, 24 + ret void +} From 1b751df695e7a4fdeee0f6ce8e4cfd1ce4e9dba0 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 2 Nov 2018 04:39:03 +0100 Subject: [PATCH 68/70] asm/enum: regenerate enums --- asm/enum/Makefile | 1 + asm/enum/atomicordering_string.go | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 asm/enum/atomicordering_string.go diff --git a/asm/enum/Makefile b/asm/enum/Makefile index 62a8aa73..d6230077 100644 --- a/asm/enum/Makefile +++ b/asm/enum/Makefile @@ -1,4 +1,5 @@ all: + string2enum -linecomment -type AtomicOrdering /home/u/Desktop/go/src/github.com/llir/l/ir/enum string2enum -linecomment -type CallingConv /home/u/Desktop/go/src/github.com/llir/l/ir/enum string2enum -linecomment -type DLLStorageClass /home/u/Desktop/go/src/github.com/llir/l/ir/enum string2enum -linecomment -type FastMathFlag /home/u/Desktop/go/src/github.com/llir/l/ir/enum diff --git a/asm/enum/atomicordering_string.go b/asm/enum/atomicordering_string.go new file mode 100644 index 00000000..96212bd2 --- /dev/null +++ b/asm/enum/atomicordering_string.go @@ -0,0 +1,22 @@ +// Code generated by "stringer -linecomment -type AtomicOrdering /home/u/Desktop/go/src/github.com/llir/l/ir/enum"; DO NOT EDIT. + +package enum + +import "fmt" +import "github.com/llir/l/ir/enum" + +const _AtomicOrdering_name = "noneacq_relacquiremonotonicreleaseseq_cstunordered" + +var _AtomicOrdering_index = [...]uint8{0, 4, 11, 18, 27, 34, 41, 50} + +func AtomicOrderingFromString(s string) enum.AtomicOrdering { + if len(s) == 0 { + return 0 + } + for i := range _AtomicOrdering_index[:len(_AtomicOrdering_index)-1] { + if s == _AtomicOrdering_name[_AtomicOrdering_index[i]:_AtomicOrdering_index[i+1]] { + return enum.AtomicOrdering(i) + } + } + panic(fmt.Errorf("unable to locate AtomicOrdering enum corresponding to %q", s)) +} From a2e3864669719c6e797b809e2385d0381acc94bf Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 2 Nov 2018 14:27:47 +0100 Subject: [PATCH 69/70] asm: add test cases for bitwise instructions --- asm/asm_test.go | 2 ++ asm/testdata/inst_binary.ll | 10 +++++----- asm/testdata/inst_bitwise.ll | 9 +++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 asm/testdata/inst_bitwise.ll diff --git a/asm/asm_test.go b/asm/asm_test.go index 5c18ec1e..c566efea 100644 --- a/asm/asm_test.go +++ b/asm/asm_test.go @@ -10,6 +10,7 @@ func TestParseFile(t *testing.T) { path string }{ {path: "testdata/inst_binary.ll"}, + {path: "testdata/inst_bitwise.ll"}, } for _, g := range golden { _, err := ParseFile(g.path) @@ -25,6 +26,7 @@ func TestTranslate(t *testing.T) { path string }{ {path: "testdata/inst_binary.ll"}, + {path: "testdata/inst_bitwise.ll"}, } for _, g := range golden { m, err := ParseFile(g.path) diff --git a/asm/testdata/inst_binary.ll b/asm/testdata/inst_binary.ll index 5d22ce7c..beab9bca 100644 --- a/asm/testdata/inst_binary.ll +++ b/asm/testdata/inst_binary.ll @@ -1,15 +1,15 @@ define void @f() { add i32 1, 2 - fadd i32 3, 4 + fadd double 3.0, 4.0 sub i32 5, 6 - fsub i32 7, 8 + fsub double 7.0, 8.0 mul i32 9, 10 - fmul i32 11, 12 + fmul double 11.0, 12.0 udiv i32 13, 14 sdiv i32 15, 16 - fdiv i32 17, 18 + fdiv double 17.0, 18.0 urem i32 19, 20 srem i32 21, 22 - frem i32 23, 24 + frem double 23.0, 24.0 ret void } diff --git a/asm/testdata/inst_bitwise.ll b/asm/testdata/inst_bitwise.ll new file mode 100644 index 00000000..647ef945 --- /dev/null +++ b/asm/testdata/inst_bitwise.ll @@ -0,0 +1,9 @@ +define void @f() { + shl i32 1, 2 + lshr i32 3, 4 + ashr i32 5, 6 + and i32 7, 8 + or i32 9, 10 + xor i32 11, 12 + ret void +} From c0d8f96288abcf0ba6d87fdbaac74de7ad248773 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Fri, 2 Nov 2018 14:34:59 +0100 Subject: [PATCH 70/70] asm: split instruction translation into dedicated files --- asm/inst_aggregate.go | 34 ++ asm/inst_binary.go | 348 ++++++++++++++++ asm/inst_bitwise.go | 175 ++++++++ asm/inst_conversion.go | 166 ++++++++ asm/inst_memory.go | 94 +++++ asm/inst_other.go | 123 ++++++ asm/inst_vector.go | 46 ++ asm/local.go | 928 ----------------------------------------- 8 files changed, 986 insertions(+), 928 deletions(-) create mode 100644 asm/inst_aggregate.go create mode 100644 asm/inst_binary.go create mode 100644 asm/inst_bitwise.go create mode 100644 asm/inst_conversion.go create mode 100644 asm/inst_memory.go create mode 100644 asm/inst_other.go create mode 100644 asm/inst_vector.go diff --git a/asm/inst_aggregate.go b/asm/inst_aggregate.go new file mode 100644 index 00000000..0d75df82 --- /dev/null +++ b/asm/inst_aggregate.go @@ -0,0 +1,34 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// --- [ Aggregate instructions ] ---------------------------------------------- + +// ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstExtractValue(inst ir.Instruction, old *ast.ExtractValueInst) (*ir.InstExtractValue, error) { + i, ok := inst.(*ir.InstExtractValue) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstExtractValue, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstInsertValue(inst ir.Instruction, old *ast.InsertValueInst) (*ir.InstInsertValue, error) { + i, ok := inst.(*ir.InstInsertValue) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstInsertValue, got %T", inst)) + } + // TODO: implement + return i, nil +} diff --git a/asm/inst_binary.go b/asm/inst_binary.go new file mode 100644 index 00000000..e34b7217 --- /dev/null +++ b/asm/inst_binary.go @@ -0,0 +1,348 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +// --- [ Binary instructions ] ------------------------------------------------- + +// ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstAdd(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { + i, ok := inst.(*ir.InstAdd) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAdd, got %T", inst)) + } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) + // X operand. + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(x.Type(), old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFAdd(inst ir.Instruction, old *ast.FAddInst) (*ir.InstFAdd, error) { + i, ok := inst.(*ir.InstFAdd) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFAdd, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // X operand. + // TODO: remove xType in favour of x.Type(). + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstSub(inst ir.Instruction, old *ast.SubInst) (*ir.InstSub, error) { + i, ok := inst.(*ir.InstSub) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSub, got %T", inst)) + } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFSub(inst ir.Instruction, old *ast.FSubInst) (*ir.InstFSub, error) { + i, ok := inst.(*ir.InstFSub) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFSub, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstMul(inst ir.Instruction, old *ast.MulInst) (*ir.InstMul, error) { + i, ok := inst.(*ir.InstMul) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstMul, got %T", inst)) + } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFMul(inst ir.Instruction, old *ast.FMulInst) (*ir.InstFMul, error) { + i, ok := inst.(*ir.InstFMul) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFMul, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstUDiv(inst ir.Instruction, old *ast.UDivInst) (*ir.InstUDiv, error) { + i, ok := inst.(*ir.InstUDiv) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUDiv, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstSDiv(inst ir.Instruction, old *ast.SDivInst) (*ir.InstSDiv, error) { + i, ok := inst.(*ir.InstSDiv) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSDiv, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFDiv(inst ir.Instruction, old *ast.FDivInst) (*ir.InstFDiv, error) { + i, ok := inst.(*ir.InstFDiv) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFDiv, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstURem(inst ir.Instruction, old *ast.URemInst) (*ir.InstURem, error) { + i, ok := inst.(*ir.InstURem) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstURem, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstSRem(inst ir.Instruction, old *ast.SRemInst) (*ir.InstSRem, error) { + i, ok := inst.(*ir.InstSRem) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSRem, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFRem(inst ir.Instruction, old *ast.FRemInst) (*ir.InstFRem, error) { + i, ok := inst.(*ir.InstFRem) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFRem, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} diff --git a/asm/inst_bitwise.go b/asm/inst_bitwise.go new file mode 100644 index 00000000..e21790ad --- /dev/null +++ b/asm/inst_bitwise.go @@ -0,0 +1,175 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" + "github.com/pkg/errors" +) + +// --- [ Bitwise instructions ] ------------------------------------------------ + +// ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstShl(inst ir.Instruction, old *ast.ShlInst) (*ir.InstShl, error) { + i, ok := inst.(*ir.InstShl) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShl, got %T", inst)) + } + // Overflow flags. + i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstLShr(inst ir.Instruction, old *ast.LShrInst) (*ir.InstLShr, error) { + i, ok := inst.(*ir.InstLShr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLShr, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstAShr(inst ir.Instruction, old *ast.AShrInst) (*ir.InstAShr, error) { + i, ok := inst.(*ir.InstAShr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAShr, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstAnd(inst ir.Instruction, old *ast.AndInst) (*ir.InstAnd, error) { + i, ok := inst.(*ir.InstAnd) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAnd, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstOr(inst ir.Instruction, old *ast.OrInst) (*ir.InstOr, error) { + i, ok := inst.(*ir.InstOr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstOr, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} + +// ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstXor(inst ir.Instruction, old *ast.XorInst) (*ir.InstXor, error) { + i, ok := inst.(*ir.InstXor) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstXor, got %T", inst)) + } + // X operand. + xType, err := fgen.gen.irType(old.X().Typ()) + if err != nil { + return nil, errors.WithStack(err) + } + x, err := fgen.astToIRTypeValue(old.X()) + if err != nil { + return nil, errors.WithStack(err) + } + i.X = x + // Y operand. + y, err := fgen.astToIRValue(xType, old.Y()) + if err != nil { + return nil, errors.WithStack(err) + } + i.Y = y + return i, nil +} diff --git a/asm/inst_conversion.go b/asm/inst_conversion.go new file mode 100644 index 00000000..870eda48 --- /dev/null +++ b/asm/inst_conversion.go @@ -0,0 +1,166 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// --- [ Conversion instructions ] --------------------------------------------- + +// ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstTrunc(inst ir.Instruction, old *ast.TruncInst) (*ir.InstTrunc, error) { + i, ok := inst.(*ir.InstTrunc) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstTrunc, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstZExt(inst ir.Instruction, old *ast.ZExtInst) (*ir.InstZExt, error) { + i, ok := inst.(*ir.InstZExt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstZExt, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstSExt(inst ir.Instruction, old *ast.SExtInst) (*ir.InstSExt, error) { + i, ok := inst.(*ir.InstSExt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSExt, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFPTrunc(inst ir.Instruction, old *ast.FPTruncInst) (*ir.InstFPTrunc, error) { + i, ok := inst.(*ir.InstFPTrunc) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPTrunc, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFPExt(inst ir.Instruction, old *ast.FPExtInst) (*ir.InstFPExt, error) { + i, ok := inst.(*ir.InstFPExt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPExt, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFPToUI(inst ir.Instruction, old *ast.FPToUIInst) (*ir.InstFPToUI, error) { + i, ok := inst.(*ir.InstFPToUI) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPToUI, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFPToSI(inst ir.Instruction, old *ast.FPToSIInst) (*ir.InstFPToSI, error) { + i, ok := inst.(*ir.InstFPToSI) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPToSI, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstUIToFP(inst ir.Instruction, old *ast.UIToFPInst) (*ir.InstUIToFP, error) { + i, ok := inst.(*ir.InstUIToFP) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUIToFP, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstSIToFP(inst ir.Instruction, old *ast.SIToFPInst) (*ir.InstSIToFP, error) { + i, ok := inst.(*ir.InstSIToFP) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSIToFP, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstPtrToInt(inst ir.Instruction, old *ast.PtrToIntInst) (*ir.InstPtrToInt, error) { + i, ok := inst.(*ir.InstPtrToInt) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPtrToInt, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstIntToPtr(inst ir.Instruction, old *ast.IntToPtrInst) (*ir.InstIntToPtr, error) { + i, ok := inst.(*ir.InstIntToPtr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstIntToPtr, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstBitCast(inst ir.Instruction, old *ast.BitCastInst) (*ir.InstBitCast, error) { + i, ok := inst.(*ir.InstBitCast) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstBitCast, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstAddrSpaceCast(inst ir.Instruction, old *ast.AddrSpaceCastInst) (*ir.InstAddrSpaceCast, error) { + i, ok := inst.(*ir.InstAddrSpaceCast) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAddrSpaceCast, got %T", inst)) + } + // TODO: implement + return i, nil +} diff --git a/asm/inst_memory.go b/asm/inst_memory.go new file mode 100644 index 00000000..31c1a218 --- /dev/null +++ b/asm/inst_memory.go @@ -0,0 +1,94 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// --- [ Memory instructions ] ------------------------------------------------- + +// ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstAlloca(inst ir.Instruction, old *ast.AllocaInst) (*ir.InstAlloca, error) { + i, ok := inst.(*ir.InstAlloca) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAlloca, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstLoad(inst ir.Instruction, old *ast.LoadInst) (*ir.InstLoad, error) { + i, ok := inst.(*ir.InstLoad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLoad, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstStore(inst ir.Instruction, old *ast.StoreInst) (*ir.InstStore, error) { + i, ok := inst.(*ir.InstStore) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstStore, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFence(inst ir.Instruction, old *ast.FenceInst) (*ir.InstFence, error) { + i, ok := inst.(*ir.InstFence) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFence, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstCmpXchg(inst ir.Instruction, old *ast.CmpXchgInst) (*ir.InstCmpXchg, error) { + i, ok := inst.(*ir.InstCmpXchg) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCmpXchg, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstAtomicRMW(inst ir.Instruction, old *ast.AtomicRMWInst) (*ir.InstAtomicRMW, error) { + i, ok := inst.(*ir.InstAtomicRMW) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAtomicRMW, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstGetElementPtr(inst ir.Instruction, old *ast.GetElementPtrInst) (*ir.InstGetElementPtr, error) { + i, ok := inst.(*ir.InstGetElementPtr) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstGetElementPtr, got %T", inst)) + } + // TODO: implement + return i, nil +} diff --git a/asm/inst_other.go b/asm/inst_other.go new file mode 100644 index 00000000..7050cb10 --- /dev/null +++ b/asm/inst_other.go @@ -0,0 +1,123 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// --- [ Other instructions ] -------------------------------------------------- + +// ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstICmp(inst ir.Instruction, old *ast.ICmpInst) (*ir.InstICmp, error) { + i, ok := inst.(*ir.InstICmp) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstICmp, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstFCmp(inst ir.Instruction, old *ast.FCmpInst) (*ir.InstFCmp, error) { + i, ok := inst.(*ir.InstFCmp) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFCmp, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // TODO: implement + return i, nil +} + +// ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstPhi(inst ir.Instruction, old *ast.PhiInst) (*ir.InstPhi, error) { + i, ok := inst.(*ir.InstPhi) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPhi, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstSelect(inst ir.Instruction, old *ast.SelectInst) (*ir.InstSelect, error) { + i, ok := inst.(*ir.InstSelect) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSelect, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstCall(inst ir.Instruction, old *ast.CallInst) (*ir.InstCall, error) { + i, ok := inst.(*ir.InstCall) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCall, got %T", inst)) + } + // Fast math flags. + i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) + // Calling convention. + i.CallingConv = irOptCallingConv(old.CallingConv()) + return i, nil +} + +// ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstVAArg(inst ir.Instruction, old *ast.VAArgInst) (*ir.InstVAArg, error) { + i, ok := inst.(*ir.InstVAArg) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstVAArg, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstLandingPad(inst ir.Instruction, old *ast.LandingPadInst) (*ir.InstLandingPad, error) { + i, ok := inst.(*ir.InstLandingPad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLandingPad, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstCatchPad(inst ir.Instruction, old *ast.CatchPadInst) (*ir.InstCatchPad, error) { + i, ok := inst.(*ir.InstCatchPad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCatchPad, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstCleanupPad(inst ir.Instruction, old *ast.CleanupPadInst) (*ir.InstCleanupPad, error) { + i, ok := inst.(*ir.InstCleanupPad) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCleanupPad, got %T", inst)) + } + // TODO: implement + return i, nil +} diff --git a/asm/inst_vector.go b/asm/inst_vector.go new file mode 100644 index 00000000..bc08616f --- /dev/null +++ b/asm/inst_vector.go @@ -0,0 +1,46 @@ +package asm + +import ( + "fmt" + + "github.com/llir/l/ir" + "github.com/mewmew/l-tm/asm/ll/ast" +) + +// --- [ Vector instructions ] ------------------------------------------------- + +// ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstExtractElement(inst ir.Instruction, old *ast.ExtractElementInst) (*ir.InstExtractElement, error) { + i, ok := inst.(*ir.InstExtractElement) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstExtractElement, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstInsertElement(inst ir.Instruction, old *ast.InsertElementInst) (*ir.InstInsertElement, error) { + i, ok := inst.(*ir.InstInsertElement) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstInsertElement, got %T", inst)) + } + // TODO: implement + return i, nil +} + +// ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +func (fgen *funcGen) astToIRInstShuffleVector(inst ir.Instruction, old *ast.ShuffleVectorInst) (*ir.InstShuffleVector, error) { + i, ok := inst.(*ir.InstShuffleVector) + if !ok { + // NOTE: panic since this would indicate a bug in the implementation. + panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShuffleVector, got %T", inst)) + } + // TODO: implement + return i, nil +} diff --git a/asm/local.go b/asm/local.go index ee366127..39d18b72 100644 --- a/asm/local.go +++ b/asm/local.go @@ -555,934 +555,6 @@ func (fgen *funcGen) astToIRValueInst(inst ir.Instruction, old ast.ValueInstruct } } -// --- [ Binary instructions ] ------------------------------------------------- - -// ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstAdd(inst ir.Instruction, old *ast.AddInst) (*ir.InstAdd, error) { - i, ok := inst.(*ir.InstAdd) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAdd, got %T", inst)) - } - // Overflow flags. - i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) - // X operand. - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(x.Type(), old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFAdd(inst ir.Instruction, old *ast.FAddInst) (*ir.InstFAdd, error) { - i, ok := inst.(*ir.InstFAdd) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFAdd, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // X operand. - // TODO: remove xType in favour of x.Type(). - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstSub(inst ir.Instruction, old *ast.SubInst) (*ir.InstSub, error) { - i, ok := inst.(*ir.InstSub) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSub, got %T", inst)) - } - // Overflow flags. - i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFSub(inst ir.Instruction, old *ast.FSubInst) (*ir.InstFSub, error) { - i, ok := inst.(*ir.InstFSub) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFSub, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstMul(inst ir.Instruction, old *ast.MulInst) (*ir.InstMul, error) { - i, ok := inst.(*ir.InstMul) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstMul, got %T", inst)) - } - // Overflow flags. - i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFMul(inst ir.Instruction, old *ast.FMulInst) (*ir.InstFMul, error) { - i, ok := inst.(*ir.InstFMul) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFMul, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstUDiv(inst ir.Instruction, old *ast.UDivInst) (*ir.InstUDiv, error) { - i, ok := inst.(*ir.InstUDiv) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUDiv, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstSDiv(inst ir.Instruction, old *ast.SDivInst) (*ir.InstSDiv, error) { - i, ok := inst.(*ir.InstSDiv) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSDiv, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFDiv(inst ir.Instruction, old *ast.FDivInst) (*ir.InstFDiv, error) { - i, ok := inst.(*ir.InstFDiv) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFDiv, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstURem(inst ir.Instruction, old *ast.URemInst) (*ir.InstURem, error) { - i, ok := inst.(*ir.InstURem) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstURem, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstSRem(inst ir.Instruction, old *ast.SRemInst) (*ir.InstSRem, error) { - i, ok := inst.(*ir.InstSRem) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSRem, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFRem(inst ir.Instruction, old *ast.FRemInst) (*ir.InstFRem, error) { - i, ok := inst.(*ir.InstFRem) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFRem, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// --- [ Bitwise instructions ] ------------------------------------------------ - -// ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstShl(inst ir.Instruction, old *ast.ShlInst) (*ir.InstShl, error) { - i, ok := inst.(*ir.InstShl) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShl, got %T", inst)) - } - // Overflow flags. - i.OverflowFlags = irOverflowFlags(old.OverflowFlags()) - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstLShr(inst ir.Instruction, old *ast.LShrInst) (*ir.InstLShr, error) { - i, ok := inst.(*ir.InstLShr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLShr, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstAShr(inst ir.Instruction, old *ast.AShrInst) (*ir.InstAShr, error) { - i, ok := inst.(*ir.InstAShr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAShr, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstAnd(inst ir.Instruction, old *ast.AndInst) (*ir.InstAnd, error) { - i, ok := inst.(*ir.InstAnd) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAnd, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstOr(inst ir.Instruction, old *ast.OrInst) (*ir.InstOr, error) { - i, ok := inst.(*ir.InstOr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstOr, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstXor(inst ir.Instruction, old *ast.XorInst) (*ir.InstXor, error) { - i, ok := inst.(*ir.InstXor) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstXor, got %T", inst)) - } - // X operand. - xType, err := fgen.gen.irType(old.X().Typ()) - if err != nil { - return nil, errors.WithStack(err) - } - x, err := fgen.astToIRTypeValue(old.X()) - if err != nil { - return nil, errors.WithStack(err) - } - i.X = x - // Y operand. - y, err := fgen.astToIRValue(xType, old.Y()) - if err != nil { - return nil, errors.WithStack(err) - } - i.Y = y - return i, nil -} - -// --- [ Vector instructions ] ------------------------------------------------- - -// ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstExtractElement(inst ir.Instruction, old *ast.ExtractElementInst) (*ir.InstExtractElement, error) { - i, ok := inst.(*ir.InstExtractElement) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstExtractElement, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstInsertElement(inst ir.Instruction, old *ast.InsertElementInst) (*ir.InstInsertElement, error) { - i, ok := inst.(*ir.InstInsertElement) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstInsertElement, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstShuffleVector(inst ir.Instruction, old *ast.ShuffleVectorInst) (*ir.InstShuffleVector, error) { - i, ok := inst.(*ir.InstShuffleVector) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstShuffleVector, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// --- [ Aggregate instructions ] ---------------------------------------------- - -// ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstExtractValue(inst ir.Instruction, old *ast.ExtractValueInst) (*ir.InstExtractValue, error) { - i, ok := inst.(*ir.InstExtractValue) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstExtractValue, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstInsertValue(inst ir.Instruction, old *ast.InsertValueInst) (*ir.InstInsertValue, error) { - i, ok := inst.(*ir.InstInsertValue) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstInsertValue, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// --- [ Memory instructions ] ------------------------------------------------- - -// ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstAlloca(inst ir.Instruction, old *ast.AllocaInst) (*ir.InstAlloca, error) { - i, ok := inst.(*ir.InstAlloca) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAlloca, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstLoad(inst ir.Instruction, old *ast.LoadInst) (*ir.InstLoad, error) { - i, ok := inst.(*ir.InstLoad) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLoad, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstStore(inst ir.Instruction, old *ast.StoreInst) (*ir.InstStore, error) { - i, ok := inst.(*ir.InstStore) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstStore, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFence(inst ir.Instruction, old *ast.FenceInst) (*ir.InstFence, error) { - i, ok := inst.(*ir.InstFence) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFence, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstCmpXchg(inst ir.Instruction, old *ast.CmpXchgInst) (*ir.InstCmpXchg, error) { - i, ok := inst.(*ir.InstCmpXchg) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCmpXchg, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstAtomicRMW(inst ir.Instruction, old *ast.AtomicRMWInst) (*ir.InstAtomicRMW, error) { - i, ok := inst.(*ir.InstAtomicRMW) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAtomicRMW, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstGetElementPtr(inst ir.Instruction, old *ast.GetElementPtrInst) (*ir.InstGetElementPtr, error) { - i, ok := inst.(*ir.InstGetElementPtr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstGetElementPtr, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// --- [ Conversion instructions ] --------------------------------------------- - -// ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstTrunc(inst ir.Instruction, old *ast.TruncInst) (*ir.InstTrunc, error) { - i, ok := inst.(*ir.InstTrunc) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstTrunc, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstZExt(inst ir.Instruction, old *ast.ZExtInst) (*ir.InstZExt, error) { - i, ok := inst.(*ir.InstZExt) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstZExt, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstSExt(inst ir.Instruction, old *ast.SExtInst) (*ir.InstSExt, error) { - i, ok := inst.(*ir.InstSExt) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSExt, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFPTrunc(inst ir.Instruction, old *ast.FPTruncInst) (*ir.InstFPTrunc, error) { - i, ok := inst.(*ir.InstFPTrunc) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPTrunc, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFPExt(inst ir.Instruction, old *ast.FPExtInst) (*ir.InstFPExt, error) { - i, ok := inst.(*ir.InstFPExt) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPExt, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFPToUI(inst ir.Instruction, old *ast.FPToUIInst) (*ir.InstFPToUI, error) { - i, ok := inst.(*ir.InstFPToUI) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPToUI, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFPToSI(inst ir.Instruction, old *ast.FPToSIInst) (*ir.InstFPToSI, error) { - i, ok := inst.(*ir.InstFPToSI) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFPToSI, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstUIToFP(inst ir.Instruction, old *ast.UIToFPInst) (*ir.InstUIToFP, error) { - i, ok := inst.(*ir.InstUIToFP) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstUIToFP, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstSIToFP(inst ir.Instruction, old *ast.SIToFPInst) (*ir.InstSIToFP, error) { - i, ok := inst.(*ir.InstSIToFP) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSIToFP, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstPtrToInt(inst ir.Instruction, old *ast.PtrToIntInst) (*ir.InstPtrToInt, error) { - i, ok := inst.(*ir.InstPtrToInt) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPtrToInt, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstIntToPtr(inst ir.Instruction, old *ast.IntToPtrInst) (*ir.InstIntToPtr, error) { - i, ok := inst.(*ir.InstIntToPtr) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstIntToPtr, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstBitCast(inst ir.Instruction, old *ast.BitCastInst) (*ir.InstBitCast, error) { - i, ok := inst.(*ir.InstBitCast) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstBitCast, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstAddrSpaceCast(inst ir.Instruction, old *ast.AddrSpaceCastInst) (*ir.InstAddrSpaceCast, error) { - i, ok := inst.(*ir.InstAddrSpaceCast) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstAddrSpaceCast, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// --- [ Other instructions ] -------------------------------------------------- - -// ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstICmp(inst ir.Instruction, old *ast.ICmpInst) (*ir.InstICmp, error) { - i, ok := inst.(*ir.InstICmp) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstICmp, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstFCmp(inst ir.Instruction, old *ast.FCmpInst) (*ir.InstFCmp, error) { - i, ok := inst.(*ir.InstFCmp) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstFCmp, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // TODO: implement - return i, nil -} - -// ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstPhi(inst ir.Instruction, old *ast.PhiInst) (*ir.InstPhi, error) { - i, ok := inst.(*ir.InstPhi) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstPhi, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstSelect(inst ir.Instruction, old *ast.SelectInst) (*ir.InstSelect, error) { - i, ok := inst.(*ir.InstSelect) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstSelect, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstCall(inst ir.Instruction, old *ast.CallInst) (*ir.InstCall, error) { - i, ok := inst.(*ir.InstCall) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCall, got %T", inst)) - } - // Fast math flags. - i.FastMathFlags = irFastMathFlags(old.FastMathFlags()) - // Calling convention. - i.CallingConv = irOptCallingConv(old.CallingConv()) - return i, nil -} - -// ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstVAArg(inst ir.Instruction, old *ast.VAArgInst) (*ir.InstVAArg, error) { - i, ok := inst.(*ir.InstVAArg) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstVAArg, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstLandingPad(inst ir.Instruction, old *ast.LandingPadInst) (*ir.InstLandingPad, error) { - i, ok := inst.(*ir.InstLandingPad) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstLandingPad, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstCatchPad(inst ir.Instruction, old *ast.CatchPadInst) (*ir.InstCatchPad, error) { - i, ok := inst.(*ir.InstCatchPad) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCatchPad, got %T", inst)) - } - // TODO: implement - return i, nil -} - -// ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -func (fgen *funcGen) astToIRInstCleanupPad(inst ir.Instruction, old *ast.CleanupPadInst) (*ir.InstCleanupPad, error) { - i, ok := inst.(*ir.InstCleanupPad) - if !ok { - // NOTE: panic since this would indicate a bug in the implementation. - panic(fmt.Errorf("invalid IR instruction for AST instruction; expected *ir.InstCleanupPad, got %T", inst)) - } - // TODO: implement - return i, nil -} - // ### [ Helper functions ] #################################################### // NOTE: aggregateElemType is copied from llir/l/ir/inst_aggregate.go and the