summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/obj/ppc64/doc.go
blob: da10ea379d0fa44005d91d344eb5d68699b90b15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package ppc64 implements a PPC64 assembler that assembles Go asm into
the corresponding PPC64 instructions as defined by the Power ISA 3.0B.

This document provides information on how to write code in Go assembler
for PPC64, focusing on the differences between Go and PPC64 assembly language.
It assumes some knowledge of PPC64 assembler. The original implementation of
PPC64 in Go defined many opcodes that are different from PPC64 opcodes, but
updates to the Go assembly language used mnemonics that are mostly similar if not
identical to the PPC64 mneumonics, such as VMX and VSX instructions. Not all detail
is included here; refer to the Power ISA document if interested in more detail.

Starting with Go 1.15 the Go objdump supports the -gnu option, which provides a
side by side view of the Go assembler and the PPC64 assembler output. This is
extremely helpful in determining what final PPC64 assembly is generated from the
corresponding Go assembly.

In the examples below, the Go assembly is on the left, PPC64 assembly on the right.

1. Operand ordering

In Go asm, the last operand (right) is the target operand, but with PPC64 asm,
the first operand (left) is the target. The order of the remaining operands is
not consistent: in general opcodes with 3 operands that perform math or logical
operations have their operands in reverse order. Opcodes for vector instructions
and those with more than 3 operands usually have operands in the same order except
for the target operand, which is first in PPC64 asm and last in Go asm.

Example:

	ADD R3, R4, R5		<=>	add r5, r4, r3

2. Constant operands

In Go asm, an operand that starts with '$' indicates a constant value. If the
instruction using the constant has an immediate version of the opcode, then an
immediate value is used with the opcode if possible.

Example:

	ADD $1, R3, R4		<=> 	addi r4, r3, 1

3. Opcodes setting condition codes

In PPC64 asm, some instructions other than compares have variations that can set
the condition code where meaningful. This is indicated by adding '.' to the end
of the PPC64 instruction. In Go asm, these instructions have 'CC' at the end of
the opcode. The possible settings of the condition code depend on the instruction.
CR0 is the default for fixed-point instructions; CR1 for floating point; CR6 for
vector instructions.

Example:

	ANDCC R3, R4, R5		<=>	and. r5, r3, r4 (set CR0)

4. Loads and stores from memory

In Go asm, opcodes starting with 'MOV' indicate a load or store. When the target
is a memory reference, then it is a store; when the target is a register and the
source is a memory reference, then it is a load.

MOV{B,H,W,D} variations identify the size as byte, halfword, word, doubleword.

Adding 'Z' to the opcode for a load indicates zero extend; if omitted it is sign extend.
Adding 'U' to a load or store indicates an update of the base register with the offset.
Adding 'BR' to an opcode indicates byte-reversed load or store, or the order opposite
of the expected endian order. If 'BR' is used then zero extend is assumed.

Memory references n(Ra) indicate the address in Ra + n. When used with an update form
of an opcode, the value in Ra is incremented by n.

Memory references (Ra+Rb) or (Ra)(Rb) indicate the address Ra + Rb, used by indexed
loads or stores. Both forms are accepted. When used with an update then the base register
is updated by the value in the index register.

Examples:

	MOVD (R3), R4		<=>	ld r4,0(r3)
	MOVW (R3), R4		<=>	lwa r4,0(r3)
	MOVWZU 4(R3), R4		<=>	lwzu r4,4(r3)
	MOVWZ (R3+R5), R4		<=>	lwzx r4,r3,r5
	MOVHZ  (R3), R4		<=>	lhz r4,0(r3)
	MOVHU 2(R3), R4		<=>	lhau r4,2(r3)
	MOVBZ (R3), R4		<=>	lbz r4,0(r3)

	MOVD R4,(R3)		<=>	std r4,0(r3)
	MOVW R4,(R3)		<=>	stw r4,0(r3)
	MOVW R4,(R3+R5)		<=>	stwx r4,r3,r5
	MOVWU R4,4(R3)		<=>	stwu r4,4(r3)
	MOVH R4,2(R3)		<=>	sth r4,2(r3)
	MOVBU R4,(R3)(R5)		<=>	stbux r4,r3,r5

4. Compares

When an instruction does a compare or other operation that might
result in a condition code, then the resulting condition is set
in a field of the condition register. The condition register consists
of 8 4-bit fields named CR0 - CR7. When a compare instruction
identifies a CR then the resulting condition is set in that field
to be read by a later branch or isel instruction. Within these fields,
bits are set to indicate less than, greater than, or equal conditions.

Once an instruction sets a condition, then a subsequent branch, isel or
other instruction can read the condition field and operate based on the
bit settings.

Examples:

	CMP R3, R4			<=>	cmp r3, r4	(CR0 assumed)
	CMP R3, R4, CR1		<=>	cmp cr1, r3, r4

Note that the condition register is the target operand of compare opcodes, so
the remaining operands are in the same order for Go asm and PPC64 asm.
When CR0 is used then it is implicit and does not need to be specified.

5. Branches

Many branches are represented as a form of the BC instruction. There are
other extended opcodes to make it easier to see what type of branch is being
used.

The following is a brief description of the BC instruction and its commonly
used operands.

BC op1, op2, op3

	  op1: type of branch
	      16 -> bctr (branch on ctr)
	      12 -> bcr  (branch if cr bit is set)
	      8  -> bcr+bctr (branch on ctr and cr values)
		4  -> bcr != 0 (branch if specified cr bit is not set)

		There are more combinations but these are the most common.

	  op2: condition register field and condition bit

		This contains an immediate value indicating which condition field
		to read and what bits to test. Each field is 4 bits long with CR0
	      at bit 0, CR1 at bit 4, etc. The value is computed as 4*CR+condition
	      with these condition values:

	      0 -> LT
	      1 -> GT
	      2 -> EQ
	      3 -> OVG

		Thus 0 means test CR0 for LT, 5 means CR1 for GT, 30 means CR7 for EQ.

	  op3: branch target

Examples:

	BC 12, 0, target		<=>	blt cr0, target
	BC 12, 2, target		<=>	beq cr0, target
	BC 12, 5, target		<=>	bgt cr1, target
	BC 12, 30, target		<=>	beq cr7, target
	BC 4, 6, target		<=>	bne cr1, target
	BC 4, 1, target		<=>	ble cr1, target

	The following extended opcodes are available for ease of use and readability:

	BNE CR2, target		<=>	bne cr2, target
	BEQ CR4, target		<=>	beq cr4, target
	BLT target			<=>	blt target (cr0 default)
	BGE CR7, target		<=>	bge cr7, target

Refer to the ISA for more information on additional values for the BC instruction,
how to handle OVG information, and much more.

5. Align directive

Starting with Go 1.12, Go asm supports the PCALIGN directive, which indicates
that the next instruction should be aligned to the specified value. Currently
8 and 16 are the only supported values, and a maximum of 2 NOPs will be added
to align the code. That means in the case where the code is aligned to 4 but
PCALIGN $16 is at that location, the code will only be aligned to 8 to avoid
adding 3 NOPs.

The purpose of this directive is to improve performance for cases like loops
where better alignment (8 or 16 instead of 4) might be helpful. This directive
exists in PPC64 assembler and is frequently used by PPC64 assembler writers.

PCALIGN $16
PCALIGN $8

By default, functions in Go are aligned to 16 bytes, as is the case in all
other compilers for PPC64. If there is a PCALIGN directive requesting alignment
greater than 16, then the alignment of the containing function must be
promoted to that same alignment or greater.

The behavior of PCALIGN is changed in Go 1.21 to be more straightforward to
ensure the alignment required for some instructions in power10. The acceptable
values are 8, 16, 32 and 64, and the use of those values will always provide the
specified alignment.

6. Shift instructions

The simple scalar shifts on PPC64 expect a shift count that fits in 5 bits for
32-bit values or 6 bit for 64-bit values. If the shift count is a constant value
greater than the max then the assembler sets it to the max for that size (31 for
32 bit values, 63 for 64 bit values). If the shift count is in a register, then
only the low 5 or 6 bits of the register will be used as the shift count. The
Go compiler will add appropriate code to compare the shift value to achieve the
correct result, and the assembler does not add extra checking.

Examples:

	SRAD $8,R3,R4		=>	sradi r4,r3,8
	SRD $8,R3,R4		=>	rldicl r4,r3,56,8
	SLD $8,R3,R4		=>	rldicr r4,r3,8,55
	SRAW $16,R4,R5		=>	srawi r5,r4,16
	SRW $40,R4,R5		=>	rlwinm r5,r4,0,0,31
	SLW $12,R4,R5		=>	rlwinm r5,r4,12,0,19

Some non-simple shifts have operands in the Go assembly which don't map directly
onto operands in the PPC64 assembly. When an operand in a shift instruction in the
Go assembly is a bit mask, that mask is represented as a start and end bit in the
PPC64 assembly instead of a mask. See the ISA for more detail on these types of shifts.
Here are a few examples:

	RLWMI $7,R3,$65535,R6 	=>	rlwimi r6,r3,7,16,31
	RLDMI $0,R4,$7,R6 		=>	rldimi r6,r4,0,61

More recently, Go opcodes were added which map directly onto the PPC64 opcodes. It is
recommended to use the newer opcodes to avoid confusion.

	RLDICL $0,R4,$15,R6		=>	rldicl r6,r4,0,15
	RLDICR $0,R4,$15,R6		=>	rldicr r6.r4,0,15

# Register naming

1. Special register usage in Go asm

The following registers should not be modified by user Go assembler code.

	R0: Go code expects this register to contain the value 0.
	R1: Stack pointer
	R2: TOC pointer when compiled with -shared or -dynlink (a.k.a position independent code)
	R13: TLS pointer
	R30: g (goroutine)

Register names:

	Rn is used for general purpose registers. (0-31)
	Fn is used for floating point registers. (0-31)
	Vn is used for vector registers. Slot 0 of Vn overlaps with Fn. (0-31)
	VSn is used for vector-scalar registers. V0-V31 overlap with VS32-VS63. (0-63)
	CTR represents the count register.
	LR represents the link register.
	CR represents the condition register
	CRn represents a condition register field. (0-7)
	CRnLT represents CR bit 0 of CR field n. (0-7)
	CRnGT represents CR bit 1 of CR field n. (0-7)
	CRnEQ represents CR bit 2 of CR field n. (0-7)
	CRnSO represents CR bit 3 of CR field n. (0-7)

# GOPPC64 >= power10 and its effects on Go asm

When GOPPC64=power10 is used to compile a Go program for ppc64le/linux, MOV*, FMOV*, and ADD
opcodes which would require 2 or more machine instructions to emulate a 32 bit constant, or
symbolic reference are implemented using prefixed instructions.

A user who wishes granular control over the generated machine code is advised to use Go asm
opcodes which explicitly translate to one PPC64 machine instruction. Most common opcodes
are supported.

Some examples of how pseudo-op assembly changes with GOPPC64:

	Go asm                       GOPPC64 <= power9          GOPPC64 >= power10
	MOVD mypackage·foo(SB), R3   addis r2, r3, ...          pld r3, ...
	                             ld    r3, r3, ...

	MOVD 131072(R3), R4          addis r31, r4, 2           pld r4, 131072(r3)
	                             ld    r4, 0(R3)

	ADD $131073, R3              lis  r31, 2                paddi r3, r3, 131073
	                             addi r31, 1
	                             add  r3,r31,r3

	MOVD $131073, R3             lis  r3, 2                 pli r3, 131073
	                             addi r3, 1

	MOVD $mypackage·foo(SB), R3  addis r2, r3, ...          pla r3, ...
	                             addi  r3, r3, ...
*/
package ppc64