Files
llgo/ssa/package.go

332 lines
7.4 KiB
Go
Raw Normal View History

2024-04-15 04:00:38 +08:00
/*
* Copyright (c) 2024 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.
*/
2024-04-15 17:12:30 +08:00
package ssa
2024-04-15 04:00:38 +08:00
import (
"go/constant"
"go/types"
2024-04-15 05:48:48 +08:00
"github.com/goplus/llvm"
2024-04-15 04:00:38 +08:00
"golang.org/x/tools/go/types/typeutil"
)
2024-04-21 16:04:05 +08:00
// -----------------------------------------------------------------------------
2024-04-21 15:12:57 +08:00
type dbgFlags = int
const (
DbgFlagInstruction dbgFlags = 1 << iota
DbgFlagAll = DbgFlagInstruction
)
var (
debugInstr bool
)
// SetDebug sets debug flags.
func SetDebug(dbgFlags dbgFlags) {
debugInstr = (dbgFlags & DbgFlagInstruction) != 0
}
2024-04-19 00:05:57 +08:00
// -----------------------------------------------------------------------------
2024-04-20 23:57:55 +08:00
// InitFlags is a set of flags for initializing the LLVM library.
2024-04-19 00:05:57 +08:00
type InitFlags int
const (
InitNativeTarget InitFlags = 1 << iota
InitAllTargets
InitAllTargetInfos
InitAllTargetMCs
InitNativeAsmPrinter
InitAllAsmPrinters
InitAllAsmParsers
InitNative = InitNativeTarget | InitNativeAsmPrinter
InitAll = InitAllTargets | InitAllAsmParsers | InitAllAsmPrinters | InitAllTargetInfos | InitAllTargetMCs
)
2024-04-20 23:57:55 +08:00
// Initialize initializes the LLVM library.
2024-04-19 00:05:57 +08:00
func Initialize(flags InitFlags) {
if flags&InitAllTargetInfos != 0 {
llvm.InitializeAllTargetInfos()
}
if flags&InitAllTargets != 0 {
llvm.InitializeAllTargets()
}
if flags&InitAllTargetMCs != 0 {
llvm.InitializeAllTargetMCs()
}
if flags&InitAllAsmParsers != 0 {
llvm.InitializeAllAsmParsers()
}
if flags&InitAllAsmPrinters != 0 {
llvm.InitializeAllAsmPrinters()
}
if flags&InitNativeTarget != 0 {
llvm.InitializeNativeTarget()
}
if flags&InitNativeAsmPrinter != 0 {
llvm.InitializeNativeAsmPrinter()
}
}
// -----------------------------------------------------------------------------
2024-04-18 01:23:01 +08:00
type aProgram struct {
2024-04-15 04:00:38 +08:00
ctx llvm.Context
typs typeutil.Map
2024-04-15 17:12:30 +08:00
2024-04-27 13:57:21 +08:00
rt *types.Scope
2024-04-27 17:39:25 +08:00
rtget func() *types.Package
2024-04-27 13:57:21 +08:00
2024-04-15 17:12:30 +08:00
target *Target
td llvm.TargetData
2024-04-16 00:43:29 +08:00
// tm llvm.TargetMachine
2024-04-15 04:00:38 +08:00
intType llvm.Type
2024-04-18 15:03:10 +08:00
int1Type llvm.Type
2024-04-15 04:00:38 +08:00
int8Type llvm.Type
int16Type llvm.Type
int32Type llvm.Type
int64Type llvm.Type
2024-04-16 03:05:20 +08:00
voidType llvm.Type
voidPtrTy llvm.Type
2024-04-18 15:03:10 +08:00
2024-04-27 18:13:16 +08:00
rtIfaceTy llvm.Type
rtSliceTy llvm.Type
2024-04-27 13:57:21 +08:00
anyTy Type
2024-04-19 00:05:57 +08:00
voidTy Type
2024-04-18 15:03:10 +08:00
boolTy Type
intTy Type
f64Ty Type
2024-04-15 04:00:38 +08:00
}
2024-04-20 23:57:55 +08:00
// A Program presents a program.
2024-04-18 01:23:01 +08:00
type Program = *aProgram
2024-04-18 01:18:41 +08:00
2024-04-20 23:57:55 +08:00
// NewProgram creates a new program.
2024-04-18 01:18:41 +08:00
func NewProgram(target *Target) Program {
2024-04-15 17:12:30 +08:00
if target == nil {
target = &Target{}
}
2024-04-15 04:00:38 +08:00
ctx := llvm.NewContext()
// TODO(xsw): Finalize may cause panic, so comment it.
// ctx.Finalize()
2024-04-15 17:12:30 +08:00
td := llvm.NewTargetData("") // TODO(xsw): target config
2024-04-18 15:03:10 +08:00
return &aProgram{ctx: ctx, target: target, td: td}
2024-04-15 04:00:38 +08:00
}
2024-04-27 17:39:25 +08:00
// SetRuntime sets the runtime.
func (p Program) SetRuntime(runtime func() *types.Package) {
2024-04-27 13:57:21 +08:00
p.rtget = runtime
}
func (p Program) runtime() *types.Scope {
if p.rt == nil {
2024-04-27 17:39:25 +08:00
p.rt = p.rtget().Scope()
2024-04-27 13:57:21 +08:00
}
return p.rt
}
2024-04-27 18:13:16 +08:00
func (p Program) rtNamed(name string) *types.Named {
2024-04-27 17:39:25 +08:00
return p.runtime().Lookup(name).Type().(*types.Named)
}
2024-04-27 18:13:16 +08:00
func (p Program) rtType(name string) Type {
return p.Type(p.rtNamed(name))
}
func (p Program) rtIface() llvm.Type {
if p.rtIfaceTy.IsNil() {
p.rtIfaceTy = p.rtType("Interface").ll
}
return p.rtIfaceTy
}
func (p Program) rtSlice() llvm.Type {
if p.rtSliceTy.IsNil() {
p.rtSliceTy = p.rtType("Slice").ll
}
return p.rtSliceTy
}
2024-04-20 23:57:55 +08:00
// NewPackage creates a new package.
2024-04-18 15:03:10 +08:00
func (p Program) NewPackage(name, pkgPath string) Package {
2024-04-15 05:48:48 +08:00
mod := p.ctx.NewModule(pkgPath)
// TODO(xsw): Finalize may cause panic, so comment it.
// mod.Finalize()
2024-04-21 15:12:57 +08:00
fns := make(map[string]Function)
gbls := make(map[string]Global)
return &aPackage{mod, fns, gbls, p}
2024-04-18 01:18:41 +08:00
}
2024-04-20 23:57:55 +08:00
// Void returns void type.
2024-04-19 00:05:57 +08:00
func (p Program) Void() Type {
if p.voidTy == nil {
p.voidTy = &aType{p.tyVoid(), types.Typ[types.Invalid], vkInvalid}
}
return p.voidTy
}
2024-04-20 23:57:55 +08:00
// Bool returns bool type.
2024-04-18 15:03:10 +08:00
func (p Program) Bool() Type {
if p.boolTy == nil {
2024-04-21 15:12:57 +08:00
p.boolTy = p.Type(types.Typ[types.Bool])
2024-04-18 15:03:10 +08:00
}
return p.boolTy
}
2024-04-27 21:32:48 +08:00
// Any returns any type.
2024-04-27 13:57:21 +08:00
func (p Program) Any() Type {
if p.anyTy == nil {
p.anyTy = p.Type(tyAny)
}
return p.anyTy
}
2024-04-20 23:57:55 +08:00
// Int returns int type.
2024-04-18 15:03:10 +08:00
func (p Program) Int() Type {
if p.intTy == nil {
2024-04-21 15:12:57 +08:00
p.intTy = p.Type(types.Typ[types.Int])
2024-04-18 15:03:10 +08:00
}
return p.intTy
}
2024-04-20 23:57:55 +08:00
// Float64 returns float64 type.
2024-04-18 15:03:10 +08:00
func (p Program) Float64() Type {
if p.f64Ty == nil {
2024-04-21 15:12:57 +08:00
p.f64Ty = p.Type(types.Typ[types.Float64])
2024-04-18 15:03:10 +08:00
}
return p.f64Ty
2024-04-15 04:00:38 +08:00
}
2024-04-19 00:05:57 +08:00
// -----------------------------------------------------------------------------
2024-04-15 04:00:38 +08:00
// A Package is a single analyzed Go package containing Members for
// all package-level functions, variables, constants and types it
// declares. These may be accessed directly via Members, or via the
// type-specific accessor methods Func, Type, Var and Const.
//
// Members also contains entries for "init" (the synthetic package
// initializer) and "init#%d", the nth declared init function,
// and unspecified other things too.
2024-04-18 01:23:01 +08:00
type aPackage struct {
2024-04-15 04:00:38 +08:00
mod llvm.Module
2024-04-21 15:12:57 +08:00
fns map[string]Function
vars map[string]Global
2024-04-18 01:18:41 +08:00
prog Program
2024-04-15 04:00:38 +08:00
}
2024-04-18 01:23:01 +08:00
type Package = *aPackage
2024-04-18 01:18:41 +08:00
2024-04-25 21:44:23 +08:00
// NewConst creates a new named constant.
2024-04-18 15:03:10 +08:00
func (p Package) NewConst(name string, val constant.Value) NamedConst {
2024-04-18 01:23:01 +08:00
return &aNamedConst{}
2024-04-15 04:00:38 +08:00
}
2024-04-20 23:57:55 +08:00
// NewVar creates a new global variable.
2024-04-18 15:03:10 +08:00
func (p Package) NewVar(name string, typ types.Type) Global {
2024-04-21 15:12:57 +08:00
t := p.prog.Type(typ)
2024-04-18 15:03:10 +08:00
gbl := llvm.AddGlobal(p.mod, t.ll, name)
2024-04-21 15:12:57 +08:00
ret := &aGlobal{Expr{gbl, t}}
p.vars[name] = ret
return ret
2024-04-15 04:00:38 +08:00
}
2024-04-27 17:39:25 +08:00
// VarOf returns a global variable by name.
func (p Package) VarOf(name string) Global {
return p.vars[name]
}
2024-04-20 23:57:55 +08:00
// NewFunc creates a new function.
2024-04-18 15:03:10 +08:00
func (p Package) NewFunc(name string, sig *types.Signature) Function {
t := p.prog.llvmSignature(sig)
fn := llvm.AddFunction(p.mod, name, t.ll)
2024-04-27 17:39:25 +08:00
ret := newFunction(fn, t, p, p.prog)
2024-04-21 15:12:57 +08:00
p.fns[name] = ret
return ret
}
// FuncOf returns a function by name.
func (p Package) FuncOf(name string) Function {
return p.fns[name]
2024-04-15 04:00:38 +08:00
}
2024-04-27 17:39:25 +08:00
func (p Package) rtFunc(fnName string) Expr {
fn := p.prog.runtime().Lookup(fnName).(*types.Func)
name := FullName(fn.Pkg(), fnName)
v, ok := p.fns[name]
if !ok {
v = p.NewFunc(name, fn.Type().(*types.Signature))
}
return v.Expr
2024-04-21 15:12:57 +08:00
}
// -----------------------------------------------------------------------------
2024-04-20 23:57:55 +08:00
// String returns a string representation of the package.
2024-04-18 15:03:10 +08:00
func (p Package) String() string {
2024-04-16 00:43:29 +08:00
return p.mod.String()
}
/*
2024-04-15 17:12:30 +08:00
type CodeGenFileType = llvm.CodeGenFileType
const (
AssemblyFile = llvm.AssemblyFile
ObjectFile = llvm.ObjectFile
)
func (p *Package) CodeGen(ft CodeGenFileType) (ret []byte, err error) {
buf, err := p.prog.targetMachine().EmitToMemoryBuffer(p.mod, ft)
if err != nil {
return
}
ret = buf.Bytes()
buf.Dispose()
return
}
func (p *Package) Bitcode() []byte {
2024-04-15 04:00:38 +08:00
buf := llvm.WriteBitcodeToMemoryBuffer(p.mod)
2024-04-15 05:48:48 +08:00
ret := buf.Bytes()
buf.Dispose()
return ret
}
func (p *Package) WriteTo(w io.Writer) (int64, error) {
2024-04-15 17:12:30 +08:00
n, err := w.Write(p.Bitcode())
2024-04-15 04:00:38 +08:00
return int64(n), err
}
func (p *Package) WriteFile(file string) (err error) {
f, err := os.Create(file)
if err != nil {
return
}
defer f.Close()
return llvm.WriteBitcodeToFile(p.mod, f)
}
2024-04-16 00:43:29 +08:00
*/
2024-04-19 00:05:57 +08:00
// -----------------------------------------------------------------------------