2014-11-27 08:06:42 +08:00
|
|
|
//===- value.go - govalue and operations ----------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the govalue type, which combines an LLVM value with its Go
|
|
|
|
// type, and implements various basic operations on govalues.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
package irgen
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"go/token"
|
2015-01-14 04:45:08 +08:00
|
|
|
"llvm.org/llgo/third_party/gotools/go/exact"
|
|
|
|
"llvm.org/llgo/third_party/gotools/go/types"
|
2014-11-27 08:06:42 +08:00
|
|
|
"llvm.org/llvm/bindings/go/llvm"
|
|
|
|
)
|
|
|
|
|
|
|
|
// govalue contains an LLVM value and a Go type,
|
|
|
|
// representing the result of a Go expression.
|
|
|
|
type govalue struct {
|
|
|
|
value llvm.Value
|
|
|
|
typ types.Type
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *govalue) String() string {
|
|
|
|
return fmt.Sprintf("[llgo.govalue typ:%s value:%v]", v.typ, v.value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new dynamic value from a (LLVM Value, Type) pair.
|
|
|
|
func newValue(v llvm.Value, t types.Type) *govalue {
|
|
|
|
return &govalue{v, t}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(axw) remove this, use .typ directly
|
|
|
|
func (v *govalue) Type() types.Type {
|
|
|
|
return v.typ
|
|
|
|
}
|
|
|
|
|
|
|
|
// newValueFromConst converts a constant value to an LLVM value.
|
|
|
|
func (fr *frame) newValueFromConst(v exact.Value, typ types.Type) *govalue {
|
|
|
|
switch {
|
|
|
|
case v == nil:
|
|
|
|
llvmtyp := fr.types.ToLLVM(typ)
|
|
|
|
return newValue(llvm.ConstNull(llvmtyp), typ)
|
|
|
|
|
|
|
|
case isString(typ):
|
|
|
|
if isUntyped(typ) {
|
|
|
|
typ = types.Typ[types.String]
|
|
|
|
}
|
|
|
|
llvmtyp := fr.types.ToLLVM(typ)
|
|
|
|
strval := exact.StringVal(v)
|
|
|
|
strlen := len(strval)
|
|
|
|
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
|
|
|
|
var ptr llvm.Value
|
|
|
|
if strlen > 0 {
|
|
|
|
init := llvm.ConstString(strval, false)
|
|
|
|
ptr = llvm.AddGlobal(fr.module.Module, init.Type(), "")
|
|
|
|
ptr.SetInitializer(init)
|
|
|
|
ptr.SetLinkage(llvm.InternalLinkage)
|
|
|
|
ptr = llvm.ConstBitCast(ptr, i8ptr)
|
|
|
|
} else {
|
|
|
|
ptr = llvm.ConstNull(i8ptr)
|
|
|
|
}
|
|
|
|
len_ := llvm.ConstInt(fr.types.inttype, uint64(strlen), false)
|
|
|
|
llvmvalue := llvm.Undef(llvmtyp)
|
|
|
|
llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0})
|
|
|
|
llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1})
|
|
|
|
return newValue(llvmvalue, typ)
|
|
|
|
|
|
|
|
case isInteger(typ):
|
|
|
|
if isUntyped(typ) {
|
|
|
|
typ = types.Typ[types.Int]
|
|
|
|
}
|
|
|
|
llvmtyp := fr.types.ToLLVM(typ)
|
|
|
|
var llvmvalue llvm.Value
|
|
|
|
if isUnsigned(typ) {
|
|
|
|
v, _ := exact.Uint64Val(v)
|
|
|
|
llvmvalue = llvm.ConstInt(llvmtyp, v, false)
|
|
|
|
} else {
|
|
|
|
v, _ := exact.Int64Val(v)
|
|
|
|
llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true)
|
|
|
|
}
|
|
|
|
return newValue(llvmvalue, typ)
|
|
|
|
|
|
|
|
case isBoolean(typ):
|
|
|
|
if isUntyped(typ) {
|
|
|
|
typ = types.Typ[types.Bool]
|
|
|
|
}
|
|
|
|
return newValue(boolLLVMValue(exact.BoolVal(v)), typ)
|
|
|
|
|
|
|
|
case isFloat(typ):
|
|
|
|
if isUntyped(typ) {
|
|
|
|
typ = types.Typ[types.Float64]
|
|
|
|
}
|
|
|
|
llvmtyp := fr.types.ToLLVM(typ)
|
|
|
|
floatval, _ := exact.Float64Val(v)
|
|
|
|
llvmvalue := llvm.ConstFloat(llvmtyp, floatval)
|
|
|
|
return newValue(llvmvalue, typ)
|
|
|
|
|
|
|
|
case typ == types.Typ[types.UnsafePointer]:
|
|
|
|
llvmtyp := fr.types.ToLLVM(typ)
|
|
|
|
v, _ := exact.Uint64Val(v)
|
|
|
|
llvmvalue := llvm.ConstInt(fr.types.inttype, v, false)
|
|
|
|
llvmvalue = llvm.ConstIntToPtr(llvmvalue, llvmtyp)
|
|
|
|
return newValue(llvmvalue, typ)
|
|
|
|
|
|
|
|
case isComplex(typ):
|
|
|
|
if isUntyped(typ) {
|
|
|
|
typ = types.Typ[types.Complex128]
|
|
|
|
}
|
|
|
|
llvmtyp := fr.types.ToLLVM(typ)
|
|
|
|
floattyp := llvmtyp.StructElementTypes()[0]
|
|
|
|
llvmvalue := llvm.ConstNull(llvmtyp)
|
|
|
|
realv := exact.Real(v)
|
|
|
|
imagv := exact.Imag(v)
|
|
|
|
realfloatval, _ := exact.Float64Val(realv)
|
|
|
|
imagfloatval, _ := exact.Float64Val(imagv)
|
|
|
|
llvmre := llvm.ConstFloat(floattyp, realfloatval)
|
|
|
|
llvmim := llvm.ConstFloat(floattyp, imagfloatval)
|
|
|
|
llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0})
|
|
|
|
llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1})
|
|
|
|
return newValue(llvmvalue, typ)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special case for string -> [](byte|rune)
|
|
|
|
if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) {
|
|
|
|
if v.Kind() == exact.String {
|
|
|
|
strval := fr.newValueFromConst(v, types.Typ[types.String])
|
|
|
|
return fr.convert(strval, typ)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fr *frame) binaryOp(lhs *govalue, op token.Token, rhs *govalue) *govalue {
|
|
|
|
if op == token.NEQ {
|
|
|
|
result := fr.binaryOp(lhs, token.EQL, rhs)
|
|
|
|
return fr.unaryOp(result, token.NOT)
|
|
|
|
}
|
|
|
|
|
|
|
|
var result llvm.Value
|
|
|
|
b := fr.builder
|
|
|
|
|
|
|
|
switch typ := lhs.typ.Underlying().(type) {
|
|
|
|
case *types.Struct:
|
|
|
|
// TODO(axw) use runtime equality algorithm (will be suitably inlined).
|
|
|
|
// For now, we use compare all fields unconditionally and bitwise AND
|
|
|
|
// to avoid branching (i.e. so we don't create additional blocks).
|
|
|
|
value := newValue(boolLLVMValue(true), types.Typ[types.Bool])
|
|
|
|
for i := 0; i < typ.NumFields(); i++ {
|
|
|
|
t := typ.Field(i).Type()
|
|
|
|
lhs := newValue(b.CreateExtractValue(lhs.value, i, ""), t)
|
|
|
|
rhs := newValue(b.CreateExtractValue(rhs.value, i, ""), t)
|
|
|
|
value = fr.binaryOp(value, token.AND, fr.binaryOp(lhs, token.EQL, rhs))
|
|
|
|
}
|
|
|
|
return value
|
|
|
|
|
|
|
|
case *types.Array:
|
|
|
|
// TODO(pcc): as above.
|
|
|
|
value := newValue(boolLLVMValue(true), types.Typ[types.Bool])
|
|
|
|
t := typ.Elem()
|
|
|
|
for i := int64(0); i < typ.Len(); i++ {
|
|
|
|
lhs := newValue(b.CreateExtractValue(lhs.value, int(i), ""), t)
|
|
|
|
rhs := newValue(b.CreateExtractValue(rhs.value, int(i), ""), t)
|
|
|
|
value = fr.binaryOp(value, token.AND, fr.binaryOp(lhs, token.EQL, rhs))
|
|
|
|
}
|
|
|
|
return value
|
|
|
|
|
|
|
|
case *types.Slice:
|
|
|
|
// []T == nil or nil == []T
|
|
|
|
lhsptr := b.CreateExtractValue(lhs.value, 0, "")
|
|
|
|
rhsptr := b.CreateExtractValue(rhs.value, 0, "")
|
|
|
|
isnil := b.CreateICmp(llvm.IntEQ, lhsptr, rhsptr, "")
|
|
|
|
isnil = b.CreateZExt(isnil, llvm.Int8Type(), "")
|
|
|
|
return newValue(isnil, types.Typ[types.Bool])
|
|
|
|
|
|
|
|
case *types.Signature:
|
|
|
|
// func == nil or nil == func
|
|
|
|
isnil := b.CreateICmp(llvm.IntEQ, lhs.value, rhs.value, "")
|
|
|
|
isnil = b.CreateZExt(isnil, llvm.Int8Type(), "")
|
|
|
|
return newValue(isnil, types.Typ[types.Bool])
|
|
|
|
|
|
|
|
case *types.Interface:
|
|
|
|
return fr.compareInterfaces(lhs, rhs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Strings.
|
|
|
|
if isString(lhs.typ) {
|
|
|
|
if isString(rhs.typ) {
|
|
|
|
switch op {
|
|
|
|
case token.ADD:
|
|
|
|
return fr.concatenateStrings(lhs, rhs)
|
|
|
|
case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ:
|
|
|
|
return fr.compareStrings(lhs, rhs, op)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprint("Unimplemented operator: ", op))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Complex numbers.
|
|
|
|
if isComplex(lhs.typ) {
|
|
|
|
// XXX Should we represent complex numbers as vectors?
|
|
|
|
lhsval := lhs.value
|
|
|
|
rhsval := rhs.value
|
|
|
|
a_ := b.CreateExtractValue(lhsval, 0, "")
|
|
|
|
b_ := b.CreateExtractValue(lhsval, 1, "")
|
|
|
|
c_ := b.CreateExtractValue(rhsval, 0, "")
|
|
|
|
d_ := b.CreateExtractValue(rhsval, 1, "")
|
|
|
|
switch op {
|
|
|
|
case token.QUO:
|
|
|
|
// (a+bi)/(c+di) = (ac+bd)/(c**2+d**2) + (bc-ad)/(c**2+d**2)i
|
|
|
|
ac := b.CreateFMul(a_, c_, "")
|
|
|
|
bd := b.CreateFMul(b_, d_, "")
|
|
|
|
bc := b.CreateFMul(b_, c_, "")
|
|
|
|
ad := b.CreateFMul(a_, d_, "")
|
|
|
|
cpow2 := b.CreateFMul(c_, c_, "")
|
|
|
|
dpow2 := b.CreateFMul(d_, d_, "")
|
|
|
|
denom := b.CreateFAdd(cpow2, dpow2, "")
|
|
|
|
realnumer := b.CreateFAdd(ac, bd, "")
|
|
|
|
imagnumer := b.CreateFSub(bc, ad, "")
|
|
|
|
real_ := b.CreateFDiv(realnumer, denom, "")
|
|
|
|
imag_ := b.CreateFDiv(imagnumer, denom, "")
|
|
|
|
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
|
|
|
|
result = b.CreateInsertValue(lhsval, imag_, 1, "")
|
|
|
|
case token.MUL:
|
|
|
|
// (a+bi)(c+di) = (ac-bd)+(bc+ad)i
|
|
|
|
ac := b.CreateFMul(a_, c_, "")
|
|
|
|
bd := b.CreateFMul(b_, d_, "")
|
|
|
|
bc := b.CreateFMul(b_, c_, "")
|
|
|
|
ad := b.CreateFMul(a_, d_, "")
|
|
|
|
real_ := b.CreateFSub(ac, bd, "")
|
|
|
|
imag_ := b.CreateFAdd(bc, ad, "")
|
|
|
|
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
|
|
|
|
result = b.CreateInsertValue(lhsval, imag_, 1, "")
|
|
|
|
case token.ADD:
|
|
|
|
real_ := b.CreateFAdd(a_, c_, "")
|
|
|
|
imag_ := b.CreateFAdd(b_, d_, "")
|
|
|
|
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
|
|
|
|
result = b.CreateInsertValue(lhsval, imag_, 1, "")
|
|
|
|
case token.SUB:
|
|
|
|
real_ := b.CreateFSub(a_, c_, "")
|
|
|
|
imag_ := b.CreateFSub(b_, d_, "")
|
|
|
|
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
|
|
|
|
result = b.CreateInsertValue(lhsval, imag_, 1, "")
|
|
|
|
case token.EQL:
|
|
|
|
realeq := b.CreateFCmp(llvm.FloatOEQ, a_, c_, "")
|
|
|
|
imageq := b.CreateFCmp(llvm.FloatOEQ, b_, d_, "")
|
|
|
|
result = b.CreateAnd(realeq, imageq, "")
|
|
|
|
result = b.CreateZExt(result, llvm.Int8Type(), "")
|
|
|
|
return newValue(result, types.Typ[types.Bool])
|
|
|
|
default:
|
|
|
|
panic(fmt.Errorf("unhandled operator: %v", op))
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Floats and integers.
|
|
|
|
// TODO determine the NaN rules.
|
|
|
|
|
|
|
|
switch op {
|
|
|
|
case token.MUL:
|
|
|
|
if isFloat(lhs.typ) {
|
|
|
|
result = b.CreateFMul(lhs.value, rhs.value, "")
|
|
|
|
} else {
|
|
|
|
result = b.CreateMul(lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.QUO:
|
|
|
|
switch {
|
|
|
|
case isFloat(lhs.typ):
|
|
|
|
result = b.CreateFDiv(lhs.value, rhs.value, "")
|
|
|
|
case !isUnsigned(lhs.typ):
|
|
|
|
result = b.CreateSDiv(lhs.value, rhs.value, "")
|
|
|
|
default:
|
|
|
|
result = b.CreateUDiv(lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.REM:
|
|
|
|
switch {
|
|
|
|
case isFloat(lhs.typ):
|
|
|
|
result = b.CreateFRem(lhs.value, rhs.value, "")
|
|
|
|
case !isUnsigned(lhs.typ):
|
|
|
|
result = b.CreateSRem(lhs.value, rhs.value, "")
|
|
|
|
default:
|
|
|
|
result = b.CreateURem(lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.ADD:
|
|
|
|
if isFloat(lhs.typ) {
|
|
|
|
result = b.CreateFAdd(lhs.value, rhs.value, "")
|
|
|
|
} else {
|
|
|
|
result = b.CreateAdd(lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.SUB:
|
|
|
|
if isFloat(lhs.typ) {
|
|
|
|
result = b.CreateFSub(lhs.value, rhs.value, "")
|
|
|
|
} else {
|
|
|
|
result = b.CreateSub(lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.SHL, token.SHR:
|
|
|
|
return fr.shift(lhs, rhs, op)
|
|
|
|
case token.EQL:
|
|
|
|
if isFloat(lhs.typ) {
|
|
|
|
result = b.CreateFCmp(llvm.FloatOEQ, lhs.value, rhs.value, "")
|
|
|
|
} else {
|
|
|
|
result = b.CreateICmp(llvm.IntEQ, lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
result = b.CreateZExt(result, llvm.Int8Type(), "")
|
|
|
|
return newValue(result, types.Typ[types.Bool])
|
|
|
|
case token.LSS:
|
|
|
|
switch {
|
|
|
|
case isFloat(lhs.typ):
|
|
|
|
result = b.CreateFCmp(llvm.FloatOLT, lhs.value, rhs.value, "")
|
|
|
|
case !isUnsigned(lhs.typ):
|
|
|
|
result = b.CreateICmp(llvm.IntSLT, lhs.value, rhs.value, "")
|
|
|
|
default:
|
|
|
|
result = b.CreateICmp(llvm.IntULT, lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
result = b.CreateZExt(result, llvm.Int8Type(), "")
|
|
|
|
return newValue(result, types.Typ[types.Bool])
|
|
|
|
case token.LEQ:
|
|
|
|
switch {
|
|
|
|
case isFloat(lhs.typ):
|
|
|
|
result = b.CreateFCmp(llvm.FloatOLE, lhs.value, rhs.value, "")
|
|
|
|
case !isUnsigned(lhs.typ):
|
|
|
|
result = b.CreateICmp(llvm.IntSLE, lhs.value, rhs.value, "")
|
|
|
|
default:
|
|
|
|
result = b.CreateICmp(llvm.IntULE, lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
result = b.CreateZExt(result, llvm.Int8Type(), "")
|
|
|
|
return newValue(result, types.Typ[types.Bool])
|
|
|
|
case token.GTR:
|
|
|
|
switch {
|
|
|
|
case isFloat(lhs.typ):
|
|
|
|
result = b.CreateFCmp(llvm.FloatOGT, lhs.value, rhs.value, "")
|
|
|
|
case !isUnsigned(lhs.typ):
|
|
|
|
result = b.CreateICmp(llvm.IntSGT, lhs.value, rhs.value, "")
|
|
|
|
default:
|
|
|
|
result = b.CreateICmp(llvm.IntUGT, lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
result = b.CreateZExt(result, llvm.Int8Type(), "")
|
|
|
|
return newValue(result, types.Typ[types.Bool])
|
|
|
|
case token.GEQ:
|
|
|
|
switch {
|
|
|
|
case isFloat(lhs.typ):
|
|
|
|
result = b.CreateFCmp(llvm.FloatOGE, lhs.value, rhs.value, "")
|
|
|
|
case !isUnsigned(lhs.typ):
|
|
|
|
result = b.CreateICmp(llvm.IntSGE, lhs.value, rhs.value, "")
|
|
|
|
default:
|
|
|
|
result = b.CreateICmp(llvm.IntUGE, lhs.value, rhs.value, "")
|
|
|
|
}
|
|
|
|
result = b.CreateZExt(result, llvm.Int8Type(), "")
|
|
|
|
return newValue(result, types.Typ[types.Bool])
|
|
|
|
case token.AND: // a & b
|
|
|
|
result = b.CreateAnd(lhs.value, rhs.value, "")
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.AND_NOT: // a &^ b
|
|
|
|
rhsval := rhs.value
|
|
|
|
rhsval = b.CreateXor(rhsval, llvm.ConstAllOnes(rhsval.Type()), "")
|
|
|
|
result = b.CreateAnd(lhs.value, rhsval, "")
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.OR: // a | b
|
|
|
|
result = b.CreateOr(lhs.value, rhs.value, "")
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
case token.XOR: // a ^ b
|
|
|
|
result = b.CreateXor(lhs.value, rhs.value, "")
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprint("Unimplemented operator: ", op))
|
|
|
|
}
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fr *frame) shift(lhs *govalue, rhs *govalue, op token.Token) *govalue {
|
|
|
|
rhs = fr.convert(rhs, lhs.Type())
|
|
|
|
lhsval := lhs.value
|
|
|
|
bits := rhs.value
|
|
|
|
unsigned := isUnsigned(lhs.Type())
|
|
|
|
// Shifting >= width of lhs yields undefined behaviour, so we must select.
|
|
|
|
max := llvm.ConstInt(bits.Type(), uint64(lhsval.Type().IntTypeWidth()-1), false)
|
|
|
|
var result llvm.Value
|
|
|
|
lessEqualWidth := fr.builder.CreateICmp(llvm.IntULE, bits, max, "")
|
|
|
|
if !unsigned && op == token.SHR {
|
|
|
|
bits := fr.builder.CreateSelect(lessEqualWidth, bits, max, "")
|
|
|
|
result = fr.builder.CreateAShr(lhsval, bits, "")
|
|
|
|
} else {
|
|
|
|
if op == token.SHL {
|
|
|
|
result = fr.builder.CreateShl(lhsval, bits, "")
|
|
|
|
} else {
|
|
|
|
result = fr.builder.CreateLShr(lhsval, bits, "")
|
|
|
|
}
|
|
|
|
zero := llvm.ConstNull(lhsval.Type())
|
|
|
|
result = fr.builder.CreateSelect(lessEqualWidth, result, zero, "")
|
|
|
|
}
|
|
|
|
return newValue(result, lhs.typ)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fr *frame) unaryOp(v *govalue, op token.Token) *govalue {
|
|
|
|
switch op {
|
|
|
|
case token.SUB:
|
|
|
|
var value llvm.Value
|
|
|
|
if isComplex(v.typ) {
|
|
|
|
realv := fr.builder.CreateExtractValue(v.value, 0, "")
|
|
|
|
imagv := fr.builder.CreateExtractValue(v.value, 1, "")
|
|
|
|
negzero := llvm.ConstFloatFromString(realv.Type(), "-0")
|
|
|
|
realv = fr.builder.CreateFSub(negzero, realv, "")
|
|
|
|
imagv = fr.builder.CreateFSub(negzero, imagv, "")
|
|
|
|
value = llvm.Undef(v.value.Type())
|
|
|
|
value = fr.builder.CreateInsertValue(value, realv, 0, "")
|
|
|
|
value = fr.builder.CreateInsertValue(value, imagv, 1, "")
|
|
|
|
} else if isFloat(v.typ) {
|
|
|
|
negzero := llvm.ConstFloatFromString(fr.types.ToLLVM(v.Type()), "-0")
|
|
|
|
value = fr.builder.CreateFSub(negzero, v.value, "")
|
|
|
|
} else {
|
|
|
|
value = fr.builder.CreateNeg(v.value, "")
|
|
|
|
}
|
|
|
|
return newValue(value, v.typ)
|
|
|
|
case token.ADD:
|
|
|
|
return v // No-op
|
|
|
|
case token.NOT:
|
|
|
|
value := fr.builder.CreateXor(v.value, boolLLVMValue(true), "")
|
|
|
|
return newValue(value, v.typ)
|
|
|
|
case token.XOR:
|
|
|
|
lhs := v.value
|
|
|
|
rhs := llvm.ConstAllOnes(lhs.Type())
|
|
|
|
value := fr.builder.CreateXor(lhs, rhs, "")
|
|
|
|
return newValue(value, v.typ)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("Unhandled operator: %s", op))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fr *frame) convert(v *govalue, dsttyp types.Type) *govalue {
|
|
|
|
b := fr.builder
|
|
|
|
|
|
|
|
// If it's a stack allocated value, we'll want to compare the
|
|
|
|
// value type, not the pointer type.
|
|
|
|
srctyp := v.typ
|
|
|
|
|
|
|
|
// Get the underlying type, if any.
|
|
|
|
origdsttyp := dsttyp
|
|
|
|
dsttyp = dsttyp.Underlying()
|
|
|
|
srctyp = srctyp.Underlying()
|
|
|
|
|
|
|
|
// Identical (underlying) types? Just swap in the destination type.
|
|
|
|
if types.Identical(srctyp, dsttyp) {
|
|
|
|
return newValue(v.value, origdsttyp)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Both pointer types with identical underlying types? Same as above.
|
|
|
|
if srctyp, ok := srctyp.(*types.Pointer); ok {
|
|
|
|
if dsttyp, ok := dsttyp.(*types.Pointer); ok {
|
|
|
|
srctyp := srctyp.Elem().Underlying()
|
|
|
|
dsttyp := dsttyp.Elem().Underlying()
|
|
|
|
if types.Identical(srctyp, dsttyp) {
|
|
|
|
return newValue(v.value, origdsttyp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// string ->
|
|
|
|
if isString(srctyp) {
|
|
|
|
// (untyped) string -> string
|
|
|
|
// XXX should untyped strings be able to escape go/types?
|
|
|
|
if isString(dsttyp) {
|
|
|
|
return newValue(v.value, origdsttyp)
|
|
|
|
}
|
|
|
|
|
|
|
|
// string -> []byte
|
|
|
|
if isSlice(dsttyp, types.Byte) {
|
|
|
|
value := v.value
|
|
|
|
strdata := fr.builder.CreateExtractValue(value, 0, "")
|
|
|
|
strlen := fr.builder.CreateExtractValue(value, 1, "")
|
|
|
|
|
|
|
|
// Data must be copied, to prevent changes in
|
|
|
|
// the byte slice from mutating the string.
|
|
|
|
newdata := fr.createMalloc(strlen)
|
|
|
|
fr.memcpy(newdata, strdata, strlen)
|
|
|
|
|
|
|
|
struct_ := llvm.Undef(fr.types.ToLLVM(dsttyp))
|
|
|
|
struct_ = fr.builder.CreateInsertValue(struct_, newdata, 0, "")
|
|
|
|
struct_ = fr.builder.CreateInsertValue(struct_, strlen, 1, "")
|
|
|
|
struct_ = fr.builder.CreateInsertValue(struct_, strlen, 2, "")
|
|
|
|
return newValue(struct_, origdsttyp)
|
|
|
|
}
|
|
|
|
|
|
|
|
// string -> []rune
|
|
|
|
if isSlice(dsttyp, types.Rune) {
|
|
|
|
return fr.stringToRuneSlice(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// []byte -> string
|
|
|
|
if isSlice(srctyp, types.Byte) && isString(dsttyp) {
|
|
|
|
value := v.value
|
|
|
|
data := fr.builder.CreateExtractValue(value, 0, "")
|
|
|
|
len := fr.builder.CreateExtractValue(value, 1, "")
|
|
|
|
|
|
|
|
// Data must be copied, to prevent changes in
|
|
|
|
// the byte slice from mutating the string.
|
|
|
|
newdata := fr.createMalloc(len)
|
|
|
|
fr.memcpy(newdata, data, len)
|
|
|
|
|
|
|
|
struct_ := llvm.Undef(fr.types.ToLLVM(types.Typ[types.String]))
|
|
|
|
struct_ = fr.builder.CreateInsertValue(struct_, newdata, 0, "")
|
|
|
|
struct_ = fr.builder.CreateInsertValue(struct_, len, 1, "")
|
|
|
|
return newValue(struct_, types.Typ[types.String])
|
|
|
|
}
|
|
|
|
|
|
|
|
// []rune -> string
|
|
|
|
if isSlice(srctyp, types.Rune) && isString(dsttyp) {
|
|
|
|
return fr.runeSliceToString(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// rune -> string
|
|
|
|
if isString(dsttyp) && isInteger(srctyp) {
|
|
|
|
return fr.runeToString(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unsafe pointer conversions.
|
|
|
|
llvm_type := fr.types.ToLLVM(dsttyp)
|
|
|
|
if dsttyp == types.Typ[types.UnsafePointer] { // X -> unsafe.Pointer
|
|
|
|
if _, isptr := srctyp.(*types.Pointer); isptr {
|
|
|
|
return newValue(v.value, origdsttyp)
|
|
|
|
} else if srctyp == types.Typ[types.Uintptr] {
|
|
|
|
value := b.CreateIntToPtr(v.value, llvm_type, "")
|
|
|
|
return newValue(value, origdsttyp)
|
|
|
|
}
|
|
|
|
} else if srctyp == types.Typ[types.UnsafePointer] { // unsafe.Pointer -> X
|
|
|
|
if _, isptr := dsttyp.(*types.Pointer); isptr {
|
|
|
|
return newValue(v.value, origdsttyp)
|
|
|
|
} else if dsttyp == types.Typ[types.Uintptr] {
|
|
|
|
value := b.CreatePtrToInt(v.value, llvm_type, "")
|
|
|
|
return newValue(value, origdsttyp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lv := v.value
|
|
|
|
srcType := lv.Type()
|
|
|
|
switch srcType.TypeKind() {
|
|
|
|
case llvm.IntegerTypeKind:
|
|
|
|
switch llvm_type.TypeKind() {
|
|
|
|
case llvm.IntegerTypeKind:
|
|
|
|
srcBits := srcType.IntTypeWidth()
|
|
|
|
dstBits := llvm_type.IntTypeWidth()
|
|
|
|
delta := srcBits - dstBits
|
|
|
|
switch {
|
|
|
|
case delta < 0:
|
|
|
|
if !isUnsigned(srctyp) {
|
|
|
|
lv = b.CreateSExt(lv, llvm_type, "")
|
|
|
|
} else {
|
|
|
|
lv = b.CreateZExt(lv, llvm_type, "")
|
|
|
|
}
|
|
|
|
case delta > 0:
|
|
|
|
lv = b.CreateTrunc(lv, llvm_type, "")
|
|
|
|
}
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
case llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
|
|
|
if !isUnsigned(v.Type()) {
|
|
|
|
lv = b.CreateSIToFP(lv, llvm_type, "")
|
|
|
|
} else {
|
|
|
|
lv = b.CreateUIToFP(lv, llvm_type, "")
|
|
|
|
}
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
}
|
|
|
|
case llvm.DoubleTypeKind:
|
|
|
|
switch llvm_type.TypeKind() {
|
|
|
|
case llvm.FloatTypeKind:
|
|
|
|
lv = b.CreateFPTrunc(lv, llvm_type, "")
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
case llvm.IntegerTypeKind:
|
|
|
|
if !isUnsigned(dsttyp) {
|
|
|
|
lv = b.CreateFPToSI(lv, llvm_type, "")
|
|
|
|
} else {
|
|
|
|
lv = b.CreateFPToUI(lv, llvm_type, "")
|
|
|
|
}
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
}
|
|
|
|
case llvm.FloatTypeKind:
|
|
|
|
switch llvm_type.TypeKind() {
|
|
|
|
case llvm.DoubleTypeKind:
|
|
|
|
lv = b.CreateFPExt(lv, llvm_type, "")
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
case llvm.IntegerTypeKind:
|
|
|
|
if !isUnsigned(dsttyp) {
|
|
|
|
lv = b.CreateFPToSI(lv, llvm_type, "")
|
|
|
|
} else {
|
|
|
|
lv = b.CreateFPToUI(lv, llvm_type, "")
|
|
|
|
}
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Complex -> complex. Complexes are only convertible to other
|
|
|
|
// complexes, contant conversions aside. So we can just check the
|
|
|
|
// source type here; given that the types are not identical
|
|
|
|
// (checked above), we can assume the destination type is the alternate
|
|
|
|
// complex type.
|
|
|
|
if isComplex(srctyp) {
|
|
|
|
var fpcast func(llvm.Builder, llvm.Value, llvm.Type, string) llvm.Value
|
|
|
|
var fptype llvm.Type
|
|
|
|
if srctyp == types.Typ[types.Complex64] {
|
|
|
|
fpcast = (llvm.Builder).CreateFPExt
|
|
|
|
fptype = llvm.DoubleType()
|
|
|
|
} else {
|
|
|
|
fpcast = (llvm.Builder).CreateFPTrunc
|
|
|
|
fptype = llvm.FloatType()
|
|
|
|
}
|
|
|
|
if fpcast != nil {
|
|
|
|
realv := b.CreateExtractValue(lv, 0, "")
|
|
|
|
imagv := b.CreateExtractValue(lv, 1, "")
|
|
|
|
realv = fpcast(b, realv, fptype, "")
|
|
|
|
imagv = fpcast(b, imagv, fptype, "")
|
|
|
|
lv = llvm.Undef(fr.types.ToLLVM(dsttyp))
|
|
|
|
lv = b.CreateInsertValue(lv, realv, 0, "")
|
|
|
|
lv = b.CreateInsertValue(lv, imagv, 1, "")
|
|
|
|
return newValue(lv, origdsttyp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
panic(fmt.Sprintf("unimplemented conversion: %s (%s) -> %s", v.typ, lv.Type(), origdsttyp))
|
|
|
|
}
|
|
|
|
|
|
|
|
// extractRealValue extracts the real component of a complex number.
|
|
|
|
func (fr *frame) extractRealValue(v *govalue) *govalue {
|
|
|
|
component := fr.builder.CreateExtractValue(v.value, 0, "")
|
|
|
|
if component.Type().TypeKind() == llvm.FloatTypeKind {
|
|
|
|
return newValue(component, types.Typ[types.Float32])
|
|
|
|
}
|
|
|
|
return newValue(component, types.Typ[types.Float64])
|
|
|
|
}
|
|
|
|
|
|
|
|
// extractRealValue extracts the imaginary component of a complex number.
|
|
|
|
func (fr *frame) extractImagValue(v *govalue) *govalue {
|
|
|
|
component := fr.builder.CreateExtractValue(v.value, 1, "")
|
|
|
|
if component.Type().TypeKind() == llvm.FloatTypeKind {
|
|
|
|
return newValue(component, types.Typ[types.Float32])
|
|
|
|
}
|
|
|
|
return newValue(component, types.Typ[types.Float64])
|
|
|
|
}
|
|
|
|
|
|
|
|
func boolLLVMValue(v bool) (lv llvm.Value) {
|
|
|
|
if v {
|
|
|
|
return llvm.ConstInt(llvm.Int8Type(), 1, false)
|
|
|
|
}
|
|
|
|
return llvm.ConstNull(llvm.Int8Type())
|
|
|
|
}
|