func (v *LLVMValue) UnaryOp(op token.Token) Value { b := v.compiler.builder switch op { case token.SUB: var value llvm.Value if isFloat(v.typ) { zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type())) value = b.CreateFSub(zero, v.LLVMValue(), "") } else { value = b.CreateNeg(v.LLVMValue(), "") } return v.compiler.NewValue(value, v.typ) case token.ADD: return v // No-op case token.NOT: value := b.CreateNot(v.LLVMValue(), "") return v.compiler.NewValue(value, v.typ) case token.XOR: lhs := v.LLVMValue() rhs := llvm.ConstAllOnes(lhs.Type()) value := b.CreateXor(lhs, rhs, "") return v.compiler.NewValue(value, v.typ) default: panic(fmt.Sprintf("Unhandled operator: %s", op)) } panic("unreachable") }
func (c *compiler) slice(x, low, high *LLVMValue) *LLVMValue { if low != nil { low = low.Convert(types.Typ[types.Int]).(*LLVMValue) } else { low = c.NewValue(llvm.ConstNull(c.types.inttype), types.Typ[types.Int]) } if high != nil { high = high.Convert(types.Typ[types.Int]).(*LLVMValue) } else { // all bits set is -1 high = c.NewValue(llvm.ConstAllOnes(c.types.inttype), types.Typ[types.Int]) } switch typ := x.Type().Underlying().(type) { case *types.Pointer: // *array sliceslice := c.runtime.sliceslice.LLVMValue() i8slice := sliceslice.Type().ElementType().ReturnType() sliceValue := llvm.Undef(i8slice) // temporary slice arraytyp := typ.Elem().Underlying().(*types.Array) arrayptr := x.LLVMValue() arrayptr = c.builder.CreateBitCast(arrayptr, i8slice.StructElementTypes()[0], "") arraylen := llvm.ConstInt(c.llvmtypes.inttype, uint64(arraytyp.Len()), false) sliceValue = c.builder.CreateInsertValue(sliceValue, arrayptr, 0, "") sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 1, "") sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 2, "") sliceTyp := types.NewSlice(arraytyp.Elem()) runtimeTyp := c.types.ToRuntime(sliceTyp) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()} result := c.builder.CreateCall(sliceslice, args, "") llvmSliceTyp := c.types.ToLLVM(sliceTyp) return c.NewValue(c.coerceSlice(result, llvmSliceTyp), sliceTyp) case *types.Slice: sliceslice := c.runtime.sliceslice.LLVMValue() i8slice := sliceslice.Type().ElementType().ReturnType() sliceValue := x.LLVMValue() sliceTyp := sliceValue.Type() sliceValue = c.coerceSlice(sliceValue, i8slice) runtimeTyp := c.types.ToRuntime(x.Type()) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()} result := c.builder.CreateCall(sliceslice, args, "") return c.NewValue(c.coerceSlice(result, sliceTyp), x.Type()) case *types.Basic: stringslice := c.runtime.stringslice.LLVMValue() llv := x.LLVMValue() args := []llvm.Value{ c.coerceString(llv, stringslice.Type().ElementType().ParamTypes()[0]), low.LLVMValue(), high.LLVMValue(), } result := c.builder.CreateCall(stringslice, args, "") return c.NewValue(c.coerceString(result, llv.Type()), x.Type()) default: panic("unimplemented") } panic("unreachable") }
func boolLLVMValue(v bool) (lv llvm.Value) { if v { lv = llvm.ConstAllOnes(llvm.Int1Type()) } else { lv = llvm.ConstNull(llvm.Int1Type()) } return lv }
func (d *SubprogramDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false), FileDescriptor(d.File).path(), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.MDString(d.DisplayName), llvm.MDString(""), // mips linkage name llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), info.MDNode(d.Type), llvm.ConstNull(llvm.Int1Type()), // not static llvm.ConstAllOnes(llvm.Int1Type()), // locally defined (not extern) llvm.ConstNull(llvm.Int32Type()), // virtuality llvm.ConstNull(llvm.Int32Type()), // index into a virtual function info.MDNode(nil), // basetype containing the vtable pointer llvm.ConstInt(llvm.Int32Type(), 0, false), // flags llvm.ConstNull(llvm.Int1Type()), // not optimised d.Function, info.MDNode(nil), // Template parameters info.MDNode(nil), // function declaration descriptor llvm.MDNode(nil), // function variables llvm.ConstInt(llvm.Int32Type(), uint64(d.ScopeLine), false), // Line number where the scope of the subprogram begins }) }
func constInt1(v bool) llvm.Value { if v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) }
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue { switch { case v == nil: 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)", typ, typ, v, v)) }
func (lhs *LLVMValue) BinaryOp(op token.Token, rhs_ Value) Value { if op == token.NEQ { result := lhs.BinaryOp(token.EQL, rhs_) return result.UnaryOp(token.NOT) } var result llvm.Value c := lhs.compiler b := lhs.compiler.builder rhs := rhs_.(*LLVMValue) 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). var value Value = c.NewValue(boolLLVMValue(true), types.Typ[types.Bool]) for i := 0; i < typ.NumFields(); i++ { t := typ.Field(i).Type() lhs := c.NewValue(b.CreateExtractValue(lhs.LLVMValue(), i, ""), t) rhs := c.NewValue(b.CreateExtractValue(rhs.LLVMValue(), i, ""), t) value = value.BinaryOp(token.AND, lhs.BinaryOp(token.EQL, rhs)) } return value case *types.Slice: // []T == nil isnil := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "") return c.NewValue(isnil, types.Typ[types.Bool]) case *types.Signature: // func == nil isnil := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "") return c.NewValue(isnil, types.Typ[types.Bool]) case *types.Interface: return c.compareInterfaces(lhs, rhs) } // Strings. if isString(lhs.typ) { if isString(rhs.typ) { switch op { case token.ADD: return c.concatenateStrings(lhs, rhs) case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ: return c.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.LLVMValue() rhsval := rhs.LLVMValue() 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, "") default: panic(fmt.Errorf("unhandled operator: %v", op)) } return lhs.compiler.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.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateMul(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, lhs.typ) case token.QUO: switch { case isFloat(lhs.typ): result = b.CreateFDiv(lhs.LLVMValue(), rhs.LLVMValue(), "") case !isUnsigned(lhs.typ): result = b.CreateSDiv(lhs.LLVMValue(), rhs.LLVMValue(), "") default: result = b.CreateUDiv(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, lhs.typ) case token.REM: switch { case isFloat(lhs.typ): result = b.CreateFRem(lhs.LLVMValue(), rhs.LLVMValue(), "") case !isUnsigned(lhs.typ): result = b.CreateSRem(lhs.LLVMValue(), rhs.LLVMValue(), "") default: result = b.CreateURem(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, lhs.typ) case token.ADD: if isFloat(lhs.typ) { result = b.CreateFAdd(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateAdd(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, lhs.typ) case token.SUB: if isFloat(lhs.typ) { result = b.CreateFSub(lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateSub(lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, lhs.typ) case token.SHL, token.SHR: return lhs.shift(rhs, op) case token.EQL: if isFloat(lhs.typ) { result = b.CreateFCmp(llvm.FloatOEQ, lhs.LLVMValue(), rhs.LLVMValue(), "") } else { result = b.CreateICmp(llvm.IntEQ, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, types.Typ[types.Bool]) case token.LSS: switch { case isFloat(lhs.typ): result = b.CreateFCmp(llvm.FloatOLT, lhs.LLVMValue(), rhs.LLVMValue(), "") case !isUnsigned(lhs.typ): result = b.CreateICmp(llvm.IntSLT, lhs.LLVMValue(), rhs.LLVMValue(), "") default: result = b.CreateICmp(llvm.IntULT, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, types.Typ[types.Bool]) case token.LEQ: switch { case isFloat(lhs.typ): result = b.CreateFCmp(llvm.FloatOLE, lhs.LLVMValue(), rhs.LLVMValue(), "") case !isUnsigned(lhs.typ): result = b.CreateICmp(llvm.IntSLE, lhs.LLVMValue(), rhs.LLVMValue(), "") default: result = b.CreateICmp(llvm.IntULE, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, types.Typ[types.Bool]) case token.GTR: switch { case isFloat(lhs.typ): result = b.CreateFCmp(llvm.FloatOGT, lhs.LLVMValue(), rhs.LLVMValue(), "") case !isUnsigned(lhs.typ): result = b.CreateICmp(llvm.IntSGT, lhs.LLVMValue(), rhs.LLVMValue(), "") default: result = b.CreateICmp(llvm.IntUGT, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, types.Typ[types.Bool]) case token.GEQ: switch { case isFloat(lhs.typ): result = b.CreateFCmp(llvm.FloatOGE, lhs.LLVMValue(), rhs.LLVMValue(), "") case !isUnsigned(lhs.typ): result = b.CreateICmp(llvm.IntSGE, lhs.LLVMValue(), rhs.LLVMValue(), "") default: result = b.CreateICmp(llvm.IntUGE, lhs.LLVMValue(), rhs.LLVMValue(), "") } return lhs.compiler.NewValue(result, types.Typ[types.Bool]) case token.AND: // a & b result = b.CreateAnd(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewValue(result, lhs.typ) case token.AND_NOT: // a &^ b rhsval := rhs.LLVMValue() rhsval = b.CreateXor(rhsval, llvm.ConstAllOnes(rhsval.Type()), "") result = b.CreateAnd(lhs.LLVMValue(), rhsval, "") return lhs.compiler.NewValue(result, lhs.typ) case token.OR: // a | b result = b.CreateOr(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewValue(result, lhs.typ) case token.XOR: // a ^ b result = b.CreateXor(lhs.LLVMValue(), rhs.LLVMValue(), "") return lhs.compiler.NewValue(result, lhs.typ) default: panic(fmt.Sprint("Unimplemented operator: ", op)) } panic("unreachable") }
// phiValue returns a new value with the same value and type as the given Phi. // This is used for go.tools/ssa instructions that introduce new ssa.Values, // but would otherwise not generate a new LLVM value. func phiValue(c *compiler, v *LLVMValue) *LLVMValue { llv := v.LLVMValue() llv = c.builder.CreateSelect(llvm.ConstAllOnes(llvm.Int1Type()), llv, llv, "") return c.NewValue(llv, v.Type()) }