@@ -1863,15 +1863,14 @@ func (c *ctxt7) offsetshift(p *obj.Prog, v int64, cls int) int64 {
18631863 return vs
18641864}
18651865
1866- /*
1867- * if v contains a single 16-bit value aligned
1868- * on a 16-bit field, and thus suitable for movk/movn,
1869- * return the field index 0 to 3; otherwise return -1.
1870- */
1866+ // movcon checks if v contains a single 16 bit value that is aligned on
1867+ // a 16 bit boundary, suitable for use with a movk/movn instruction. The
1868+ // field offset in bits is returned (being a multiple 16), otherwise -1 is
1869+ // returned indicating an unsuitable value.
18711870func movcon (v int64 ) int {
18721871 for s := 0 ; s < 64 ; s += 16 {
18731872 if (uint64 (v ) &^ (uint64 (0xFFFF ) << uint (s ))) == 0 {
1874- return s / 16
1873+ return s
18751874 }
18761875 }
18771876 return - 1
@@ -1903,46 +1902,57 @@ func rclass(r int16) int {
19031902}
19041903
19051904// conclass classifies a constant.
1906- func conclass (v int64 ) int {
1905+ func conclass (v int64 , mode int ) int {
1906+ // For constants used with instructions that produce 32 bit results, rewrite the
1907+ // high 32 bits to be a repetition of the low 32 bits, so that the BITCON test can
1908+ // be shared for both 32 bit and 64 bit inputs. A 32 bit operation will zero the
1909+ // high 32 bit of the destination register anyway.
1910+ vbitcon := uint64 (v )
1911+ if mode == 32 {
1912+ vbitcon = uint64 (v )<< 32 | uint64 (v )
1913+ }
1914+
1915+ vnotcon := ^ v
1916+ if mode == 32 {
1917+ vnotcon = int64 (uint32 (vnotcon ))
1918+ }
1919+
19071920 if v == 0 {
19081921 return C_ZCON
19091922 }
19101923 if isaddcon (v ) {
19111924 if v <= 0xFFF {
1912- if isbitcon (uint64 ( v ) ) {
1925+ if isbitcon (vbitcon ) {
19131926 return C_ABCON0
19141927 }
19151928 return C_ADDCON0
19161929 }
1917- if isbitcon (uint64 ( v ) ) {
1930+ if isbitcon (vbitcon ) {
19181931 return C_ABCON
19191932 }
19201933 if movcon (v ) >= 0 {
19211934 return C_AMCON
19221935 }
1923- if movcon (^ v ) >= 0 {
1936+ if movcon (vnotcon ) >= 0 {
19241937 return C_AMCON
19251938 }
19261939 return C_ADDCON
19271940 }
19281941
1929- t := movcon (v )
1930- if t >= 0 {
1931- if isbitcon (uint64 (v )) {
1942+ if t := movcon (v ); t >= 0 {
1943+ if isbitcon (vbitcon ) {
19321944 return C_MBCON
19331945 }
19341946 return C_MOVCON
19351947 }
1936-
1937- t = movcon (^ v )
1938- if t >= 0 {
1939- if isbitcon (uint64 (v )) {
1948+ if t := movcon (vnotcon ); t >= 0 {
1949+ if isbitcon (vbitcon ) {
19401950 return C_MBCON
19411951 }
19421952 return C_MOVCON
19431953 }
19441954
1945- if isbitcon (uint64 ( v ) ) {
1955+ if isbitcon (vbitcon ) {
19461956 return C_BITCON
19471957 }
19481958
@@ -1957,63 +1967,11 @@ func conclass(v int64) int {
19571967 return C_VCON
19581968}
19591969
1960- // con32class reclassifies the constant of 32-bit instruction. Because the constant type is 32-bit,
1961- // but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it.
1970+ // con32class reclassifies the constant used with an instruction that produces
1971+ // a 32 bit result. The constant is at most 32 bits but is saved in Offset as
1972+ // a int64. con32class treats it as uint32 type and reclassifies it.
19621973func (c * ctxt7 ) con32class (a * obj.Addr ) int {
1963- v := uint32 (a .Offset )
1964- // For 32-bit instruction with constant, rewrite
1965- // the high 32-bit to be a repetition of the low
1966- // 32-bit, so that the BITCON test can be shared
1967- // for both 32-bit and 64-bit. 32-bit ops will
1968- // zero the high 32-bit of the destination register
1969- // anyway.
1970- vbitcon := uint64 (v )<< 32 | uint64 (v )
1971- if v == 0 {
1972- return C_ZCON
1973- }
1974- if isaddcon (int64 (v )) {
1975- if v <= 0xFFF {
1976- if isbitcon (vbitcon ) {
1977- return C_ABCON0
1978- }
1979- return C_ADDCON0
1980- }
1981- if isbitcon (vbitcon ) {
1982- return C_ABCON
1983- }
1984- if movcon (int64 (v )) >= 0 {
1985- return C_AMCON
1986- }
1987- if movcon (int64 (^ v )) >= 0 {
1988- return C_AMCON
1989- }
1990- return C_ADDCON
1991- }
1992-
1993- t := movcon (int64 (v ))
1994- if t >= 0 {
1995- if isbitcon (vbitcon ) {
1996- return C_MBCON
1997- }
1998- return C_MOVCON
1999- }
2000-
2001- t = movcon (int64 (^ v ))
2002- if t >= 0 {
2003- if isbitcon (vbitcon ) {
2004- return C_MBCON
2005- }
2006- return C_MOVCON
2007- }
2008-
2009- if isbitcon (vbitcon ) {
2010- return C_BITCON
2011- }
2012-
2013- if isaddcon2 (int64 (v )) {
2014- return C_ADDCON2
2015- }
2016- return C_LCON
1974+ return conclass (int64 (uint32 (a .Offset )), 32 )
20171975}
20181976
20191977// con64class reclassifies the constant of C_VCON and C_LCON class.
@@ -2219,7 +2177,7 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
22192177 if a .Reg != 0 && a .Reg != REGZERO {
22202178 break
22212179 }
2222- return conclass (c .instoffset )
2180+ return conclass (c .instoffset , 64 )
22232181
22242182 case obj .NAME_EXTERN , obj .NAME_STATIC :
22252183 if a .Sym == nil {
@@ -4161,18 +4119,18 @@ func (c *ctxt7) asmout(p *obj.Prog, out []uint32) (count int) {
41614119 c .ctxt .Diag ("zero shifts cannot be handled correctly: %v" , p )
41624120 }
41634121 s := movcon (d )
4164- if s < 0 || s >= 4 {
4122+ if s < 0 || s >= 64 {
41654123 c .ctxt .Diag ("bad constant for MOVK: %#x\n %v" , uint64 (d ), p )
41664124 }
4167- if (o1 & S64 ) == 0 && s >= 2 {
4125+ if (o1 & S64 ) == 0 && s >= 32 {
41684126 c .ctxt .Diag ("illegal bit position\n %v" , p )
41694127 }
4170- if ((uint64 (d ) >> uint (s * 16 )) >> 16 ) != 0 {
4128+ if ((uint64 (d ) >> uint (s )) >> 16 ) != 0 {
41714129 c .ctxt .Diag ("requires uimm16\n %v" , p )
41724130 }
41734131 rt := int (p .To .Reg )
41744132
4175- o1 |= uint32 ((((d >> uint (s * 16 )) & 0xFFFF ) << 5 ) | int64 ((uint32 (s )& 3 )<< 21 ) | int64 (rt & 31 ))
4133+ o1 |= uint32 ((((d >> uint (s )) & 0xFFFF ) << 5 ) | int64 ((uint32 (s >> 4 )& 3 )<< 21 ) | int64 (rt & 31 ))
41764134
41774135 case 34 : /* mov $lacon,R */
41784136 rt , r , rf := p .To .Reg , p .From .Reg , int16 (REGTMP )
@@ -7464,32 +7422,32 @@ func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint3
74647422 if as == AMOVW {
74657423 d := uint32 (a .Offset )
74667424 s := movcon (int64 (d ))
7467- if s < 0 || 16 * s >= 32 {
7425+ if s < 0 || s >= 32 {
74687426 d = ^ d
74697427 s = movcon (int64 (d ))
7470- if s < 0 || 16 * s >= 32 {
7428+ if s < 0 || s >= 32 {
74717429 c .ctxt .Diag ("impossible 32-bit move wide: %#x\n %v" , uint32 (a .Offset ), p )
74727430 }
74737431 o1 = c .opirr (p , AMOVNW )
74747432 } else {
74757433 o1 = c .opirr (p , AMOVZW )
74767434 }
7477- o1 |= MOVCONST (int64 (d ), s , rt )
7435+ o1 |= MOVCONST (int64 (d ), s >> 4 , rt )
74787436 }
74797437 if as == AMOVD {
74807438 d := a .Offset
74817439 s := movcon (d )
7482- if s < 0 || 16 * s >= 64 {
7440+ if s < 0 || s >= 64 {
74837441 d = ^ d
74847442 s = movcon (d )
7485- if s < 0 || 16 * s >= 64 {
7443+ if s < 0 || s >= 64 {
74867444 c .ctxt .Diag ("impossible 64-bit move wide: %#x\n %v" , uint64 (a .Offset ), p )
74877445 }
74887446 o1 = c .opirr (p , AMOVN )
74897447 } else {
74907448 o1 = c .opirr (p , AMOVZ )
74917449 }
7492- o1 |= MOVCONST (d , s , rt )
7450+ o1 |= MOVCONST (d , s >> 4 , rt )
74937451 }
74947452 return o1
74957453}
0 commit comments