Builder.BinOp
This commit is contained in:
32
ssa/builder.go
Normal file
32
ssa/builder.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Builder struct {
|
||||||
|
impl llvm.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
type BasicBlock struct {
|
||||||
|
impl llvm.BasicBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p BasicBlock) End() {
|
||||||
|
}
|
||||||
69
ssa/decl.go
69
ssa/decl.go
@@ -28,14 +28,79 @@ import (
|
|||||||
//
|
//
|
||||||
// NB: a NamedConst is not a Value; it contains a constant Value, which
|
// NB: a NamedConst is not a Value; it contains a constant Value, which
|
||||||
// it augments with the name and position of its 'const' declaration.
|
// it augments with the name and position of its 'const' declaration.
|
||||||
type NamedConst struct {
|
type TyNamedConst struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NamedConst = *TyNamedConst
|
||||||
|
|
||||||
// A Global is a named Value holding the address of a package-level
|
// A Global is a named Value holding the address of a package-level
|
||||||
// variable.
|
// variable.
|
||||||
//
|
//
|
||||||
// Pos() returns the position of the ast.ValueSpec.Names[*]
|
// Pos() returns the position of the ast.ValueSpec.Names[*]
|
||||||
// identifier.
|
// identifier.
|
||||||
type Global struct {
|
type TyGlobal struct {
|
||||||
impl llvm.Value
|
impl llvm.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Global = *TyGlobal
|
||||||
|
|
||||||
|
// Function represents the parameters, results, and code of a function
|
||||||
|
// or method.
|
||||||
|
//
|
||||||
|
// If Blocks is nil, this indicates an external function for which no
|
||||||
|
// Go source code is available. In this case, FreeVars, Locals, and
|
||||||
|
// Params are nil too. Clients performing whole-program analysis must
|
||||||
|
// handle external functions specially.
|
||||||
|
//
|
||||||
|
// Blocks contains the function's control-flow graph (CFG).
|
||||||
|
// Blocks[0] is the function entry point; block order is not otherwise
|
||||||
|
// semantically significant, though it may affect the readability of
|
||||||
|
// the disassembly.
|
||||||
|
// To iterate over the blocks in dominance order, use DomPreorder().
|
||||||
|
//
|
||||||
|
// Recover is an optional second entry point to which control resumes
|
||||||
|
// after a recovered panic. The Recover block may contain only a return
|
||||||
|
// statement, preceded by a load of the function's named return
|
||||||
|
// parameters, if any.
|
||||||
|
//
|
||||||
|
// A nested function (Parent()!=nil) that refers to one or more
|
||||||
|
// lexically enclosing local variables ("free variables") has FreeVars.
|
||||||
|
// Such functions cannot be called directly but require a
|
||||||
|
// value created by MakeClosure which, via its Bindings, supplies
|
||||||
|
// values for these parameters.
|
||||||
|
//
|
||||||
|
// If the function is a method (Signature.Recv() != nil) then the first
|
||||||
|
// element of Params is the receiver parameter.
|
||||||
|
//
|
||||||
|
// A Go package may declare many functions called "init".
|
||||||
|
// For each one, Object().Name() returns "init" but Name() returns
|
||||||
|
// "init#1", etc, in declaration order.
|
||||||
|
//
|
||||||
|
// Pos() returns the declaring ast.FuncLit.Type.Func or the position
|
||||||
|
// of the ast.FuncDecl.Name, if the function was explicit in the
|
||||||
|
// source. Synthetic wrappers, for which Synthetic != "", may share
|
||||||
|
// the same position as the function they wrap.
|
||||||
|
// Syntax.Pos() always returns the position of the declaring "func" token.
|
||||||
|
//
|
||||||
|
// Type() returns the function's Signature.
|
||||||
|
//
|
||||||
|
// A generic function is a function or method that has uninstantiated type
|
||||||
|
// parameters (TypeParams() != nil). Consider a hypothetical generic
|
||||||
|
// method, (*Map[K,V]).Get. It may be instantiated with all ground
|
||||||
|
// (non-parameterized) types as (*Map[string,int]).Get or with
|
||||||
|
// parameterized types as (*Map[string,U]).Get, where U is a type parameter.
|
||||||
|
// In both instantiations, Origin() refers to the instantiated generic
|
||||||
|
// method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of
|
||||||
|
// the generic method. TypeArgs() refers to [string,U] or [string,int],
|
||||||
|
// respectively, and is nil in the generic method.
|
||||||
|
type TyFunction struct {
|
||||||
|
impl llvm.Value
|
||||||
|
prog Program
|
||||||
|
}
|
||||||
|
|
||||||
|
type Function = *TyFunction
|
||||||
|
|
||||||
|
func (p *TyFunction) BodyStart() *BasicBlock {
|
||||||
|
body := llvm.AddBasicBlock(p.impl, "entry")
|
||||||
|
return &BasicBlock{body}
|
||||||
|
}
|
||||||
|
|||||||
17
ssa/expr.go
Normal file
17
ssa/expr.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ssa
|
||||||
74
ssa/func.go
74
ssa/func.go
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ssa
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llvm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Function represents the parameters, results, and code of a function
|
|
||||||
// or method.
|
|
||||||
//
|
|
||||||
// If Blocks is nil, this indicates an external function for which no
|
|
||||||
// Go source code is available. In this case, FreeVars, Locals, and
|
|
||||||
// Params are nil too. Clients performing whole-program analysis must
|
|
||||||
// handle external functions specially.
|
|
||||||
//
|
|
||||||
// Blocks contains the function's control-flow graph (CFG).
|
|
||||||
// Blocks[0] is the function entry point; block order is not otherwise
|
|
||||||
// semantically significant, though it may affect the readability of
|
|
||||||
// the disassembly.
|
|
||||||
// To iterate over the blocks in dominance order, use DomPreorder().
|
|
||||||
//
|
|
||||||
// Recover is an optional second entry point to which control resumes
|
|
||||||
// after a recovered panic. The Recover block may contain only a return
|
|
||||||
// statement, preceded by a load of the function's named return
|
|
||||||
// parameters, if any.
|
|
||||||
//
|
|
||||||
// A nested function (Parent()!=nil) that refers to one or more
|
|
||||||
// lexically enclosing local variables ("free variables") has FreeVars.
|
|
||||||
// Such functions cannot be called directly but require a
|
|
||||||
// value created by MakeClosure which, via its Bindings, supplies
|
|
||||||
// values for these parameters.
|
|
||||||
//
|
|
||||||
// If the function is a method (Signature.Recv() != nil) then the first
|
|
||||||
// element of Params is the receiver parameter.
|
|
||||||
//
|
|
||||||
// A Go package may declare many functions called "init".
|
|
||||||
// For each one, Object().Name() returns "init" but Name() returns
|
|
||||||
// "init#1", etc, in declaration order.
|
|
||||||
//
|
|
||||||
// Pos() returns the declaring ast.FuncLit.Type.Func or the position
|
|
||||||
// of the ast.FuncDecl.Name, if the function was explicit in the
|
|
||||||
// source. Synthetic wrappers, for which Synthetic != "", may share
|
|
||||||
// the same position as the function they wrap.
|
|
||||||
// Syntax.Pos() always returns the position of the declaring "func" token.
|
|
||||||
//
|
|
||||||
// Type() returns the function's Signature.
|
|
||||||
//
|
|
||||||
// A generic function is a function or method that has uninstantiated type
|
|
||||||
// parameters (TypeParams() != nil). Consider a hypothetical generic
|
|
||||||
// method, (*Map[K,V]).Get. It may be instantiated with all ground
|
|
||||||
// (non-parameterized) types as (*Map[string,int]).Get or with
|
|
||||||
// parameterized types as (*Map[string,U]).Get, where U is a type parameter.
|
|
||||||
// In both instantiations, Origin() refers to the instantiated generic
|
|
||||||
// method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of
|
|
||||||
// the generic method. TypeArgs() refers to [string,U] or [string,int],
|
|
||||||
// respectively, and is nil in the generic method.
|
|
||||||
type Function struct {
|
|
||||||
impl llvm.Value
|
|
||||||
}
|
|
||||||
178
ssa/operator.go
Normal file
178
ssa/operator.go
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/token"
|
||||||
|
|
||||||
|
"github.com/goplus/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type valueKind = int
|
||||||
|
|
||||||
|
type Value struct {
|
||||||
|
impl llvm.Value
|
||||||
|
kind valueKind
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
mathOpBase = token.ADD
|
||||||
|
mathOpLast = token.REM
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
vkInvalid valueKind = iota
|
||||||
|
vkSigned
|
||||||
|
vkUnsigned
|
||||||
|
vkFloat
|
||||||
|
vkComplex
|
||||||
|
vkString
|
||||||
|
vkBool
|
||||||
|
)
|
||||||
|
|
||||||
|
var mathOpToLLVM = []llvm.Opcode{
|
||||||
|
int(token.ADD-mathOpBase)<<2 | vkSigned: llvm.Add,
|
||||||
|
int(token.ADD-mathOpBase)<<2 | vkUnsigned: llvm.Add,
|
||||||
|
int(token.ADD-mathOpBase)<<2 | vkFloat: llvm.FAdd,
|
||||||
|
|
||||||
|
int(token.SUB-mathOpBase)<<2 | vkSigned: llvm.Sub,
|
||||||
|
int(token.SUB-mathOpBase)<<2 | vkUnsigned: llvm.Sub,
|
||||||
|
int(token.SUB-mathOpBase)<<2 | vkFloat: llvm.FSub,
|
||||||
|
|
||||||
|
int(token.MUL-mathOpBase)<<2 | vkSigned: llvm.Mul,
|
||||||
|
int(token.MUL-mathOpBase)<<2 | vkUnsigned: llvm.Mul,
|
||||||
|
int(token.MUL-mathOpBase)<<2 | vkFloat: llvm.FMul,
|
||||||
|
|
||||||
|
int(token.QUO-mathOpBase)<<2 | vkSigned: llvm.SDiv,
|
||||||
|
int(token.QUO-mathOpBase)<<2 | vkUnsigned: llvm.UDiv,
|
||||||
|
int(token.QUO-mathOpBase)<<2 | vkFloat: llvm.FDiv,
|
||||||
|
|
||||||
|
int(token.REM-mathOpBase)<<2 | vkSigned: llvm.SRem,
|
||||||
|
int(token.REM-mathOpBase)<<2 | vkUnsigned: llvm.URem,
|
||||||
|
int(token.REM-mathOpBase)<<2 | vkFloat: llvm.FRem,
|
||||||
|
}
|
||||||
|
|
||||||
|
func mathOpIdx(op token.Token, x valueKind) int {
|
||||||
|
return int(op-mathOpBase)<<2 | x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADD SUB MUL QUO REM + - * / %
|
||||||
|
func isMathOp(op token.Token) bool {
|
||||||
|
return op >= mathOpBase && op <= mathOpLast
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
logicOpBase = token.AND
|
||||||
|
logicOpLast = token.AND_NOT
|
||||||
|
)
|
||||||
|
|
||||||
|
var logicOpToLLVM = []llvm.Opcode{
|
||||||
|
token.AND - logicOpBase: llvm.And,
|
||||||
|
token.OR - logicOpBase: llvm.Or,
|
||||||
|
token.XOR - logicOpBase: llvm.Xor,
|
||||||
|
token.SHL - logicOpBase: llvm.Shl,
|
||||||
|
token.SHR - logicOpBase: llvm.LShr,
|
||||||
|
}
|
||||||
|
|
||||||
|
// AND OR XOR SHL SHR AND_NOT & | ^ << >> &^
|
||||||
|
func isLogicOp(op token.Token) bool {
|
||||||
|
return op >= logicOpBase && op <= logicOpLast
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
predOpBase = token.EQL
|
||||||
|
predOpLast = token.GEQ
|
||||||
|
)
|
||||||
|
|
||||||
|
var intPredOpToLLVM = []llvm.IntPredicate{
|
||||||
|
token.EQL - predOpBase: llvm.IntEQ,
|
||||||
|
token.NEQ - predOpBase: llvm.IntNE,
|
||||||
|
token.LSS - predOpBase: llvm.IntSLT,
|
||||||
|
token.LEQ - predOpBase: llvm.IntSLE,
|
||||||
|
token.GTR - predOpBase: llvm.IntSGT,
|
||||||
|
token.GEQ - predOpBase: llvm.IntSGE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var uintPredOpToLLVM = []llvm.IntPredicate{
|
||||||
|
token.EQL - predOpBase: llvm.IntEQ,
|
||||||
|
token.NEQ - predOpBase: llvm.IntNE,
|
||||||
|
token.LSS - predOpBase: llvm.IntULT,
|
||||||
|
token.LEQ - predOpBase: llvm.IntULE,
|
||||||
|
token.GTR - predOpBase: llvm.IntUGT,
|
||||||
|
token.GEQ - predOpBase: llvm.IntUGE,
|
||||||
|
}
|
||||||
|
|
||||||
|
var floatPredOpToLLVM = []llvm.FloatPredicate{
|
||||||
|
token.EQL - predOpBase: llvm.FloatOEQ,
|
||||||
|
token.NEQ - predOpBase: llvm.FloatONE,
|
||||||
|
token.LSS - predOpBase: llvm.FloatOLT,
|
||||||
|
token.LEQ - predOpBase: llvm.FloatOLE,
|
||||||
|
token.GTR - predOpBase: llvm.FloatOGT,
|
||||||
|
token.GEQ - predOpBase: llvm.FloatOGE,
|
||||||
|
}
|
||||||
|
|
||||||
|
// EQL NEQ LSS LEQ GTR GEQ == != < <= < >=
|
||||||
|
func isPredOp(op token.Token) bool {
|
||||||
|
return op >= predOpBase && op <= predOpLast
|
||||||
|
}
|
||||||
|
|
||||||
|
// op:
|
||||||
|
// ADD SUB MUL QUO REM + - * / %
|
||||||
|
// AND OR XOR SHL SHR AND_NOT & | ^ << >> &^
|
||||||
|
// EQL NEQ LSS LEQ GTR GEQ == != < <= < >=
|
||||||
|
func (b Builder) BinOp(op token.Token, x, y Value) (v Value) {
|
||||||
|
switch {
|
||||||
|
case isMathOp(op): // op: + - * / %
|
||||||
|
switch x.kind {
|
||||||
|
case vkString, vkComplex:
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
idx := mathOpIdx(op, x.kind)
|
||||||
|
if llop := mathOpToLLVM[idx]; llop != 0 {
|
||||||
|
v.impl = llvm.CreateBinOp(b.impl, llop, x.impl, y.impl)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case isLogicOp(op): // op: & | ^ << >> &^
|
||||||
|
if op == token.AND_NOT {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
llop := logicOpToLLVM[op-logicOpBase]
|
||||||
|
if op == token.SHR && x.kind == vkUnsigned {
|
||||||
|
llop = llvm.AShr
|
||||||
|
}
|
||||||
|
v.impl = llvm.CreateBinOp(b.impl, llop, x.impl, y.impl)
|
||||||
|
return
|
||||||
|
case isPredOp(op): // op: == != < <= < >=
|
||||||
|
switch x.kind {
|
||||||
|
case vkSigned:
|
||||||
|
pred := intPredOpToLLVM[op-predOpBase]
|
||||||
|
v.impl = llvm.CreateICmp(b.impl, pred, x.impl, y.impl)
|
||||||
|
return
|
||||||
|
case vkUnsigned:
|
||||||
|
pred := uintPredOpToLLVM[op-predOpBase]
|
||||||
|
v.impl = llvm.CreateICmp(b.impl, pred, x.impl, y.impl)
|
||||||
|
return
|
||||||
|
case vkFloat:
|
||||||
|
pred := floatPredOpToLLVM[op-predOpBase]
|
||||||
|
v.impl = llvm.ConstFCmp(pred, x.impl, y.impl)
|
||||||
|
return
|
||||||
|
case vkString, vkComplex, vkBool:
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -25,8 +25,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// A Program is a partial or complete Go program converted to SSA form.
|
// A Program is a partial or complete Go program converted to SSA form.
|
||||||
type Program struct {
|
type TyProgram struct {
|
||||||
ctx llvm.Context
|
ctx llvm.Context
|
||||||
|
b Builder
|
||||||
typs typeutil.Map
|
typs typeutil.Map
|
||||||
|
|
||||||
target *Target
|
target *Target
|
||||||
@@ -42,20 +43,28 @@ type Program struct {
|
|||||||
voidPtrTy llvm.Type
|
voidPtrTy llvm.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProgram(target *Target) *Program {
|
type Program = *TyProgram
|
||||||
|
|
||||||
|
func NewProgram(target *Target) Program {
|
||||||
if target == nil {
|
if target == nil {
|
||||||
target = &Target{}
|
target = &Target{}
|
||||||
}
|
}
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
ctx.Finalize()
|
ctx.Finalize()
|
||||||
|
b := ctx.NewBuilder()
|
||||||
|
b.Finalize()
|
||||||
td := llvm.NewTargetData("") // TODO(xsw): target config
|
td := llvm.NewTargetData("") // TODO(xsw): target config
|
||||||
return &Program{ctx: ctx, target: target, td: td}
|
return &TyProgram{ctx: ctx, b: Builder{b}, target: target, td: td}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) NewPackage(name, pkgPath string) *Package {
|
func (p *TyProgram) NewPackage(name, pkgPath string) Package {
|
||||||
mod := p.ctx.NewModule(pkgPath)
|
mod := p.ctx.NewModule(pkgPath)
|
||||||
mod.Finalize()
|
mod.Finalize()
|
||||||
return &Package{mod, p}
|
return &TyPackage{mod, p}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TyProgram) Builder() Builder {
|
||||||
|
return p.b
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Package is a single analyzed Go package containing Members for
|
// A Package is a single analyzed Go package containing Members for
|
||||||
@@ -66,26 +75,28 @@ func (p *Program) NewPackage(name, pkgPath string) *Package {
|
|||||||
// Members also contains entries for "init" (the synthetic package
|
// Members also contains entries for "init" (the synthetic package
|
||||||
// initializer) and "init#%d", the nth declared init function,
|
// initializer) and "init#%d", the nth declared init function,
|
||||||
// and unspecified other things too.
|
// and unspecified other things too.
|
||||||
type Package struct {
|
type TyPackage struct {
|
||||||
mod llvm.Module
|
mod llvm.Module
|
||||||
prog *Program
|
prog Program
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) NewConst(name string, val constant.Value) *NamedConst {
|
type Package = *TyPackage
|
||||||
return &NamedConst{}
|
|
||||||
|
func (p *TyPackage) NewConst(name string, val constant.Value) NamedConst {
|
||||||
|
return &TyNamedConst{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) NewVar(name string, typ types.Type) *Global {
|
func (p *TyPackage) NewVar(name string, typ types.Type) Global {
|
||||||
gbl := llvm.AddGlobal(p.mod, p.prog.llvmType(typ), name)
|
gbl := llvm.AddGlobal(p.mod, p.prog.llvmType(typ), name)
|
||||||
return &Global{gbl}
|
return &TyGlobal{gbl}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) NewFunc(name string, sig *types.Signature) *Function {
|
func (p *TyPackage) NewFunc(name string, sig *types.Signature) Function {
|
||||||
fn := llvm.AddFunction(p.mod, name, p.prog.llvmSignature(sig))
|
fn := llvm.AddFunction(p.mod, name, p.prog.llvmSignature(sig))
|
||||||
return &Function{fn}
|
return &TyFunction{fn, p.prog}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) String() string {
|
func (p *TyPackage) String() string {
|
||||||
return p.mod.String()
|
return p.mod.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func asmPkg(t *testing.T, p *Package) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func assertPkg(t *testing.T, p *Package, expected string) {
|
func assertPkg(t *testing.T, p Package, expected string) {
|
||||||
if v := p.String(); v != expected {
|
if v := p.String(); v != expected {
|
||||||
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||||
}
|
}
|
||||||
|
|||||||
34
ssa/type.go
34
ssa/type.go
@@ -29,7 +29,7 @@ type Type struct {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (p *Program) llvmType(typ types.Type) llvm.Type {
|
func (p *TyProgram) llvmType(typ types.Type) llvm.Type {
|
||||||
if v := p.typs.At(typ); v != nil {
|
if v := p.typs.At(typ); v != nil {
|
||||||
return v.(llvm.Type)
|
return v.(llvm.Type)
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ func (p *Program) llvmType(typ types.Type) llvm.Type {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) llvmSignature(sig *types.Signature) llvm.Type {
|
func (p *TyProgram) llvmSignature(sig *types.Signature) llvm.Type {
|
||||||
if v := p.typs.At(sig); v != nil {
|
if v := p.typs.At(sig); v != nil {
|
||||||
return v.(llvm.Type)
|
return v.(llvm.Type)
|
||||||
}
|
}
|
||||||
@@ -47,56 +47,56 @@ func (p *Program) llvmSignature(sig *types.Signature) llvm.Type {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyVoidPtr() llvm.Type {
|
func (p *TyProgram) tyVoidPtr() llvm.Type {
|
||||||
if p.voidPtrTy.IsNil() {
|
if p.voidPtrTy.IsNil() {
|
||||||
p.voidPtrTy = llvm.PointerType(p.tyVoid(), 0)
|
p.voidPtrTy = llvm.PointerType(p.tyVoid(), 0)
|
||||||
}
|
}
|
||||||
return p.voidPtrTy
|
return p.voidPtrTy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyVoid() llvm.Type {
|
func (p *TyProgram) tyVoid() llvm.Type {
|
||||||
if p.voidType.IsNil() {
|
if p.voidType.IsNil() {
|
||||||
p.voidType = p.ctx.VoidType()
|
p.voidType = p.ctx.VoidType()
|
||||||
}
|
}
|
||||||
return p.voidType
|
return p.voidType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyInt() llvm.Type {
|
func (p *TyProgram) tyInt() llvm.Type {
|
||||||
if p.intType.IsNil() {
|
if p.intType.IsNil() {
|
||||||
p.intType = llvmIntType(p.ctx, p.td.PointerSize())
|
p.intType = llvmIntType(p.ctx, p.td.PointerSize())
|
||||||
}
|
}
|
||||||
return p.intType
|
return p.intType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyInt8() llvm.Type {
|
func (p *TyProgram) tyInt8() llvm.Type {
|
||||||
if p.int8Type.IsNil() {
|
if p.int8Type.IsNil() {
|
||||||
p.int8Type = p.ctx.Int8Type()
|
p.int8Type = p.ctx.Int8Type()
|
||||||
}
|
}
|
||||||
return p.int8Type
|
return p.int8Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyInt16() llvm.Type {
|
func (p *TyProgram) tyInt16() llvm.Type {
|
||||||
if p.int16Type.IsNil() {
|
if p.int16Type.IsNil() {
|
||||||
p.int16Type = p.ctx.Int16Type()
|
p.int16Type = p.ctx.Int16Type()
|
||||||
}
|
}
|
||||||
return p.int16Type
|
return p.int16Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyInt32() llvm.Type {
|
func (p *TyProgram) tyInt32() llvm.Type {
|
||||||
if p.int32Type.IsNil() {
|
if p.int32Type.IsNil() {
|
||||||
p.int32Type = p.ctx.Int32Type()
|
p.int32Type = p.ctx.Int32Type()
|
||||||
}
|
}
|
||||||
return p.int32Type
|
return p.int32Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) tyInt64() llvm.Type {
|
func (p *TyProgram) tyInt64() llvm.Type {
|
||||||
if p.int64Type.IsNil() {
|
if p.int64Type.IsNil() {
|
||||||
p.int64Type = p.ctx.Int64Type()
|
p.int64Type = p.ctx.Int64Type()
|
||||||
}
|
}
|
||||||
return p.int64Type
|
return p.int64Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMType(typ types.Type) llvm.Type {
|
func (p *TyProgram) toLLVMType(typ types.Type) llvm.Type {
|
||||||
switch t := typ.(type) {
|
switch t := typ.(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
@@ -146,19 +146,19 @@ func llvmIntType(ctx llvm.Context, size int) llvm.Type {
|
|||||||
return ctx.Int64Type()
|
return ctx.Int64Type()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMNamedStruct(name string, typ *types.Struct) llvm.Type {
|
func (p *TyProgram) toLLVMNamedStruct(name string, typ *types.Struct) llvm.Type {
|
||||||
t := p.ctx.StructCreateNamed(name)
|
t := p.ctx.StructCreateNamed(name)
|
||||||
fields := p.toLLVMFields(typ)
|
fields := p.toLLVMFields(typ)
|
||||||
t.StructSetBody(fields, false)
|
t.StructSetBody(fields, false)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMStruct(typ *types.Struct) llvm.Type {
|
func (p *TyProgram) toLLVMStruct(typ *types.Struct) llvm.Type {
|
||||||
fields := p.toLLVMFields(typ)
|
fields := p.toLLVMFields(typ)
|
||||||
return p.ctx.StructType(fields, false)
|
return p.ctx.StructType(fields, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMFields(typ *types.Struct) []llvm.Type {
|
func (p *TyProgram) toLLVMFields(typ *types.Struct) []llvm.Type {
|
||||||
n := typ.NumFields()
|
n := typ.NumFields()
|
||||||
fields := make([]llvm.Type, n)
|
fields := make([]llvm.Type, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
@@ -167,11 +167,11 @@ func (p *Program) toLLVMFields(typ *types.Struct) []llvm.Type {
|
|||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMTuple(t *types.Tuple) llvm.Type {
|
func (p *TyProgram) toLLVMTuple(t *types.Tuple) llvm.Type {
|
||||||
return p.ctx.StructType(p.toLLVMTypes(t), false)
|
return p.ctx.StructType(p.toLLVMTypes(t), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMTypes(t *types.Tuple) []llvm.Type {
|
func (p *TyProgram) toLLVMTypes(t *types.Tuple) []llvm.Type {
|
||||||
n := t.Len()
|
n := t.Len()
|
||||||
ret := make([]llvm.Type, n)
|
ret := make([]llvm.Type, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
@@ -180,7 +180,7 @@ func (p *Program) toLLVMTypes(t *types.Tuple) []llvm.Type {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMFunc(sig *types.Signature) llvm.Type {
|
func (p *TyProgram) toLLVMFunc(sig *types.Signature) llvm.Type {
|
||||||
params := p.toLLVMTypes(sig.Params())
|
params := p.toLLVMTypes(sig.Params())
|
||||||
results := sig.Results()
|
results := sig.Results()
|
||||||
var ret llvm.Type
|
var ret llvm.Type
|
||||||
@@ -195,7 +195,7 @@ func (p *Program) toLLVMFunc(sig *types.Signature) llvm.Type {
|
|||||||
return llvm.FunctionType(ret, params, sig.Variadic())
|
return llvm.FunctionType(ret, params, sig.Variadic())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) toLLVMNamed(typ *types.Named) llvm.Type {
|
func (p *TyProgram) toLLVMNamed(typ *types.Named) llvm.Type {
|
||||||
name := typ.Obj().Name()
|
name := typ.Obj().Name()
|
||||||
switch typ := typ.Underlying().(type) {
|
switch typ := typ.Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
|
|||||||
Reference in New Issue
Block a user