Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1 | //===- value.go - govalue and operations ----------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file defines the govalue type, which combines an LLVM value with its Go |
| 11 | // type, and implements various basic operations on govalues. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | package irgen |
| 16 | |
| 17 | import ( |
| 18 | "fmt" |
| 19 | "go/token" |
Andrew Wilkins | 6436a4a | 2016-03-15 05:36:43 +0000 | [diff] [blame] | 20 | |
Peter Collingbourne | 56109b7 | 2015-01-13 20:45:08 +0000 | [diff] [blame] | 21 | "llvm.org/llgo/third_party/gotools/go/exact" |
| 22 | "llvm.org/llgo/third_party/gotools/go/types" |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 23 | "llvm.org/llvm/bindings/go/llvm" |
| 24 | ) |
| 25 | |
| 26 | // govalue contains an LLVM value and a Go type, |
| 27 | // representing the result of a Go expression. |
| 28 | type govalue struct { |
| 29 | value llvm.Value |
| 30 | typ types.Type |
| 31 | } |
| 32 | |
| 33 | func (v *govalue) String() string { |
| 34 | return fmt.Sprintf("[llgo.govalue typ:%s value:%v]", v.typ, v.value) |
| 35 | } |
| 36 | |
| 37 | // Create a new dynamic value from a (LLVM Value, Type) pair. |
| 38 | func newValue(v llvm.Value, t types.Type) *govalue { |
| 39 | return &govalue{v, t} |
| 40 | } |
| 41 | |
| 42 | // TODO(axw) remove this, use .typ directly |
| 43 | func (v *govalue) Type() types.Type { |
| 44 | return v.typ |
| 45 | } |
| 46 | |
| 47 | // newValueFromConst converts a constant value to an LLVM value. |
| 48 | func (fr *frame) newValueFromConst(v exact.Value, typ types.Type) *govalue { |
| 49 | switch { |
| 50 | case v == nil: |
| 51 | llvmtyp := fr.types.ToLLVM(typ) |
| 52 | return newValue(llvm.ConstNull(llvmtyp), typ) |
| 53 | |
| 54 | case isString(typ): |
| 55 | if isUntyped(typ) { |
| 56 | typ = types.Typ[types.String] |
| 57 | } |
| 58 | llvmtyp := fr.types.ToLLVM(typ) |
| 59 | strval := exact.StringVal(v) |
| 60 | strlen := len(strval) |
| 61 | i8ptr := llvm.PointerType(llvm.Int8Type(), 0) |
| 62 | var ptr llvm.Value |
| 63 | if strlen > 0 { |
| 64 | init := llvm.ConstString(strval, false) |
| 65 | ptr = llvm.AddGlobal(fr.module.Module, init.Type(), "") |
| 66 | ptr.SetInitializer(init) |
| 67 | ptr.SetLinkage(llvm.InternalLinkage) |
| 68 | ptr = llvm.ConstBitCast(ptr, i8ptr) |
| 69 | } else { |
| 70 | ptr = llvm.ConstNull(i8ptr) |
| 71 | } |
| 72 | len_ := llvm.ConstInt(fr.types.inttype, uint64(strlen), false) |
| 73 | llvmvalue := llvm.Undef(llvmtyp) |
| 74 | llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0}) |
| 75 | llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1}) |
| 76 | return newValue(llvmvalue, typ) |
| 77 | |
| 78 | case isInteger(typ): |
| 79 | if isUntyped(typ) { |
| 80 | typ = types.Typ[types.Int] |
| 81 | } |
| 82 | llvmtyp := fr.types.ToLLVM(typ) |
| 83 | var llvmvalue llvm.Value |
| 84 | if isUnsigned(typ) { |
| 85 | v, _ := exact.Uint64Val(v) |
| 86 | llvmvalue = llvm.ConstInt(llvmtyp, v, false) |
| 87 | } else { |
| 88 | v, _ := exact.Int64Val(v) |
| 89 | llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true) |
| 90 | } |
| 91 | return newValue(llvmvalue, typ) |
| 92 | |
| 93 | case isBoolean(typ): |
| 94 | if isUntyped(typ) { |
| 95 | typ = types.Typ[types.Bool] |
| 96 | } |
| 97 | return newValue(boolLLVMValue(exact.BoolVal(v)), typ) |
| 98 | |
| 99 | case isFloat(typ): |
| 100 | if isUntyped(typ) { |
| 101 | typ = types.Typ[types.Float64] |
| 102 | } |
| 103 | llvmtyp := fr.types.ToLLVM(typ) |
| 104 | floatval, _ := exact.Float64Val(v) |
| 105 | llvmvalue := llvm.ConstFloat(llvmtyp, floatval) |
| 106 | return newValue(llvmvalue, typ) |
| 107 | |
| 108 | case typ == types.Typ[types.UnsafePointer]: |
| 109 | llvmtyp := fr.types.ToLLVM(typ) |
| 110 | v, _ := exact.Uint64Val(v) |
| 111 | llvmvalue := llvm.ConstInt(fr.types.inttype, v, false) |
| 112 | llvmvalue = llvm.ConstIntToPtr(llvmvalue, llvmtyp) |
| 113 | return newValue(llvmvalue, typ) |
| 114 | |
| 115 | case isComplex(typ): |
| 116 | if isUntyped(typ) { |
| 117 | typ = types.Typ[types.Complex128] |
| 118 | } |
| 119 | llvmtyp := fr.types.ToLLVM(typ) |
| 120 | floattyp := llvmtyp.StructElementTypes()[0] |
| 121 | llvmvalue := llvm.ConstNull(llvmtyp) |
| 122 | realv := exact.Real(v) |
| 123 | imagv := exact.Imag(v) |
| 124 | realfloatval, _ := exact.Float64Val(realv) |
| 125 | imagfloatval, _ := exact.Float64Val(imagv) |
| 126 | llvmre := llvm.ConstFloat(floattyp, realfloatval) |
| 127 | llvmim := llvm.ConstFloat(floattyp, imagfloatval) |
| 128 | llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0}) |
| 129 | llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1}) |
| 130 | return newValue(llvmvalue, typ) |
| 131 | } |
| 132 | |
| 133 | // Special case for string -> [](byte|rune) |
| 134 | if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) { |
| 135 | if v.Kind() == exact.String { |
| 136 | strval := fr.newValueFromConst(v, types.Typ[types.String]) |
| 137 | return fr.convert(strval, typ) |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v)) |
| 142 | } |
| 143 | |
| 144 | func (fr *frame) binaryOp(lhs *govalue, op token.Token, rhs *govalue) *govalue { |
| 145 | if op == token.NEQ { |
| 146 | result := fr.binaryOp(lhs, token.EQL, rhs) |
| 147 | return fr.unaryOp(result, token.NOT) |
| 148 | } |
| 149 | |
| 150 | var result llvm.Value |
| 151 | b := fr.builder |
| 152 | |
| 153 | switch typ := lhs.typ.Underlying().(type) { |
| 154 | case *types.Struct: |
| 155 | // TODO(axw) use runtime equality algorithm (will be suitably inlined). |
| 156 | // For now, we use compare all fields unconditionally and bitwise AND |
| 157 | // to avoid branching (i.e. so we don't create additional blocks). |
| 158 | value := newValue(boolLLVMValue(true), types.Typ[types.Bool]) |
| 159 | for i := 0; i < typ.NumFields(); i++ { |
| 160 | t := typ.Field(i).Type() |
| 161 | lhs := newValue(b.CreateExtractValue(lhs.value, i, ""), t) |
| 162 | rhs := newValue(b.CreateExtractValue(rhs.value, i, ""), t) |
| 163 | value = fr.binaryOp(value, token.AND, fr.binaryOp(lhs, token.EQL, rhs)) |
| 164 | } |
| 165 | return value |
| 166 | |
| 167 | case *types.Array: |
| 168 | // TODO(pcc): as above. |
| 169 | value := newValue(boolLLVMValue(true), types.Typ[types.Bool]) |
| 170 | t := typ.Elem() |
| 171 | for i := int64(0); i < typ.Len(); i++ { |
| 172 | lhs := newValue(b.CreateExtractValue(lhs.value, int(i), ""), t) |
| 173 | rhs := newValue(b.CreateExtractValue(rhs.value, int(i), ""), t) |
| 174 | value = fr.binaryOp(value, token.AND, fr.binaryOp(lhs, token.EQL, rhs)) |
| 175 | } |
| 176 | return value |
| 177 | |
| 178 | case *types.Slice: |
| 179 | // []T == nil or nil == []T |
| 180 | lhsptr := b.CreateExtractValue(lhs.value, 0, "") |
| 181 | rhsptr := b.CreateExtractValue(rhs.value, 0, "") |
| 182 | isnil := b.CreateICmp(llvm.IntEQ, lhsptr, rhsptr, "") |
| 183 | isnil = b.CreateZExt(isnil, llvm.Int8Type(), "") |
| 184 | return newValue(isnil, types.Typ[types.Bool]) |
| 185 | |
| 186 | case *types.Signature: |
| 187 | // func == nil or nil == func |
| 188 | isnil := b.CreateICmp(llvm.IntEQ, lhs.value, rhs.value, "") |
| 189 | isnil = b.CreateZExt(isnil, llvm.Int8Type(), "") |
| 190 | return newValue(isnil, types.Typ[types.Bool]) |
| 191 | |
| 192 | case *types.Interface: |
| 193 | return fr.compareInterfaces(lhs, rhs) |
| 194 | } |
| 195 | |
| 196 | // Strings. |
| 197 | if isString(lhs.typ) { |
| 198 | if isString(rhs.typ) { |
| 199 | switch op { |
| 200 | case token.ADD: |
| 201 | return fr.concatenateStrings(lhs, rhs) |
| 202 | case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ: |
| 203 | return fr.compareStrings(lhs, rhs, op) |
| 204 | default: |
| 205 | panic(fmt.Sprint("Unimplemented operator: ", op)) |
| 206 | } |
| 207 | } |
| 208 | panic("unimplemented") |
| 209 | } |
| 210 | |
| 211 | // Complex numbers. |
| 212 | if isComplex(lhs.typ) { |
| 213 | // XXX Should we represent complex numbers as vectors? |
| 214 | lhsval := lhs.value |
| 215 | rhsval := rhs.value |
| 216 | a_ := b.CreateExtractValue(lhsval, 0, "") |
| 217 | b_ := b.CreateExtractValue(lhsval, 1, "") |
| 218 | c_ := b.CreateExtractValue(rhsval, 0, "") |
| 219 | d_ := b.CreateExtractValue(rhsval, 1, "") |
| 220 | switch op { |
| 221 | case token.QUO: |
| 222 | // (a+bi)/(c+di) = (ac+bd)/(c**2+d**2) + (bc-ad)/(c**2+d**2)i |
| 223 | ac := b.CreateFMul(a_, c_, "") |
| 224 | bd := b.CreateFMul(b_, d_, "") |
| 225 | bc := b.CreateFMul(b_, c_, "") |
| 226 | ad := b.CreateFMul(a_, d_, "") |
| 227 | cpow2 := b.CreateFMul(c_, c_, "") |
| 228 | dpow2 := b.CreateFMul(d_, d_, "") |
| 229 | denom := b.CreateFAdd(cpow2, dpow2, "") |
| 230 | realnumer := b.CreateFAdd(ac, bd, "") |
| 231 | imagnumer := b.CreateFSub(bc, ad, "") |
| 232 | real_ := b.CreateFDiv(realnumer, denom, "") |
| 233 | imag_ := b.CreateFDiv(imagnumer, denom, "") |
| 234 | lhsval = b.CreateInsertValue(lhsval, real_, 0, "") |
| 235 | result = b.CreateInsertValue(lhsval, imag_, 1, "") |
| 236 | case token.MUL: |
| 237 | // (a+bi)(c+di) = (ac-bd)+(bc+ad)i |
| 238 | ac := b.CreateFMul(a_, c_, "") |
| 239 | bd := b.CreateFMul(b_, d_, "") |
| 240 | bc := b.CreateFMul(b_, c_, "") |
| 241 | ad := b.CreateFMul(a_, d_, "") |
| 242 | real_ := b.CreateFSub(ac, bd, "") |
| 243 | imag_ := b.CreateFAdd(bc, ad, "") |
| 244 | lhsval = b.CreateInsertValue(lhsval, real_, 0, "") |
| 245 | result = b.CreateInsertValue(lhsval, imag_, 1, "") |
| 246 | case token.ADD: |
| 247 | real_ := b.CreateFAdd(a_, c_, "") |
| 248 | imag_ := b.CreateFAdd(b_, d_, "") |
| 249 | lhsval = b.CreateInsertValue(lhsval, real_, 0, "") |
| 250 | result = b.CreateInsertValue(lhsval, imag_, 1, "") |
| 251 | case token.SUB: |
| 252 | real_ := b.CreateFSub(a_, c_, "") |
| 253 | imag_ := b.CreateFSub(b_, d_, "") |
| 254 | lhsval = b.CreateInsertValue(lhsval, real_, 0, "") |
| 255 | result = b.CreateInsertValue(lhsval, imag_, 1, "") |
| 256 | case token.EQL: |
| 257 | realeq := b.CreateFCmp(llvm.FloatOEQ, a_, c_, "") |
| 258 | imageq := b.CreateFCmp(llvm.FloatOEQ, b_, d_, "") |
| 259 | result = b.CreateAnd(realeq, imageq, "") |
| 260 | result = b.CreateZExt(result, llvm.Int8Type(), "") |
| 261 | return newValue(result, types.Typ[types.Bool]) |
| 262 | default: |
| 263 | panic(fmt.Errorf("unhandled operator: %v", op)) |
| 264 | } |
| 265 | return newValue(result, lhs.typ) |
| 266 | } |
| 267 | |
| 268 | // Floats and integers. |
| 269 | // TODO determine the NaN rules. |
| 270 | |
| 271 | switch op { |
| 272 | case token.MUL: |
| 273 | if isFloat(lhs.typ) { |
| 274 | result = b.CreateFMul(lhs.value, rhs.value, "") |
| 275 | } else { |
| 276 | result = b.CreateMul(lhs.value, rhs.value, "") |
| 277 | } |
| 278 | return newValue(result, lhs.typ) |
| 279 | case token.QUO: |
| 280 | switch { |
| 281 | case isFloat(lhs.typ): |
| 282 | result = b.CreateFDiv(lhs.value, rhs.value, "") |
| 283 | case !isUnsigned(lhs.typ): |
| 284 | result = b.CreateSDiv(lhs.value, rhs.value, "") |
| 285 | default: |
| 286 | result = b.CreateUDiv(lhs.value, rhs.value, "") |
| 287 | } |
| 288 | return newValue(result, lhs.typ) |
| 289 | case token.REM: |
| 290 | switch { |
| 291 | case isFloat(lhs.typ): |
| 292 | result = b.CreateFRem(lhs.value, rhs.value, "") |
| 293 | case !isUnsigned(lhs.typ): |
| 294 | result = b.CreateSRem(lhs.value, rhs.value, "") |
| 295 | default: |
| 296 | result = b.CreateURem(lhs.value, rhs.value, "") |
| 297 | } |
| 298 | return newValue(result, lhs.typ) |
| 299 | case token.ADD: |
| 300 | if isFloat(lhs.typ) { |
| 301 | result = b.CreateFAdd(lhs.value, rhs.value, "") |
| 302 | } else { |
| 303 | result = b.CreateAdd(lhs.value, rhs.value, "") |
| 304 | } |
| 305 | return newValue(result, lhs.typ) |
| 306 | case token.SUB: |
| 307 | if isFloat(lhs.typ) { |
| 308 | result = b.CreateFSub(lhs.value, rhs.value, "") |
| 309 | } else { |
| 310 | result = b.CreateSub(lhs.value, rhs.value, "") |
| 311 | } |
| 312 | return newValue(result, lhs.typ) |
| 313 | case token.SHL, token.SHR: |
| 314 | return fr.shift(lhs, rhs, op) |
| 315 | case token.EQL: |
| 316 | if isFloat(lhs.typ) { |
| 317 | result = b.CreateFCmp(llvm.FloatOEQ, lhs.value, rhs.value, "") |
| 318 | } else { |
| 319 | result = b.CreateICmp(llvm.IntEQ, lhs.value, rhs.value, "") |
| 320 | } |
| 321 | result = b.CreateZExt(result, llvm.Int8Type(), "") |
| 322 | return newValue(result, types.Typ[types.Bool]) |
| 323 | case token.LSS: |
| 324 | switch { |
| 325 | case isFloat(lhs.typ): |
| 326 | result = b.CreateFCmp(llvm.FloatOLT, lhs.value, rhs.value, "") |
| 327 | case !isUnsigned(lhs.typ): |
| 328 | result = b.CreateICmp(llvm.IntSLT, lhs.value, rhs.value, "") |
| 329 | default: |
| 330 | result = b.CreateICmp(llvm.IntULT, lhs.value, rhs.value, "") |
| 331 | } |
| 332 | result = b.CreateZExt(result, llvm.Int8Type(), "") |
| 333 | return newValue(result, types.Typ[types.Bool]) |
| 334 | case token.LEQ: |
| 335 | switch { |
| 336 | case isFloat(lhs.typ): |
| 337 | result = b.CreateFCmp(llvm.FloatOLE, lhs.value, rhs.value, "") |
| 338 | case !isUnsigned(lhs.typ): |
| 339 | result = b.CreateICmp(llvm.IntSLE, lhs.value, rhs.value, "") |
| 340 | default: |
| 341 | result = b.CreateICmp(llvm.IntULE, lhs.value, rhs.value, "") |
| 342 | } |
| 343 | result = b.CreateZExt(result, llvm.Int8Type(), "") |
| 344 | return newValue(result, types.Typ[types.Bool]) |
| 345 | case token.GTR: |
| 346 | switch { |
| 347 | case isFloat(lhs.typ): |
| 348 | result = b.CreateFCmp(llvm.FloatOGT, lhs.value, rhs.value, "") |
| 349 | case !isUnsigned(lhs.typ): |
| 350 | result = b.CreateICmp(llvm.IntSGT, lhs.value, rhs.value, "") |
| 351 | default: |
| 352 | result = b.CreateICmp(llvm.IntUGT, lhs.value, rhs.value, "") |
| 353 | } |
| 354 | result = b.CreateZExt(result, llvm.Int8Type(), "") |
| 355 | return newValue(result, types.Typ[types.Bool]) |
| 356 | case token.GEQ: |
| 357 | switch { |
| 358 | case isFloat(lhs.typ): |
| 359 | result = b.CreateFCmp(llvm.FloatOGE, lhs.value, rhs.value, "") |
| 360 | case !isUnsigned(lhs.typ): |
| 361 | result = b.CreateICmp(llvm.IntSGE, lhs.value, rhs.value, "") |
| 362 | default: |
| 363 | result = b.CreateICmp(llvm.IntUGE, lhs.value, rhs.value, "") |
| 364 | } |
| 365 | result = b.CreateZExt(result, llvm.Int8Type(), "") |
| 366 | return newValue(result, types.Typ[types.Bool]) |
| 367 | case token.AND: // a & b |
| 368 | result = b.CreateAnd(lhs.value, rhs.value, "") |
| 369 | return newValue(result, lhs.typ) |
| 370 | case token.AND_NOT: // a &^ b |
| 371 | rhsval := rhs.value |
| 372 | rhsval = b.CreateXor(rhsval, llvm.ConstAllOnes(rhsval.Type()), "") |
| 373 | result = b.CreateAnd(lhs.value, rhsval, "") |
| 374 | return newValue(result, lhs.typ) |
| 375 | case token.OR: // a | b |
| 376 | result = b.CreateOr(lhs.value, rhs.value, "") |
| 377 | return newValue(result, lhs.typ) |
| 378 | case token.XOR: // a ^ b |
| 379 | result = b.CreateXor(lhs.value, rhs.value, "") |
| 380 | return newValue(result, lhs.typ) |
| 381 | default: |
| 382 | panic(fmt.Sprint("Unimplemented operator: ", op)) |
| 383 | } |
| 384 | panic("unreachable") |
| 385 | } |
| 386 | |
| 387 | func (fr *frame) shift(lhs *govalue, rhs *govalue, op token.Token) *govalue { |
| 388 | rhs = fr.convert(rhs, lhs.Type()) |
| 389 | lhsval := lhs.value |
| 390 | bits := rhs.value |
| 391 | unsigned := isUnsigned(lhs.Type()) |
| 392 | // Shifting >= width of lhs yields undefined behaviour, so we must select. |
| 393 | max := llvm.ConstInt(bits.Type(), uint64(lhsval.Type().IntTypeWidth()-1), false) |
| 394 | var result llvm.Value |
| 395 | lessEqualWidth := fr.builder.CreateICmp(llvm.IntULE, bits, max, "") |
| 396 | if !unsigned && op == token.SHR { |
| 397 | bits := fr.builder.CreateSelect(lessEqualWidth, bits, max, "") |
| 398 | result = fr.builder.CreateAShr(lhsval, bits, "") |
| 399 | } else { |
| 400 | if op == token.SHL { |
| 401 | result = fr.builder.CreateShl(lhsval, bits, "") |
| 402 | } else { |
| 403 | result = fr.builder.CreateLShr(lhsval, bits, "") |
| 404 | } |
| 405 | zero := llvm.ConstNull(lhsval.Type()) |
| 406 | result = fr.builder.CreateSelect(lessEqualWidth, result, zero, "") |
| 407 | } |
| 408 | return newValue(result, lhs.typ) |
| 409 | } |
| 410 | |
| 411 | func (fr *frame) unaryOp(v *govalue, op token.Token) *govalue { |
| 412 | switch op { |
| 413 | case token.SUB: |
| 414 | var value llvm.Value |
| 415 | if isComplex(v.typ) { |
| 416 | realv := fr.builder.CreateExtractValue(v.value, 0, "") |
| 417 | imagv := fr.builder.CreateExtractValue(v.value, 1, "") |
| 418 | negzero := llvm.ConstFloatFromString(realv.Type(), "-0") |
| 419 | realv = fr.builder.CreateFSub(negzero, realv, "") |
| 420 | imagv = fr.builder.CreateFSub(negzero, imagv, "") |
| 421 | value = llvm.Undef(v.value.Type()) |
| 422 | value = fr.builder.CreateInsertValue(value, realv, 0, "") |
| 423 | value = fr.builder.CreateInsertValue(value, imagv, 1, "") |
| 424 | } else if isFloat(v.typ) { |
| 425 | negzero := llvm.ConstFloatFromString(fr.types.ToLLVM(v.Type()), "-0") |
| 426 | value = fr.builder.CreateFSub(negzero, v.value, "") |
| 427 | } else { |
| 428 | value = fr.builder.CreateNeg(v.value, "") |
| 429 | } |
| 430 | return newValue(value, v.typ) |
| 431 | case token.ADD: |
| 432 | return v // No-op |
| 433 | case token.NOT: |
| 434 | value := fr.builder.CreateXor(v.value, boolLLVMValue(true), "") |
| 435 | return newValue(value, v.typ) |
| 436 | case token.XOR: |
| 437 | lhs := v.value |
| 438 | rhs := llvm.ConstAllOnes(lhs.Type()) |
| 439 | value := fr.builder.CreateXor(lhs, rhs, "") |
| 440 | return newValue(value, v.typ) |
| 441 | default: |
| 442 | panic(fmt.Sprintf("Unhandled operator: %s", op)) |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | func (fr *frame) convert(v *govalue, dsttyp types.Type) *govalue { |
| 447 | b := fr.builder |
| 448 | |
| 449 | // If it's a stack allocated value, we'll want to compare the |
| 450 | // value type, not the pointer type. |
| 451 | srctyp := v.typ |
| 452 | |
| 453 | // Get the underlying type, if any. |
| 454 | origdsttyp := dsttyp |
| 455 | dsttyp = dsttyp.Underlying() |
| 456 | srctyp = srctyp.Underlying() |
| 457 | |
| 458 | // Identical (underlying) types? Just swap in the destination type. |
| 459 | if types.Identical(srctyp, dsttyp) { |
| 460 | return newValue(v.value, origdsttyp) |
| 461 | } |
| 462 | |
| 463 | // Both pointer types with identical underlying types? Same as above. |
| 464 | if srctyp, ok := srctyp.(*types.Pointer); ok { |
| 465 | if dsttyp, ok := dsttyp.(*types.Pointer); ok { |
| 466 | srctyp := srctyp.Elem().Underlying() |
| 467 | dsttyp := dsttyp.Elem().Underlying() |
| 468 | if types.Identical(srctyp, dsttyp) { |
| 469 | return newValue(v.value, origdsttyp) |
| 470 | } |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | // string -> |
| 475 | if isString(srctyp) { |
| 476 | // (untyped) string -> string |
| 477 | // XXX should untyped strings be able to escape go/types? |
| 478 | if isString(dsttyp) { |
| 479 | return newValue(v.value, origdsttyp) |
| 480 | } |
| 481 | |
| 482 | // string -> []byte |
| 483 | if isSlice(dsttyp, types.Byte) { |
Andrew Wilkins | 6436a4a | 2016-03-15 05:36:43 +0000 | [diff] [blame] | 484 | sliceValue := fr.runtime.stringToByteArray.callOnly(fr, v.value)[0] |
| 485 | return newValue(sliceValue, origdsttyp) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 486 | } |
| 487 | |
| 488 | // string -> []rune |
| 489 | if isSlice(dsttyp, types.Rune) { |
| 490 | return fr.stringToRuneSlice(v) |
| 491 | } |
| 492 | } |
| 493 | |
| 494 | // []byte -> string |
| 495 | if isSlice(srctyp, types.Byte) && isString(dsttyp) { |
Andrew Wilkins | 6436a4a | 2016-03-15 05:36:43 +0000 | [diff] [blame] | 496 | data := fr.builder.CreateExtractValue(v.value, 0, "") |
| 497 | len := fr.builder.CreateExtractValue(v.value, 1, "") |
| 498 | stringValue := fr.runtime.byteArrayToString.callOnly(fr, data, len)[0] |
| 499 | return newValue(stringValue, dsttyp) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 500 | } |
| 501 | |
| 502 | // []rune -> string |
| 503 | if isSlice(srctyp, types.Rune) && isString(dsttyp) { |
| 504 | return fr.runeSliceToString(v) |
| 505 | } |
| 506 | |
| 507 | // rune -> string |
| 508 | if isString(dsttyp) && isInteger(srctyp) { |
| 509 | return fr.runeToString(v) |
| 510 | } |
| 511 | |
| 512 | // Unsafe pointer conversions. |
| 513 | llvm_type := fr.types.ToLLVM(dsttyp) |
| 514 | if dsttyp == types.Typ[types.UnsafePointer] { // X -> unsafe.Pointer |
| 515 | if _, isptr := srctyp.(*types.Pointer); isptr { |
| 516 | return newValue(v.value, origdsttyp) |
| 517 | } else if srctyp == types.Typ[types.Uintptr] { |
| 518 | value := b.CreateIntToPtr(v.value, llvm_type, "") |
| 519 | return newValue(value, origdsttyp) |
| 520 | } |
| 521 | } else if srctyp == types.Typ[types.UnsafePointer] { // unsafe.Pointer -> X |
| 522 | if _, isptr := dsttyp.(*types.Pointer); isptr { |
| 523 | return newValue(v.value, origdsttyp) |
| 524 | } else if dsttyp == types.Typ[types.Uintptr] { |
| 525 | value := b.CreatePtrToInt(v.value, llvm_type, "") |
| 526 | return newValue(value, origdsttyp) |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | lv := v.value |
| 531 | srcType := lv.Type() |
| 532 | switch srcType.TypeKind() { |
| 533 | case llvm.IntegerTypeKind: |
| 534 | switch llvm_type.TypeKind() { |
| 535 | case llvm.IntegerTypeKind: |
| 536 | srcBits := srcType.IntTypeWidth() |
| 537 | dstBits := llvm_type.IntTypeWidth() |
| 538 | delta := srcBits - dstBits |
| 539 | switch { |
| 540 | case delta < 0: |
| 541 | if !isUnsigned(srctyp) { |
| 542 | lv = b.CreateSExt(lv, llvm_type, "") |
| 543 | } else { |
| 544 | lv = b.CreateZExt(lv, llvm_type, "") |
| 545 | } |
| 546 | case delta > 0: |
| 547 | lv = b.CreateTrunc(lv, llvm_type, "") |
| 548 | } |
| 549 | return newValue(lv, origdsttyp) |
| 550 | case llvm.FloatTypeKind, llvm.DoubleTypeKind: |
| 551 | if !isUnsigned(v.Type()) { |
| 552 | lv = b.CreateSIToFP(lv, llvm_type, "") |
| 553 | } else { |
| 554 | lv = b.CreateUIToFP(lv, llvm_type, "") |
| 555 | } |
| 556 | return newValue(lv, origdsttyp) |
| 557 | } |
| 558 | case llvm.DoubleTypeKind: |
| 559 | switch llvm_type.TypeKind() { |
| 560 | case llvm.FloatTypeKind: |
| 561 | lv = b.CreateFPTrunc(lv, llvm_type, "") |
| 562 | return newValue(lv, origdsttyp) |
| 563 | case llvm.IntegerTypeKind: |
| 564 | if !isUnsigned(dsttyp) { |
| 565 | lv = b.CreateFPToSI(lv, llvm_type, "") |
| 566 | } else { |
| 567 | lv = b.CreateFPToUI(lv, llvm_type, "") |
| 568 | } |
| 569 | return newValue(lv, origdsttyp) |
| 570 | } |
| 571 | case llvm.FloatTypeKind: |
| 572 | switch llvm_type.TypeKind() { |
| 573 | case llvm.DoubleTypeKind: |
| 574 | lv = b.CreateFPExt(lv, llvm_type, "") |
| 575 | return newValue(lv, origdsttyp) |
| 576 | case llvm.IntegerTypeKind: |
| 577 | if !isUnsigned(dsttyp) { |
| 578 | lv = b.CreateFPToSI(lv, llvm_type, "") |
| 579 | } else { |
| 580 | lv = b.CreateFPToUI(lv, llvm_type, "") |
| 581 | } |
| 582 | return newValue(lv, origdsttyp) |
| 583 | } |
| 584 | } |
| 585 | |
| 586 | // Complex -> complex. Complexes are only convertible to other |
| 587 | // complexes, contant conversions aside. So we can just check the |
| 588 | // source type here; given that the types are not identical |
| 589 | // (checked above), we can assume the destination type is the alternate |
| 590 | // complex type. |
| 591 | if isComplex(srctyp) { |
| 592 | var fpcast func(llvm.Builder, llvm.Value, llvm.Type, string) llvm.Value |
| 593 | var fptype llvm.Type |
| 594 | if srctyp == types.Typ[types.Complex64] { |
| 595 | fpcast = (llvm.Builder).CreateFPExt |
| 596 | fptype = llvm.DoubleType() |
| 597 | } else { |
| 598 | fpcast = (llvm.Builder).CreateFPTrunc |
| 599 | fptype = llvm.FloatType() |
| 600 | } |
| 601 | if fpcast != nil { |
| 602 | realv := b.CreateExtractValue(lv, 0, "") |
| 603 | imagv := b.CreateExtractValue(lv, 1, "") |
| 604 | realv = fpcast(b, realv, fptype, "") |
| 605 | imagv = fpcast(b, imagv, fptype, "") |
| 606 | lv = llvm.Undef(fr.types.ToLLVM(dsttyp)) |
| 607 | lv = b.CreateInsertValue(lv, realv, 0, "") |
| 608 | lv = b.CreateInsertValue(lv, imagv, 1, "") |
| 609 | return newValue(lv, origdsttyp) |
| 610 | } |
| 611 | } |
| 612 | panic(fmt.Sprintf("unimplemented conversion: %s (%s) -> %s", v.typ, lv.Type(), origdsttyp)) |
| 613 | } |
| 614 | |
| 615 | // extractRealValue extracts the real component of a complex number. |
| 616 | func (fr *frame) extractRealValue(v *govalue) *govalue { |
| 617 | component := fr.builder.CreateExtractValue(v.value, 0, "") |
| 618 | if component.Type().TypeKind() == llvm.FloatTypeKind { |
| 619 | return newValue(component, types.Typ[types.Float32]) |
| 620 | } |
| 621 | return newValue(component, types.Typ[types.Float64]) |
| 622 | } |
| 623 | |
| 624 | // extractRealValue extracts the imaginary component of a complex number. |
| 625 | func (fr *frame) extractImagValue(v *govalue) *govalue { |
| 626 | component := fr.builder.CreateExtractValue(v.value, 1, "") |
| 627 | if component.Type().TypeKind() == llvm.FloatTypeKind { |
| 628 | return newValue(component, types.Typ[types.Float32]) |
| 629 | } |
| 630 | return newValue(component, types.Typ[types.Float64]) |
| 631 | } |
| 632 | |
| 633 | func boolLLVMValue(v bool) (lv llvm.Value) { |
| 634 | if v { |
| 635 | return llvm.ConstInt(llvm.Int8Type(), 1, false) |
| 636 | } |
| 637 | return llvm.ConstNull(llvm.Int8Type()) |
| 638 | } |