diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4e9e236d..c81adb62 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -32,10 +32,10 @@ jobs: - name: Install LLVM ${{ matrix.llvm }} and libgc-dev if: startsWith(matrix.os, 'ubuntu') run: | - echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.llvm }} main' | sudo tee /etc/apt/sources.list.d/llvm.list + echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{ matrix.llvm }} main" | sudo tee /etc/apt/sources.list.d/llvm.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update - sudo apt-get install --no-install-recommends clang-${{ matrix.llvm }} llvm-${{ matrix.llvm }}-dev libgc-dev + sudo apt-get install -y llvm-${{ matrix.llvm }}-dev clang-${{ matrix.llvm }} lld-${{ matrix.llvm }} pkg-config libgc-dev libcjson-dev libsqlite3-dev python3.11-dev echo /usr/lib/llvm-${{ matrix.llvm }}/bin >> $GITHUB_PATH - name: Clang information diff --git a/README.md b/README.md index 9439f51b..e0dd75b7 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,18 @@ Here are the Go packages that can be imported correctly: * [sync/atomic](https://pkg.go.dev/sync/atomic) (partially) +## Dependencies + +- [Go 1.20+](https://go.dev) (build only) +- [LLVM 17](https://llvm.org) +- [Clang 17](https://clang.llvm.org) +- [LLD 17](https://lld.llvm.org) +- [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/) +- [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/) +- [cJSON 1.7+](https://github.com/DaveGamble/cJSON) (optional, for [`github.com/goplus/llgo/c/cjson`](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)) +- [SQLite 3](https://www.sqlite.org) (optional, for [`github.com/goplus/llgo/c/sqlite`](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite)) +- [Python 3.11+](https://www.python.org) (optional, for [`github.com/goplus/llgo/py`](https://pkg.go.dev/github.com/goplus/llgo/py)) + ## How to install Follow these steps to generate the `llgo` command (its usage is the same as the `go` command): @@ -218,20 +230,24 @@ Follow these steps to generate the `llgo` command (its usage is the same as the ### on macOS ```sh -brew update # execute if needed -brew install libgc -brew install llvm@17 +brew update # execute if needed +brew install llvm@17 pkg-config libgc +brew install cjson sqlite python@3.12 # optional +export PATH=$(brew --prefix llvm@17)/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.zshrc +export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers go install -v ./... ``` -### on Linux +### on Linux (Debian/Ubuntu) ```sh -echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main' | sudo tee /etc/apt/sources.list.d/llvm.list +echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-17 main" | sudo tee /etc/apt/sources.list.d/llvm.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - -sudo apt-get update # execute if needed -sudo apt-get install libgc-dev -sudo apt-get install --no-install-recommends llvm-17-dev +sudo apt-get update # execute if needed +sudo apt-get install -y llvm-17-dev clang-17 lld-17 pkg-config libgc-dev +sudo apt-get install -y libcjson-dev libsqlite3-dev python3.12-dev # optional +export PATH=/usr/lib/llvm-17/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.bashrc +export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers go install -v ./... ``` @@ -251,6 +267,7 @@ TODO How do I generate these tools? ```sh +export CC=clang CXX=clang++ # only for go build; optional if you have other compatible compilers go install -v ./... # compile all tools except pydump cd chore/_xtool llgo install ./... # compile pydump diff --git a/cl/_testrt/index/in.go b/cl/_testrt/index/in.go index db5019e1..5c66cc86 100644 --- a/cl/_testrt/index/in.go +++ b/cl/_testrt/index/in.go @@ -1,25 +1,33 @@ package main -import "github.com/goplus/llgo/c" - type point struct { x int y int } +type N [2]int +type T *N +type S []int + func main() { a := [...]point{{1, 2}, {3, 4}, {5, 6}}[2] - c.Printf(c.Str("%d %d\n"), a.x, a.y) + println(a.x, a.y) b := [...][2]int{[2]int{1, 2}, [2]int{3, 4}}[1] - c.Printf(c.Str("%d %d\n"), b[0], b[1]) + println(b[0], b[1]) var i int = 2 - n := [...]int{1, 2, 3, 4, 5}[i] - c.Printf(c.Str("%d\n"), n) - c.Printf(c.Str("%d\n"), [...]int{1, 2, 3, 4, 5}[i]) + println([...]int{1, 2, 3, 4, 5}[i]) s := "123456" - c.Printf(c.Str("%c\n"), s[i]) - c.Printf(c.Str("%c\n"), "123456"[1]) + println(string(s[i])) + println(string("123456"[1])) + + var n = N{1, 2} + var t T = &n + println(t[1]) + var s1 = S{1, 2, 3, 4} + println(s1[1]) + + println([2]int{}[0]) } diff --git a/cl/_testrt/index/out.ll b/cl/_testrt/index/out.ll index 34d43925..b41b0160 100644 --- a/cl/_testrt/index/out.ll +++ b/cl/_testrt/index/out.ll @@ -3,17 +3,12 @@ source_filename = "main" %main.point = type { i64, i64 } %"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } +%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 } @"main.init$guard" = global i1 false, align 1 @__llgo_argc = global i32 0, align 4 @__llgo_argv = global ptr null, align 8 -@0 = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1 -@1 = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1 -@2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 -@3 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 -@4 = private unnamed_addr constant [4 x i8] c"%c\0A\00", align 1 -@5 = private unnamed_addr constant [6 x i8] c"123456", align 1 -@6 = private unnamed_addr constant [4 x i8] c"%c\0A\00", align 1 +@0 = private unnamed_addr constant [6 x i8] c"123456", align 1 define void @main.init() { _llgo_0: @@ -61,82 +56,112 @@ _llgo_0: %19 = load i64, ptr %18, align 4 %20 = getelementptr inbounds %main.point, ptr %3, i32 0, i32 1 %21 = load i64, ptr %20, align 4 - %22 = call i32 (ptr, ...) @printf(ptr @0, i64 %19, i64 %21) - %23 = alloca [2 x i64], align 8 - %24 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %23, i64 16) - %25 = alloca [2 x [2 x i64]], align 8 - %26 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %25, i64 32) - %27 = getelementptr inbounds [2 x i64], ptr %26, i64 0 - %28 = getelementptr inbounds i64, ptr %27, i64 0 - %29 = getelementptr inbounds i64, ptr %27, i64 1 - %30 = getelementptr inbounds [2 x i64], ptr %26, i64 1 - %31 = getelementptr inbounds i64, ptr %30, i64 0 - %32 = getelementptr inbounds i64, ptr %30, i64 1 - store i64 1, ptr %28, align 4 - store i64 2, ptr %29, align 4 - store i64 3, ptr %31, align 4 - store i64 4, ptr %32, align 4 - %33 = load [2 x [2 x i64]], ptr %26, align 4 - %34 = getelementptr inbounds [2 x i64], ptr %26, i64 1 - %35 = load [2 x i64], ptr %34, align 4 - store [2 x i64] %35, ptr %24, align 4 - %36 = getelementptr inbounds i64, ptr %24, i64 0 - %37 = load i64, ptr %36, align 4 - %38 = getelementptr inbounds i64, ptr %24, i64 1 - %39 = load i64, ptr %38, align 4 - %40 = call i32 (ptr, ...) @printf(ptr @1, i64 %37, i64 %39) - %41 = alloca [5 x i64], align 8 - %42 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %41, i64 40) - %43 = getelementptr inbounds i64, ptr %42, i64 0 - %44 = getelementptr inbounds i64, ptr %42, i64 1 - %45 = getelementptr inbounds i64, ptr %42, i64 2 - %46 = getelementptr inbounds i64, ptr %42, i64 3 - %47 = getelementptr inbounds i64, ptr %42, i64 4 - store i64 1, ptr %43, align 4 - store i64 2, ptr %44, align 4 - store i64 3, ptr %45, align 4 - store i64 4, ptr %46, align 4 - store i64 5, ptr %47, align 4 - %48 = load [5 x i64], ptr %42, align 4 - %49 = getelementptr inbounds i64, ptr %42, i64 2 - %50 = load i64, ptr %49, align 4 - %51 = call i32 (ptr, ...) @printf(ptr @2, i64 %50) - %52 = alloca [5 x i64], align 8 - %53 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %52, i64 40) - %54 = getelementptr inbounds i64, ptr %53, i64 0 - %55 = getelementptr inbounds i64, ptr %53, i64 1 - %56 = getelementptr inbounds i64, ptr %53, i64 2 - %57 = getelementptr inbounds i64, ptr %53, i64 3 - %58 = getelementptr inbounds i64, ptr %53, i64 4 - store i64 1, ptr %54, align 4 - store i64 2, ptr %55, align 4 - store i64 3, ptr %56, align 4 - store i64 4, ptr %57, align 4 - store i64 5, ptr %58, align 4 - %59 = load [5 x i64], ptr %53, align 4 - %60 = getelementptr inbounds i64, ptr %53, i64 2 - %61 = load i64, ptr %60, align 4 - %62 = call i32 (ptr, ...) @printf(ptr @3, i64 %61) - %63 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %64 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %63, i32 0, i32 0 - store ptr @5, ptr %64, align 8 - %65 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %63, i32 0, i32 1 - store i64 6, ptr %65, align 4 - %66 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %63, align 8 - %67 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %66, 0 - %68 = getelementptr inbounds i8, ptr %67, i64 2 - %69 = load i8, ptr %68, align 1 - %70 = call i32 (ptr, ...) @printf(ptr @4, i8 %69) - %71 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 - %72 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %71, i32 0, i32 0 - store ptr @5, ptr %72, align 8 - %73 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %71, i32 0, i32 1 - store i64 6, ptr %73, align 4 - %74 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %71, align 8 - %75 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %74, 0 - %76 = getelementptr inbounds i8, ptr %75, i64 1 - %77 = load i8, ptr %76, align 1 - %78 = call i32 (ptr, ...) @printf(ptr @6, i8 %77) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %19) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %21) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %22 = alloca [2 x i64], align 8 + %23 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %22, i64 16) + %24 = alloca [2 x [2 x i64]], align 8 + %25 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %24, i64 32) + %26 = getelementptr inbounds [2 x i64], ptr %25, i64 0 + %27 = getelementptr inbounds i64, ptr %26, i64 0 + %28 = getelementptr inbounds i64, ptr %26, i64 1 + %29 = getelementptr inbounds [2 x i64], ptr %25, i64 1 + %30 = getelementptr inbounds i64, ptr %29, i64 0 + %31 = getelementptr inbounds i64, ptr %29, i64 1 + store i64 1, ptr %27, align 4 + store i64 2, ptr %28, align 4 + store i64 3, ptr %30, align 4 + store i64 4, ptr %31, align 4 + %32 = load [2 x [2 x i64]], ptr %25, align 4 + %33 = getelementptr inbounds [2 x i64], ptr %25, i64 1 + %34 = load [2 x i64], ptr %33, align 4 + store [2 x i64] %34, ptr %23, align 4 + %35 = getelementptr inbounds i64, ptr %23, i64 0 + %36 = load i64, ptr %35, align 4 + %37 = getelementptr inbounds i64, ptr %23, i64 1 + %38 = load i64, ptr %37, align 4 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %36) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %38) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %39 = alloca [5 x i64], align 8 + %40 = call ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr %39, i64 40) + %41 = getelementptr inbounds i64, ptr %40, i64 0 + %42 = getelementptr inbounds i64, ptr %40, i64 1 + %43 = getelementptr inbounds i64, ptr %40, i64 2 + %44 = getelementptr inbounds i64, ptr %40, i64 3 + %45 = getelementptr inbounds i64, ptr %40, i64 4 + store i64 1, ptr %41, align 4 + store i64 2, ptr %42, align 4 + store i64 3, ptr %43, align 4 + store i64 4, ptr %44, align 4 + store i64 5, ptr %45, align 4 + %46 = load [5 x i64], ptr %40, align 4 + %47 = getelementptr inbounds i64, ptr %40, i64 2 + %48 = load i64, ptr %47, align 4 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %48) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %49 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %50 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %49, i32 0, i32 0 + store ptr @0, ptr %50, align 8 + %51 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %49, i32 0, i32 1 + store i64 6, ptr %51, align 4 + %52 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %49, align 8 + %53 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %52, 0 + %54 = getelementptr inbounds i8, ptr %53, i64 2 + %55 = load i8, ptr %54, align 1 + %56 = sext i8 %55 to i32 + %57 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringFromRune"(i32 %56) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %57) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %58 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %59 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %58, i32 0, i32 0 + store ptr @0, ptr %59, align 8 + %60 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %58, i32 0, i32 1 + store i64 6, ptr %60, align 4 + %61 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %58, align 8 + %62 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %61, 0 + %63 = getelementptr inbounds i8, ptr %62, i64 1 + %64 = load i8, ptr %63, align 1 + %65 = sext i8 %64 to i32 + %66 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringFromRune"(i32 %65) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %66) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %67 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16) + %68 = getelementptr inbounds i64, ptr %67, i64 0 + %69 = getelementptr inbounds i64, ptr %67, i64 1 + store i64 1, ptr %68, align 4 + store i64 2, ptr %69, align 4 + %70 = getelementptr inbounds i64, ptr %67, i64 1 + %71 = load i64, ptr %70, align 4 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %71) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %72 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 32) + %73 = getelementptr inbounds i64, ptr %72, i64 0 + store i64 1, ptr %73, align 4 + %74 = getelementptr inbounds i64, ptr %72, i64 1 + store i64 2, ptr %74, align 4 + %75 = getelementptr inbounds i64, ptr %72, i64 2 + store i64 3, ptr %75, align 4 + %76 = getelementptr inbounds i64, ptr %72, i64 3 + store i64 4, ptr %76, align 4 + %77 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8 + %78 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %77, i32 0, i32 0 + store ptr %72, ptr %78, align 8 + %79 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %77, i32 0, i32 1 + store i64 4, ptr %79, align 4 + %80 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %77, i32 0, i32 2 + store i64 4, ptr %80, align 4 + %81 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %77, align 8 + %82 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %81, 0 + %83 = getelementptr inbounds i64, ptr %82, i64 1 + %84 = load i64, ptr %83, align 4 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %84) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 0) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) ret i32 0 } @@ -144,4 +169,12 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"() declare ptr @"github.com/goplus/llgo/internal/runtime.Zeroinit"(ptr, i64) -declare i32 @printf(ptr, ...) +declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) + +declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringFromRune"(i32) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String") + +declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) diff --git a/cl/compile.go b/cl/compile.go index dbfe8fa1..de6f140d 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -757,10 +757,14 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue case *ssa.Index: x := p.compileValue(b, v.X) idx := p.compileValue(b, v.Index) - ret = b.Index(x, idx, func(e llssa.Expr) (ret llssa.Expr) { + ret = b.Index(x, idx, func(e llssa.Expr) (ret llssa.Expr, zero bool) { if e == x { - if n, ok := v.X.(*ssa.UnOp); ok { - return p.compileValue(b, n.X) + switch n := v.X.(type) { + case *ssa.Const: + zero = true + return + case *ssa.UnOp: + return p.compileValue(b, n.X), false } } panic(fmt.Errorf("todo: addr of %v", e)) diff --git a/internal/build/build.go b/internal/build/build.go index 9aa89734..b25ef650 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -290,7 +290,7 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, llFiles []string, conf if app == "" { app = filepath.Join(conf.BinPath, name+conf.AppExt) } - const N = 5 + const N = 6 args := make([]string, N, len(pkg.Imports)+len(llFiles)+(N+1)) args[0] = "-o" args[1] = app @@ -298,11 +298,13 @@ func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, llFiles []string, conf args[3] = "-Xlinker" if runtime.GOOS == "darwin" { // ld64.lld (macOS) args[4] = "-dead_strip" + args[5] = "" // It's ok to leave it empty, as we can assume libpthread is built-in on macOS. } else { // ld.lld (Unix), lld-link (Windows), wasm-ld (WebAssembly) args[4] = "--gc-sections" + args[5] = "-lpthread" // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions. } - //args[5] = "-fuse-ld=lld" // TODO(xsw): to check lld exists or not - //args[6] = "-O2" + //args[6] = "-fuse-ld=lld" // TODO(xsw): to check lld exists or not + //args[7] = "-O2" needRuntime := false needPyInit := false packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) { diff --git a/ssa/datastruct.go b/ssa/datastruct.go index 819e6d21..343f951e 100644 --- a/ssa/datastruct.go +++ b/ssa/datastruct.go @@ -163,13 +163,14 @@ func (b Builder) checkIndex(idx Expr) Expr { // Example printed form: // // t2 = t0[t1] -func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr { +func (b Builder) Index(x, idx Expr, addr func(Expr) (Expr, bool)) Expr { if debugInstr { log.Printf("Index %v, %v\n", x.impl, idx.impl) } prog := b.Prog var telem Type var ptr Expr + var zero bool switch t := x.raw.Type.Underlying().(type) { case *types.Basic: if t.Kind() != types.String { @@ -180,7 +181,7 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr { case *types.Array: telem = prog.Index(x.Type) if addr != nil { - ptr = addr(x) + ptr, zero = addr(x) } else { /* size := SizeOf(prog, telem, t.Len()) @@ -190,7 +191,11 @@ func (b Builder) Index(x, idx Expr, addr func(Expr) Expr) Expr { panic("unreachable") } } + // TODO check range idx = b.checkIndex(idx) + if zero { + return Expr{llvm.ConstNull(telem.ll), telem} + } pt := prog.Pointer(telem) indices := []llvm.Value{idx.impl} buf := Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt} diff --git a/ssa/type.go b/ssa/type.go index 7258c751..97986f95 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -61,11 +61,16 @@ const ( // ----------------------------------------------------------------------------- func indexType(t types.Type) types.Type { - switch t := t.(type) { + typ := t +retry: + switch t := typ.(type) { + case *types.Named: + typ = t.Underlying() + goto retry case *types.Slice: return t.Elem() case *types.Pointer: - switch t := t.Elem().(type) { + switch t := t.Elem().Underlying().(type) { case *types.Array: return t.Elem() } @@ -193,7 +198,7 @@ func (p Program) Pointer(typ Type) Type { } func (p Program) Elem(typ Type) Type { - elem := typ.raw.Type.(interface { + elem := typ.raw.Type.Underlying().(interface { Elem() types.Type }).Elem() return p.rawType(elem)