fix(loong64): FP immediates through R30 and unsigned branch forms
Assisted-by: GLM 5.3
This commit is contained in:
@@ -347,21 +347,94 @@ TEXT ·sb(SB), NOSPLIT, $0
|
||||
}
|
||||
}
|
||||
|
||||
// TestLOONG64_movImmToFp checks the immediate-to-FP move forms.
|
||||
// TestLOONG64_movImmToFp checks the immediate-to-FP move: MOVW $c, Fd is the
|
||||
// only spelling the toolchain accepts, expanding to ori (or addi.w for the
|
||||
// negative span) into R30 plus movgr2fr.w. The pinned words are the
|
||||
// toolchain's own bytes; the other widths and out-of-range constants are
|
||||
// illegal combinations there and are diagnosed here.
|
||||
func TestLOONG64_movImmToFp(t *testing.T) {
|
||||
fn := firstTextLOONG64(t, `#include "textflag.h"
|
||||
TEXT ·fpmov(SB), NOSPLIT, $0
|
||||
MOVV $0x1, F0
|
||||
MOVW $0x1, F0
|
||||
MOVW $0x2, F4
|
||||
MOVW $-1, F4
|
||||
RET
|
||||
`)
|
||||
code := assembleLOONG64Helper(t, fn)
|
||||
want := []byte{
|
||||
0x00, 0x04, 0x80, 0x03, // ori f0, r0, 1
|
||||
0x04, 0x08, 0x80, 0x03, // ori f4, r0, 2
|
||||
0x1e, 0x04, 0x80, 0x03, // ori r30, r0, 1
|
||||
0xc0, 0xa7, 0x14, 0x01, // movgr2fr.w f0, r30
|
||||
0x1e, 0x08, 0x80, 0x03, // ori r30, r0, 2
|
||||
0xc4, 0xa7, 0x14, 0x01, // movgr2fr.w f4, r30
|
||||
0x1e, 0xfc, 0xbf, 0x02, // addi.w r30, r0, -1
|
||||
0xc4, 0xa7, 0x14, 0x01, // movgr2fr.w f4, r30
|
||||
0x20, 0x00, 0x00, 0x4c, // jirl r0, r1, 0
|
||||
}
|
||||
if !bytes.Equal(code, want) {
|
||||
t.Errorf("code = % x\nwant % x", code, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestLOONG64_movImmToFpErrors checks the immediate-to-FP diagnostics: the
|
||||
// widths the toolchain rejects as illegal combinations, and constants beyond
|
||||
// the 12-bit ori/addi.w span (the toolchain never materialises a wider
|
||||
// constant on this path).
|
||||
func TestLOONG64_movImmToFpErrors(t *testing.T) {
|
||||
cases := []string{
|
||||
"MOVV $1, F0",
|
||||
"MOVF $2, F4",
|
||||
"MOVD $2, F4",
|
||||
"MOVW $100000, F1",
|
||||
"MOVW $-2049, F1",
|
||||
"MOVW $4096, F1",
|
||||
}
|
||||
for _, src := range cases {
|
||||
fn := firstTextLOONG64(t, "#include \"textflag.h\"\nTEXT ·e(SB), NOSPLIT, $0\n\t"+src+"\n\tRET\n")
|
||||
if _, _, _, _, _, err := assembleLOONG64(fn); err == nil {
|
||||
t.Errorf("%s: expected an error, got none", src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestLOONG64_branch16Unsigned pins the unsigned two-operand branches: with
|
||||
// one register BLTU/BGEU keep the register-register form against R0 (never
|
||||
// taken), the toolchain's encoding, where a beqz would test the wrong
|
||||
// condition; the three-operand forms are unchanged.
|
||||
func TestLOONG64_branch16Unsigned(t *testing.T) {
|
||||
fn := firstTextLOONG64(t, `#include "textflag.h"
|
||||
TEXT ·u(SB), NOSPLIT, $0
|
||||
BLTU R4, done
|
||||
BGEU R5, done
|
||||
BLTU R6, R7, done
|
||||
BGEU R8, R9, done
|
||||
done:
|
||||
RET
|
||||
`)
|
||||
code := assembleLOONG64Helper(t, fn)
|
||||
wantWords(t, code,
|
||||
0x68001080, // bltu r4, r0, +4
|
||||
0x6C000CA0, // bgeu r5, r0, +3
|
||||
0x680008C7, // bltu r6, r7, +2
|
||||
0x6C000509, // bgeu r8, r9, +1
|
||||
0x4C000020, // jirl r0, r1, 0
|
||||
)
|
||||
}
|
||||
|
||||
// TestLOONG64_bitFieldRange checks the BSTRINS/BSTRPICK bit-number
|
||||
// validation, mirroring the toolchain's "illegal bit number" rule: 0..31 for
|
||||
// the .w forms, 0..63 for the .d forms, and lsb <= msb.
|
||||
func TestLOONG64_bitFieldRange(t *testing.T) {
|
||||
cases := []string{
|
||||
"BSTRINSW $32, R4, $0, R5",
|
||||
"BSTRPICKW $31, R4, $32, R5",
|
||||
"BSTRINSV $64, R4, $0, R5",
|
||||
"BSTRPICKV $3, R4, $4, R5",
|
||||
"BSTRINSW $-1, R4, $0, R5",
|
||||
}
|
||||
for _, src := range cases {
|
||||
fn := firstTextLOONG64(t, "#include \"textflag.h\"\nTEXT ·e(SB), NOSPLIT, $0\n\t"+src+"\n\tRET\n")
|
||||
if _, _, _, _, _, err := assembleLOONG64(fn); err == nil {
|
||||
t.Errorf("%s: expected an error, got none", src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user