func (f *Function) AllocInstr(instr *ssa.Alloc) (string, *Error) { asm := "" if instr == nil { return ErrorMsg("AllocInstr: nil instr") } if instr.Heap { msg := "Heap allocations are unsupported (are all print and log statements removed?), ssa variable: %v, type: %v" msgstr := fmt.Sprintf(msg, instr.Name(), instr.Type()) return ErrorMsg(msgstr) } //Alloc values are always addresses, and have pointer types, so the type //of the allocated variable is actually //Type().Underlying().(*types.Pointer).Elem(). info := f.identifiers[instr.Name()] if info.local == nil { ice(fmt.Sprintf("expected %v to be a local variable", instr.Name())) } if _, ok := info.typ.(*types.Pointer); ok { } else { } f.identifiers[instr.Name()] = info return asm, nil }
func visitAlloc(instr *ssa.Alloc, infer *TypeInfer, ctx *Context) { allocType := instr.Type().(*types.Pointer).Elem() switch t := allocType.Underlying().(type) { case *types.Array: // Static size array ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} if instr.Heap { ctx.F.Prog.arrays[ctx.F.locals[instr]] = make(Elems, t.Len()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc (array@heap) of type %s (%d elems)", ctx.F.locals[instr], instr.Type(), t.Len())) } else { ctx.F.arrays[ctx.F.locals[instr]] = make(Elems, t.Len()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc (array@local) of type %s (%d elems)", ctx.F.locals[instr], instr.Type(), t.Len())) } case *types.Struct: ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} if instr.Heap { ctx.F.Prog.structs[ctx.F.locals[instr]] = make(Fields, t.NumFields()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc (struct@heap) of type %s (%d fields)", ctx.F.locals[instr], instr.Type(), t.NumFields())) } else { ctx.F.structs[ctx.F.locals[instr]] = make(Fields, t.NumFields()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc (struct@local) of type %s (%d fields)", ctx.F.locals[instr], instr.Type(), t.NumFields())) } case *types.Pointer: switch pt := t.Elem().Underlying().(type) { case *types.Array: ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} if instr.Heap { ctx.F.Prog.arrays[ctx.F.locals[instr]] = make(Elems, pt.Len()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc/indirect (array@heap) of type %s (%d elems)", ctx.F.locals[instr], instr.Type(), pt.Len())) } else { ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} ctx.F.arrays[ctx.F.locals[instr]] = make(Elems, pt.Len()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc/indirect (array@local) of type %s (%d elems)", ctx.F.locals[instr], instr.Type(), pt.Len())) } case *types.Struct: ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} if instr.Heap { ctx.F.Prog.structs[ctx.F.locals[instr]] = make(Fields, pt.NumFields()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc/indirect (struct@heap) of type %s (%d fields)", ctx.F.locals[instr], instr.Type(), pt.NumFields())) } else { ctx.F.structs[ctx.F.locals[instr]] = make(Fields, pt.NumFields()) infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc/indirect (struct@local) of type %s (%d fields)", ctx.F.locals[instr], instr.Type(), pt.NumFields())) } default: ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc/indirect of type %s", ctx.F.locals[instr], instr.Type().Underlying())) } default: ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} infer.Logger.Print(ctx.F.Sprintf(NewSymbol+"%s = alloc of type %s", ctx.F.locals[instr], instr.Type().Underlying())) } }
// Return true iff we think it might be beneficial to turn this alloc instruction // into a statically allocated global. // Precondition: we are compiling the init function. func (fr *frame) shouldStaticallyAllocate(alloc *ssa.Alloc) bool { // First, see if the allocated type is an array or struct, and if so determine // the number of elements in the type. If the type is anything else, we // statically allocate unconditionally. var numElems int64 switch ty := deref(alloc.Type()).Underlying().(type) { case *types.Array: numElems = ty.Len() case *types.Struct: numElems = int64(ty.NumFields()) default: return true } // We treat the number of referrers to the alloc instruction as a rough // proxy for the number of elements initialized. If the data structure // is densely initialized (> 1/4 elements initialized), enable the // optimization. return int64(len(*alloc.Referrers()))*4 > numElems }
// visitAlloc is for variable allocation (usually by 'new') // Everything allocated here are pointers func visitAlloc(inst *ssa.Alloc, fr *frame) { locn := loc(fr, inst.Pos()) allocType := inst.Type().(*types.Pointer).Elem() if allocType == nil { panic("Alloc: Cannot Alloc for non-pointer type") } var val ssa.Value = inst switch t := allocType.Underlying().(type) { case *types.Array: vd := utils.NewDef(val) fr.locals[val] = vd if inst.Heap { fr.env.arrays[vd] = make(Elems) fmt.Fprintf(os.Stderr, " %s = Alloc (array@heap) of type %s (%d elems) at %s\n", cyan(reg(inst)), inst.Type().String(), t.Len(), locn) } else { fr.arrays[vd] = make(Elems) fmt.Fprintf(os.Stderr, " %s = Alloc (array@local) of type %s (%d elems) at %s\n", cyan(reg(inst)), inst.Type().String(), t.Len(), locn) } case *types.Chan: // VD will be created in MakeChan so no need to allocate here. fmt.Fprintf(os.Stderr, " %s = Alloc (chan) of type %s at %s\n", cyan(reg(inst)), inst.Type().String(), locn) case *types.Struct: vd := utils.NewDef(val) fr.locals[val] = vd if inst.Heap { fr.env.structs[vd] = make(Fields, t.NumFields()) fmt.Fprintf(os.Stderr, " %s = Alloc (struct@heap) of type %s (%d fields) at %s\n", cyan(reg(inst)), inst.Type().String(), t.NumFields(), locn) } else { fr.structs[vd] = make(Fields, t.NumFields()) fmt.Fprintf(os.Stderr, " %s = Alloc (struct@local) of type %s (%d fields) at %s\n", cyan(reg(inst)), inst.Type().String(), t.NumFields(), locn) } default: fmt.Fprintf(os.Stderr, " # %s = "+red("Alloc %s")+" of type %s\n", inst.Name(), inst.String(), t.String()) } }