build: link globals importpath.name=value
This commit is contained in:
23
ssa/expr.go
23
ssa/expr.go
@@ -301,32 +301,11 @@ func (b Builder) CMalloc(n Expr) Expr {
|
||||
// Str returns a Go string constant expression.
|
||||
func (b Builder) Str(v string) Expr {
|
||||
prog := b.Prog
|
||||
data := b.createGlobalStr(v)
|
||||
data := b.Pkg.createGlobalStr(v)
|
||||
size := llvm.ConstInt(prog.tyInt(), uint64(len(v)), false)
|
||||
return Expr{aggregateValue(b.impl, prog.rtString(), data, size), prog.String()}
|
||||
}
|
||||
|
||||
func (b Builder) createGlobalStr(v string) (ret llvm.Value) {
|
||||
if ret, ok := b.Pkg.strs[v]; ok {
|
||||
return ret
|
||||
}
|
||||
prog := b.Prog
|
||||
if v != "" {
|
||||
typ := llvm.ArrayType(prog.tyInt8(), len(v))
|
||||
global := llvm.AddGlobal(b.Pkg.mod, typ, "")
|
||||
global.SetInitializer(b.Prog.ctx.ConstString(v, false))
|
||||
global.SetLinkage(llvm.PrivateLinkage)
|
||||
global.SetGlobalConstant(true)
|
||||
global.SetUnnamedAddr(true)
|
||||
global.SetAlignment(1)
|
||||
ret = llvm.ConstInBoundsGEP(typ, global, []llvm.Value{prog.Val(0).impl})
|
||||
} else {
|
||||
ret = llvm.ConstNull(prog.CStr().ll)
|
||||
}
|
||||
b.Pkg.strs[v] = ret
|
||||
return
|
||||
}
|
||||
|
||||
// unsafeString(data *byte, size int) string
|
||||
func (b Builder) unsafeString(data, size llvm.Value) Expr {
|
||||
prog := b.Prog
|
||||
|
||||
53
ssa/globals.go
Normal file
53
ssa/globals.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/goplus/llvm"
|
||||
)
|
||||
|
||||
func (pkg Package) AddGlobalString(name string, value string) {
|
||||
prog := pkg.Prog
|
||||
styp := prog.String()
|
||||
data := pkg.createGlobalStr(value)
|
||||
length := prog.IntVal(uint64(len(value)), prog.Uintptr())
|
||||
cv := llvm.ConstNamedStruct(styp.ll, []llvm.Value{data, length.impl})
|
||||
pkg.NewVarEx(name, prog.Pointer(styp)).Init(Expr{cv, styp})
|
||||
}
|
||||
|
||||
// Undefined global string var by names
|
||||
func (pkg Package) Undefined(names ...string) error {
|
||||
prog := pkg.Prog
|
||||
styp := prog.rtString()
|
||||
for _, name := range names {
|
||||
global := pkg.VarOf(name)
|
||||
if global == nil {
|
||||
continue
|
||||
}
|
||||
typ := prog.Elem(global.Type)
|
||||
if typ.ll != styp {
|
||||
return fmt.Errorf("%s: not a var of type string (type:%v)", name, typ.RawType())
|
||||
}
|
||||
newGlobal := llvm.AddGlobal(pkg.mod, styp, "")
|
||||
global.impl.ReplaceAllUsesWith(newGlobal)
|
||||
global.impl.EraseFromParentAsGlobal()
|
||||
newGlobal.SetName(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -788,6 +788,27 @@ func (p Package) InitDebug(name, pkgPath string, positioner Positioner) {
|
||||
p.cu = p.di.createCompileUnit(name, pkgPath)
|
||||
}
|
||||
|
||||
func (p Package) createGlobalStr(v string) (ret llvm.Value) {
|
||||
if ret, ok := p.strs[v]; ok {
|
||||
return ret
|
||||
}
|
||||
prog := p.Prog
|
||||
if v != "" {
|
||||
typ := llvm.ArrayType(prog.tyInt8(), len(v))
|
||||
global := llvm.AddGlobal(p.mod, typ, "")
|
||||
global.SetInitializer(prog.ctx.ConstString(v, false))
|
||||
global.SetLinkage(llvm.PrivateLinkage)
|
||||
global.SetGlobalConstant(true)
|
||||
global.SetUnnamedAddr(true)
|
||||
global.SetAlignment(1)
|
||||
ret = llvm.ConstInBoundsGEP(typ, global, []llvm.Value{prog.Val(0).impl})
|
||||
} else {
|
||||
ret = llvm.ConstNull(prog.CStr().ll)
|
||||
}
|
||||
p.strs[v] = ret
|
||||
return
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
|
||||
@@ -557,3 +557,65 @@ _llgo_0:
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
func TestGlobalStrings(t *testing.T) {
|
||||
prog := NewProgram(nil)
|
||||
prog.SetRuntime(func() *types.Package {
|
||||
fset := token.NewFileSet()
|
||||
imp := packages.NewImporter(fset)
|
||||
pkg, _ := imp.Import(PkgRuntime)
|
||||
return pkg
|
||||
})
|
||||
pkg := prog.NewPackage("bar", "foo/bar")
|
||||
typ := types.NewPointer(types.Typ[types.String])
|
||||
a := pkg.NewVar("foo/bar.a", typ, InGo)
|
||||
if pkg.NewVar("foo/bar.a", typ, InGo) != a {
|
||||
t.Fatal("NewVar(a) failed")
|
||||
}
|
||||
a.InitNil()
|
||||
pkg.NewVarEx("foo/bar.a", prog.Type(typ, InGo))
|
||||
b := pkg.NewVar("foo/bar.b", typ, InGo)
|
||||
b.InitNil()
|
||||
c := pkg.NewVar("foo/bar.c", types.NewPointer(types.Typ[types.Int]), InGo)
|
||||
c.Init(prog.Val(100))
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
source_filename = "foo/bar"
|
||||
|
||||
%"github.com/goplus/llgo/runtime/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@"foo/bar.a" = global %"github.com/goplus/llgo/runtime/internal/runtime.String" zeroinitializer, align 8
|
||||
@"foo/bar.b" = global %"github.com/goplus/llgo/runtime/internal/runtime.String" zeroinitializer, align 8
|
||||
@"foo/bar.c" = global i64 100, align 8
|
||||
`)
|
||||
err := pkg.Undefined("foo/bar.a", "foo/bar.b")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pkg.Undefined("foo.bar.d")
|
||||
err = pkg.Undefined("foo/bar.c")
|
||||
if err == nil {
|
||||
t.Fatal("must err")
|
||||
}
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
source_filename = "foo/bar"
|
||||
|
||||
%"github.com/goplus/llgo/runtime/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@"foo/bar.c" = global i64 100, align 8
|
||||
@"foo/bar.a" = external global %"github.com/goplus/llgo/runtime/internal/runtime.String"
|
||||
@"foo/bar.b" = external global %"github.com/goplus/llgo/runtime/internal/runtime.String"
|
||||
`)
|
||||
global := prog.NewPackage("", "global")
|
||||
global.AddGlobalString("foo/bar.a", "1.0")
|
||||
global.AddGlobalString("foo/bar.b", "info")
|
||||
assertPkg(t, global, `; ModuleID = 'global'
|
||||
source_filename = "global"
|
||||
|
||||
%"github.com/goplus/llgo/runtime/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@0 = private unnamed_addr constant [3 x i8] c"1.0", align 1
|
||||
@"foo/bar.a" = global %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @0, i64 3 }, align 8
|
||||
@1 = private unnamed_addr constant [4 x i8] c"info", align 1
|
||||
@"foo/bar.b" = global %"github.com/goplus/llgo/runtime/internal/runtime.String" { ptr @1, i64 4 }, align 8
|
||||
`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user