diff --git a/src/cmd/asm/internal/asm/testdata/riscv64error.s b/src/cmd/asm/internal/asm/testdata/riscv64error.s index cdb8a028bd..2dc9db3fb1 100644 --- a/src/cmd/asm/internal/asm/testdata/riscv64error.s +++ b/src/cmd/asm/internal/asm/testdata/riscv64error.s @@ -38,5 +38,8 @@ TEXT errors(SB),$0 SLLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31" SRLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31" SRAIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31" - + SD X5, 4294967296(X6) // ERROR "constant 4294967296 too large" + SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1" + SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1" + FNES F1, (X5) // ERROR "needs an integer register output" RET diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 4ff1d910ce..93bda45096 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -1043,154 +1043,154 @@ func immI(as obj.As, imm int64, nbits uint) uint32 { return uint32(imm) } -func wantImmI(ctxt *obj.Link, as obj.As, imm int64, nbits uint) { +func wantImmI(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) { if err := immIFits(imm, nbits); err != nil { - ctxt.Diag("%v: %v", as, err) + ctxt.Diag("%v: %v", ins, err) } } -func wantReg(ctxt *obj.Link, as obj.As, pos string, descr string, r, min, max uint32) { +func wantReg(ctxt *obj.Link, ins *instruction, pos string, descr string, r, min, max uint32) { if r < min || r > max { var suffix string if r != obj.REG_NONE { suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r))) } - ctxt.Diag("%v: expected %s register in %s position%s", as, descr, pos, suffix) + ctxt.Diag("%v: expected %s register in %s position%s", ins, descr, pos, suffix) } } -func wantNoneReg(ctxt *obj.Link, as obj.As, pos string, r uint32) { +func wantNoneReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) { if r != obj.REG_NONE { - ctxt.Diag("%v: expected no register in %s but got register %s", as, pos, RegName(int(r))) + ctxt.Diag("%v: expected no register in %s but got register %s", ins, pos, RegName(int(r))) } } // wantIntReg checks that r is an integer register. -func wantIntReg(ctxt *obj.Link, as obj.As, pos string, r uint32) { - wantReg(ctxt, as, pos, "integer", r, REG_X0, REG_X31) +func wantIntReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) { + wantReg(ctxt, ins, pos, "integer", r, REG_X0, REG_X31) } // wantFloatReg checks that r is a floating-point register. -func wantFloatReg(ctxt *obj.Link, as obj.As, pos string, r uint32) { - wantReg(ctxt, as, pos, "float", r, REG_F0, REG_F31) +func wantFloatReg(ctxt *obj.Link, ins *instruction, pos string, r uint32) { + wantReg(ctxt, ins, pos, "float", r, REG_F0, REG_F31) } // wantEvenOffset checks that the offset is a multiple of two. -func wantEvenOffset(ctxt *obj.Link, as obj.As, offset int64) { +func wantEvenOffset(ctxt *obj.Link, ins *instruction, offset int64) { if err := immEven(offset); err != nil { - ctxt.Diag("%v: %v", as, err) + ctxt.Diag("%v: %v", ins, err) } } func validateRIII(ctxt *obj.Link, ins *instruction) { - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantIntReg(ctxt, ins.as, "rs1", ins.rs1) - wantIntReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantIntReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateRFFF(ctxt *obj.Link, ins *instruction) { - wantFloatReg(ctxt, ins.as, "rd", ins.rd) - wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) - wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantFloatReg(ctxt, ins, "rd", ins.rd) + wantFloatReg(ctxt, ins, "rs1", ins.rs1) + wantFloatReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateRFFFF(ctxt *obj.Link, ins *instruction) { - wantFloatReg(ctxt, ins.as, "rd", ins.rd) - wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) - wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) - wantFloatReg(ctxt, ins.as, "rs3", ins.rs3) + wantFloatReg(ctxt, ins, "rd", ins.rd) + wantFloatReg(ctxt, ins, "rs1", ins.rs1) + wantFloatReg(ctxt, ins, "rs2", ins.rs2) + wantFloatReg(ctxt, ins, "rs3", ins.rs3) } func validateRFFI(ctxt *obj.Link, ins *instruction) { - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) - wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantFloatReg(ctxt, ins, "rs1", ins.rs1) + wantFloatReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateRFI(ctxt *obj.Link, ins *instruction) { - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) - wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantNoneReg(ctxt, ins, "rs1", ins.rs1) + wantFloatReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateRIF(ctxt *obj.Link, ins *instruction) { - wantFloatReg(ctxt, ins.as, "rd", ins.rd) - wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) - wantIntReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantFloatReg(ctxt, ins, "rd", ins.rd) + wantNoneReg(ctxt, ins, "rs1", ins.rs1) + wantIntReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateRFF(ctxt *obj.Link, ins *instruction) { - wantFloatReg(ctxt, ins.as, "rd", ins.rd) - wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) - wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantFloatReg(ctxt, ins, "rd", ins.rd) + wantNoneReg(ctxt, ins, "rs1", ins.rs1) + wantFloatReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateII(ctxt *obj.Link, ins *instruction) { - wantImmI(ctxt, ins.as, ins.imm, 12) - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantIntReg(ctxt, ins.as, "rs1", ins.rs1) - wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantImmI(ctxt, ins, ins.imm, 12) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateIF(ctxt *obj.Link, ins *instruction) { - wantImmI(ctxt, ins.as, ins.imm, 12) - wantFloatReg(ctxt, ins.as, "rd", ins.rd) - wantIntReg(ctxt, ins.as, "rs1", ins.rs1) - wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantImmI(ctxt, ins, ins.imm, 12) + wantFloatReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateSI(ctxt *obj.Link, ins *instruction) { - wantImmI(ctxt, ins.as, ins.imm, 12) - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantIntReg(ctxt, ins.as, "rs1", ins.rs1) - wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantImmI(ctxt, ins, ins.imm, 12) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateSF(ctxt *obj.Link, ins *instruction) { - wantImmI(ctxt, ins.as, ins.imm, 12) - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) - wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantImmI(ctxt, ins, ins.imm, 12) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantFloatReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateB(ctxt *obj.Link, ins *instruction) { // Offsets are multiples of two, so accept 13 bit immediates for the // 12 bit slot. We implicitly drop the least significant bit in encodeB. - wantEvenOffset(ctxt, ins.as, ins.imm) - wantImmI(ctxt, ins.as, ins.imm, 13) - wantNoneReg(ctxt, ins.as, "rd", ins.rd) - wantIntReg(ctxt, ins.as, "rs1", ins.rs1) - wantIntReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantEvenOffset(ctxt, ins, ins.imm) + wantImmI(ctxt, ins, ins.imm, 13) + wantNoneReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantIntReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateU(ctxt *obj.Link, ins *instruction) { - wantImmI(ctxt, ins.as, ins.imm, 20) - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) - wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantImmI(ctxt, ins, ins.imm, 20) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantNoneReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateJ(ctxt *obj.Link, ins *instruction) { // Offsets are multiples of two, so accept 21 bit immediates for the // 20 bit slot. We implicitly drop the least significant bit in encodeJ. - wantEvenOffset(ctxt, ins.as, ins.imm) - wantImmI(ctxt, ins.as, ins.imm, 21) - wantIntReg(ctxt, ins.as, "rd", ins.rd) - wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) - wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) - wantNoneReg(ctxt, ins.as, "rs3", ins.rs3) + wantEvenOffset(ctxt, ins, ins.imm) + wantImmI(ctxt, ins, ins.imm, 21) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantNoneReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) } func validateRaw(ctxt *obj.Link, ins *instruction) { @@ -1727,14 +1727,26 @@ func encodingForAs(as obj.As) (encoding, error) { } type instruction struct { - as obj.As // Assembler opcode - rd uint32 // Destination register - rs1 uint32 // Source register 1 - rs2 uint32 // Source register 2 - rs3 uint32 // Source register 3 - imm int64 // Immediate - funct3 uint32 // Function 3 - funct7 uint32 // Function 7 (or Function 2) + p *obj.Prog // Prog that instruction is for + as obj.As // Assembler opcode + rd uint32 // Destination register + rs1 uint32 // Source register 1 + rs2 uint32 // Source register 2 + rs3 uint32 // Source register 3 + imm int64 // Immediate + funct3 uint32 // Function 3 + funct7 uint32 // Function 7 (or Function 2) +} + +func (ins *instruction) String() string { + if ins.p == nil { + return ins.as.String() + } + var suffix string + if ins.p.As != ins.as { + suffix = fmt.Sprintf(" (%v)", ins.as) + } + return fmt.Sprintf("%v%v", ins.p, suffix) } func (ins *instruction) encode() (uint32, error) { @@ -2200,13 +2212,13 @@ func instructionsForProg(p *obj.Prog) []*instruction { ins.imm = p.To.Offset case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD: - return instructionsForMOV(p) + inss = instructionsForMOV(p) case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD: - return instructionsForLoad(p, ins.as, p.From.Reg) + inss = instructionsForLoad(p, ins.as, p.From.Reg) case ASW, ASH, ASB, ASD, AFSW, AFSD: - return instructionsForStore(p, ins.as, p.To.Reg) + inss = instructionsForStore(p, ins.as, p.To.Reg) case ALRW, ALRD: // Set aq to use acquire access ordering @@ -2246,7 +2258,7 @@ func instructionsForProg(p *obj.Prog) []*instruction { case AFNES, AFNED: // Replace FNE[SD] with FEQ[SD] and NOT. if p.To.Type != obj.TYPE_REG { - p.Ctxt.Diag("%v needs an integer register output", ins.as) + p.Ctxt.Diag("%v needs an integer register output", p) return nil } if ins.as == AFNES { @@ -2335,6 +2347,11 @@ func instructionsForProg(p *obj.Prog) []*instruction { p.Ctxt.Diag("%v: shift amount out of range 0 to 31", p) } } + + for _, ins := range inss { + ins.p = p + } + return inss } @@ -2346,6 +2363,12 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ctxt.Retpoline = false // don't keep printing } + // If errors were encountered during preprocess/validation, proceeding + // and attempting to encode said instructions will only lead to panics. + if ctxt.Errors > 0 { + return + } + for p := cursym.Func().Text; p != nil; p = p.Link { switch p.As { case AJAL: