From 434e4caf1b93530b225494ba30d9e39ba15ecf4f Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Thu, 19 Sep 2019 01:01:07 +1000 Subject: [PATCH] cmd/internal/obj/riscv: implement floating point instructions Add support for assembling various single-precision and double-precision floating point instructions. Based on the riscv-go port. Updates #27532 Change-Id: Iac1aec9b03bb6cbf116b229daeef944d4df550fa Reviewed-on: https://go-review.googlesource.com/c/go/+/196839 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot --- src/cmd/asm/internal/asm/testdata/riscvenc.s | 71 +++++++- src/cmd/internal/obj/riscv/anames.go | 4 +- src/cmd/internal/obj/riscv/cpu.go | 4 +- src/cmd/internal/obj/riscv/obj.go | 174 +++++++++++++++++++ 4 files changed, 248 insertions(+), 5 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/riscvenc.s b/src/cmd/asm/internal/asm/testdata/riscvenc.s index 8ee7f18a16..f0d31fda87 100644 --- a/src/cmd/asm/internal/asm/testdata/riscvenc.s +++ b/src/cmd/asm/internal/asm/testdata/riscvenc.s @@ -95,7 +95,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 SB $0, X5, X6 // 23005300 SB $4, X5, X6 // 23025300 - // 5.2: Integer Computational Instructions (RV64I) + // 5.2: Integer Computational Instructions (RV64I) ADDIW $1, X5, X6 // 1b831200 SLLIW $1, X5, X6 // 1b931200 SRLIW $1, X5, X6 // 1bd31200 @@ -132,6 +132,75 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 RDTIME X5 // f32210c0 RDINSTRET X5 // f32220c0 + // 11.5: Single-Precision Load and Store Instructions + FLW $0, X5, F0 // 07a00200 + FLW $4, X5, F0 // 07a04200 + FSW $0, F0, X5 // 27a00200 + FSW $4, F0, X5 // 27a20200 + + // 11.6: Single-Precision Floating-Point Computational Instructions + FADDS F1, F0, F2 // 53011000 + FSUBS F1, F0, F2 // 53011008 + FMULS F1, F0, F2 // 53011010 + FDIVS F1, F0, F2 // 53011018 + FMINS F1, F0, F2 // 53011028 + FMAXS F1, F0, F2 // 53111028 + FSQRTS F0, F1 // d3000058 + + // 11.7: Single-Precision Floating-Point Conversion and Move Instructions + FCVTWS F0, X5 // d31200c0 + FCVTLS F0, X5 // d31220c0 + FCVTSW X5, F0 // 538002d0 + FCVTSL X5, F0 // 538022d0 + FCVTWUS F0, X5 // d31210c0 + FCVTLUS F0, X5 // d31230c0 + FCVTSWU X5, F0 // 538012d0 + FCVTSLU X5, F0 // 538032d0 + FSGNJS F1, F0, F2 // 53011020 + FSGNJNS F1, F0, F2 // 53111020 + FSGNJXS F1, F0, F2 // 53211020 + FMVXS F0, X5 // d30200e0 + FMVSX X5, F0 // 538002f0 + FMVXW F0, X5 // d30200e0 + FMVWX X5, F0 // 538002f0 + + // 11.8: Single-Precision Floating-Point Compare Instructions + FEQS F0, F1, X7 // d3a300a0 + FLTS F0, F1, X7 // d39300a0 + FLES F0, F1, X7 // d38300a0 + + // 12.3: Double-Precision Load and Store Instructions + FLD $0, X5, F0 // 07b00200 + FLD $4, X5, F0 // 07b04200 + FSD $0, F0, X5 // 27b00200 + FSD $4, F0, X5 // 27b20200 + + // 12.4: Double-Precision Floating-Point Computational Instructions + FADDD F1, F0, F2 // 53011002 + FSUBD F1, F0, F2 // 5301100a + FMULD F1, F0, F2 // 53011012 + FDIVD F1, F0, F2 // 5301101a + FMIND F1, F0, F2 // 5301102a + FMAXD F1, F0, F2 // 5311102a + FSQRTD F0, F1 // d300005a + + // 12.5: Double-Precision Floating-Point Conversion and Move Instructions + FCVTWD F0, X5 // d31200c2 + FCVTLD F0, X5 // d31220c2 + FCVTDW X5, F0 // 538002d2 + FCVTDL X5, F0 // 538022d2 + FCVTWUD F0, X5 // d31210c2 + FCVTLUD F0, X5 // d31230c2 + FCVTDWU X5, F0 // 538012d2 + FCVTDLU X5, F0 // 538032d2 + FCVTSD F0, F1 // d3001040 + FCVTDS F0, F1 // d3000042 + FSGNJD F1, F0, F2 // 53011022 + FSGNJND F1, F0, F2 // 53111022 + FSGNJXD F1, F0, F2 // 53211022 + FMVXD F0, X5 // d30200e2 + FMVDX X5, F0 // 538002f2 + // Privileged ISA // 3.2.1: Environment Call and Breakpoint diff --git a/src/cmd/internal/obj/riscv/anames.go b/src/cmd/internal/obj/riscv/anames.go index c034b637bd..7d0e52f91b 100644 --- a/src/cmd/internal/obj/riscv/anames.go +++ b/src/cmd/internal/obj/riscv/anames.go @@ -133,10 +133,10 @@ var Anames = []string{ "FSGNJS", "FSGNJNS", "FSGNJXS", - "FMVSX", "FMVXS", - "FMVWX", + "FMVSX", "FMVXW", + "FMVWX", "FEQS", "FLTS", "FLES", diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index 8c6817284b..0f33716676 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -368,10 +368,10 @@ const ( AFSGNJS AFSGNJNS AFSGNJXS - AFMVSX AFMVXS - AFMVWX + AFMVSX AFMVXW + AFMVWX // 11.8: Single-Precision Floating-Point Compare Instructions AFEQS diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 46188c1e30..578b4e8cce 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -96,6 +96,16 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { if p.To.Type == obj.TYPE_NONE { p.To.Type, p.To.Reg = obj.TYPE_REG, REG_ZERO } + + case AFSQRTS, AFSQRTD: + // These instructions expect a zero (i.e. float register 0) + // to be the second input operand. + p.Reg = p.From.Reg + p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_F0} + + case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD: + // Set the rounding mode in funct3 to round to zero. + p.Scond = 1 } } @@ -159,6 +169,11 @@ func regI(r int16) uint32 { return regVal(r, REG_X0, REG_X31) } +// regF returns a float register. +func regF(r int16) uint32 { + return regVal(r, REG_F0, REG_F31) +} + // regAddr extracts a register from an Addr. func regAddr(a obj.Addr, min, max int16) uint32 { if a.Type != obj.TYPE_REG { @@ -172,6 +187,11 @@ func regIAddr(a obj.Addr) uint32 { return regAddr(a, REG_X0, REG_X31) } +// regFAddr extracts the float register from an Addr. +func regFAddr(a obj.Addr) uint32 { + return regAddr(a, REG_F0, REG_F31) +} + // immFits reports whether immediate value x fits in nbits bits as a // signed integer. func immFits(x int64, nbits uint) bool { @@ -213,6 +233,11 @@ func wantIntReg(p *obj.Prog, pos string, r int16) { wantReg(p, pos, "integer", r, REG_X0, REG_X31) } +// wantFloatReg checks that r is a floating-point register. +func wantFloatReg(p *obj.Prog, pos string, r int16) { + wantReg(p, pos, "float", r, REG_F0, REG_F31) +} + func wantRegAddr(p *obj.Prog, pos string, a *obj.Addr, descr string, min int16, max int16) { if a == nil { p.Ctxt.Diag("%v\texpected register in %s position but got nothing", p, pos) @@ -232,24 +257,68 @@ func wantIntRegAddr(p *obj.Prog, pos string, a *obj.Addr) { wantRegAddr(p, pos, a, "integer", REG_X0, REG_X31) } +// wantFloatRegAddr checks that a contains a floating-point register. +func wantFloatRegAddr(p *obj.Prog, pos string, a *obj.Addr) { + wantRegAddr(p, pos, a, "float", REG_F0, REG_F31) +} + func validateRIII(p *obj.Prog) { wantIntRegAddr(p, "from", &p.From) wantIntReg(p, "reg", p.Reg) wantIntRegAddr(p, "to", &p.To) } +func validateRFFF(p *obj.Prog) { + wantFloatRegAddr(p, "from", &p.From) + wantFloatReg(p, "reg", p.Reg) + wantFloatRegAddr(p, "to", &p.To) +} + +func validateRFFI(p *obj.Prog) { + wantFloatRegAddr(p, "from", &p.From) + wantFloatReg(p, "reg", p.Reg) + wantIntRegAddr(p, "to", &p.To) +} + +func validateRFI(p *obj.Prog) { + wantFloatRegAddr(p, "from", &p.From) + wantIntRegAddr(p, "to", &p.To) +} + +func validateRIF(p *obj.Prog) { + wantIntRegAddr(p, "from", &p.From) + wantFloatRegAddr(p, "to", &p.To) +} + +func validateRFF(p *obj.Prog) { + wantFloatRegAddr(p, "from", &p.From) + wantFloatRegAddr(p, "to", &p.To) +} + func validateII(p *obj.Prog) { wantImm(p, "from", p.From, 12) wantIntReg(p, "reg", p.Reg) wantIntRegAddr(p, "to", &p.To) } +func validateIF(p *obj.Prog) { + wantImm(p, "from", p.From, 12) + wantIntReg(p, "reg", p.Reg) + wantFloatRegAddr(p, "to", &p.To) +} + func validateSI(p *obj.Prog) { wantImm(p, "from", p.From, 12) wantIntReg(p, "reg", p.Reg) wantIntRegAddr(p, "to", &p.To) } +func validateSF(p *obj.Prog) { + wantImm(p, "from", p.From, 12) + wantFloatReg(p, "reg", p.Reg) + wantIntRegAddr(p, "to", &p.To) +} + func validateRaw(p *obj.Prog) { // Treat the raw value specially as a 32-bit unsigned integer. // Nobody wants to enter negative machine code. @@ -282,6 +351,26 @@ func encodeRIII(p *obj.Prog) uint32 { return encodeR(p, regI(p.Reg), regIAddr(p.From), regIAddr(p.To)) } +func encodeRFFF(p *obj.Prog) uint32 { + return encodeR(p, regF(p.Reg), regFAddr(p.From), regFAddr(p.To)) +} + +func encodeRFFI(p *obj.Prog) uint32 { + return encodeR(p, regF(p.Reg), regFAddr(p.From), regIAddr(p.To)) +} + +func encodeRFI(p *obj.Prog) uint32 { + return encodeR(p, regFAddr(p.From), 0, regIAddr(p.To)) +} + +func encodeRIF(p *obj.Prog) uint32 { + return encodeR(p, regIAddr(p.From), 0, regFAddr(p.To)) +} + +func encodeRFF(p *obj.Prog) uint32 { + return encodeR(p, regFAddr(p.From), 0, regFAddr(p.To)) +} + // encodeI encodes an I-type RISC-V instruction. func encodeI(p *obj.Prog, rd uint32) uint32 { imm := immI(p.From, 12) @@ -298,6 +387,10 @@ func encodeII(p *obj.Prog) uint32 { return encodeI(p, regIAddr(p.To)) } +func encodeIF(p *obj.Prog) uint32 { + return encodeI(p, regFAddr(p.To)) +} + // encodeS encodes an S-type RISC-V instruction. func encodeS(p *obj.Prog, rs2 uint32) uint32 { imm := immI(p.From, 12) @@ -313,6 +406,10 @@ func encodeSI(p *obj.Prog) uint32 { return encodeS(p, regI(p.Reg)) } +func encodeSF(p *obj.Prog) uint32 { + return encodeS(p, regF(p.Reg)) +} + // encodeRaw encodes a raw instruction value. func encodeRaw(p *obj.Prog) uint32 { // Treat the raw value specially as a 32-bit unsigned integer. @@ -346,10 +443,17 @@ var ( // indicates an S-type instruction with rs2 being a float register. rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4} + rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4} + rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4} + rFIEncoding = encoding{encode: encodeRFI, validate: validateRFI, length: 4} + rIFEncoding = encoding{encode: encodeRIF, validate: validateRIF, length: 4} + rFFEncoding = encoding{encode: encodeRFF, validate: validateRFF, length: 4} iIEncoding = encoding{encode: encodeII, validate: validateII, length: 4} + iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4} sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4} + sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4} // rawEncoding encodes a raw instruction byte sequence. rawEncoding = encoding{encode: encodeRaw, validate: validateRaw, length: 4} @@ -436,6 +540,76 @@ var encodingForAs = [ALAST & obj.AMask]encoding{ ARDTIME & obj.AMask: iIEncoding, ARDINSTRET & obj.AMask: iIEncoding, + // 11.5: Single-Precision Load and Store Instructions + AFLW & obj.AMask: iFEncoding, + AFSW & obj.AMask: sFEncoding, + + // 11.6: Single-Precision Floating-Point Computational Instructions + AFADDS & obj.AMask: rFFFEncoding, + AFSUBS & obj.AMask: rFFFEncoding, + AFMULS & obj.AMask: rFFFEncoding, + AFDIVS & obj.AMask: rFFFEncoding, + AFMINS & obj.AMask: rFFFEncoding, + AFMAXS & obj.AMask: rFFFEncoding, + AFSQRTS & obj.AMask: rFFFEncoding, + + // 11.7: Single-Precision Floating-Point Conversion and Move Instructions + AFCVTWS & obj.AMask: rFIEncoding, + AFCVTLS & obj.AMask: rFIEncoding, + AFCVTSW & obj.AMask: rIFEncoding, + AFCVTSL & obj.AMask: rIFEncoding, + AFCVTWUS & obj.AMask: rFIEncoding, + AFCVTLUS & obj.AMask: rFIEncoding, + AFCVTSWU & obj.AMask: rIFEncoding, + AFCVTSLU & obj.AMask: rIFEncoding, + AFSGNJS & obj.AMask: rFFFEncoding, + AFSGNJNS & obj.AMask: rFFFEncoding, + AFSGNJXS & obj.AMask: rFFFEncoding, + AFMVXS & obj.AMask: rFIEncoding, + AFMVSX & obj.AMask: rIFEncoding, + AFMVXW & obj.AMask: rFIEncoding, + AFMVWX & obj.AMask: rIFEncoding, + + // 11.8: Single-Precision Floating-Point Compare Instructions + AFEQS & obj.AMask: rFFIEncoding, + AFLTS & obj.AMask: rFFIEncoding, + AFLES & obj.AMask: rFFIEncoding, + + // 12.3: Double-Precision Load and Store Instructions + AFLD & obj.AMask: iFEncoding, + AFSD & obj.AMask: sFEncoding, + + // 12.4: Double-Precision Floating-Point Computational Instructions + AFADDD & obj.AMask: rFFFEncoding, + AFSUBD & obj.AMask: rFFFEncoding, + AFMULD & obj.AMask: rFFFEncoding, + AFDIVD & obj.AMask: rFFFEncoding, + AFMIND & obj.AMask: rFFFEncoding, + AFMAXD & obj.AMask: rFFFEncoding, + AFSQRTD & obj.AMask: rFFFEncoding, + + // 12.5: Double-Precision Floating-Point Conversion and Move Instructions + AFCVTWD & obj.AMask: rFIEncoding, + AFCVTLD & obj.AMask: rFIEncoding, + AFCVTDW & obj.AMask: rIFEncoding, + AFCVTDL & obj.AMask: rIFEncoding, + AFCVTWUD & obj.AMask: rFIEncoding, + AFCVTLUD & obj.AMask: rFIEncoding, + AFCVTDWU & obj.AMask: rIFEncoding, + AFCVTDLU & obj.AMask: rIFEncoding, + AFCVTSD & obj.AMask: rFFEncoding, + AFCVTDS & obj.AMask: rFFEncoding, + AFSGNJD & obj.AMask: rFFFEncoding, + AFSGNJND & obj.AMask: rFFFEncoding, + AFSGNJXD & obj.AMask: rFFFEncoding, + AFMVXD & obj.AMask: rFIEncoding, + AFMVDX & obj.AMask: rIFEncoding, + + // 12.6: Double-Precision Floating-Point Compare Instructions + AFEQD & obj.AMask: rFFIEncoding, + AFLTD & obj.AMask: rFFIEncoding, + AFLED & obj.AMask: rFFIEncoding, + // Privileged ISA // 3.2.1: Environment Call and Breakpoint -- 2.50.0