Example #1
0
File: linker.go Project: 8l/leaf
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
}
Example #2
0
File: line.go Project: 8l/leaf
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)
	}
}