func (f *Function) IndexAddr(instr *ssa.IndexAddr) (string, *Error) { ctx := context{f, instr} if instr == nil { return ErrorMsg("nil instr") } asm := "" xInfo := f.identifiers[instr.X.Name()] assignment := f.Ident(instr) assignment.ptr = xInfo if a, e := f.spillAllIdent(xInfo, instr); e != nil { return a, e } else { asm += a } xReg, xOffset, _ := xInfo.Addr() a1, addr := f.allocIdentReg(instr, assignment, assignment.size()) asm += a1 a, idx, err := f.LoadValueSimple(instr, instr.Index) if err != nil { return "", err } asm += a asm += MulImm32RegReg(ctx, uint32(sizeofElem(xInfo.typ)), idx, idx, true) if isSlice(xInfo.typ) { // TODO: add bounds checking optypes := GetIntegerOpDataType(false, sizePtr()) asm += MovMemReg(ctx, optypes, xInfo.name, xOffset, &xReg, addr, false) } else if isArray(xInfo.typ) { asm += Lea(ctx, xInfo.name, xOffset, &xReg, addr, false) //assignment.aliases = append(assignment.aliases, xInfo) } else if isSimd(xInfo.typ) { asm += Lea(ctx, xInfo.name, xOffset, &xReg, addr, false) //assignment.aliases = append(assignment.aliases, xInfo) } else { ice(fmt.Sprintf("indexing non-slice/array variable, type %v", xInfo.typ)) } optypes := GetIntegerOpDataType(false, idx.size()) asm += AddRegReg(ctx, optypes, idx, addr, false) a, e := f.StoreValue(instr, assignment, addr) if e != nil { return "", e } asm += a f.freeReg(idx) f.freeReg(addr) asm = fmt.Sprintf("// BEGIN ssa.IndexAddr: %v = %v\n", instr.Name(), instr) + asm asm += fmt.Sprintf("// END ssa.IndexAddr: %v = %v\n", instr.Name(), instr) return asm, nil }
func visitIndexAddr(instr *ssa.IndexAddr, infer *TypeInfer, ctx *Context) { elem, array, index := instr, instr.X, instr.Index // Array. if aType, ok := derefType(array.Type()).Underlying().(*types.Array); ok { aInst, ok := ctx.F.locals[array] if !ok { aInst, ok = ctx.F.Prog.globals[array] if !ok { infer.Logger.Fatalf("index-addr: %s: array %+v", ErrUnknownValue, array) return } } // Check status of instance. switch inst := aInst.(type) { case *Value: // Continue case *External: // External infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"index-addr: array %+v is external", aInst)) ctx.F.locals[elem] = inst case *Const: infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"index-addr: array %+v is a constant", aInst)) if inst.Const.IsNil() { ctx.F.locals[elem] = inst } return default: infer.Logger.Fatalf("index-addr: %s: array is not instance %+v", ErrUnknownValue, aInst) return } // Find the array. elems, ok := ctx.F.arrays[aInst] if !ok { elems, ok = ctx.F.Prog.arrays[aInst] if !ok { infer.Logger.Fatalf("index-addr: %s: array uninitialised %s", ErrUnknownValue, aInst) return } } infer.Logger.Print(ctx.F.Sprintf(ValSymbol+"%s = %s"+FieldSymbol+"[%s] of type %s", instr.Name(), aInst, index, aType.String())) if elems[index] != nil { infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"accessed as %s", elems[index])) } else { elems[index] = &Value{elem, ctx.F.InstanceID(), ctx.L.Index} infer.Logger.Printf(ctx.F.Sprintf(SubSymbol+"elem uninitialised, set to %s", elem.Name())) } initNestedRefVar(infer, ctx, elems[index], false) ctx.F.locals[elem] = elems[index] return } // Slices. if sType, ok := derefType(array.Type()).Underlying().(*types.Slice); ok { sInst, ok := ctx.F.locals[array] if !ok { sInst, ok = ctx.F.Prog.globals[array] if !ok { infer.Logger.Fatalf("index-addr: %s: slice %+v", ErrUnknownValue, array) return } } // Check status of instance. switch inst := sInst.(type) { case *Value: // Continue if basic, ok := sType.Elem().(*types.Basic); ok && basic.Kind() == types.Byte { ctx.F.locals[elem] = inst return } case *External: // External infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"index-addr: slice %+v is external", sInst)) ctx.F.locals[elem] = inst return case *Const: infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"index-addr: slice %+v is a constant", sInst)) if inst.Const.IsNil() { ctx.F.locals[elem] = inst } return default: infer.Logger.Fatalf("index-addr: %s: slice is not instance %+v", ErrUnknownValue, sInst) return } // Find the slice. elems, ok := ctx.F.arrays[sInst] if !ok { elems, ok = ctx.F.Prog.arrays[sInst] if !ok { infer.Logger.Fatalf("index-addr: %s: slice uninitialised %+v", ErrUnknownValue, sInst) return } } infer.Logger.Print(ctx.F.Sprintf(ValSymbol+"%s = %s"+FieldSymbol+"[%s] (slice) of type %s", instr.Name(), sInst, index, sType.String())) if elems[index] != nil { infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"accessed as %s", elems[index])) } else { elems[index] = &Value{elem, ctx.F.InstanceID(), ctx.L.Index} infer.Logger.Printf(ctx.F.Sprintf(SubSymbol+"elem uninitialised, set to %s", elem.Name())) } initNestedRefVar(infer, ctx, elems[index], false) ctx.F.locals[elem] = elems[index] return } infer.Logger.Fatalf("index-addr: %s: not array/slice %+v", ErrInvalidVarRead, array) }
func visitIndexAddr(inst *ssa.IndexAddr, fr *frame) { elem := inst array := inst.X index := inst.Index _, isArray := deref(array.Type()).Underlying().(*types.Array) _, isSlice := deref(array.Type()).Underlying().(*types.Slice) if isArray || isSlice { switch vd, kind := fr.get(array); kind { case Array: fmt.Fprintf(os.Stderr, " %s = &%s(=%s)[%d] of type %s\n", cyan(reg(elem)), array.Name(), vd.String(), index, elem.Type().String()) if fr.env.arrays[vd][index] == nil { // First use vdelem := utils.NewDef(elem) fr.env.arrays[vd][index] = vdelem fmt.Fprintf(os.Stderr, " ^ accessed for the first time: use %s as elem definition\n", elem.Name()) } else if fr.env.arrays[vd][index].Var != elem { // Previously defined fmt.Fprintf(os.Stderr, " ^ elem %s previously defined as %s\n", elem.Name(), reg(fr.env.arrays[vd][index].Var)) } // else Accessed before (and unchanged) fr.locals[elem] = fr.env.arrays[vd][index] case LocalArray: fmt.Fprintf(os.Stderr, " %s = &%s(=%s)[%d] (local) of type %s\n", cyan(reg(elem)), array.Name(), vd.String(), index, elem.Type().String()) if fr.arrays[vd][index] == nil { // First use vdElem := utils.NewDef(elem) fr.arrays[vd][index] = vdElem fmt.Fprintf(os.Stderr, " ^ accessed for the first time: use %s as elem definition\n", elem.Name()) } else if fr.arrays[vd][index].Var != elem { // Previously defined fmt.Fprintf(os.Stderr, " ^ elem %s previously defined as %s\n", elem.Name(), reg(fr.arrays[vd][index].Var)) } // else Accessed before (and unchanged) fr.locals[elem] = fr.arrays[vd][index] case Nothing, Untracked: // Nothing: Very likely external struct. // Untracked: likely branches of return values (e.g. returning nil) fmt.Fprintf(os.Stderr, " %s = &%s(=%s)[%d] (external) of type %s\n", cyan(reg(elem)), inst.X.Name(), vd.String(), index, elem.Type().String()) vd := utils.NewDef(array) // New external array fr.locals[array] = vd fr.env.arrays[vd] = make(Elems) vdElem := utils.NewDef(elem) // New external elem fr.env.arrays[vd][index] = vdElem fr.locals[elem] = vdElem fmt.Fprintf(os.Stderr, " ^ accessed for the first time: use %s as elem definition of type %s\n", elem.Name(), inst.Type().(*types.Pointer).Elem().Underlying().String()) default: panic(fmt.Sprintf("IndexAddr: Cannot access non-array %s", reg(array))) } } else { panic(fmt.Sprintf("IndexAddr: Cannot access field - %s not an array", reg(array))) } }