Example #1
0
File: asm.go Project: ckeyer/gosrc
// asmInstruction assembles an instruction.
// MOVW R9, (R10)
func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
	// fmt.Printf("%s %+v\n", obj.Aconv(op), a)
	prog := &obj.Prog{
		Ctxt:   p.ctxt,
		Lineno: p.histLineNum,
		As:     int16(op),
	}
	switch len(a) {
	case 0:
		// Nothing to do.
	case 1:
		if p.arch.UnaryDst[op] {
			// prog.From is no address.
			prog.To = a[0]
		} else {
			prog.From = a[0]
			// prog.To is no address.
		}
		if p.arch.Thechar == '9' && arch.IsPPC64NEG(op) {
			// NEG: From and To are both a[0].
			prog.To = a[0]
			prog.From = a[0]
			break
		}
	case 2:
		if p.arch.Thechar == '5' {
			if arch.IsARMCMP(op) {
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				break
			}
			// Strange special cases.
			if arch.IsARMSTREX(op) {
				/*
					STREX x, (y)
						from=(y) reg=x to=x
					STREX (x), y
						from=(x) reg=y to=y
				*/
				if a[0].Type == obj.TYPE_REG && a[1].Type != obj.TYPE_REG {
					prog.From = a[1]
					prog.Reg = a[0].Reg
					prog.To = a[0]
					break
				} else if a[0].Type != obj.TYPE_REG && a[1].Type == obj.TYPE_REG {
					prog.From = a[0]
					prog.Reg = a[1].Reg
					prog.To = a[1]
					break
				}
				p.errorf("unrecognized addressing for %s", obj.Aconv(op))
				return
			}
			if arch.IsARMFloatCmp(op) {
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				break
			}
		} else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) {
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			break
		} else if p.arch.Thechar == '0' {
			if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				break
			}
		}
		prog.From = a[0]
		prog.To = a[1]
	case 3:
		switch p.arch.Thechar {
		case '0':
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.To = a[2]
		case '5':
			// Special cases.
			if arch.IsARMSTREX(op) {
				/*
					STREX x, (y), z
						from=(y) reg=x to=z
				*/
				prog.From = a[1]
				prog.Reg = p.getRegister(prog, op, &a[0])
				prog.To = a[2]
				break
			}
			// Otherwise the 2nd operand (a[1]) must be a register.
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.To = a[2]
		case '7':
			// ARM64 instructions with one input and two outputs.
			if arch.IsARM64STLXR(op) {
				prog.From = a[0]
				prog.To = a[1]
				if a[2].Type != obj.TYPE_REG {
					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op))
					return
				}
				prog.RegTo2 = a[2].Reg
				break
			}
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.To = a[2]
		case '6', '8':
			prog.From = a[0]
			prog.From3 = newAddr(a[1])
			prog.To = a[2]
		case '9':
			if arch.IsPPC64CMP(op) {
				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[2])
				prog.To = a[1]
				break
			}
			// Arithmetic. Choices are:
			// reg reg reg
			// imm reg reg
			// reg imm reg
			// If the immediate is the middle argument, use From3.
			switch a[1].Type {
			case obj.TYPE_REG:
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				prog.To = a[2]
			case obj.TYPE_CONST:
				prog.From = a[0]
				prog.From3 = newAddr(a[1])
				prog.To = a[2]
			default:
				p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
				return
			}
		default:
			p.errorf("TODO: implement three-operand instructions for this architecture")
			return
		}
	case 4:
		if p.arch.Thechar == '5' && arch.IsARMMULA(op) {
			// All must be registers.
			p.getRegister(prog, op, &a[0])
			r1 := p.getRegister(prog, op, &a[1])
			p.getRegister(prog, op, &a[2])
			r3 := p.getRegister(prog, op, &a[3])
			prog.From = a[0]
			prog.To = a[2]
			prog.To.Type = obj.TYPE_REGREG2
			prog.To.Offset = int64(r3)
			prog.Reg = r1
			break
		}
		if p.arch.Thechar == '7' {
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.From3 = newAddr(a[2])
			prog.To = a[3]
			break
		}
		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
			// 2nd operand must always be a register.
			// TODO: Do we need to guard this with the instruction type?
			// That is, are there 4-operand instructions without this property?
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.From3 = newAddr(a[2])
			prog.To = a[3]
			break
		}
		p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
		return
	case 5:
		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
			// Always reg, reg, con, con, reg.  (con, con is a 'mask').
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			mask1 := p.getConstant(prog, op, &a[2])
			mask2 := p.getConstant(prog, op, &a[3])
			var mask uint32
			if mask1 < mask2 {
				mask = (^uint32(0) >> uint(mask1)) & (^uint32(0) << uint(31-mask2))
			} else {
				mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1)))
			}
			prog.From3 = &obj.Addr{
				Type:   obj.TYPE_CONST,
				Offset: int64(mask),
			}
			prog.To = a[4]
			break
		}
		p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
		return
	case 6:
		if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
			// Strange special case: MCR, MRC.
			prog.To.Type = obj.TYPE_CONST
			x0 := p.getConstant(prog, op, &a[0])
			x1 := p.getConstant(prog, op, &a[1])
			x2 := int64(p.getRegister(prog, op, &a[2]))
			x3 := int64(p.getRegister(prog, op, &a[3]))
			x4 := int64(p.getRegister(prog, op, &a[4]))
			x5 := p.getConstant(prog, op, &a[5])
			// Cond is handled specially for this instruction.
			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
			if !ok {
				p.errorf("unrecognized condition code .%q", cond)
			}
			prog.To.Offset = offset
			cond = ""
			prog.As = MRC // Both instructions are coded as MRC.
			break
		}
		fallthrough
	default:
		p.errorf("can't handle %s instruction with %d operands", obj.Aconv(op), len(a))
		return
	}

	p.append(prog, cond, true)
}
Example #2
0
File: asm.go Project: hurkgu/go
// asmInstruction assembles an instruction.
// MOVW R9, (R10)
func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
	// fmt.Printf("%s %+v\n", op, a)
	prog := &obj.Prog{
		Ctxt:   p.ctxt,
		Lineno: p.histLineNum,
		As:     op,
	}
	switch len(a) {
	case 0:
		// Nothing to do.
	case 1:
		if p.arch.UnaryDst[op] {
			// prog.From is no address.
			prog.To = a[0]
		} else {
			prog.From = a[0]
			// prog.To is no address.
		}
		if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
			// NEG: From and To are both a[0].
			prog.To = a[0]
			prog.From = a[0]
			break
		}
	case 2:
		if p.arch.Family == sys.ARM {
			if arch.IsARMCMP(op) {
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				break
			}
			// Strange special cases.
			if arch.IsARMSTREX(op) {
				/*
					STREX x, (y)
						from=(y) reg=x to=x
					STREX (x), y
						from=(x) reg=y to=y
				*/
				if a[0].Type == obj.TYPE_REG && a[1].Type != obj.TYPE_REG {
					prog.From = a[1]
					prog.Reg = a[0].Reg
					prog.To = a[0]
					break
				} else if a[0].Type != obj.TYPE_REG && a[1].Type == obj.TYPE_REG {
					prog.From = a[0]
					prog.Reg = a[1].Reg
					prog.To = a[1]
					break
				}
				p.errorf("unrecognized addressing for %s", op)
				return
			}
			if arch.IsARMFloatCmp(op) {
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				break
			}
		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			break
		} else if p.arch.Family == sys.MIPS64 {
			if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				break
			}
		}
		prog.From = a[0]
		prog.To = a[1]
	case 3:
		switch p.arch.Family {
		case sys.MIPS64:
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.To = a[2]
		case sys.ARM:
			// Special cases.
			if arch.IsARMSTREX(op) {
				/*
					STREX x, (y), z
						from=(y) reg=x to=z
				*/
				prog.From = a[1]
				prog.Reg = p.getRegister(prog, op, &a[0])
				prog.To = a[2]
				break
			}
			// Otherwise the 2nd operand (a[1]) must be a register.
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.To = a[2]
		case sys.AMD64:
			// Catch missing operand here, because we store immediate as part of From3, and can't distinguish
			// missing operand from legal value 0 in obj/x86/asm6.
			if arch.IsAMD4OP(op) {
				p.errorf("4 operands required, but only 3 are provided for %s instruction", op)
			}
			prog.From = a[0]
			prog.From3 = newAddr(a[1])
			prog.To = a[2]
		case sys.ARM64:
			// ARM64 instructions with one input and two outputs.
			if arch.IsARM64STLXR(op) {
				prog.From = a[0]
				prog.To = a[1]
				if a[2].Type != obj.TYPE_REG {
					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
					return
				}
				prog.RegTo2 = a[2].Reg
				break
			}
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.To = a[2]
		case sys.I386:
			prog.From = a[0]
			prog.From3 = newAddr(a[1])
			prog.To = a[2]
		case sys.PPC64:
			if arch.IsPPC64CMP(op) {
				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[2])
				prog.To = a[1]
				break
			}
			// Arithmetic. Choices are:
			// reg reg reg
			// imm reg reg
			// reg imm reg
			// If the immediate is the middle argument, use From3.
			switch a[1].Type {
			case obj.TYPE_REG:
				prog.From = a[0]
				prog.Reg = p.getRegister(prog, op, &a[1])
				prog.To = a[2]
			case obj.TYPE_CONST:
				prog.From = a[0]
				prog.From3 = newAddr(a[1])
				prog.To = a[2]
			default:
				p.errorf("invalid addressing modes for %s instruction", op)
				return
			}
		case sys.S390X:
			if arch.IsS390xWithLength(op) || arch.IsS390xWithIndex(op) {
				prog.From = a[1]
				prog.From3 = newAddr(a[0])
			} else {
				prog.Reg = p.getRegister(prog, op, &a[1])
				prog.From = a[0]
			}
			prog.To = a[2]
		default:
			p.errorf("TODO: implement three-operand instructions for this architecture")
			return
		}
	case 4:
		if p.arch.Family == sys.ARM && arch.IsARMMULA(op) {
			// All must be registers.
			p.getRegister(prog, op, &a[0])
			r1 := p.getRegister(prog, op, &a[1])
			p.getRegister(prog, op, &a[2])
			r3 := p.getRegister(prog, op, &a[3])
			prog.From = a[0]
			prog.To = a[2]
			prog.To.Type = obj.TYPE_REGREG2
			prog.To.Offset = int64(r3)
			prog.Reg = r1
			break
		}
		if p.arch.Family == sys.AMD64 {
			// 4 operand instruction have form  ymm1, ymm2, ymm3/m256, imm8
			// So From3 is always just a register, so we store imm8 in Offset field,
			// to avoid increasing size of Prog.
			prog.From = a[1]
			prog.From3 = newAddr(a[2])
			if a[0].Type != obj.TYPE_CONST {
				p.errorf("first operand must be an immediate in %s instruction", op)
			}
			if prog.From3.Type != obj.TYPE_REG {
				p.errorf("third operand must be a register in %s instruction", op)
			}
			prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0]))
			prog.To = a[3]
			prog.RegTo2 = -1
			break
		}
		if p.arch.Family == sys.ARM64 {
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.From3 = newAddr(a[2])
			prog.To = a[3]
			break
		}
		if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
			// 2nd operand must always be a register.
			// TODO: Do we need to guard this with the instruction type?
			// That is, are there 4-operand instructions without this property?
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			prog.From3 = newAddr(a[2])
			prog.To = a[3]
			break
		}
		if p.arch.Family == sys.S390X {
			prog.From = a[1]
			prog.Reg = p.getRegister(prog, op, &a[2])
			prog.From3 = newAddr(a[0])
			prog.To = a[3]
			break
		}
		p.errorf("can't handle %s instruction with 4 operands", op)
		return
	case 5:
		if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
			// Always reg, reg, con, con, reg.  (con, con is a 'mask').
			prog.From = a[0]
			prog.Reg = p.getRegister(prog, op, &a[1])
			mask1 := p.getConstant(prog, op, &a[2])
			mask2 := p.getConstant(prog, op, &a[3])
			var mask uint32
			if mask1 < mask2 {
				mask = (^uint32(0) >> uint(mask1)) & (^uint32(0) << uint(31-mask2))
			} else {
				mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1)))
			}
			prog.From3 = &obj.Addr{
				Type:   obj.TYPE_CONST,
				Offset: int64(mask),
			}
			prog.To = a[4]
			break
		}
		p.errorf("can't handle %s instruction with 5 operands", op)
		return
	case 6:
		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
			// Strange special case: MCR, MRC.
			prog.To.Type = obj.TYPE_CONST
			x0 := p.getConstant(prog, op, &a[0])
			x1 := p.getConstant(prog, op, &a[1])
			x2 := int64(p.getRegister(prog, op, &a[2]))
			x3 := int64(p.getRegister(prog, op, &a[3]))
			x4 := int64(p.getRegister(prog, op, &a[4]))
			x5 := p.getConstant(prog, op, &a[5])
			// Cond is handled specially for this instruction.
			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
			if !ok {
				p.errorf("unrecognized condition code .%q", cond)
			}
			prog.To.Offset = offset
			cond = ""
			prog.As = MRC // Both instructions are coded as MRC.
			break
		}
		fallthrough
	default:
		p.errorf("can't handle %s instruction with %d operands", op, len(a))
		return
	}

	p.append(prog, cond, true)
}