func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { if p.As == ALEAL || p.As == ALEAQ { return } if a.Reg == REG_BP { ctxt.Diag("invalid address: %v", p) return } if a.Reg == REG_TLS { a.Reg = REG_BP } if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE { switch a.Reg { // all ok case REG_BP, REG_SP, REG_R15: break default: if a.Index != REG_NONE { ctxt.Diag("invalid address %v", p) } a.Index = a.Reg if a.Index != REG_NONE { a.Scale = 1 } a.Reg = REG_R15 } } }
/* * substitute s for v in a * return failure to substitute */ func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { if copyas(a, v) { reg := int(int(s.Reg)) if reg >= x86.REG_AX && reg <= x86.REG_R15 || reg >= x86.REG_X0 && reg <= x86.REG_X0+15 { if f != 0 { a.Reg = int16(reg) } } return 0 } if regtyp(v) { reg := int(int(v.Reg)) if a.Type == obj.TYPE_MEM && int(a.Reg) == reg { if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE { return 1 /* can't use BP-base with index */ } if f != 0 { a.Reg = s.Reg } } // return 0; if int(a.Index) == reg { if f != 0 { a.Index = s.Reg } return 0 } return 0 } return 0 }
// registerIndirect parses the general form of a register indirection. // It is can be (R1), (R2*scale), or (R1)(R2*scale) where R1 may be a simple // register or register pair R:R or (R, R) or (R+R). // Or it might be a pseudo-indirection like (FP). // We are sitting on the opening parenthesis. func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) { p.get('(') tok := p.next() name := tok.String() r1, r2, scale, ok := p.register(name, 0) if !ok { p.errorf("indirect through non-register %s", tok) } p.get(')') a.Type = obj.TYPE_MEM if r1 < 0 { // Pseudo-register reference. if r2 != 0 { p.errorf("cannot use pseudo-register in pair") return } // For SB, SP, and FP, there must be a name here. 0(FP) is not legal. if name != "PC" && a.Name == obj.NAME_NONE { p.errorf("cannot reference %s without a symbol", name) } p.setPseudoRegister(a, name, false, prefix) return } a.Reg = r1 if r2 != 0 { // TODO: Consistency in the encoding would be nice here. if p.arch.Thechar == '5' || p.arch.Thechar == '7' { // Special form // ARM: destination register pair (R1, R2). // ARM64: register pair (R1, R2) for LDP/STP. if prefix != 0 || scale != 0 { p.errorf("illegal address mode for register pair") return } a.Type = obj.TYPE_REGREG a.Offset = int64(r2) // Nothing may follow return } if p.arch.Thechar == '9' { // Special form for PPC64: (R1+R2); alias for (R1)(R2*1). if prefix != 0 || scale != 0 { p.errorf("illegal address mode for register+register") return } a.Type = obj.TYPE_MEM a.Scale = 1 a.Index = r2 // Nothing may follow. return } } if r2 != 0 { p.errorf("indirect through register pair") } if prefix == '$' { a.Type = obj.TYPE_ADDR } if r1 == arch.RPC && prefix != 0 { p.errorf("illegal addressing mode for PC") } if scale == 0 && p.peek() == '(' { // General form (R)(R*scale). p.next() tok := p.next() r1, r2, scale, ok = p.register(tok.String(), 0) if !ok { p.errorf("indirect through non-register %s", tok) } if r2 != 0 { p.errorf("unimplemented two-register form") } a.Index = r1 a.Scale = int16(scale) p.get(')') } else if scale != 0 { // First (R) was missing, all we have is (R*scale). a.Reg = 0 a.Index = r1 a.Scale = int16(scale) } }
/* * generate code to compute address of n, * a reference to a (perhaps nested) field inside * an array or struct. * return 0 on failure, 1 on success. * on success, leaves usable address in a. * * caller is responsible for calling sudoclean * after successful sudoaddable, * to release the register used for a. */ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { if n.Type == nil { return false } *a = obj.Addr{} switch n.Op { case gc.OLITERAL: if !gc.Isconst(n, gc.CTINT) { break } v := n.Int() if v >= 32000 || v <= -32000 { break } switch as { default: return false case x86.AADDB, x86.AADDW, x86.AADDL, x86.AADDQ, x86.ASUBB, x86.ASUBW, x86.ASUBL, x86.ASUBQ, x86.AANDB, x86.AANDW, x86.AANDL, x86.AANDQ, x86.AORB, x86.AORW, x86.AORL, x86.AORQ, x86.AXORB, x86.AXORW, x86.AXORL, x86.AXORQ, x86.AINCB, x86.AINCW, x86.AINCL, x86.AINCQ, x86.ADECB, x86.ADECW, x86.ADECL, x86.ADECQ, x86.AMOVB, x86.AMOVW, x86.AMOVL, x86.AMOVQ: break } cleani += 2 reg := &clean[cleani-1] reg1 := &clean[cleani-2] reg.Op = gc.OEMPTY reg1.Op = gc.OEMPTY gc.Naddr(a, n) return true case gc.ODOT, gc.ODOTPTR: cleani += 2 reg := &clean[cleani-1] reg1 := &clean[cleani-2] reg.Op = gc.OEMPTY reg1.Op = gc.OEMPTY var nn *gc.Node var oary [10]int64 o := gc.Dotoffset(n, oary[:], &nn) if nn == nil { sudoclean() return false } if nn.Addable && o == 1 && oary[0] >= 0 { // directly addressable set of DOTs n1 := *nn n1.Type = n.Type n1.Xoffset += oary[0] gc.Naddr(a, &n1) return true } gc.Regalloc(reg, gc.Types[gc.Tptr], nil) n1 := *reg n1.Op = gc.OINDREG if oary[0] >= 0 { gc.Agen(nn, reg) n1.Xoffset = oary[0] } else { gc.Cgen(nn, reg) gc.Cgen_checknil(reg) n1.Xoffset = -(oary[0] + 1) } for i := 1; i < o; i++ { if oary[i] >= 0 { gc.Fatalf("can't happen") } gins(movptr, &n1, reg) gc.Cgen_checknil(reg) n1.Xoffset = -(oary[i] + 1) } a.Type = obj.TYPE_NONE a.Index = obj.TYPE_NONE gc.Fixlargeoffset(&n1) gc.Naddr(a, &n1) return true case gc.OINDEX: return false } return false }