func (self *linker) link(out io.Writer) []error { ptr := uint32(0) for _, c := range self.codes { c.start = ptr ptr += c.Size() } assert(ptr < segSize) for s, c := range self.codeMap { self.syms[s] = c.start } buf := new(bytes.Buffer) for _, c := range self.codes { assert(uint32(buf.Len()) == c.start) for _, i := range c.insts { if i.sym != nil { v, found := self.syms[*i.sym] assert(found) op := i.inst.Op() switch op { default: assert(uint16(i.inst) == 0) i.inst = setImm(i.inst, uint16(v)) case inst.OpLui: assert(uint16(i.inst) == 0) i.inst = setImm(i.inst, uint16(v>>16)) case inst.OpJ, inst.OpJal: // TODO: check jump range pc := uint32(buf.Len()) + 4 i.inst = inst.Jinst(op, int32(v-pc)>>2) case inst.OpRinst, inst.OpBne, inst.OpBeq: panic("bug") } } writeInst(buf, i.inst) } } // TODO: avoid a double memory copy here e := img.Write(out, codeStart, buf.Bytes()) if e != nil { return []error{e} } return nil }
func (g *Gen) lineGen(f *funcTask, index int, task *lineTask) { fn := f.build op := task.ast.Inst.Op t := task.ast.Inst.OpToken args := task.ast.Inst.Args line := task.build switch op { case "j", "jal": // j/jal <label> if len(args) != 1 { g.errorFmt(t, op, "<label>") return } lab, valid := parseSym(args[0]) if !valid { g.invalidArg(t, op, 0, "label") return } local := fn.LocateLabel(lab) if local >= 0 { delta := local - (index + 1) if !jumpInRange(delta) { g.errorf(t, "jump out of range") return } d := int32(delta) if op == "j" { line.Inst = inst.Jinst(inst.OpJ, d) } else { // "jal" line.Inst = inst.Jinst(inst.OpJal, d) } return } target := g.funcMap[lab] if target == nil { g.errorf(t, "jump target %q not found", lab) return } here := int(f.start/4) + index there := int(target.start / 4) delta := there - (here + 1) if !jumpInRange(delta) { g.errorf(t, "jump out of range") return } d := int32(delta) line.Inst = inst.Jinst(inst.OpCode(op), d) case "bne", "beq": // bne/beq $s, $t, <label> if len(args) != 3 { g.errorFmt(t, op, "$s, $t, <label>") return } rs, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rt, valid := parseReg(args[1]) if !valid { g.invalidArg(t, op, 1, "reg") return } lab, valid := parseSym(args[2]) if !valid { g.invalidArg(t, op, 2, "label") return } local := fn.LocateLabel(lab) if local < 0 { // label not found g.errorf(t, "label %q not found", lab) return } delta := local - (index + 1) if !branchInRange(delta) { g.errorf(t, "branch out of range, try use a jump") return } d := uint16(int16(delta)) line.Inst = inst.Iinst(inst.OpCode(op), rs, rt, d) case "add", "sub", "and", "or", "xor", "nor", "slt", "mul", "mulu", "div", "divu", "mod", "modu": if len(args) != 3 { g.errorFmt(t, op, "$d, $s, $t") return } rd, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rs, valid := parseReg(args[1]) if !valid { g.invalidArg(t, op, 1, "reg") return } rt, valid := parseReg(args[2]) if !valid { g.invalidArg(t, op, 2, "reg") return } line.Inst = inst.Rinst(rs, rt, rd, inst.FunctCode(op)) case "sllv", "srlv", "srav": if len(args) != 3 { g.errorFmt(t, op, "$d, $t, $s") return } rd, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rt, valid := parseReg(args[1]) if !valid { g.invalidArg(t, op, 1, "reg") return } rs, valid := parseReg(args[2]) if !valid { g.invalidArg(t, op, 2, "reg") return } line.Inst = inst.Rinst(rs, rt, rd, inst.FunctCode(op)) case "sll", "srl", "sra": if len(args) != 3 { g.errorFmt(t, op, "$d, $t, shamt") return } rd, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rt, valid := parseReg(args[1]) if !valid { g.invalidArg(t, op, 1, "reg") return } shamt, valid := parseImm(args[2]) if !valid { g.invalidArg(t, op, 2, "shamt") return } if !shamtInRange(shamt) { g.errorf(t, "shamt out of range", op) return } sh := uint8(shamt) line.Inst = inst.RinstShamt(0, rt, rd, sh, inst.FunctCode(op)) case "andi", "ori": if len(args) != 3 { g.errorFmt(t, op, "$t, $s, imm") return } rt, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rs, valid := parseReg(args[1]) if !valid { g.invalidArg(t, op, 1, "reg") return } s, im, valid := parseSymImm(args[2]) if !valid { g.invalidArg(t, op, 2, "immediate") return } imu := uint16(im) if s == "" { if !imuInRange(im) { g.errorf(t, "unsigned immediate out of range", op) return } } else { fill, found := g.findSym(s) if !found { g.errorf(t, "symbol %q not found", s) return } imu = uint16(fill) } line.Inst = inst.Iinst(inst.OpCode(op), rs, rt, imu) case "addi", "slti": if len(args) != 3 { g.errorFmt(t, op, "$t, $s, imm") return } rt, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rs, valid := parseReg(args[1]) if !valid { g.invalidArg(t, op, 1, "reg") return } s, im, valid := parseSymImm(args[2]) if !valid { g.invalidArg(t, op, 2, "immediate or symbol") return } ims := uint16(int16(im)) if s == "" { if !imsInRange(im) { g.errorf(t, "signed immediate out of range", op) return } } else { fill, found := g.findSym(s) if !found { g.errorf(t, "symbol %q not found", s) return } ims = uint16(fill) } line.Inst = inst.Iinst(inst.OpCode(op), rs, rt, ims) case "lui": if len(args) != 2 { g.errorFmt(t, op, "$t, imm") return } rt, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } s, im, valid := parseSymImm(args[1]) if !valid { g.invalidArg(t, op, 1, "immediate or symbol") return } imu := uint16(im) if s == "" { if !imuInRange(im) { g.errorf(t, "unsigned immediate out of range", op) return } } else { fill, found := g.findSym(s) if !found { g.errorf(t, "symbol %q not found", s) return } imu = uint16(fill >> 16) } line.Inst = inst.Iinst(inst.OpCode(op), 0, rt, imu) case "lw", "lu", "lhu", "lb", "lbu", "sw", "sh", "sb": if len(args) != 2 { g.errorFmt(t, op, "$t, imm($s)") return } rt, valid := parseReg(args[0]) if !valid { g.invalidArg(t, op, 0, "reg") return } rs, im, valid := parseAddr(args[1]) if !valid { g.invalidArg(t, op, 1, "address") return } if !imsInRange(im) { g.errorf(t, "signed immediate out of range", op) return } ims := uint16(int16(im)) line.Inst = inst.Iinst(inst.OpCode(op), rs, rt, ims) default: g.errorf(t, "unknown instruction op name %q", op) } }