2024-04-18 01:18:41 +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.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
package ssa
|
2024-04-18 15:03:10 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
2024-04-21 15:12:57 +08:00
|
|
|
|
"bytes"
|
|
|
|
|
|
"fmt"
|
2024-04-20 22:05:45 +08:00
|
|
|
|
"go/constant"
|
2024-04-18 22:18:43 +08:00
|
|
|
|
"go/token"
|
2024-04-19 00:05:57 +08:00
|
|
|
|
"go/types"
|
2024-04-21 15:12:57 +08:00
|
|
|
|
"log"
|
2024-04-18 22:18:43 +08:00
|
|
|
|
|
2024-04-18 15:03:10 +08:00
|
|
|
|
"github.com/goplus/llvm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2024-04-18 22:18:43 +08:00
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
type Expr struct {
|
|
|
|
|
|
impl llvm.Value
|
|
|
|
|
|
Type
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-26 00:31:02 +08:00
|
|
|
|
/*
|
|
|
|
|
|
// TypeOf returns the type of the expression.
|
|
|
|
|
|
func (v Expr) TypeOf() types.Type {
|
|
|
|
|
|
return v.t
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2024-04-19 00:05:57 +08:00
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
func llvmValues(vals []Expr) []llvm.Value {
|
|
|
|
|
|
ret := make([]llvm.Value, len(vals))
|
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
|
ret[i] = v.impl
|
|
|
|
|
|
}
|
|
|
|
|
|
return ret
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
2024-04-21 00:22:39 +08:00
|
|
|
|
func (p Program) Null(t Type) Expr {
|
|
|
|
|
|
return Expr{llvm.ConstNull(t.ll), t}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-20 22:05:45 +08:00
|
|
|
|
func (p Program) BoolVal(v bool) Expr {
|
|
|
|
|
|
t := p.Bool()
|
|
|
|
|
|
var bv uint64
|
|
|
|
|
|
if v {
|
|
|
|
|
|
bv = 1
|
|
|
|
|
|
}
|
|
|
|
|
|
ret := llvm.ConstInt(t.ll, bv, v)
|
|
|
|
|
|
return Expr{ret, t}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-21 15:12:57 +08:00
|
|
|
|
func (p Program) IntVal(v uint64, t Type) Expr {
|
|
|
|
|
|
ret := llvm.ConstInt(t.ll, v, false)
|
2024-04-20 22:30:38 +08:00
|
|
|
|
return Expr{ret, t}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-19 00:05:57 +08:00
|
|
|
|
func (p Program) Val(v interface{}) Expr {
|
|
|
|
|
|
switch v := v.(type) {
|
|
|
|
|
|
case int:
|
2024-04-21 15:12:57 +08:00
|
|
|
|
return p.IntVal(uint64(v), p.Int())
|
2024-04-20 22:05:45 +08:00
|
|
|
|
case bool:
|
|
|
|
|
|
return p.BoolVal(v)
|
2024-04-19 00:05:57 +08:00
|
|
|
|
case float64:
|
|
|
|
|
|
t := p.Float64()
|
|
|
|
|
|
ret := llvm.ConstFloat(t.ll, v)
|
|
|
|
|
|
return Expr{ret, t}
|
|
|
|
|
|
}
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-21 15:12:57 +08:00
|
|
|
|
func (b Builder) Const(v constant.Value, typ Type) Expr {
|
|
|
|
|
|
switch t := typ.t.(type) {
|
2024-04-20 22:05:45 +08:00
|
|
|
|
case *types.Basic:
|
2024-04-21 15:12:57 +08:00
|
|
|
|
kind := t.Kind()
|
|
|
|
|
|
switch {
|
|
|
|
|
|
case kind == types.Bool:
|
2024-04-20 22:05:45 +08:00
|
|
|
|
return b.prog.BoolVal(constant.BoolVal(v))
|
2024-04-21 15:12:57 +08:00
|
|
|
|
case kind >= types.Int && kind <= types.Uintptr:
|
|
|
|
|
|
if v, exact := constant.Uint64Val(v); exact {
|
|
|
|
|
|
return b.prog.IntVal(v, typ)
|
2024-04-20 22:30:38 +08:00
|
|
|
|
}
|
2024-04-20 22:05:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-19 00:05:57 +08:00
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
2024-04-18 22:18:43 +08:00
|
|
|
|
const (
|
|
|
|
|
|
mathOpBase = token.ADD
|
|
|
|
|
|
mathOpLast = token.REM
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
2024-04-20 22:05:45 +08:00
|
|
|
|
token.SHR - logicOpBase: llvm.AShr, // Arithmetic Shift Right
|
2024-04-18 22:18:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-20 17:31:49 +08:00
|
|
|
|
// The BinOp instruction yields the result of binary operation (x op y).
|
|
|
|
|
|
// op can be:
|
2024-04-18 22:18:43 +08:00
|
|
|
|
// 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 Expr) Expr {
|
2024-04-21 15:12:57 +08:00
|
|
|
|
if debugInstr {
|
|
|
|
|
|
log.Printf("BinOp %d, %v, %v\n", op, x.impl, y.impl)
|
|
|
|
|
|
}
|
2024-04-18 22:18:43 +08:00
|
|
|
|
switch {
|
|
|
|
|
|
case isMathOp(op): // op: + - * / %
|
|
|
|
|
|
kind := x.kind
|
|
|
|
|
|
switch kind {
|
|
|
|
|
|
case vkString, vkComplex:
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
idx := mathOpIdx(op, kind)
|
|
|
|
|
|
if llop := mathOpToLLVM[idx]; llop != 0 {
|
|
|
|
|
|
return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type}
|
|
|
|
|
|
}
|
|
|
|
|
|
case isLogicOp(op): // op: & | ^ << >> &^
|
|
|
|
|
|
if op == token.AND_NOT {
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
kind := x.kind
|
|
|
|
|
|
llop := logicOpToLLVM[op-logicOpBase]
|
|
|
|
|
|
if op == token.SHR && kind == vkUnsigned {
|
2024-04-20 22:05:45 +08:00
|
|
|
|
llop = llvm.LShr // Logical Shift Right
|
2024-04-18 22:18:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type}
|
|
|
|
|
|
case isPredOp(op): // op: == != < <= < >=
|
|
|
|
|
|
tret := b.prog.Bool()
|
|
|
|
|
|
kind := x.kind
|
|
|
|
|
|
switch kind {
|
|
|
|
|
|
case vkSigned:
|
|
|
|
|
|
pred := intPredOpToLLVM[op-predOpBase]
|
|
|
|
|
|
return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
|
|
|
|
|
|
case vkUnsigned:
|
|
|
|
|
|
pred := uintPredOpToLLVM[op-predOpBase]
|
|
|
|
|
|
return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
|
|
|
|
|
|
case vkFloat:
|
|
|
|
|
|
pred := floatPredOpToLLVM[op-predOpBase]
|
2024-04-22 15:09:08 +08:00
|
|
|
|
return Expr{llvm.CreateFCmp(b.impl, pred, x.impl, y.impl), tret}
|
2024-04-18 22:18:43 +08:00
|
|
|
|
case vkString, vkComplex, vkBool:
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-20 17:31:49 +08:00
|
|
|
|
// The UnOp instruction yields the result of (op x).
|
|
|
|
|
|
// ARROW is channel receive.
|
|
|
|
|
|
// MUL is pointer indirection (load).
|
|
|
|
|
|
// XOR is bitwise complement.
|
|
|
|
|
|
// SUB is negation.
|
|
|
|
|
|
// NOT is logical negation.
|
|
|
|
|
|
func (b Builder) UnOp(op token.Token, x Expr) Expr {
|
|
|
|
|
|
switch op {
|
|
|
|
|
|
case token.MUL:
|
|
|
|
|
|
return b.Load(x)
|
|
|
|
|
|
}
|
2024-04-21 15:12:57 +08:00
|
|
|
|
if debugInstr {
|
|
|
|
|
|
log.Printf("UnOp %v, %v\n", op, x.impl)
|
|
|
|
|
|
}
|
2024-04-20 17:31:49 +08:00
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Load returns the value at the pointer ptr.
|
|
|
|
|
|
func (b Builder) Load(ptr Expr) Expr {
|
2024-04-21 15:12:57 +08:00
|
|
|
|
if debugInstr {
|
2024-04-25 21:44:23 +08:00
|
|
|
|
log.Printf("Load %v\n", ptr.impl)
|
2024-04-21 15:12:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
telem := b.prog.Elem(ptr.Type)
|
2024-04-20 17:31:49 +08:00
|
|
|
|
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-20 22:05:45 +08:00
|
|
|
|
// Store stores val at the pointer ptr.
|
|
|
|
|
|
func (b Builder) Store(ptr, val Expr) Builder {
|
2024-04-21 15:12:57 +08:00
|
|
|
|
if debugInstr {
|
2024-04-25 21:44:23 +08:00
|
|
|
|
log.Printf("Store %v, %v\n", ptr.impl, val.impl)
|
2024-04-21 15:12:57 +08:00
|
|
|
|
}
|
2024-04-20 22:05:45 +08:00
|
|
|
|
b.impl.CreateStore(val.impl, ptr.impl)
|
|
|
|
|
|
return b
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-21 15:12:57 +08:00
|
|
|
|
// The IndexAddr instruction yields the address of the element at
|
|
|
|
|
|
// index `idx` of collection `x`. `idx` is an integer expression.
|
|
|
|
|
|
//
|
|
|
|
|
|
// The elements of maps and strings are not addressable; use Lookup (map),
|
|
|
|
|
|
// Index (string), or MapUpdate instead.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Dynamically, this instruction panics if `x` evaluates to a nil *array
|
|
|
|
|
|
// pointer.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Example printed form:
|
|
|
|
|
|
//
|
|
|
|
|
|
// t2 = &t0[t1]
|
|
|
|
|
|
func (b Builder) IndexAddr(x, idx Expr) Expr {
|
|
|
|
|
|
if debugInstr {
|
|
|
|
|
|
log.Printf("IndexAddr %v, %v\n", x.impl, idx.impl)
|
|
|
|
|
|
}
|
|
|
|
|
|
prog := b.prog
|
|
|
|
|
|
telem := prog.Index(x.Type)
|
|
|
|
|
|
pt := prog.Pointer(telem)
|
|
|
|
|
|
indices := []llvm.Value{idx.impl}
|
|
|
|
|
|
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, x.impl, indices), pt}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The Alloc instruction reserves space for a variable of the given type,
|
|
|
|
|
|
// zero-initializes it, and yields its address.
|
|
|
|
|
|
//
|
|
|
|
|
|
// If heap is false, Alloc zero-initializes the same local variable in
|
|
|
|
|
|
// the call frame and returns its address; in this case the Alloc must
|
|
|
|
|
|
// be present in Function.Locals. We call this a "local" alloc.
|
|
|
|
|
|
//
|
|
|
|
|
|
// If heap is true, Alloc allocates a new zero-initialized variable
|
|
|
|
|
|
// each time the instruction is executed. We call this a "new" alloc.
|
|
|
|
|
|
//
|
|
|
|
|
|
// When Alloc is applied to a channel, map or slice type, it returns
|
|
|
|
|
|
// the address of an uninitialized (nil) reference of that kind; store
|
|
|
|
|
|
// the result of MakeSlice, MakeMap or MakeChan in that location to
|
|
|
|
|
|
// instantiate these types.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Example printed form:
|
|
|
|
|
|
//
|
|
|
|
|
|
// t0 = local int
|
|
|
|
|
|
// t1 = new int
|
|
|
|
|
|
func (b Builder) Alloc(t Type, heap bool) (ret Expr) {
|
|
|
|
|
|
if debugInstr {
|
|
|
|
|
|
log.Printf("Alloc %v, %v\n", t.ll, heap)
|
|
|
|
|
|
}
|
|
|
|
|
|
telem := b.prog.Elem(t)
|
|
|
|
|
|
if heap {
|
|
|
|
|
|
ret.impl = llvm.CreateAlloca(b.impl, telem.ll)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
// TODO: zero-initialize
|
|
|
|
|
|
ret.Type = t
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-26 00:31:02 +08:00
|
|
|
|
// The ChangeType instruction applies to X a value-preserving type
|
|
|
|
|
|
// change to Type().
|
|
|
|
|
|
//
|
|
|
|
|
|
// Type changes are permitted:
|
|
|
|
|
|
// - between a named type and its underlying type.
|
|
|
|
|
|
// - between two named types of the same underlying type.
|
|
|
|
|
|
// - between (possibly named) pointers to identical base types.
|
|
|
|
|
|
// - from a bidirectional channel to a read- or write-channel,
|
|
|
|
|
|
// optionally adding/removing a name.
|
|
|
|
|
|
// - between a type (t) and an instance of the type (tσ), i.e.
|
|
|
|
|
|
// Type() == σ(X.Type()) (or X.Type()== σ(Type())) where
|
|
|
|
|
|
// σ is the type substitution of Parent().TypeParams by
|
|
|
|
|
|
// Parent().TypeArgs.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This operation cannot fail dynamically.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Type changes may to be to or from a type parameter (or both). All
|
|
|
|
|
|
// types in the type set of X.Type() have a value-preserving type
|
|
|
|
|
|
// change to all types in the type set of Type().
|
|
|
|
|
|
//
|
|
|
|
|
|
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
|
|
|
|
|
|
// from an explicit conversion in the source.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Example printed form:
|
|
|
|
|
|
//
|
|
|
|
|
|
// t1 = changetype *int <- IntPtr (t0)
|
|
|
|
|
|
func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
|
|
|
|
|
|
if debugInstr {
|
|
|
|
|
|
log.Printf("ChangeType %v, %v\n", t.t, x.impl)
|
|
|
|
|
|
}
|
|
|
|
|
|
typ := t.t
|
|
|
|
|
|
switch typ.(type) {
|
|
|
|
|
|
case *types.Pointer:
|
|
|
|
|
|
ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr")
|
|
|
|
|
|
ret.Type = b.prog.Type(typ)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-18 22:18:43 +08:00
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
2024-04-21 15:12:57 +08:00
|
|
|
|
// The Call instruction represents a function or method call.
|
|
|
|
|
|
//
|
|
|
|
|
|
// The Call instruction yields the function result if there is exactly
|
|
|
|
|
|
// one. Otherwise it returns a tuple, the components of which are
|
|
|
|
|
|
// accessed via Extract.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Example printed form:
|
|
|
|
|
|
//
|
|
|
|
|
|
// t2 = println(t0, t1)
|
|
|
|
|
|
// t4 = t3()
|
|
|
|
|
|
// t7 = invoke t5.Println(...t6)
|
2024-04-19 00:05:57 +08:00
|
|
|
|
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
2024-04-21 15:12:57 +08:00
|
|
|
|
if debugInstr {
|
|
|
|
|
|
var b bytes.Buffer
|
2024-04-25 21:44:23 +08:00
|
|
|
|
fmt.Fprint(&b, "Call ", fn.impl.Name())
|
2024-04-21 15:12:57 +08:00
|
|
|
|
for _, arg := range args {
|
|
|
|
|
|
fmt.Fprint(&b, ", ", arg.impl)
|
|
|
|
|
|
}
|
|
|
|
|
|
log.Println(b.String())
|
|
|
|
|
|
}
|
2024-04-19 00:05:57 +08:00
|
|
|
|
switch t := fn.t.(type) {
|
|
|
|
|
|
case *types.Signature:
|
|
|
|
|
|
ret.Type = b.prog.retType(t)
|
|
|
|
|
|
default:
|
|
|
|
|
|
panic("todo")
|
2024-04-18 15:03:10 +08:00
|
|
|
|
}
|
2024-04-19 00:05:57 +08:00
|
|
|
|
ret.impl = llvm.CreateCall(b.impl, fn.ll, fn.impl, llvmValues(args))
|
|
|
|
|
|
return
|
2024-04-18 15:03:10 +08:00
|
|
|
|
}
|
2024-04-18 22:18:43 +08:00
|
|
|
|
|
2024-04-26 00:31:02 +08:00
|
|
|
|
// A Builtin represents a specific use of a built-in function, e.g. len.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Builtins are immutable values. Builtins do not have addresses.
|
|
|
|
|
|
//
|
|
|
|
|
|
// `fn` indicates the function: one of the built-in functions from the
|
|
|
|
|
|
// Go spec (excluding "make" and "new").
|
|
|
|
|
|
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|
|
|
|
|
panic("todo")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-18 22:18:43 +08:00
|
|
|
|
// -----------------------------------------------------------------------------
|