return false
}
-// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is
-// one of the RLD-like instructions that require special handling.
-// The FMADD-like instructions behave similarly.
-func IsPPC64RLD(op obj.As) bool {
- switch op {
- case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
- ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
- ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC:
- return true
- case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC,
- ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC,
- ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC,
- ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC:
- return true
- }
- return false
-}
-
-func IsPPC64ISEL(op obj.As) bool {
- return op == ppc64.AISEL
-}
-
// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
// one of the CMP instructions that require special handling.
func IsPPC64CMP(op obj.As) bool {
prog.To = a[1]
break
}
- // Arithmetic. Choices are:
- // reg reg reg
- // imm reg reg
- // reg imm reg
- // If the immediate is the middle argument, use From3.
+
+ prog.From = a[0]
+ prog.To = a[2]
+
+ // If the second argument is not a register argument, it must be
+ // passed RestArgs/SetFrom3
switch a[1].Type {
case obj.TYPE_REG:
- prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
- prog.To = a[2]
- case obj.TYPE_CONST:
- prog.From = a[0]
- prog.SetFrom3(a[1])
- prog.To = a[2]
default:
- p.errorf("invalid addressing modes for %s instruction", op)
- return
+ prog.SetFrom3(a[1])
}
case sys.RISCV64:
// RISCV64 instructions with one input and two outputs.
break
}
if p.arch.Family == sys.PPC64 {
- if arch.IsPPC64RLD(op) {
- prog.From = a[0]
- prog.Reg = p.getRegister(prog, op, &a[1])
- prog.SetFrom3(a[2])
- prog.To = a[3]
- break
- } else if arch.IsPPC64ISEL(op) {
- // ISEL BC,RB,RA,RT becomes isel rt,ra,rb,bc
- prog.SetFrom3(a[2]) // ra
- prog.From = a[0] // bc
- prog.Reg = p.getRegister(prog, op, &a[1]) // rb
- prog.To = a[3] // rt
- break
- }
- // Else, it is a VA-form instruction
- // reg reg reg reg
- // imm reg reg reg
- // Or a VX-form instruction
- // imm imm reg reg
+ prog.From = a[0]
+ prog.To = a[3]
+ // If the second argument is not a register argument, it must be
+ // passed RestArgs/SetFrom3
if a[1].Type == obj.TYPE_REG {
- prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
- prog.SetFrom3(a[2])
- prog.To = a[3]
- break
- } else if a[1].Type == obj.TYPE_CONST {
- prog.From = a[0]
- prog.Reg = p.getRegister(prog, op, &a[2])
- prog.SetFrom3(a[1])
- prog.To = a[3]
- break
+ prog.SetRestArgs([]obj.Addr{a[2]})
} else {
- p.errorf("invalid addressing modes for %s instruction", op)
- return
+ // Don't set prog.Reg if a1 isn't a reg arg.
+ prog.SetRestArgs([]obj.Addr{a[1], a[2]})
}
+ break
}
if p.arch.Family == sys.RISCV64 {
prog.From = a[0]
prog.As = MRC // Both instructions are coded as MRC.
break
}
+ if p.arch.Family == sys.PPC64 {
+ prog.From = a[0]
+ // Second arg is always a register type on ppc64.
+ prog.Reg = p.getRegister(prog, op, &a[1])
+ prog.SetRestArgs([]obj.Addr{a[2], a[3], a[4]})
+ prog.To = a[5]
+ break
+ }
fallthrough
default:
p.errorf("can't handle %s instruction with %d operands", op, len(a))
ADD $1234567, R5 // 641f001263ffd6877cbf2a14
ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14
ADDEX R3, R5, $3, R6 // 7cc32f54
+ ADDEX R3, $3, R5, R6 // 7cc32f54
ADDIS $8, R3 // 3c630008
ADDIS $1000, R3, R4 // 3c8303e8
VNCIPHERLAST V1, V2, V3 // 10611549
VSBOX V1, V2 // 104105c8
VSHASIGMAW $1, V1, $15, V2 // 10418e82
+ VSHASIGMAW $1, $15, V1, V2 // 10418e82
VSHASIGMAD $2, V1, $15, V2 // 104196c2
+ VSHASIGMAD $2, $15, V1, V2 // 104196c2
LXVD2X (R3)(R4), VS1 // 7c241e98
LXVD2X (R3)(R0), VS1 // 7c201e98
XXPERM VS1, VS2, VS3 // f06110d0
XXSLDWI VS1, VS2, $1, VS3 // f0611110
XXSLDWI V1, V2, $1, V3 // f0611117
+ XXSLDWI V1, $1, V2, V3 // f0611117
XXSLDWI VS33, VS34, $1, VS35 // f0611117
+ XXSLDWI VS33, $1, VS34, VS35 // f0611117
+ XXPERMDI VS33, VS34, $1, VS35 // f0611157
+ XXPERMDI VS33, $1, VS34, VS35 // f0611157
XSCVDPSP VS1, VS2 // f0400c24
XVCVDPSP VS1, VS2 // f0400e24
XSCVSXDDP VS1, VS2 // f0400de0
}
}
- // Rewrite SUB constants into ADD.
switch p.As {
+ // Rewrite SUB constants into ADD.
case ASUBC:
if p.From.Type == obj.TYPE_CONST {
p.From.Offset = -p.From.Offset
p.From.Offset = -p.From.Offset
p.As = AADD
}
+
+ // To maintain backwards compatibility, we accept some 4 argument usage of
+ // several opcodes which was likely not intended, but did work. These are not
+ // added to optab to avoid the chance this behavior might be used with newer
+ // instructions.
+ //
+ // Rewrite argument ordering like "ADDEX R3, $3, R4, R5" into
+ // "ADDEX R3, R4, $3, R5"
+ case AVSHASIGMAW, AVSHASIGMAD, AADDEX, AXXSLDWI, AXXPERMDI:
+ if len(p.RestArgs) == 2 && p.Reg == 0 && p.RestArgs[0].Addr.Type == obj.TYPE_CONST && p.RestArgs[1].Addr.Type == obj.TYPE_REG {
+ p.Reg = p.RestArgs[1].Addr.Reg
+ p.RestArgs = p.RestArgs[:1]
+ }
}
+
if c.ctxt.Headtype == objabi.Haix {
c.rewriteToUseTOC(p)
} else if c.ctxt.Flag_dynlink {