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 }
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 }
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) }
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 } }
func (f *Function) SSE2Intrinsic(call *ssa.Call, sse2intrinsic Intrinsic) (string, *Error) { args := call.Common().Args return sse2Intrinsic(f, call, call, sse2intrinsic, args), nil }
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) }
// 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()) } } } }
func (caller *frame) call(c *ssa.Call) { caller.callCommon(c, c.Common()) }