// valString returns the string representation for the value v. // Setting floatFmt forces an integer value to be formatted in // normalized floating-point format. // TODO(gri) Move this code into package exact. func valString(v exact.Value, floatFmt bool) string { switch v.Kind() { case exact.Int: if floatFmt { return floatString(v) } case exact.Float: return floatString(v) case exact.Complex: re := exact.Real(v) im := exact.Imag(v) var s string if exact.Sign(re) != 0 { s = floatString(re) if exact.Sign(im) >= 0 { s += " + " } else { s += " - " im = exact.UnaryOp(token.SUB, im, 0) // negate im } } // im != 0, otherwise v would be exact.Int or exact.Float return s + floatString(im) + "i" } return v.String() }
func (p *exporter) value(x exact.Value) { if trace { p.tracef("value { ") defer p.tracef("} ") } switch kind := x.Kind(); kind { case exact.Bool: tag := falseTag if exact.BoolVal(x) { tag = trueTag } p.int(tag) case exact.Int: if i, ok := exact.Int64Val(x); ok { p.int(int64Tag) p.int64(i) return } p.int(floatTag) p.float(x) case exact.Float: p.int(fractionTag) p.fraction(x) case exact.Complex: p.int(complexTag) p.fraction(exact.Real(x)) p.fraction(exact.Imag(x)) case exact.String: p.int(stringTag) p.string(exact.StringVal(x)) default: panic(fmt.Sprintf("unexpected value kind %d", kind)) } }
func writeInt(w *bytes.Buffer, ev exact.Value, k types.BasicKind) { if k == types.Uintptr { u, _ := exact.Uint64Val(ev) w.WriteString("0x") w.WriteString(strconv.FormatUint(u, 16)) return } w.WriteString(ev.String()) switch k { case types.Int32: w.WriteByte('L') case types.Uint32: w.WriteString("UL") case types.Int64: w.WriteString("LL") case types.Uint64: w.WriteString("ULL") } }
func (cdd *CDD) Value(w *bytes.Buffer, ev exact.Value, t types.Type) { k := t.Underlying().(*types.Basic).Kind() // TODO: use t instead ev.Kind() in following switch switch ev.Kind() { case exact.Int: writeInt(w, ev, k) case exact.Float: writeFloat(w, ev, k) case exact.Complex: switch k { case types.Complex64: k = types.Float32 case types.Complex128: k = types.Float64 default: k = types.UntypedFloat } writeFloat(w, exact.Real(ev), k) im := exact.Imag(ev) if exact.Sign(im) != -1 { w.WriteByte('+') } writeFloat(w, im, k) w.WriteByte('i') case exact.String: w.WriteString("EGSTR(") w.WriteString(ev.String()) w.WriteByte(')') default: w.WriteString(ev.String()) } }
// representableConst reports whether x can be represented as // value of the given basic type kind and for the configuration // provided (only needed for int/uint sizes). // // If rounded != nil, *rounded is set to the rounded value of x for // representable floating-point values; it is left alone otherwise. // It is ok to provide the addressof the first argument for rounded. func representableConst(x exact.Value, conf *Config, as BasicKind, rounded *exact.Value) bool { switch x.Kind() { case exact.Unknown: return true case exact.Bool: return as == Bool || as == UntypedBool case exact.Int: if x, ok := exact.Int64Val(x); ok { switch as { case Int: var s = uint(conf.sizeof(Typ[as])) * 8 return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1 case Int8: const s = 8 return -1<<(s-1) <= x && x <= 1<<(s-1)-1 case Int16: const s = 16 return -1<<(s-1) <= x && x <= 1<<(s-1)-1 case Int32: const s = 32 return -1<<(s-1) <= x && x <= 1<<(s-1)-1 case Int64: return true case Uint, Uintptr: if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 { return 0 <= x && x <= int64(1)<<s-1 } return 0 <= x case Uint8: const s = 8 return 0 <= x && x <= 1<<s-1 case Uint16: const s = 16 return 0 <= x && x <= 1<<s-1 case Uint32: const s = 32 return 0 <= x && x <= 1<<s-1 case Uint64: return 0 <= x case Float32, Float64, Complex64, Complex128, UntypedInt, UntypedFloat, UntypedComplex: return true } } n := exact.BitLen(x) switch as { case Uint, Uintptr: var s = uint(conf.sizeof(Typ[as])) * 8 return exact.Sign(x) >= 0 && n <= int(s) case Uint64: return exact.Sign(x) >= 0 && n <= 64 case Float32, Complex64: if rounded == nil { return fitsFloat32(x) } r := roundFloat32(x) if r != nil { *rounded = r return true } case Float64, Complex128: if rounded == nil { return fitsFloat64(x) } r := roundFloat64(x) if r != nil { *rounded = r return true } case UntypedInt, UntypedFloat, UntypedComplex: return true } case exact.Float: switch as { case Float32, Complex64: if rounded == nil { return fitsFloat32(x) } r := roundFloat32(x) if r != nil { *rounded = r return true } case Float64, Complex128: if rounded == nil { return fitsFloat64(x) } r := roundFloat64(x) if r != nil { *rounded = r return true } case UntypedFloat, UntypedComplex: return true } case exact.Complex: switch as { case Complex64: if rounded == nil { return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x)) } re := roundFloat32(exact.Real(x)) im := roundFloat32(exact.Imag(x)) if re != nil && im != nil { *rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im)) return true } case Complex128: if rounded == nil { return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x)) } re := roundFloat64(exact.Real(x)) im := roundFloat64(exact.Imag(x)) if re != nil && im != nil { *rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im)) return true } case UntypedComplex: return true } case exact.String: return as == String || as == UntypedString default: unreachable() } return false }
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue { switch { case v.Kind() == exact.Unknown: // TODO nil literals should be represented more appropriately once the exact-package supports it. llvmtyp := c.types.ToLLVM(typ) return c.NewValue(llvm.ConstNull(llvmtyp), typ) case isString(typ): if isUntyped(typ) { typ = types.Typ[types.String] } llvmtyp := c.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(c.module.Module, init.Type(), "") ptr.SetInitializer(init) ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(c.types.inttype, uint64(strlen), false) llvmvalue := llvm.Undef(llvmtyp) llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1}) return c.NewValue(llvmvalue, typ) case isInteger(typ): if isUntyped(typ) { typ = types.Typ[types.Int] } llvmtyp := c.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 c.NewValue(llvmvalue, typ) case isBoolean(typ): if isUntyped(typ) { typ = types.Typ[types.Bool] } var llvmvalue llvm.Value if exact.BoolVal(v) { llvmvalue = llvm.ConstAllOnes(llvm.Int1Type()) } else { llvmvalue = llvm.ConstNull(llvm.Int1Type()) } return c.NewValue(llvmvalue, typ) case isFloat(typ): if isUntyped(typ) { typ = types.Typ[types.Float64] } llvmtyp := c.types.ToLLVM(typ) floatval, _ := exact.Float64Val(v) llvmvalue := llvm.ConstFloat(llvmtyp, floatval) return c.NewValue(llvmvalue, typ) case typ == types.Typ[types.UnsafePointer]: llvmtyp := c.types.ToLLVM(typ) v, _ := exact.Uint64Val(v) llvmvalue := llvm.ConstInt(llvmtyp, v, false) return c.NewValue(llvmvalue, typ) case isComplex(typ): if isUntyped(typ) { typ = types.Typ[types.Complex128] } llvmtyp := c.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 c.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 := c.NewConstValue(v, types.Typ[types.String]) return strval.Convert(typ).(*LLVMValue) } } panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", c.types.TypeString(typ), typ, v, v)) }