Beispiel #1
0
func (f *Function) SimdIntrinsic(call *ssa.Call) (string, *Error) {
	var asm string
	var err *Error

	args := call.Common().Args
	x := f.Ident(args[0])
	y := f.Ident(args[1])
	result := f.Ident(call)
	name := call.Common().StaticCallee().Name()
	if simdinstr, ok := getSimdInstr(name); ok {
		if result.typ != x.typ {
			panic(ice(fmt.Sprintf("Simd variable type (%v) and op type (%v)  dont match", result.typ.String(), x.typ.String())))
		}
		optypes := GetOpDataType(x.typ)
		a, e := packedOp(f, call, simdinstr, optypes.xmmvariant, y, x, result)
		asm = a
		err = e
	} else {
		intrinsic, ok := intrinsics[name]
		if !ok {
			panic(ice(fmt.Sprintf("Expected simd intrinsic got (%v)", name)))
		}
		a, e := intrinsic(f, call, x, y, result)
		asm = a
		err = e
	}
	asm = fmt.Sprintf("// BEGIN SIMD Intrinsic %v\n", call) + asm +
		fmt.Sprintf("// END SIMD Intrinsic %v\n", call)
	return asm, err
}
Beispiel #2
0
// genAppend generates constraints for a call to append.
func (a *analysis) genAppend(instr *ssa.Call, cgn *cgnode) {
	// Consider z = append(x, y).   y is optional.
	// This may allocate a new [1]T array; call its object w.
	// We get the following constraints:
	// 	z = x
	// 	z = &w
	//     *z = *y

	x := instr.Call.Args[0]

	z := instr
	a.copy(a.valueNode(z), a.valueNode(x), 1) // z = x

	if len(instr.Call.Args) == 1 {
		return // no allocation for z = append(x) or _ = append(x).
	}

	// TODO(adonovan): test append([]byte, ...string) []byte.

	y := instr.Call.Args[1]
	tArray := sliceToArray(instr.Call.Args[0].Type())

	var w nodeid
	w = a.nextNode()
	a.addNodes(tArray, "append")
	a.endObject(w, cgn, instr)

	a.copyElems(cgn, tArray.Elem(), z, y)        // *z = *y
	a.addressOf(instr.Type(), a.valueNode(z), w) //  z = &w
}
Beispiel #3
0
func (f *Function) Len(call *ssa.Call) (string, *Error) {
	asm := fmt.Sprintf("// BEGIN Builtin.Len: %v\n", call)
	callcommon := call.Common()
	arg := callcommon.Args[0]
	ctx := context{f, call}
	if callcommon.IsInvoke() {
		panic(ice("len is a function, not a method"))
	}
	if len(callcommon.Args) != 1 {
		panic(ice(fmt.Sprintf("too many args (%v) for len", len(callcommon.Args))))
	}

	ident := f.Ident(call.Value())
	if reflectType(ident.typ).Name() != "int" {
		panic(ice(fmt.Sprintf("len returns int not (%v)", reflectType(ident.typ).Name())))
	}

	if isArray(arg.Type()) {

		length := reflectType(arg.Type()).Len()
		if length >= math.MaxInt32 {
			panic(ice(fmt.Sprintf("array too large (%v), maximum (%v)", length, math.MaxInt32)))
		}
		a, reg := f.allocIdentReg(call, ident, sizeof(ident.typ))
		asm += a
		asm += MovImm32Reg(ctx, int32(length), reg, false)
		a, err := f.StoreValue(call, ident, reg)
		asm += a
		if err != nil {
			return asm, err
		}

	} else if isSlice(arg.Type()) {
		a, err := f.SliceLen(call, arg, ident)
		asm += a
		if err != nil {
			return asm, err
		}

	} else {
		panic(ice(fmt.Sprintf("bad type (%v) passed to len", arg.Type())))
	}
	asm += fmt.Sprintf("// END Builtin.Len: %v\n", call)
	return asm, nil
}
Beispiel #4
0
func isSSE2Intrinsic(call *ssa.Call) (Intrinsic, bool) {
	if call.Common() == nil || call.Common().StaticCallee() == nil {
		return Intrinsic{}, false
	}
	name := call.Common().StaticCallee().Name()
	return getSSE2(name)
}
Beispiel #5
0
func isSimdIntrinsic(call *ssa.Call) bool {
	if call.Common() == nil || call.Common().StaticCallee() == nil {
		return false
	}
	name := call.Common().StaticCallee().Name()
	if _, ok := getSimdInstr(name); ok {
		return ok
	} else {
		_, ok := intrinsics[name]
		return ok
	}
}
Beispiel #6
0
func (f *Function) SSE2Intrinsic(call *ssa.Call, sse2intrinsic Intrinsic) (string, *Error) {
	args := call.Common().Args
	return sse2Intrinsic(f, call, call, sse2intrinsic, args), nil
}
Beispiel #7
0
func (f *Function) Call(call *ssa.Call) (string, *Error) {
	common := call.Common()
	funct := common.Value
	if builtin, ok := funct.(*ssa.Builtin); ok {
		return f.Builtin(call, builtin)
	}
	if isSimdIntrinsic(call) {
		return f.SimdIntrinsic(call)
	}
	if sse2instr, ok := isSSE2Intrinsic(call); ok {
		return f.SSE2Intrinsic(call, sse2instr)
	}
	name := "UNKNOWN FUNC NAME"
	if call.Common().Method != nil {
		name = call.Common().Method.Name()
	} else if call.Common().StaticCallee() != nil {
		name = call.Common().StaticCallee().Name()
	}
	msg := fmt.Sprintf("function calls are not supported, func name (%v), description (%v)",
		name, call.Common().Description())
	return ErrorMsg(msg)

}
Beispiel #8
0
func visitCall(instr *ssa.Call, infer *TypeInfer, ctx *Context) {
	infer.Logger.Printf(ctx.F.Sprintf(CallSymbol+"%s = %s", instr.Name(), instr.String()))
	ctx.F.Call(instr, infer, ctx.B, ctx.L)
}
Beispiel #9
0
// Call performs call on a given unprepared call context.
func (caller *Function) Call(call *ssa.Call, infer *TypeInfer, b *Block, l *Loop) {
	if call == nil {
		infer.Logger.Fatal("Call is nil")
		return
	}
	common := call.Common()
	switch fn := common.Value.(type) {
	case *ssa.Builtin:
		switch fn.Name() {
		case "close":
			ch, ok := caller.locals[common.Args[0]]
			if !ok {
				infer.Logger.Fatalf("call close: %s: %s", common.Args[0].Name(), ErrUnknownValue)
				return
			}
			if paramName, ok := caller.revlookup[ch.String()]; ok {
				caller.FuncDef.AddStmts(&migo.CloseStatement{Chan: paramName})
			} else {
				if _, ok := common.Args[0].(*ssa.Phi); ok {
					caller.FuncDef.AddStmts(&migo.CloseStatement{Chan: common.Args[0].Name()})
				} else {
					caller.FuncDef.AddStmts(&migo.CloseStatement{Chan: ch.(*Value).Name()})
				}
			}
			infer.Logger.Print(caller.Sprintf("close %s", common.Args[0]))
			return
		case "len":
			if l.State == Enter {
				len, err := caller.callLen(common, infer)
				if err == ErrRuntimeLen {
					l.Bound = Dynamic
					return
				}
				l.Bound, l.End = Static, len
				return
			}
			caller.locals[call] = &Value{call, caller.InstanceID(), l.Index}
			infer.Logger.Printf(caller.Sprintf("  builtin.%s", common.String()))
		default:
			infer.Logger.Printf(caller.Sprintf("  builtin.%s", common.String()))
		}
	case *ssa.MakeClosure:
		infer.Logger.Printf(caller.Sprintf(SkipSymbol+" make closure %s", fn.String()))
		caller.callClosure(common, fn, infer, b, l)
	case *ssa.Function:
		if common.StaticCallee() == nil {
			infer.Logger.Fatal("Call with nil CallCommon")
		}
		callee := caller.callFn(common, infer, b, l)
		if callee != nil {
			caller.storeRetvals(infer, call.Value(), callee)
		}
	default:
		if !common.IsInvoke() {
			infer.Logger.Print("Unknown call type", common.String(), common.Description())
			return
		}
		callee := caller.invoke(common, infer, b, l)
		if callee != nil {
			caller.storeRetvals(infer, call.Value(), callee)
		} else {
			// Mock out the return values.
			switch common.Signature().Results().Len() {
			case 0:
			case 1:
				caller.locals[call.Value()] = &External{
					parent: caller.Fn,
					typ:    call.Value().Type().Underlying(),
				}
			case 2:
				caller.locals[call.Value()] = &External{typ: call.Value().Type().Underlying()}
				caller.tuples[caller.locals[call.Value()]] = make(Tuples, common.Signature().Results().Len())
			}
		}
	}
}
Beispiel #10
0
func (caller *frame) callCommon(call *ssa.Call, common *ssa.CallCommon) {
	switch fn := common.Value.(type) {
	case *ssa.Builtin:
		caller.callBuiltin(common)

	case *ssa.MakeClosure:
		// TODO(nickng) Handle calling closure
		fmt.Fprintf(os.Stderr, "   # TODO (handle closure) %s\n", fn.String())

	case *ssa.Function:
		if common.StaticCallee() == nil {
			panic("Call with nil CallCommon!")
		}

		callee := &frame{
			fn:      common.StaticCallee(),
			locals:  make(map[ssa.Value]*utils.Definition),
			arrays:  make(map[*utils.Definition]Elems),
			structs: make(map[*utils.Definition]Fields),
			tuples:  make(map[ssa.Value]Tuples),
			phi:     make(map[ssa.Value][]ssa.Value),
			recvok:  make(map[ssa.Value]*sesstype.Chan),
			retvals: make(Tuples, common.Signature().Results().Len()),
			defers:  make([]*ssa.Defer, 0),
			caller:  caller,
			env:     caller.env,   // Use the same env as caller
			gortn:   caller.gortn, // Use the same role as caller
		}

		fmt.Fprintf(os.Stderr, "++ call %s(", orange(common.StaticCallee().String()))
		callee.translate(common)
		fmt.Fprintf(os.Stderr, ")\n")

		if callee.isRecursive() {
			fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(common.StaticCallee().String()))
			callee.printCallStack()
		} else {
			if hasCode := visitFunc(callee.fn, callee); hasCode {
				caller.handleRetvals(call.Value(), callee)
			} else {
				caller.handleExtRetvals(call.Value(), callee)
			}
			fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(common.StaticCallee().String()), len(callee.retvals))
		}

	default:
		if !common.IsInvoke() {
			fmt.Fprintf(os.Stderr, "Unknown call type %v\n", common)
			return
		}

		switch vd, kind := caller.get(common.Value); kind {
		case Struct, LocalStruct:
			fmt.Fprintf(os.Stderr, "++ invoke %s.%s, type=%s\n", reg(common.Value), common.Method.String(), vd.Var.Type().String())
			// If dealing with interfaces, check that the method is invokable
			if iface, ok := common.Value.Type().Underlying().(*types.Interface); ok {
				if meth, _ := types.MissingMethod(vd.Var.Type(), iface, true); meth != nil {
					fmt.Fprintf(os.Stderr, "     ^ interface not fully implemented\n")
				} else {
					fn := findMethod(common.Value.Parent().Prog, common.Method, vd.Var.Type())
					if fn != nil {
						fmt.Fprintf(os.Stderr, "     ^ found function %s\n", fn.String())

						callee := &frame{
							fn:      fn,
							locals:  make(map[ssa.Value]*utils.Definition),
							arrays:  make(map[*utils.Definition]Elems),
							structs: make(map[*utils.Definition]Fields),
							tuples:  make(map[ssa.Value]Tuples),
							phi:     make(map[ssa.Value][]ssa.Value),
							recvok:  make(map[ssa.Value]*sesstype.Chan),
							retvals: make(Tuples, common.Signature().Results().Len()),
							defers:  make([]*ssa.Defer, 0),
							caller:  caller,
							env:     caller.env,   // Use the same env as caller
							gortn:   caller.gortn, // Use the same role as caller
						}

						common.Args = append([]ssa.Value{common.Value}, common.Args...)
						fmt.Fprintf(os.Stderr, "++ call %s(", orange(fn.String()))
						callee.translate(common)
						fmt.Fprintf(os.Stderr, ")\n")

						if callee.isRecursive() {
							fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(fn.String()))
							callee.printCallStack()
						} else {
							if hasCode := visitFunc(callee.fn, callee); hasCode {
								caller.handleRetvals(call.Value(), callee)
							} else {
								caller.handleExtRetvals(call.Value(), callee)
							}
							fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(fn.String()), len(callee.retvals))
						}

					} else {
						panic(fmt.Sprintf("Cannot call function: %s.%s is abstract (program not well-formed)", common.Value, common.Method.String()))
					}
				}
			} else {
				fmt.Fprintf(os.Stderr, "     ^ method %s.%s does not exist\n", reg(common.Value), common.Method.String())
			}

		default:
			fmt.Fprintf(os.Stderr, "++ invoke %s.%s\n", reg(common.Value), common.Method.String())
		}
	}
}
Beispiel #11
0
func (caller *frame) call(c *ssa.Call) {
	caller.callCommon(c, c.Common())
}