mirror of
https://github.com/golang/go
synced 2024-11-17 16:14:42 -07:00
cmd/internal/obj/ppc64: rework argument classifications
This introduces a number of new classifications which will make it easier to generate functions to assemble the new instructions of ISA 3.1, and potentially earlier versions. No code generation changes should occur as a result of these. These allow finer control over how an opcode is matched to an optab entry. Literal values are now classified based on the smallest number of bits needed to encode, and matching rules will accept a literal if it can be zero/sign extended to fit a larger literal class. Likewise, support classifying even register numbers for GPR, VSX, and FPR instructions. Some instructions require and even/odd register pair, and these are usually represented by specifying the even register, and similarly encoded. Likewise, add a unit test for the argument classifier function (aclass). This caught an off-by-one bug in aclass which is also fixed. Updates #44549 Change-Id: Ia03013aea8b56c4d59b7c3812cdd67ddb3b720b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/350152 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com> Run-TryBot: Cherry Mui <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
b8da7e4c4c
commit
5a3d0f5a63
@ -350,41 +350,64 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
C_NONE = iota
|
||||
C_REG
|
||||
C_FREG
|
||||
C_VREG
|
||||
C_VSREG
|
||||
C_CREG
|
||||
C_SPR /* special processor register */
|
||||
C_ZCON
|
||||
C_SCON /* 16 bit signed */
|
||||
C_UCON /* 32 bit signed, low 16 bits 0 */
|
||||
C_ADDCON /* -0x8000 <= v < 0 */
|
||||
C_ANDCON /* 0 < v <= 0xFFFF */
|
||||
C_LCON /* other 32 */
|
||||
C_DCON /* other 64 (could subdivide further) */
|
||||
C_SACON /* $n(REG) where n <= int16 */
|
||||
C_LACON /* $n(REG) where int16 < n <= int32 */
|
||||
C_DACON /* $n(REG) where int32 < n */
|
||||
C_SBRA
|
||||
C_LBRA
|
||||
C_LBRAPIC
|
||||
C_ZOREG // conjecture: either (1) register + zeroed offset, or (2) "R0" implies zero or C_REG
|
||||
C_SOREG // D/DS form memory operation
|
||||
C_LOREG // 32 bit addis + D/DS-form memory operation
|
||||
C_FPSCR
|
||||
C_XER
|
||||
C_LR
|
||||
C_CTR
|
||||
C_ANY
|
||||
C_GOK
|
||||
C_ADDR
|
||||
C_TLS_LE
|
||||
C_TLS_IE
|
||||
C_TEXTSIZE
|
||||
C_NONE = iota
|
||||
C_REGP /* An even numbered gpr which can be used a gpr pair argument */
|
||||
C_REG /* Any gpr register */
|
||||
C_FREGP /* An even numbered fpr which can be used a fpr pair argument */
|
||||
C_FREG /* Any fpr register */
|
||||
C_VREG /* Any vector register */
|
||||
C_VSREGP /* An even numbered vsx register which can be used as a vsx register pair argument */
|
||||
C_VSREG /* Any vector-scalar register */
|
||||
C_CREG /* The condition registor (CR) or a condition register field (CRx) */
|
||||
C_SPR /* special processor register */
|
||||
C_ZCON /* The constant zero */
|
||||
C_U1CON /* 1 bit unsigned constant */
|
||||
C_U2CON /* 2 bit unsigned constant */
|
||||
C_U3CON /* 3 bit unsigned constant */
|
||||
C_U4CON /* 4 bit unsigned constant */
|
||||
C_U5CON /* 5 bit unsigned constant */
|
||||
C_U8CON /* 8 bit unsigned constant */
|
||||
C_U15CON /* 15 bit unsigned constant */
|
||||
C_S16CON /* 16 bit signed constant */
|
||||
C_U16CON /* 16 bit unsigned constant */
|
||||
C_32S16CON /* Any 32 bit constant of the form 0x....0000, signed or unsigned */
|
||||
C_32CON /* Any constant which fits into 32 bits. Can be signed or unsigned */
|
||||
C_S34CON /* 34 bit signed constant */
|
||||
C_64CON /* Any constant which fits into 64 bits. Can be signed or unsigned */
|
||||
C_SACON /* $n(REG) where n <= int16 */
|
||||
C_LACON /* $n(REG) where n <= int32 */
|
||||
C_DACON /* $n(REG) where n <= int64 */
|
||||
C_SBRA /* A short offset argument to a branching instruction */
|
||||
C_LBRA /* A long offset argument to a branching instruction */
|
||||
C_LBRAPIC /* Like C_LBRA, but requires an extra NOP for potential TOC restore by the linker. */
|
||||
C_ZOREG /* An reg+reg memory arg, or a $0+reg memory op */
|
||||
C_SOREG /* An $n+reg memory arg where n is a 16 bit signed offset */
|
||||
C_LOREG /* An $n+reg memory arg where n is a 32 bit signed offset */
|
||||
C_FPSCR /* The fpscr register */
|
||||
C_XER /* The xer, holds the carry bit */
|
||||
C_LR /* The link register */
|
||||
C_CTR /* The count register */
|
||||
C_ANY /* Any argument */
|
||||
C_GOK /* A non-matched argument */
|
||||
C_ADDR /* A symbolic memory location */
|
||||
C_TLS_LE /* A thread local, local-exec, type memory arg */
|
||||
C_TLS_IE /* A thread local, initial-exec, type memory arg */
|
||||
C_TEXTSIZE /* An argument with Type obj.TYPE_TEXTSIZE */
|
||||
|
||||
C_NCLASS /* must be the last */
|
||||
|
||||
/* Aliased names which should be cleaned up, or integrated. */
|
||||
C_SCON = C_U15CON
|
||||
C_UCON = C_32S16CON
|
||||
C_ADDCON = C_S16CON
|
||||
C_ANDCON = C_U16CON
|
||||
C_LCON = C_32CON
|
||||
|
||||
/* Aliased names which may be generated by ppc64map for the optab. */
|
||||
C_S3216CON = C_32S16CON // TODO: these should be treated differently (e.g xoris vs addis)
|
||||
C_U3216CON = C_32S16CON
|
||||
C_S32CON = C_32CON
|
||||
C_U32CON = C_32CON
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -6,19 +6,29 @@ package ppc64
|
||||
|
||||
var cnames9 = []string{
|
||||
"NONE",
|
||||
"REGP",
|
||||
"REG",
|
||||
"FREGP",
|
||||
"FREG",
|
||||
"VREG",
|
||||
"VSREGP",
|
||||
"VSREG",
|
||||
"CREG",
|
||||
"SPR",
|
||||
"ZCON",
|
||||
"SCON",
|
||||
"UCON",
|
||||
"ADDCON",
|
||||
"ANDCON",
|
||||
"LCON",
|
||||
"DCON",
|
||||
"U1CON",
|
||||
"U2CON",
|
||||
"U3CON",
|
||||
"U4CON",
|
||||
"U5CON",
|
||||
"U8CON",
|
||||
"U15CON",
|
||||
"S16CON",
|
||||
"U16CON",
|
||||
"32S16CON",
|
||||
"32CON",
|
||||
"S34CON",
|
||||
"64CON",
|
||||
"SACON",
|
||||
"LACON",
|
||||
"DACON",
|
||||
|
@ -307,8 +307,7 @@ var optab = []Optab{
|
||||
{as: ABC, a6: C_ZOREG, type_: 15, size: 8},
|
||||
{as: ASYNC, type_: 46, size: 4},
|
||||
{as: AWORD, a1: C_LCON, type_: 40, size: 4},
|
||||
{as: ADWORD, a1: C_LCON, type_: 31, size: 8},
|
||||
{as: ADWORD, a1: C_DCON, type_: 31, size: 8},
|
||||
{as: ADWORD, a1: C_64CON, type_: 31, size: 8},
|
||||
{as: ADWORD, a1: C_LACON, type_: 31, size: 8},
|
||||
{as: AADDME, a1: C_REG, a6: C_REG, type_: 47, size: 4},
|
||||
{as: AEXTSB, a1: C_REG, a6: C_REG, type_: 48, size: 4},
|
||||
@ -336,7 +335,7 @@ var optab = []Optab{
|
||||
{as: ALDMX, a1: C_SOREG, a6: C_REG, type_: 45, size: 4}, /* load doubleword monitored, x-form */
|
||||
{as: AMADDHD, a1: C_REG, a2: C_REG, a3: C_REG, a6: C_REG, type_: 83, size: 4}, /* multiply-add high/low doubleword, va-form */
|
||||
{as: AADDEX, a1: C_REG, a2: C_REG, a3: C_SCON, a6: C_REG, type_: 94, size: 4}, /* add extended using alternate carry, z23-form */
|
||||
{as: ACRAND, a1: C_CREG, a6: C_CREG, type_: 2, size: 4}, /* logical ops for condition registers xl-form */
|
||||
{as: ACRAND, a1: C_CREG, a2: C_CREG, a6: C_CREG, type_: 2, size: 4}, /* logical ops for condition register bits xl-form */
|
||||
|
||||
/* Vector instructions */
|
||||
|
||||
@ -485,15 +484,15 @@ var optab = []Optab{
|
||||
{as: AXVCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */
|
||||
|
||||
{as: ACMP, a1: C_REG, a6: C_REG, type_: 70, size: 4},
|
||||
{as: ACMP, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4},
|
||||
{as: ACMP, a1: C_REG, a2: C_CREG, a6: C_REG, type_: 70, size: 4},
|
||||
{as: ACMP, a1: C_REG, a6: C_ADDCON, type_: 71, size: 4},
|
||||
{as: ACMP, a1: C_REG, a2: C_REG, a6: C_ADDCON, type_: 71, size: 4},
|
||||
{as: ACMP, a1: C_REG, a2: C_CREG, a6: C_ADDCON, type_: 71, size: 4},
|
||||
{as: ACMPU, a1: C_REG, a6: C_REG, type_: 70, size: 4},
|
||||
{as: ACMPU, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4},
|
||||
{as: ACMPU, a1: C_REG, a2: C_CREG, a6: C_REG, type_: 70, size: 4},
|
||||
{as: ACMPU, a1: C_REG, a6: C_ANDCON, type_: 71, size: 4},
|
||||
{as: ACMPU, a1: C_REG, a2: C_REG, a6: C_ANDCON, type_: 71, size: 4},
|
||||
{as: ACMPU, a1: C_REG, a2: C_CREG, a6: C_ANDCON, type_: 71, size: 4},
|
||||
{as: AFCMPO, a1: C_FREG, a6: C_FREG, type_: 70, size: 4},
|
||||
{as: AFCMPO, a1: C_FREG, a2: C_REG, a6: C_FREG, type_: 70, size: 4},
|
||||
{as: AFCMPO, a1: C_FREG, a2: C_CREG, a6: C_FREG, type_: 70, size: 4},
|
||||
{as: ATW, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 60, size: 4},
|
||||
{as: ATW, a1: C_LCON, a2: C_REG, a6: C_ADDCON, type_: 61, size: 4},
|
||||
{as: ADCBF, a1: C_ZOREG, type_: 43, size: 4},
|
||||
@ -584,9 +583,11 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
|
||||
// or "MOVD R5, foo+10(SP) or pseudo-register is used. The other common case is when
|
||||
// generating constants in register like "MOVD $constant, Rx".
|
||||
func (c *ctxt9) getimpliedreg(a *obj.Addr, p *obj.Prog) int {
|
||||
switch oclass(a) {
|
||||
case C_ADDCON, C_ANDCON, C_UCON, C_LCON, C_SCON, C_ZCON:
|
||||
class := oclass(a)
|
||||
if class >= C_ZCON && class <= C_64CON {
|
||||
return REGZERO
|
||||
}
|
||||
switch class {
|
||||
case C_SACON, C_LACON:
|
||||
return REGSP
|
||||
case C_LOREG, C_SOREG, C_ZOREG:
|
||||
@ -839,45 +840,49 @@ func isuint32(v uint64) bool {
|
||||
return uint64(uint32(v)) == v
|
||||
}
|
||||
|
||||
func (c *ctxt9) aclassreg(reg int16) int {
|
||||
if REG_R0 <= reg && reg <= REG_R31 {
|
||||
return C_REGP + int(reg&1)
|
||||
}
|
||||
if REG_F0 <= reg && reg <= REG_F31 {
|
||||
return C_FREGP + int(reg&1)
|
||||
}
|
||||
if REG_V0 <= reg && reg <= REG_V31 {
|
||||
return C_VREG
|
||||
}
|
||||
if REG_VS0 <= reg && reg <= REG_VS63 {
|
||||
return C_VSREGP + int(reg&1)
|
||||
}
|
||||
if REG_CR0 <= reg && reg <= REG_CR7 || reg == REG_CR {
|
||||
return C_CREG
|
||||
}
|
||||
if REG_SPR0 <= reg && reg <= REG_SPR0+1023 {
|
||||
switch reg {
|
||||
case REG_LR:
|
||||
return C_LR
|
||||
|
||||
case REG_XER:
|
||||
return C_XER
|
||||
|
||||
case REG_CTR:
|
||||
return C_CTR
|
||||
}
|
||||
|
||||
return C_SPR
|
||||
}
|
||||
if reg == REG_FPSCR {
|
||||
return C_FPSCR
|
||||
}
|
||||
return C_GOK
|
||||
}
|
||||
|
||||
func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
switch a.Type {
|
||||
case obj.TYPE_NONE:
|
||||
return C_NONE
|
||||
|
||||
case obj.TYPE_REG:
|
||||
if REG_R0 <= a.Reg && a.Reg <= REG_R31 {
|
||||
return C_REG
|
||||
}
|
||||
if REG_F0 <= a.Reg && a.Reg <= REG_F31 {
|
||||
return C_FREG
|
||||
}
|
||||
if REG_V0 <= a.Reg && a.Reg <= REG_V31 {
|
||||
return C_VREG
|
||||
}
|
||||
if REG_VS0 <= a.Reg && a.Reg <= REG_VS63 {
|
||||
return C_VSREG
|
||||
}
|
||||
if REG_CR0 <= a.Reg && a.Reg <= REG_CR7 || a.Reg == REG_CR {
|
||||
return C_CREG
|
||||
}
|
||||
if REG_SPR0 <= a.Reg && a.Reg <= REG_SPR0+1023 {
|
||||
switch a.Reg {
|
||||
case REG_LR:
|
||||
return C_LR
|
||||
|
||||
case REG_XER:
|
||||
return C_XER
|
||||
|
||||
case REG_CTR:
|
||||
return C_CTR
|
||||
}
|
||||
|
||||
return C_SPR
|
||||
}
|
||||
if a.Reg == REG_FPSCR {
|
||||
return C_FPSCR
|
||||
}
|
||||
return C_GOK
|
||||
return c.aclassreg(a.Reg)
|
||||
|
||||
case obj.TYPE_MEM:
|
||||
switch a.Name {
|
||||
@ -948,7 +953,7 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
case obj.NAME_NONE:
|
||||
c.instoffset = a.Offset
|
||||
if a.Reg != 0 {
|
||||
if -BIG <= c.instoffset && c.instoffset <= BIG {
|
||||
if -BIG <= c.instoffset && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
}
|
||||
if isint32(c.instoffset) {
|
||||
@ -985,35 +990,47 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
}
|
||||
|
||||
if c.instoffset >= 0 {
|
||||
if c.instoffset == 0 {
|
||||
return C_ZCON
|
||||
sbits := bits.Len64(uint64(c.instoffset))
|
||||
switch {
|
||||
case sbits <= 5:
|
||||
return C_ZCON + sbits
|
||||
case sbits <= 8:
|
||||
return C_U8CON
|
||||
case sbits <= 15:
|
||||
return C_U15CON
|
||||
case sbits <= 16:
|
||||
return C_U16CON
|
||||
case sbits <= 31:
|
||||
// Special case, a positive int32 value which is a multiple of 2^16
|
||||
if c.instoffset&0xFFFF == 0 {
|
||||
return C_U3216CON
|
||||
}
|
||||
return C_U32CON
|
||||
case sbits <= 32:
|
||||
return C_U32CON
|
||||
case sbits <= 33:
|
||||
return C_S34CON
|
||||
default:
|
||||
return C_64CON
|
||||
}
|
||||
if c.instoffset <= 0x7fff {
|
||||
return C_SCON
|
||||
} else {
|
||||
sbits := bits.Len64(uint64(^c.instoffset))
|
||||
switch {
|
||||
case sbits <= 15:
|
||||
return C_S16CON
|
||||
case sbits <= 31:
|
||||
// Special case, a negative int32 value which is a multiple of 2^16
|
||||
if c.instoffset&0xFFFF == 0 {
|
||||
return C_S3216CON
|
||||
}
|
||||
return C_S32CON
|
||||
case sbits <= 33:
|
||||
return C_S34CON
|
||||
default:
|
||||
return C_64CON
|
||||
}
|
||||
if c.instoffset <= 0xffff {
|
||||
return C_ANDCON
|
||||
}
|
||||
if c.instoffset&0xffff == 0 && isuint32(uint64(c.instoffset)) { /* && (instoffset & (1<<31)) == 0) */
|
||||
return C_UCON
|
||||
}
|
||||
if isint32(c.instoffset) || isuint32(uint64(c.instoffset)) {
|
||||
return C_LCON
|
||||
}
|
||||
return C_DCON
|
||||
}
|
||||
|
||||
if c.instoffset >= -0x8000 {
|
||||
return C_ADDCON
|
||||
}
|
||||
if c.instoffset&0xffff == 0 && isint32(c.instoffset) {
|
||||
return C_UCON
|
||||
}
|
||||
if isint32(c.instoffset) {
|
||||
return C_LCON
|
||||
}
|
||||
return C_DCON
|
||||
|
||||
case obj.TYPE_BRANCH:
|
||||
if a.Sym != nil && c.ctxt.Flag_dynlink {
|
||||
return C_LBRAPIC
|
||||
@ -1062,15 +1079,7 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
|
||||
|
||||
a2 := C_NONE
|
||||
if p.Reg != 0 {
|
||||
if REG_R0 <= p.Reg && p.Reg <= REG_R31 {
|
||||
a2 = C_REG
|
||||
} else if REG_V0 <= p.Reg && p.Reg <= REG_V31 {
|
||||
a2 = C_VREG
|
||||
} else if REG_VS0 <= p.Reg && p.Reg <= REG_VS63 {
|
||||
a2 = C_VSREG
|
||||
} else if REG_F0 <= p.Reg && p.Reg <= REG_F31 {
|
||||
a2 = C_FREG
|
||||
}
|
||||
a2 = c.aclassreg(p.Reg)
|
||||
}
|
||||
|
||||
// c.ctxt.Logf("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4, a5, a6)
|
||||
@ -1097,71 +1106,72 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
|
||||
return &ops[0]
|
||||
}
|
||||
|
||||
// Compare two operand types (ex C_REG, or C_SCON)
|
||||
// and return true if b is compatible with a.
|
||||
//
|
||||
// Argument comparison isn't reflexitive, so care must be taken.
|
||||
// a is the argument type as found in optab, b is the argument as
|
||||
// fitted by aclass.
|
||||
func cmp(a int, b int) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
switch a {
|
||||
case C_LCON:
|
||||
if b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON {
|
||||
return true
|
||||
}
|
||||
|
||||
case C_ADDCON:
|
||||
if b == C_ZCON || b == C_SCON {
|
||||
return true
|
||||
}
|
||||
|
||||
case C_ANDCON:
|
||||
if b == C_ZCON || b == C_SCON {
|
||||
return true
|
||||
}
|
||||
|
||||
case C_SPR:
|
||||
if b == C_LR || b == C_XER || b == C_CTR {
|
||||
return true
|
||||
}
|
||||
|
||||
case C_UCON:
|
||||
if b == C_ZCON {
|
||||
return true
|
||||
}
|
||||
case C_U1CON:
|
||||
return cmp(C_ZCON, b)
|
||||
case C_U2CON:
|
||||
return cmp(C_U1CON, b)
|
||||
case C_U3CON:
|
||||
return cmp(C_U2CON, b)
|
||||
case C_U4CON:
|
||||
return cmp(C_U3CON, b)
|
||||
case C_U5CON:
|
||||
return cmp(C_U4CON, b)
|
||||
case C_U8CON:
|
||||
return cmp(C_U5CON, b)
|
||||
case C_U15CON:
|
||||
return cmp(C_U8CON, b)
|
||||
case C_U16CON:
|
||||
return cmp(C_U15CON, b)
|
||||
|
||||
case C_SCON:
|
||||
if b == C_ZCON {
|
||||
return true
|
||||
}
|
||||
case C_S16CON:
|
||||
return cmp(C_U15CON, b)
|
||||
case C_32CON:
|
||||
return cmp(C_S16CON, b) || cmp(C_U16CON, b) || cmp(C_32S16CON, b)
|
||||
case C_S34CON:
|
||||
return cmp(C_32CON, b)
|
||||
case C_64CON:
|
||||
return cmp(C_S34CON, b)
|
||||
|
||||
case C_32S16CON:
|
||||
return cmp(C_ZCON, b)
|
||||
|
||||
case C_LACON:
|
||||
if b == C_SACON {
|
||||
return true
|
||||
}
|
||||
return cmp(C_SACON, b)
|
||||
|
||||
case C_LBRA:
|
||||
if b == C_SBRA {
|
||||
return true
|
||||
}
|
||||
return cmp(C_SBRA, b)
|
||||
|
||||
case C_SOREG:
|
||||
if b == C_ZOREG {
|
||||
return true
|
||||
}
|
||||
return cmp(C_ZOREG, b)
|
||||
|
||||
case C_LOREG:
|
||||
if b == C_SOREG || b == C_ZOREG {
|
||||
return true
|
||||
}
|
||||
return cmp(C_SOREG, b)
|
||||
|
||||
// An even/odd register input always matches the regular register types.
|
||||
case C_REG:
|
||||
if b == C_ZCON {
|
||||
return r0iszero != 0 /*TypeKind(100016)*/
|
||||
}
|
||||
|
||||
return cmp(C_REGP, b) || (b == C_ZCON && r0iszero != 0)
|
||||
case C_FREG:
|
||||
return cmp(C_FREGP, b)
|
||||
case C_VSREG:
|
||||
/* Allow any VR argument as a VSR operand. */
|
||||
if b == C_VREG {
|
||||
return true
|
||||
}
|
||||
return cmp(C_VSREGP, b) || cmp(C_VREG, b)
|
||||
|
||||
case C_ANY:
|
||||
return true
|
||||
|
@ -6,9 +6,12 @@ package ppc64
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -437,3 +440,114 @@ func TestRegValueAlignment(t *testing.T) {
|
||||
tstFunc(t.rstart, t.rend, t.msk, t.rout)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify interesting obj.Addr arguments are classified correctly.
|
||||
func TestAddrClassifier(t *testing.T) {
|
||||
type cmplx struct {
|
||||
pic int
|
||||
pic_dyn int
|
||||
dyn int
|
||||
nonpic int
|
||||
}
|
||||
tsts := [...]struct {
|
||||
arg obj.Addr
|
||||
output interface{}
|
||||
}{
|
||||
// Supported register type args
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_R1}, C_REG},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_R2}, C_REGP},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_F1}, C_FREG},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_F2}, C_FREGP},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_V2}, C_VREG},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS1}, C_VSREG},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS2}, C_VSREGP},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR}, C_CREG},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1}, C_CREG},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0}, C_SPR},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 1}, C_XER},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 8}, C_LR},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 9}, C_CTR},
|
||||
{obj.Addr{Type: obj.TYPE_REG, Reg: REG_FPSCR}, C_FPSCR},
|
||||
|
||||
// Memory type arguments.
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_GOTREF}, C_ADDR},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_TOCREF}, C_ADDR},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.STLSBSS}}, cmplx{C_TLS_IE, C_TLS_IE, C_TLS_LE, C_TLS_LE}},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_ADDR},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO}, C_SOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: BIG}, C_LOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM}, C_SOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: BIG}, C_LOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LOREG}, // 33 is FixedFrameSize-1
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE}, C_ZOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: 1}, C_SOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: BIG}, C_LOREG},
|
||||
{obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: -BIG - 33}, C_LOREG},
|
||||
|
||||
// Misc (golang initializes -0.0 to 0.0, hence the obfuscation below)
|
||||
{obj.Addr{Type: obj.TYPE_TEXTSIZE}, C_TEXTSIZE},
|
||||
{obj.Addr{Type: obj.TYPE_FCONST, Val: 0.0}, C_ZCON},
|
||||
{obj.Addr{Type: obj.TYPE_FCONST, Val: math.Float64frombits(0x8000000000000000)}, C_S16CON},
|
||||
|
||||
// Address type arguments
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1}, C_SACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: BIG}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: -BIG - 1}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1 << 32}, C_DACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_STATIC, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: 1}, C_SACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: BIG}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: 1}, C_SACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: BIG}, C_LACON},
|
||||
{obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LACON}, // 33 is FixedFrameSize-1
|
||||
|
||||
// Constant type arguments
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 0}, C_ZCON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1}, C_U1CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 2}, C_U2CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 4}, C_U3CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 8}, C_U4CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 16}, C_U5CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 32}, C_U8CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 14}, C_U15CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 15}, C_U16CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 16}, C_U3216CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 + 1<<16}, C_U32CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 32}, C_S34CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 33}, C_64CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -1}, C_S16CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10000}, C_S3216CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10001}, C_S32CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 33)}, C_S34CON},
|
||||
{obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 34)}, C_64CON},
|
||||
|
||||
// Branch like arguments
|
||||
{obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_SBRA, C_LBRAPIC, C_LBRAPIC, C_SBRA}},
|
||||
{obj.Addr{Type: obj.TYPE_BRANCH}, C_SBRA},
|
||||
}
|
||||
|
||||
pic_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Arch: &Linkppc64}, autosize: 0}
|
||||
pic_dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
|
||||
dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
|
||||
nonpic_ctxt9 := ctxt9{ctxt: &obj.Link{Arch: &Linkppc64}, autosize: 0}
|
||||
ctxts := [...]*ctxt9{&pic_ctxt9, &pic_dyn_ctxt9, &dyn_ctxt9, &nonpic_ctxt9}
|
||||
name := [...]string{"pic", "pic_dyn", "dyn", "nonpic"}
|
||||
for _, tst := range tsts {
|
||||
var expect []int
|
||||
switch tst.output.(type) {
|
||||
case cmplx:
|
||||
v := tst.output.(cmplx)
|
||||
expect = []int{v.pic, v.pic_dyn, v.dyn, v.nonpic}
|
||||
case int:
|
||||
expect = []int{tst.output.(int), tst.output.(int), tst.output.(int), tst.output.(int)}
|
||||
}
|
||||
for i, _ := range ctxts {
|
||||
if output := ctxts[i].aclass(&tst.arg); output != expect[i] {
|
||||
t.Errorf("%s.aclass(%v) = %v, expected %v\n", name[i], tst.arg, DRconv(output), DRconv(expect[i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user