mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: implement compiler for riscv64
Based on riscv-go port. Updates #27532 Change-Id: Ia329daa243db63ff334053b8807ea96b97ce3acf Reviewed-on: https://go-review.googlesource.com/c/go/+/204631 Run-TryBot: Joel Sing <joel@sing.id.au> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
91d75f4e4c
commit
98d2717499
17 changed files with 8511 additions and 12 deletions
312
src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
Normal file
312
src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import "cmd/internal/obj/riscv"
|
||||
|
||||
// Suffixes encode the bit width of various instructions:
|
||||
//
|
||||
// D (double word) = 64 bit int
|
||||
// W (word) = 32 bit int
|
||||
// H (half word) = 16 bit int
|
||||
// B (byte) = 8 bit int
|
||||
// S (single) = 32 bit float
|
||||
// D (double) = 64 bit float
|
||||
// L = 64 bit int, used when the opcode starts with F
|
||||
|
||||
func init() {
|
||||
var regNamesRISCV64 []string
|
||||
var gpMask, fpMask, gpspMask, gpspsbMask regMask
|
||||
regNamed := make(map[string]regMask)
|
||||
|
||||
// Build the list of register names, creating an appropriately indexed
|
||||
// regMask for the gp and fp registers as we go.
|
||||
//
|
||||
// If name is specified, use it rather than the riscv reg number.
|
||||
addreg := func(r int, name string) regMask {
|
||||
mask := regMask(1) << uint(len(regNamesRISCV64))
|
||||
if name == "" {
|
||||
name = riscv.RegName(r)
|
||||
}
|
||||
regNamesRISCV64 = append(regNamesRISCV64, name)
|
||||
regNamed[name] = mask
|
||||
return mask
|
||||
}
|
||||
|
||||
// General purpose registers.
|
||||
for r := riscv.REG_X0; r <= riscv.REG_X31; r++ {
|
||||
if r == riscv.REG_LR {
|
||||
// LR is not used by regalloc, so we skip it to leave
|
||||
// room for pseudo-register SB.
|
||||
continue
|
||||
}
|
||||
|
||||
mask := addreg(r, "")
|
||||
|
||||
// Add general purpose registers to gpMask.
|
||||
switch r {
|
||||
// ZERO, g, and TMP are not in any gp mask.
|
||||
case riscv.REG_ZERO, riscv.REG_G, riscv.REG_TMP:
|
||||
case riscv.REG_SP:
|
||||
gpspMask |= mask
|
||||
gpspsbMask |= mask
|
||||
default:
|
||||
gpMask |= mask
|
||||
gpspMask |= mask
|
||||
gpspsbMask |= mask
|
||||
}
|
||||
}
|
||||
|
||||
// Floating pointer registers.
|
||||
for r := riscv.REG_F0; r <= riscv.REG_F31; r++ {
|
||||
mask := addreg(r, "")
|
||||
fpMask |= mask
|
||||
}
|
||||
|
||||
// Pseudo-register: SB
|
||||
mask := addreg(-1, "SB")
|
||||
gpspsbMask |= mask
|
||||
|
||||
if len(regNamesRISCV64) > 64 {
|
||||
// regMask is only 64 bits.
|
||||
panic("Too many RISCV64 registers")
|
||||
}
|
||||
|
||||
regCtxt := regNamed["X20"]
|
||||
callerSave := gpMask | fpMask | regNamed["g"]
|
||||
|
||||
var (
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbMask, gpspMask, 0}} // SB in first input so we can load from a global, but not in second to avoid using SB as a temporary register
|
||||
gp01 = regInfo{outputs: []regMask{gpMask}}
|
||||
gp11 = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}
|
||||
gp21 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}}
|
||||
gp11sb = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}}
|
||||
|
||||
fp11 = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{fpMask}}
|
||||
fp21 = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{fpMask}}
|
||||
gpfp = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{fpMask}}
|
||||
fpgp = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{gpMask}}
|
||||
fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, 0}}
|
||||
fpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{fpMask}}
|
||||
fp2gp = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{gpMask}}
|
||||
|
||||
call = regInfo{clobbers: callerSave}
|
||||
callClosure = regInfo{inputs: []regMask{gpspMask, regCtxt, 0}, clobbers: callerSave}
|
||||
callInter = regInfo{inputs: []regMask{gpMask}, clobbers: callerSave}
|
||||
)
|
||||
|
||||
RISCV64ops := []opData{
|
||||
{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDI", argLength: 1, reg: gp11sb, asm: "ADDI", aux: "Int64"}, // arg0 + auxint
|
||||
{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1
|
||||
|
||||
// M extension. H means high (i.e., it returns the top bits of
|
||||
// the result). U means unsigned. W means word (i.e., 32-bit).
|
||||
{name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, typ: "Int64"}, // arg0 * arg1
|
||||
{name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, typ: "Int32"},
|
||||
{name: "MULH", argLength: 2, reg: gp21, asm: "MULH", commutative: true, typ: "Int64"},
|
||||
{name: "MULHU", argLength: 2, reg: gp21, asm: "MULHU", commutative: true, typ: "UInt64"},
|
||||
{name: "DIV", argLength: 2, reg: gp21, asm: "DIV", typ: "Int64"}, // arg0 / arg1
|
||||
{name: "DIVU", argLength: 2, reg: gp21, asm: "DIVU", typ: "UInt64"},
|
||||
{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},
|
||||
{name: "DIVUW", argLength: 2, reg: gp21, asm: "DIVUW", typ: "UInt32"},
|
||||
{name: "REM", argLength: 2, reg: gp21, asm: "REM", typ: "Int64"}, // arg0 % arg1
|
||||
{name: "REMU", argLength: 2, reg: gp21, asm: "REMU", typ: "UInt64"},
|
||||
{name: "REMW", argLength: 2, reg: gp21, asm: "REMW", typ: "Int32"},
|
||||
{name: "REMUW", argLength: 2, reg: gp21, asm: "REMUW", typ: "UInt32"},
|
||||
|
||||
{name: "MOVaddr", argLength: 1, reg: gp11sb, asm: "MOV", aux: "SymOff", rematerializeable: true, symEffect: "RdWr"}, // arg0 + auxint + offset encoded in aux
|
||||
// auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
|
||||
|
||||
{name: "MOVBconst", reg: gp01, asm: "MOV", typ: "UInt8", aux: "Int8", rematerializeable: true}, // 8 low bits of auxint
|
||||
{name: "MOVHconst", reg: gp01, asm: "MOV", typ: "UInt16", aux: "Int16", rematerializeable: true}, // 16 low bits of auxint
|
||||
{name: "MOVWconst", reg: gp01, asm: "MOV", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint
|
||||
{name: "MOVDconst", reg: gp01, asm: "MOV", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
|
||||
|
||||
// Loads: load <size> bits from arg0+auxint+aux and extend to 64 bits; arg1=mem
|
||||
{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // 8 bits, sign extend
|
||||
{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // 16 bits, sign extend
|
||||
{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // 32 bits, sign extend
|
||||
{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOV", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, // 64 bits
|
||||
{name: "MOVBUload", argLength: 2, reg: gpload, asm: "MOVBU", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // 8 bits, zero extend
|
||||
{name: "MOVHUload", argLength: 2, reg: gpload, asm: "MOVHU", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // 16 bits, zero extend
|
||||
{name: "MOVWUload", argLength: 2, reg: gpload, asm: "MOVWU", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // 32 bits, zero extend
|
||||
|
||||
// Stores: store <size> lowest bits in arg1 to arg0+auxint+aux; arg2=mem
|
||||
{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 8 bits
|
||||
{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16 bits
|
||||
{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32 bits
|
||||
{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOV", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 64 bits
|
||||
|
||||
// Shift ops
|
||||
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << aux1
|
||||
{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> aux1, signed
|
||||
{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> aux1, unsigned
|
||||
{name: "SLLI", argLength: 1, reg: gp11, asm: "SLLI", aux: "Int64"}, // arg0 << auxint
|
||||
{name: "SRAI", argLength: 1, reg: gp11, asm: "SRAI", aux: "Int64"}, // arg0 >> auxint, signed
|
||||
{name: "SRLI", argLength: 1, reg: gp11, asm: "SRLI", aux: "Int64"}, // arg0 >> auxint, unsigned
|
||||
|
||||
// Bitwise ops
|
||||
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1
|
||||
{name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"}, // arg0 ^ auxint
|
||||
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
|
||||
{name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"}, // arg0 | auxint
|
||||
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
|
||||
{name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"}, // arg0 & auxint
|
||||
|
||||
// Generate boolean values
|
||||
{name: "SEQZ", argLength: 1, reg: gp11, asm: "SEQZ"}, // arg0 == 0, result is 0 or 1
|
||||
{name: "SNEZ", argLength: 1, reg: gp11, asm: "SNEZ"}, // arg0 != 0, result is 0 or 1
|
||||
{name: "SLT", argLength: 2, reg: gp21, asm: "SLT"}, // arg0 < arg1, result is 0 or 1
|
||||
{name: "SLTI", argLength: 1, reg: gp11, asm: "SLTI", aux: "Int64"}, // arg0 < auxint, result is 0 or 1
|
||||
{name: "SLTU", argLength: 2, reg: gp21, asm: "SLTU"}, // arg0 < arg1, unsigned, result is 0 or 1
|
||||
{name: "SLTIU", argLength: 1, reg: gp11, asm: "SLTIU", aux: "Int64"}, // arg0 < auxint, unsigned, result is 0 or 1
|
||||
|
||||
// MOVconvert converts between pointers and integers.
|
||||
// We have a special op for this so as to not confuse GC
|
||||
// (particularly stack maps). It takes a memory arg so it
|
||||
// gets correctly ordered with respect to GC safepoints.
|
||||
{name: "MOVconvert", argLength: 2, reg: gp11, asm: "MOV"}, // arg0, but converted to int/ptr as appropriate; arg1=mem
|
||||
|
||||
// Calls
|
||||
{name: "CALLstatic", argLength: 1, reg: call, aux: "SymOff", call: true, symEffect: "None"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
|
||||
{name: "CALLclosure", argLength: 3, reg: callClosure, aux: "Int64", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||
{name: "CALLinter", argLength: 2, reg: callInter, aux: "Int64", call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||
|
||||
// Generic moves and zeros
|
||||
|
||||
// general unaligned zeroing
|
||||
// arg0 = address of memory to zero (in X5, changed as side effect)
|
||||
// arg1 = address of the last element to zero (inclusive)
|
||||
// arg2 = mem
|
||||
// auxint = element size
|
||||
// returns mem
|
||||
// mov ZERO, (X5)
|
||||
// ADD $sz, X5
|
||||
// BGEU Rarg1, X5, -2(PC)
|
||||
{
|
||||
name: "LoweredZero",
|
||||
aux: "Int64",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{regNamed["X5"], gpMask},
|
||||
clobbers: regNamed["X5"],
|
||||
},
|
||||
typ: "Mem",
|
||||
faultOnNilArg0: true,
|
||||
},
|
||||
|
||||
// general unaligned move
|
||||
// arg0 = address of dst memory (in X5, changed as side effect)
|
||||
// arg1 = address of src memory (in X6, changed as side effect)
|
||||
// arg2 = address of the last element of src (can't be X7 as we clobber it before using arg2)
|
||||
// arg3 = mem
|
||||
// auxint = alignment
|
||||
// clobbers X7 as a tmp register.
|
||||
// returns mem
|
||||
// mov (X6), X7
|
||||
// mov X7, (X5)
|
||||
// ADD $sz, X5
|
||||
// ADD $sz, X6
|
||||
// BGEU Rarg2, X5, -4(PC)
|
||||
{
|
||||
name: "LoweredMove",
|
||||
aux: "Int64",
|
||||
argLength: 4,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{regNamed["X5"], regNamed["X6"], gpMask &^ regNamed["X7"]},
|
||||
clobbers: regNamed["X5"] | regNamed["X6"] | regNamed["X7"],
|
||||
},
|
||||
typ: "Mem",
|
||||
faultOnNilArg0: true,
|
||||
faultOnNilArg1: true,
|
||||
},
|
||||
|
||||
// Lowering pass-throughs
|
||||
{name: "LoweredNilCheck", argLength: 2, faultOnNilArg0: true, nilCheck: true, reg: regInfo{inputs: []regMask{gpspMask}}}, // arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
|
||||
{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{regCtxt}}}, // scheduler ensures only at beginning of entry block
|
||||
|
||||
// LoweredGetCallerSP returns the SP of the caller of the current function.
|
||||
{name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
|
||||
|
||||
// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
|
||||
// I.e., if f calls g "calls" getcallerpc,
|
||||
// the result should be the PC within f that g will return to.
|
||||
// See runtime/stubs.go for a more detailed discussion.
|
||||
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
|
||||
|
||||
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
|
||||
// It saves all GP registers if necessary,
|
||||
// but clobbers RA (LR) because it's a call
|
||||
// and T6 (REG_TMP).
|
||||
{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}, clobbers: (callerSave &^ (gpMask | regNamed["g"])) | regNamed["X1"]}, clobberFlags: true, aux: "Sym", symEffect: "None"},
|
||||
|
||||
// There are three of these functions so that they can have three different register inputs.
|
||||
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
|
||||
// default registers to match so we don't need to copy registers around unnecessarily.
|
||||
{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X7"], regNamed["X28"]}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
|
||||
{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X6"], regNamed["X7"]}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
|
||||
{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}}, typ: "Mem"}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
|
||||
|
||||
// F extension.
|
||||
{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true, typ: "Float32"}, // arg0 + arg1
|
||||
{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS", commutative: false, typ: "Float32"}, // arg0 - arg1
|
||||
{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, typ: "Float32"}, // arg0 * arg1
|
||||
{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", commutative: false, typ: "Float32"}, // arg0 / arg1
|
||||
{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS", typ: "Float32"}, // sqrt(arg0)
|
||||
{name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS", typ: "Float32"}, // -arg0
|
||||
{name: "FMVSX", argLength: 1, reg: gpfp, asm: "FMVSX", typ: "Float32"}, // reinterpret arg0 as float
|
||||
{name: "FCVTSW", argLength: 1, reg: gpfp, asm: "FCVTSW", typ: "Float32"}, // float32(low 32 bits of arg0)
|
||||
{name: "FCVTSL", argLength: 1, reg: gpfp, asm: "FCVTSL", typ: "Float32"}, // float32(arg0)
|
||||
{name: "FCVTWS", argLength: 1, reg: fpgp, asm: "FCVTWS", typ: "Int32"}, // int32(arg0)
|
||||
{name: "FCVTLS", argLength: 1, reg: fpgp, asm: "FCVTLS", typ: "Int64"}, // int64(arg0)
|
||||
{name: "FMOVWload", argLength: 2, reg: fpload, asm: "MOVF", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load float32 from arg0+auxint+aux
|
||||
{name: "FMOVWstore", argLength: 3, reg: fpstore, asm: "MOVF", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store float32 to arg0+auxint+aux
|
||||
{name: "FEQS", argLength: 2, reg: fp2gp, asm: "FEQS", commutative: true}, // arg0 == arg1
|
||||
{name: "FNES", argLength: 2, reg: fp2gp, asm: "FNES", commutative: true}, // arg0 != arg1
|
||||
{name: "FLTS", argLength: 2, reg: fp2gp, asm: "FLTS"}, // arg0 < arg1
|
||||
{name: "FLES", argLength: 2, reg: fp2gp, asm: "FLES"}, // arg0 <= arg1
|
||||
|
||||
// D extension.
|
||||
{name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true, typ: "Float64"}, // arg0 + arg1
|
||||
{name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD", commutative: false, typ: "Float64"}, // arg0 - arg1
|
||||
{name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true, typ: "Float64"}, // arg0 * arg1
|
||||
{name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD", commutative: false, typ: "Float64"}, // arg0 / arg1
|
||||
{name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD", typ: "Float64"}, // sqrt(arg0)
|
||||
{name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD", typ: "Float64"}, // -arg0
|
||||
{name: "FMVDX", argLength: 1, reg: gpfp, asm: "FMVDX", typ: "Float64"}, // reinterpret arg0 as float
|
||||
{name: "FCVTDW", argLength: 1, reg: gpfp, asm: "FCVTDW", typ: "Float64"}, // float64(low 32 bits of arg0)
|
||||
{name: "FCVTDL", argLength: 1, reg: gpfp, asm: "FCVTDL", typ: "Float64"}, // float64(arg0)
|
||||
{name: "FCVTWD", argLength: 1, reg: fpgp, asm: "FCVTWD", typ: "Int32"}, // int32(arg0)
|
||||
{name: "FCVTLD", argLength: 1, reg: fpgp, asm: "FCVTLD", typ: "Int64"}, // int64(arg0)
|
||||
{name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", typ: "Float64"}, // float64(arg0)
|
||||
{name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", typ: "Float32"}, // float32(arg0)
|
||||
{name: "FMOVDload", argLength: 2, reg: fpload, asm: "MOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load float64 from arg0+auxint+aux
|
||||
{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store float6 to arg0+auxint+aux
|
||||
{name: "FEQD", argLength: 2, reg: fp2gp, asm: "FEQD", commutative: true}, // arg0 == arg1
|
||||
{name: "FNED", argLength: 2, reg: fp2gp, asm: "FNED", commutative: true}, // arg0 != arg1
|
||||
{name: "FLTD", argLength: 2, reg: fp2gp, asm: "FLTD"}, // arg0 < arg1
|
||||
{name: "FLED", argLength: 2, reg: fp2gp, asm: "FLED"}, // arg0 <= arg1
|
||||
}
|
||||
|
||||
RISCV64blocks := []blockData{
|
||||
{name: "BNE", controls: 1}, // Control != 0 (take a register)
|
||||
}
|
||||
|
||||
archs = append(archs, arch{
|
||||
name: "RISCV64",
|
||||
pkg: "cmd/internal/obj/riscv",
|
||||
genfile: "../../riscv64/ssa.go",
|
||||
ops: RISCV64ops,
|
||||
blocks: RISCV64blocks,
|
||||
regnames: regNamesRISCV64,
|
||||
gpregmask: gpMask,
|
||||
fpregmask: fpMask,
|
||||
framepointerreg: -1, // not used
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue