1
0
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:
Paul E. Murphy 2021-08-09 11:17:08 -05:00 committed by Lynn Boger
parent b8da7e4c4c
commit 5a3d0f5a63
4 changed files with 315 additions and 158 deletions

View File

@ -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 (

View File

@ -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",

View File

@ -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

View File

@ -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]))
}
}
}
}