// moveByType returns the reg->reg move instruction of the given type. func moveByType(t ssa.Type) obj.As { if t.IsFloat() { // Moving the whole sse2 register is faster // than moving just the correct low portion of it. // There is no xmm->xmm move with 1 byte opcode, // so use movups, which has 2 byte opcode. return x86.AMOVUPS } else { switch t.Size() { case 1: // Avoids partial register write return x86.AMOVL case 2: return x86.AMOVL case 4: return x86.AMOVL case 8: return x86.AMOVQ case 16: return x86.AMOVUPS // int128s are in SSE registers default: panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t)) } } }
// storeByType returns the store instruction of the given type. func storeByType(t ssa.Type) obj.As { width := t.Size() if t.IsFloat() { switch width { case 4: return x86.AMOVSS case 8: return x86.AMOVSD } } else { switch width { case 1: return x86.AMOVB case 2: return x86.AMOVW case 4: return x86.AMOVL case 8: return x86.AMOVQ } } panic("bad store type") }
// loadByType returns the load instruction of the given type. func loadByType(t ssa.Type) obj.As { // Avoid partial register write if !t.IsFloat() && t.Size() <= 2 { if t.Size() == 1 { return x86.AMOVBLZX } else { return x86.AMOVWLZX } } // Otherwise, there's no difference between load and store opcodes. return storeByType(t) }