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