{ARDTIMED, C_NONE, C_NONE, C_NONE, C_REG, C_REG, 62, 4, 0, 0},
{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, C_NONE, 49, 4, 0, 0},
+ {obj.APCALIGN, C_SCON, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0},
{obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, C_NONE, 0, 0, 0, 0},
{obj.APCDATA, C_DCON, C_NONE, C_NONE, C_DCON, C_NONE, 0, 0, 0, 0},
{obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, C_NONE, 0, 0, 0, 0},
{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0},
}
+// pcAlignPadLength returns the number of bytes required to align pc to alignedValue,
+// reporting an error if alignedValue is not a power of two or is out of range.
+func pcAlignPadLength(ctxt *obj.Link, pc int64, alignedValue int64) int {
+ if !((alignedValue&(alignedValue-1) == 0) && 8 <= alignedValue && alignedValue <= 2048) {
+ ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", alignedValue)
+ }
+ return int(-pc & (alignedValue - 1))
+}
+
var oprange [ALAST & obj.AMask][]Optab
var xcmp [C_NCLASS][C_NCLASS]bool
o = c.oplook(p)
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+ switch p.As {
+ case obj.APCALIGN:
+ alignedValue := p.From.Offset
+ m = pcAlignPadLength(ctxt, pc, alignedValue)
+ // Update the current text symbol alignment value.
+ if int32(alignedValue) > cursym.Func().Align {
+ cursym.Func().Align = int32(alignedValue)
+ }
+ break
+ case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
+ continue
+ default:
c.ctxt.Diag("zero-width instruction\n%v", p)
}
- continue
}
pc += int64(m)
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+ switch p.As {
+ case obj.APCALIGN:
+ alignedValue := p.From.Offset
+ m = pcAlignPadLength(ctxt, pc, alignedValue)
+ break
+ case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
+ continue
+ default:
c.ctxt.Diag("zero-width instruction\n%v", p)
}
- continue
}
pc += int64(m)
if int(o.size) > 4*len(out) {
log.Fatalf("out array in span0 is too small, need at least %d for %v", o.size/4, p)
}
+ if p.As == obj.APCALIGN {
+ alignedValue := p.From.Offset
+ v := pcAlignPadLength(c.ctxt, p.Pc, alignedValue)
+ for i = 0; i < int32(v/4); i++ {
+ // emit ANOOP instruction by the padding size
+ c.ctxt.Arch.ByteOrder.PutUint32(bp, c.oprrr(ANOOP))
+ bp = bp[4:]
+ }
+ continue
+ }
c.asmout(p, o, out[:])
for i = 0; i < int32(o.size/4); i++ {
c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
obj.ATEXT,
obj.AUNDEF,
obj.AFUNCDATA,
+ obj.APCALIGN,
obj.APCDATA,
obj.ADUFFZERO,
obj.ADUFFCOPY:
}
`
-const testFuncAlignAsmSrc = `
+var testFuncAlignAsmSources = map[string]string{
+ "arm64": `
#include "textflag.h"
TEXT ·alignPc(SB),NOSPLIT, $0-0
GLOBL ·alignPcFnAddr(SB),RODATA,$8
DATA ·alignPcFnAddr(SB)/8,$·alignPc(SB)
-`
+`,
+ "loong64": `
+#include "textflag.h"
+
+TEXT ·alignPc(SB),NOSPLIT, $0-0
+ MOVV $2, R4
+ PCALIGN $512
+ MOVV $3, R5
+ RET
+
+GLOBL ·alignPcFnAddr(SB),RODATA,$8
+DATA ·alignPcFnAddr(SB)/8,$·alignPc(SB)
+`,
+}
// TestFuncAlign verifies that the address of a function can be aligned
-// with a specific value on arm64.
+// with a specific value on arm64 and loong64.
func TestFuncAlign(t *testing.T) {
- if runtime.GOARCH != "arm64" || runtime.GOOS != "linux" {
- t.Skip("skipping on non-linux/arm64 platform")
+ testFuncAlignAsmSrc := testFuncAlignAsmSources[runtime.GOARCH]
+ if len(testFuncAlignAsmSrc) == 0 || runtime.GOOS != "linux" {
+ t.Skip("skipping on non-linux/{arm64,loong64} platform")
}
testenv.MustHaveGoBuild(t)