github.com/goplus/llgo@v0.8.3/ssa/decl.go (about)

     1  /*
     2   * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ssa
    18  
    19  import (
    20  	"go/types"
    21  	"log"
    22  	"strconv"
    23  
    24  	"github.com/goplus/llvm"
    25  )
    26  
    27  // -----------------------------------------------------------------------------
    28  
    29  const (
    30  	ClosureCtx  = "__llgo_ctx"
    31  	ClosureStub = "__llgo_stub."
    32  )
    33  
    34  // -----------------------------------------------------------------------------
    35  
    36  const (
    37  	NameValist = "__llgo_va_list"
    38  )
    39  
    40  func VArg() *types.Var {
    41  	return types.NewParam(0, nil, NameValist, types.NewSlice(tyAny))
    42  }
    43  
    44  // -----------------------------------------------------------------------------
    45  
    46  type aNamedConst struct {
    47  }
    48  
    49  // A NamedConst is a Member of a Package representing a package-level
    50  // named constant.
    51  //
    52  // Pos() returns the position of the declaring ast.ValueSpec.Names[*]
    53  // identifier.
    54  //
    55  // NB: a NamedConst is not a Value; it contains a constant Value, which
    56  // it augments with the name and position of its 'const' declaration.
    57  type NamedConst = *aNamedConst
    58  
    59  // -----------------------------------------------------------------------------
    60  
    61  type aGlobal struct {
    62  	Expr
    63  	array bool
    64  }
    65  
    66  // A Global is a named Value holding the address of a package-level
    67  // variable.
    68  type Global = *aGlobal
    69  
    70  // NewVar creates a new global variable.
    71  func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
    72  	if v, ok := p.vars[name]; ok {
    73  		return v
    74  	}
    75  	t := p.Prog.Type(typ, bg)
    76  	var gbl llvm.Value
    77  	var array bool
    78  	if t.kind == vkPtr && p.Prog.Elem(t).kind == vkArray {
    79  		typ := p.Prog.Elem(t).ll
    80  		gbl = llvm.AddGlobal(p.mod, typ, name)
    81  		gbl.SetInitializer(llvm.Undef(typ))
    82  		array = true
    83  	} else {
    84  		gbl = llvm.AddGlobal(p.mod, t.ll, name)
    85  	}
    86  	ret := &aGlobal{Expr{gbl, t}, array}
    87  	p.vars[name] = ret
    88  	return ret
    89  }
    90  
    91  // VarOf returns a global variable by name.
    92  func (p Package) VarOf(name string) Global {
    93  	return p.vars[name]
    94  }
    95  
    96  // Init initializes the global variable with the given value.
    97  func (g Global) Init(v Expr) {
    98  	if g.array && v.kind == vkPtr {
    99  		return
   100  	}
   101  	g.impl.SetInitializer(v.impl)
   102  }
   103  
   104  // -----------------------------------------------------------------------------
   105  
   106  // Function represents the parameters, results, and code of a function
   107  // or method.
   108  //
   109  // If Blocks is nil, this indicates an external function for which no
   110  // Go source code is available.  In this case, FreeVars, Locals, and
   111  // Params are nil too.  Clients performing whole-program analysis must
   112  // handle external functions specially.
   113  //
   114  // Blocks contains the function's control-flow graph (CFG).
   115  // Blocks[0] is the function entry point; block order is not otherwise
   116  // semantically significant, though it may affect the readability of
   117  // the disassembly.
   118  // To iterate over the blocks in dominance order, use DomPreorder().
   119  //
   120  // Recover is an optional second entry point to which control resumes
   121  // after a recovered panic.  The Recover block may contain only a return
   122  // statement, preceded by a load of the function's named return
   123  // parameters, if any.
   124  //
   125  // A nested function (Parent()!=nil) that refers to one or more
   126  // lexically enclosing local variables ("free variables") has FreeVars.
   127  // Such functions cannot be called directly but require a
   128  // value created by MakeClosure which, via its Bindings, supplies
   129  // values for these parameters.
   130  //
   131  // If the function is a method (Signature.Recv() != nil) then the first
   132  // element of Params is the receiver parameter.
   133  //
   134  // A Go package may declare many functions called "init".
   135  // For each one, Object().Name() returns "init" but Name() returns
   136  // "init#1", etc, in declaration order.
   137  //
   138  // Pos() returns the declaring ast.FuncLit.Type.Func or the position
   139  // of the ast.FuncDecl.Name, if the function was explicit in the
   140  // source.  Synthetic wrappers, for which Synthetic != "", may share
   141  // the same position as the function they wrap.
   142  // Syntax.Pos() always returns the position of the declaring "func" token.
   143  //
   144  // Type() returns the function's Signature.
   145  //
   146  // A generic function is a function or method that has uninstantiated type
   147  // parameters (TypeParams() != nil). Consider a hypothetical generic
   148  // method, (*Map[K,V]).Get. It may be instantiated with all ground
   149  // (non-parameterized) types as (*Map[string,int]).Get or with
   150  // parameterized types as (*Map[string,U]).Get, where U is a type parameter.
   151  // In both instantiations, Origin() refers to the instantiated generic
   152  // method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of
   153  // the generic method. TypeArgs() refers to [string,U] or [string,int],
   154  // respectively, and is nil in the generic method.
   155  type aFunction struct {
   156  	Expr
   157  	Pkg  Package
   158  	Prog Program
   159  
   160  	blks []BasicBlock
   161  
   162  	params   []Type
   163  	freeVars Expr
   164  	base     int // base = 1 if hasFreeVars; base = 0 otherwise
   165  	hasVArg  bool
   166  }
   167  
   168  // Function represents a function or method.
   169  type Function = *aFunction
   170  
   171  // NewFunc creates a new function.
   172  func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function {
   173  	return p.NewFuncEx(name, sig, bg, false)
   174  }
   175  
   176  // NewFuncEx creates a new function.
   177  func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool) Function {
   178  	if v, ok := p.fns[name]; ok {
   179  		return v
   180  	}
   181  	t := p.Prog.FuncDecl(sig, bg)
   182  	if debugInstr {
   183  		log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars)
   184  	}
   185  	fn := llvm.AddFunction(p.mod, name, t.ll)
   186  	ret := newFunction(fn, t, p, p.Prog, hasFreeVars)
   187  	p.fns[name] = ret
   188  	return ret
   189  }
   190  
   191  // FuncOf returns a function by name.
   192  func (p Package) FuncOf(name string) Function {
   193  	return p.fns[name]
   194  }
   195  
   196  func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars bool) Function {
   197  	params, hasVArg := newParams(t, prog)
   198  	base := 0
   199  	if hasFreeVars {
   200  		base = 1
   201  	}
   202  	return &aFunction{Expr{fn, t}, pkg, prog, nil, params, Expr{}, base, hasVArg}
   203  }
   204  
   205  func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {
   206  	sig := fn.raw.Type.(*types.Signature)
   207  	in := sig.Params()
   208  	if n := in.Len(); n > 0 {
   209  		if hasVArg = sig.Variadic(); hasVArg {
   210  			n--
   211  		}
   212  		params = make([]Type, n)
   213  		for i := 0; i < n; i++ {
   214  			params[i] = prog.rawType(in.At(i).Type())
   215  		}
   216  	}
   217  	return
   218  }
   219  
   220  // Params returns the function's ith parameter.
   221  func (p Function) Param(i int) Expr {
   222  	i += p.base // skip if hasFreeVars
   223  	return Expr{p.impl.Param(i), p.params[i]}
   224  }
   225  
   226  func (p Function) closureCtx(b Builder) Expr {
   227  	if p.freeVars.IsNil() {
   228  		if p.base == 0 {
   229  			panic("ssa: function has no free variables")
   230  		}
   231  		ptr := Expr{p.impl.Param(0), p.params[0]}
   232  		p.freeVars = b.Load(ptr)
   233  	}
   234  	return p.freeVars
   235  }
   236  
   237  // FreeVar returns the function's ith free variable.
   238  func (p Function) FreeVar(b Builder, i int) Expr {
   239  	ctx := p.closureCtx(b)
   240  	return b.getField(ctx, i)
   241  }
   242  
   243  // NewBuilder creates a new Builder for the function.
   244  func (p Function) NewBuilder() Builder {
   245  	prog := p.Prog
   246  	b := prog.ctx.NewBuilder()
   247  	// TODO(xsw): Finalize may cause panic, so comment it.
   248  	// b.Finalize()
   249  	return &aBuilder{b, p, prog}
   250  }
   251  
   252  // HasBody reports whether the function has a body.
   253  func (p Function) HasBody() bool {
   254  	return len(p.blks) > 0
   255  }
   256  
   257  // MakeBody creates nblk basic blocks for the function, and creates
   258  // a new Builder associated to #0 block.
   259  func (p Function) MakeBody(nblk int) Builder {
   260  	p.MakeBlocks(nblk)
   261  	b := p.NewBuilder()
   262  	b.impl.SetInsertPointAtEnd(p.blks[0].impl)
   263  	return b
   264  }
   265  
   266  // MakeBlocks creates nblk basic blocks for the function.
   267  func (p Function) MakeBlocks(nblk int) []BasicBlock {
   268  	n := len(p.blks)
   269  	if n == 0 {
   270  		p.blks = make([]BasicBlock, 0, nblk)
   271  	}
   272  	for i := 0; i < nblk; i++ {
   273  		p.addBlock(n + i)
   274  	}
   275  	return p.blks[n:]
   276  }
   277  
   278  func (p Function) addBlock(idx int) BasicBlock {
   279  	label := "_llgo_" + strconv.Itoa(idx)
   280  	blk := llvm.AddBasicBlock(p.impl, label)
   281  	ret := &aBasicBlock{blk, p, idx}
   282  	p.blks = append(p.blks, ret)
   283  	return ret
   284  }
   285  
   286  // MakeBlock creates a new basic block for the function.
   287  func (p Function) MakeBlock() BasicBlock {
   288  	return p.addBlock(len(p.blks))
   289  }
   290  
   291  // Block returns the ith basic block of the function.
   292  func (p Function) Block(idx int) BasicBlock {
   293  	return p.blks[idx]
   294  }
   295  
   296  // -----------------------------------------------------------------------------
   297  
   298  type aPyGlobal struct {
   299  	Expr
   300  }
   301  
   302  type PyGlobal = *aPyGlobal
   303  
   304  // PyNewVar creates a Python variable.
   305  func (b Builder) PyNewVar(modName, name string) PyGlobal {
   306  	pkg := b.Func.Pkg
   307  	modPtr := pkg.PyNewModVar(modName, false).Expr
   308  	mod := b.Load(modPtr)
   309  	return &aPyGlobal{pyVarExpr(mod, name)}
   310  }
   311  
   312  func (b Builder) pyLoad(ptr Expr) Expr {
   313  	pkg := b.Func.Pkg
   314  	t := ptr.raw.Type.(*pyVarTy)
   315  	fn := pkg.pyFunc("PyObject_GetAttrString", b.Prog.tyGetAttrString())
   316  	return b.Call(fn, t.mod, b.CStr(t.name))
   317  }
   318  
   319  // -----------------------------------------------------------------------------
   320  
   321  type aPyObjRef struct {
   322  	Expr
   323  	Obj Global
   324  }
   325  
   326  // PyObjRef represents a python object reference.
   327  type PyObjRef = *aPyObjRef
   328  
   329  // PyNewFunc creates a new python function.
   330  func (p Package) PyNewFunc(name string, sig *types.Signature, doInit bool) PyObjRef {
   331  	if v, ok := p.pyobjs[name]; ok {
   332  		return v
   333  	}
   334  	prog := p.Prog
   335  	obj := p.NewVar(name, prog.PyObjectPtrPtr().RawType(), InC)
   336  	if doInit {
   337  		prog.NeedPyInit = true
   338  		obj.Init(prog.Null(obj.Type))
   339  		obj.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
   340  	}
   341  	ty := &aType{obj.ll, rawType{types.NewPointer(sig)}, vkPyFuncRef}
   342  	expr := Expr{obj.impl, ty}
   343  	ret := &aPyObjRef{expr, obj}
   344  	p.pyobjs[name] = ret
   345  	return ret
   346  }
   347  
   348  // PyObjOf returns a python object by name.
   349  func (p Package) PyObjOf(name string) PyObjRef {
   350  	return p.pyobjs[name]
   351  }
   352  
   353  // PyObjs returns all used python objects in this project.
   354  func (p Package) PyObjs() map[string]PyObjRef {
   355  	return p.pyobjs
   356  }
   357  
   358  // -----------------------------------------------------------------------------