2022-08-24 17:12:49 +00:00
// Copyright (c) 2022- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
# include "ppsspp_config.h"
2022-08-26 02:26:15 +00:00
# include <algorithm>
2022-08-26 02:31:46 +00:00
# include <cstring>
2022-08-27 02:09:41 +00:00
# include "Common/BitScan.h"
2022-08-24 17:12:49 +00:00
# include "Common/RiscVEmitter.h"
namespace RiscVGen {
static inline bool SupportsCompressed ( ) {
// TODO
return true ;
}
2022-08-25 02:19:32 +00:00
static inline uint8_t BitsSupported ( ) {
// TODO
return 64 ;
}
2022-08-26 02:26:15 +00:00
static inline uint8_t FloatBitsSupported ( ) {
// TODO: 0 if not.
return 64 ;
}
2022-08-25 04:05:19 +00:00
static inline bool SupportsMulDiv ( ) {
// TODO
return true ;
}
2022-08-25 05:58:00 +00:00
static inline bool SupportsAtomic ( ) {
// TODO
return true ;
}
2022-08-26 03:30:01 +00:00
static inline bool SupportsZicsr ( ) {
// TODO
return true ;
}
2022-08-24 17:12:49 +00:00
enum class Opcode32 {
// Note: invalid, just used for FixupBranch.
ZERO = 0b0000000 ,
2022-08-25 02:19:32 +00:00
LOAD = 0b0000011 ,
2022-08-26 02:26:15 +00:00
LOAD_FP = 0b0000111 ,
2022-08-25 03:33:36 +00:00
MISC_MEM = 0b0001111 ,
2022-08-25 02:19:32 +00:00
OP_IMM = 0b0010011 ,
2022-08-25 01:01:03 +00:00
AUIPC = 0b0010111 ,
2022-08-25 03:33:36 +00:00
OP_IMM_32 = 0b0011011 ,
2022-08-25 02:19:32 +00:00
STORE = 0b0100011 ,
2022-08-26 02:26:15 +00:00
STORE_FP = 0b0100111 ,
2022-08-25 05:58:00 +00:00
AMO = 0b0101111 ,
2022-08-25 02:44:29 +00:00
OP = 0b0110011 ,
2022-08-25 01:01:03 +00:00
LUI = 0b0110111 ,
2022-08-25 03:33:36 +00:00
OP_32 = 0b0111011 ,
2022-08-26 02:26:15 +00:00
FMADD = 0b1000011 ,
FMSUB = 0b1000111 ,
FNMSUB = 0b1001011 ,
FNMADD = 0b1001111 ,
OP_FP = 0b1010011 ,
2022-08-25 02:44:29 +00:00
BRANCH = 0b1100011 ,
2022-08-25 01:01:03 +00:00
JALR = 0b1100111 ,
JAL = 0b1101111 ,
2022-08-24 17:12:49 +00:00
SYSTEM = 0b1110011 ,
} ;
2022-08-27 22:14:22 +00:00
enum class Opcode16 {
C0 = 0b00 ,
C1 = 0b01 ,
C2 = 0b10 ,
} ;
2022-08-24 17:12:49 +00:00
enum class Funct3 {
// Note: invalid, just used for FixupBranch.
ZERO = 0b000 ,
2022-08-25 01:01:03 +00:00
2022-08-24 17:12:49 +00:00
PRIV = 0b000 ,
2022-08-25 01:01:03 +00:00
2022-08-25 03:33:36 +00:00
FENCE = 0b000 ,
2022-08-25 04:05:19 +00:00
FENCE_I = 0b001 ,
2022-08-25 03:33:36 +00:00
2022-08-25 01:01:03 +00:00
BEQ = 0b000 ,
BNE = 0b001 ,
BLT = 0b100 ,
BGE = 0b101 ,
BLTU = 0b110 ,
BGEU = 0b111 ,
2022-08-25 02:19:32 +00:00
LS_B = 0b000 ,
LS_H = 0b001 ,
LS_W = 0b010 ,
2022-08-25 03:33:36 +00:00
LS_D = 0b011 ,
2022-08-25 02:19:32 +00:00
LS_BU = 0b100 ,
LS_HU = 0b101 ,
2022-08-25 03:33:36 +00:00
LS_WU = 0b110 ,
2022-08-25 02:19:32 +00:00
2022-08-25 02:44:29 +00:00
ADD = 0b000 ,
SLL = 0b001 ,
SLT = 0b010 ,
SLTU = 0b011 ,
XOR = 0b100 ,
SRL = 0b101 ,
OR = 0b110 ,
AND = 0b111 ,
2022-08-25 04:05:19 +00:00
MUL = 0b000 ,
MULH = 0b001 ,
MULHSU = 0b010 ,
MULHU = 0b011 ,
DIV = 0b100 ,
DIVU = 0b101 ,
REM = 0b110 ,
REMU = 0b111 ,
2022-08-26 02:26:15 +00:00
FSGNJ = 0b000 ,
FSGNJN = 0b001 ,
FSGNJX = 0b010 ,
FMIN = 0b000 ,
FMAX = 0b001 ,
FMV = 0b000 ,
FCLASS = 0b001 ,
FLE = 0b000 ,
FLT = 0b001 ,
FEQ = 0b010 ,
2022-08-26 03:30:01 +00:00
CSRRW = 0b001 ,
CSRRS = 0b010 ,
CSRRC = 0b011 ,
CSRRWI = 0b101 ,
CSRRSI = 0b110 ,
CSRRCI = 0b111 ,
2022-08-27 22:14:22 +00:00
C_ADDI4SPN = 0b000 ,
C_FLD = 0b001 ,
C_LW = 0b010 ,
C_FLW = 0b011 ,
C_LD = 0b011 ,
C_FSD = 0b101 ,
C_SW = 0b110 ,
C_FSW = 0b111 ,
C_SD = 0b111 ,
C_ADDI = 0b000 ,
C_JAL = 0b001 ,
C_ADDIW = 0b001 ,
C_LI = 0b010 ,
C_LUI = 0b011 ,
C_ARITH = 0b100 ,
C_J = 0b101 ,
C_BEQZ = 0b110 ,
C_BNEZ = 0b111 ,
C_SLLI = 0b000 ,
C_FLDSP = 0b001 ,
C_LWSP = 0b010 ,
C_FLWSP = 0b011 ,
C_LDSP = 0b011 ,
C_ADD = 0b100 ,
C_FSDSP = 0b101 ,
C_SWSP = 0b110 ,
C_FSWSP = 0b111 ,
C_SDSP = 0b111 ,
2022-08-24 17:12:49 +00:00
} ;
enum class Funct2 {
2022-08-26 02:26:15 +00:00
S = 0b00 ,
D = 0b01 ,
Q = 0b11 ,
2022-08-27 22:14:22 +00:00
C_SRLI = 0b00 ,
C_SRAI = 0b01 ,
C_ANDI = 0b10 ,
C_REGARITH = 0b11 ,
C_SUB = 0b00 ,
C_XOR = 0b01 ,
C_OR = 0b10 ,
C_AND = 0b11 ,
C_SUBW = 0b00 ,
C_ADDW = 0b01 ,
2022-08-24 17:12:49 +00:00
} ;
enum class Funct7 {
2022-08-25 02:44:29 +00:00
ZERO = 0b0000000 ,
SUB = 0b0100000 ,
SRA = 0b0100000 ,
2022-08-25 04:05:19 +00:00
MULDIV = 0b0000001 ,
2022-08-24 17:12:49 +00:00
} ;
2022-08-25 05:58:00 +00:00
enum class Funct5 {
AMOADD = 0b00000 ,
AMOSWAP = 0b00001 ,
LR = 0b00010 ,
SC = 0b00011 ,
AMOXOR = 0b00100 ,
AMOAND = 0b01100 ,
AMOOR = 0b01000 ,
AMOMIN = 0b10000 ,
AMOMAX = 0b10100 ,
AMOMINU = 0b11000 ,
AMOMAXU = 0b11100 ,
2022-08-26 02:26:15 +00:00
FADD = 0b00000 ,
FSUB = 0b00001 ,
FMUL = 0b00010 ,
FDIV = 0b00011 ,
FSGNJ = 0b00100 ,
FMINMAX = 0b00101 ,
FCVT_SZ = 0b01000 ,
FSQRT = 0b01011 ,
FCMP = 0b10100 ,
FCVT_TOX = 0b11000 ,
FCVT_FROMX = 0b11010 ,
FMV_TOX = 0b11100 ,
FMV_FROMX = 0b11110 ,
2022-08-25 05:58:00 +00:00
} ;
2022-08-27 22:14:22 +00:00
enum class Funct4 {
C_JR = 0b1000 ,
C_MV = 0b1000 ,
C_JALR = 0b1001 ,
C_ADD = 0b1001 ,
} ;
enum class Funct6 {
C_OP = 0b100011 ,
C_OP_32 = 0b100111 ,
} ;
2022-08-24 17:12:49 +00:00
enum class Funct12 {
ECALL = 0b000000000000 ,
EBREAK = 0b000000000001 ,
} ;
2022-08-27 22:14:22 +00:00
enum class RiscCReg {
X8 , X9 , X10 , X11 , X12 , X13 , X14 , X15 ,
} ;
2022-08-25 02:44:29 +00:00
static inline RiscVReg DecodeReg ( RiscVReg reg ) { return ( RiscVReg ) ( reg & 0x1F ) ; }
static inline bool IsGPR ( RiscVReg reg ) { return reg < 0x20 ; }
static inline bool IsFPR ( RiscVReg reg ) { return ( reg & 0x20 ) ! = 0 & & ( int ) reg < 0x40 ; }
2022-08-27 22:14:22 +00:00
static inline bool CanCompress ( RiscVReg reg ) {
return ( DecodeReg ( reg ) & 0x18 ) = = 0x08 ;
}
static inline RiscCReg CompressReg ( RiscVReg reg ) {
_assert_msg_ ( CanCompress ( reg ) , " Compressed reg must be between 8 and 15 " ) ;
return ( RiscCReg ) ( reg & 0x07 ) ;
}
2022-08-27 15:55:53 +00:00
static inline s32 SignReduce32 ( s32 v , int width ) {
int shift = 32 - width ;
return ( v < < shift ) > > shift ;
}
static inline s64 SignReduce64 ( s64 v , int width ) {
int shift = 64 - width ;
return ( v < < shift ) > > shift ;
}
// Compressed encodings have weird immediate bit order, trying to make it more readable.
static inline u8 ImmBit8 ( int imm , int bit ) {
return ( imm > > bit ) & 1 ;
}
static inline u8 ImmBits8 ( int imm , int start , int sz ) {
int mask = ( 1 < < sz ) - 1 ;
return ( imm > > start ) & mask ;
}
static inline u16 ImmBit16 ( int imm , int bit ) {
return ( imm > > bit ) & 1 ;
}
static inline u16 ImmBits16 ( int imm , int start , int sz ) {
int mask = ( 1 < < sz ) - 1 ;
return ( imm > > start ) & mask ;
}
static inline u32 ImmBit32 ( int imm , int bit ) {
return ( imm > > bit ) & 1 ;
}
static inline u32 ImmBits32 ( int imm , int start , int sz ) {
int mask = ( 1 < < sz ) - 1 ;
return ( imm > > start ) & mask ;
}
2022-08-24 17:12:49 +00:00
static inline u32 EncodeR ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Funct7 funct7 ) {
2022-08-25 02:44:29 +00:00
return ( u32 ) opcode | ( ( u32 ) DecodeReg ( rd ) < < 7 ) | ( ( u32 ) funct3 < < 12 ) | ( ( u32 ) DecodeReg ( rs1 ) < < 15 ) | ( ( u32 ) DecodeReg ( rs2 ) < < 20 ) | ( ( u32 ) funct7 < < 25 ) ;
}
static inline u32 EncodeGR ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Funct7 funct7 ) {
_assert_msg_ ( IsGPR ( rd ) , " R instruction rd must be GPR " ) ;
_assert_msg_ ( IsGPR ( rs1 ) , " R instruction rs1 must be GPR " ) ;
_assert_msg_ ( IsGPR ( rs2 ) , " R instruction rs2 must be GPR " ) ;
return EncodeR ( opcode , rd , funct3 , rs1 , rs2 , funct7 ) ;
2022-08-24 17:12:49 +00:00
}
2022-08-25 05:58:00 +00:00
static inline u32 EncodeAtomicR ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Atomic ordering , Funct5 funct5 ) {
u32 funct7 = ( ( u32 ) funct5 < < 2 ) | ( u32 ) ordering ;
return EncodeGR ( opcode , rd , funct3 , rs1 , rs2 , ( Funct7 ) funct7 ) ;
}
2022-08-24 17:12:49 +00:00
static inline u32 EncodeR4 ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Funct2 funct2 , RiscVReg rs3 ) {
2022-08-25 02:44:29 +00:00
return ( u32 ) opcode | ( ( u32 ) DecodeReg ( rd ) < < 7 ) | ( ( u32 ) funct3 < < 12 ) | ( ( u32 ) DecodeReg ( rs1 ) < < 15 ) | ( ( u32 ) DecodeReg ( rs2 ) < < 20 ) | ( ( u32 ) funct2 < < 25 ) | ( ( u32 ) DecodeReg ( rs3 ) < < 27 ) ;
2022-08-24 17:12:49 +00:00
}
2022-08-26 02:26:15 +00:00
static inline u32 EncodeFR4 ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Funct2 funct2 , RiscVReg rs3 ) {
_assert_msg_ ( IsFPR ( rd ) , " R4 instruction rd must be FPR " ) ;
_assert_msg_ ( IsFPR ( rs1 ) , " R4 instruction rs1 must be FPR " ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " R4 instruction rs2 must be FPR " ) ;
_assert_msg_ ( IsFPR ( rs3 ) , " R4 instruction rs3 must be FPR " ) ;
return EncodeR4 ( opcode , rd , funct3 , rs1 , rs2 , funct2 , rs3 ) ;
}
static inline u32 EncodeR ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Funct2 funct2 , Funct5 funct5 ) {
return EncodeR ( opcode , rd , funct3 , rs1 , rs2 , ( Funct7 ) ( ( ( u32 ) funct5 < < 2 ) | ( u32 ) funct2 ) ) ;
}
static inline u32 EncodeFR ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , Funct2 funct2 , Funct5 funct5 ) {
_assert_msg_ ( IsFPR ( rd ) , " R4 instruction rd must be FPR " ) ;
_assert_msg_ ( IsFPR ( rs1 ) , " R4 instruction rs1 must be FPR " ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " R4 instruction rs2 must be FPR " ) ;
return EncodeR ( opcode , rd , funct3 , rs1 , rs2 , ( Funct7 ) ( ( ( u32 ) funct5 < < 2 ) | ( u32 ) funct2 ) ) ;
}
2022-08-24 17:12:49 +00:00
static inline u32 EncodeI ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , s32 simm12 ) {
2022-08-27 15:55:53 +00:00
_assert_msg_ ( SignReduce32 ( simm12 , 12 ) = = simm12 , " I immediate must be signed s11.0: %d " , simm12 ) ;
2022-08-25 02:44:29 +00:00
return ( u32 ) opcode | ( ( u32 ) DecodeReg ( rd ) < < 7 ) | ( ( u32 ) funct3 < < 12 ) | ( ( u32 ) DecodeReg ( rs1 ) < < 15 ) | ( ( u32 ) simm12 < < 20 ) ;
}
static inline u32 EncodeGI ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( IsGPR ( rd ) , " I instruction rd must be GPR " ) ;
_assert_msg_ ( IsGPR ( rs1 ) , " I instruction rs1 must be GPR " ) ;
return EncodeI ( opcode , rd , funct3 , rs1 , simm12 ) ;
2022-08-24 17:12:49 +00:00
}
static inline u32 EncodeI ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , Funct12 funct12 ) {
2022-08-27 15:55:53 +00:00
return EncodeI ( opcode , rd , funct3 , rs1 , SignReduce32 ( ( s32 ) funct12 , 12 ) ) ;
2022-08-24 17:12:49 +00:00
}
2022-08-25 02:44:29 +00:00
static inline u32 EncodeGI ( Opcode32 opcode , RiscVReg rd , Funct3 funct3 , RiscVReg rs1 , Funct12 funct12 ) {
_assert_msg_ ( IsGPR ( rd ) , " I instruction rd must be GPR " ) ;
_assert_msg_ ( IsGPR ( rs1 ) , " I instruction rs1 must be GPR " ) ;
return EncodeI ( opcode , rd , funct3 , rs1 , funct12 ) ;
}
2022-08-24 17:12:49 +00:00
static inline u32 EncodeS ( Opcode32 opcode , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , s32 simm12 ) {
2022-08-27 15:55:53 +00:00
_assert_msg_ ( SignReduce32 ( simm12 , 12 ) = = simm12 , " S immediate must be signed s11.0: %d " , simm12 ) ;
u32 imm4_0 = ImmBits32 ( simm12 , 0 , 5 ) ;
u32 imm11_5 = ImmBits32 ( simm12 , 5 , 7 ) ;
return ( u32 ) opcode | ( imm4_0 < < 7 ) | ( ( u32 ) funct3 < < 12 ) | ( ( u32 ) DecodeReg ( rs1 ) < < 15 ) | ( ( u32 ) DecodeReg ( rs2 ) < < 20 ) | ( imm11_5 < < 25 ) ;
2022-08-25 02:44:29 +00:00
}
static inline u32 EncodeGS ( Opcode32 opcode , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , s32 simm12 ) {
_assert_msg_ ( IsGPR ( rs1 ) , " S instruction rs1 must be GPR " ) ;
_assert_msg_ ( IsGPR ( rs2 ) , " S instruction rs2 must be GPR " ) ;
return EncodeS ( opcode , funct3 , rs1 , rs2 , simm12 ) ;
2022-08-24 17:12:49 +00:00
}
static inline u32 EncodeB ( Opcode32 opcode , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , s32 simm13 ) {
2022-08-27 15:55:53 +00:00
_assert_msg_ ( SignReduce32 ( simm13 , 13 ) = = simm13 , " B immediate must be signed s12.0: %d " , simm13 ) ;
2022-08-24 17:12:49 +00:00
_assert_msg_ ( ( simm13 & 1 ) = = 0 , " B immediate must be even " ) ;
// This weird encoding scheme is to keep most bits the same as S, but keep sign at 31.
2022-08-27 15:55:53 +00:00
u32 imm4_1_11 = ( ImmBits32 ( simm13 , 1 , 4 ) < < 1 ) | ImmBit32 ( simm13 , 11 ) ;
u32 imm12_10_5 = ( ImmBit32 ( simm13 , 12 ) < < 6 ) | ImmBits32 ( simm13 , 5 , 6 ) ;
2022-08-25 02:44:29 +00:00
return ( u32 ) opcode | ( ( u32 ) imm4_1_11 < < 7 ) | ( ( u32 ) funct3 < < 12 ) | ( ( u32 ) DecodeReg ( rs1 ) < < 15 ) | ( ( u32 ) DecodeReg ( rs2 ) < < 20 ) | ( ( u32 ) imm12_10_5 < < 25 ) ;
}
static inline u32 EncodeGB ( Opcode32 opcode , Funct3 funct3 , RiscVReg rs1 , RiscVReg rs2 , s32 simm13 ) {
_assert_msg_ ( IsGPR ( rs1 ) , " B instruction rs1 must be GPR " ) ;
_assert_msg_ ( IsGPR ( rs2 ) , " B instruction rs2 must be GPR " ) ;
return EncodeB ( opcode , funct3 , rs1 , rs2 , simm13 ) ;
2022-08-24 17:12:49 +00:00
}
static inline u32 EncodeU ( Opcode32 opcode , RiscVReg rd , s32 simm32 ) {
_assert_msg_ ( ( simm32 & 0x0FFF ) = = 0 , " U immediate must not have lower 12 bits set " ) ;
2022-08-25 02:44:29 +00:00
return ( u32 ) opcode | ( ( u32 ) DecodeReg ( rd ) < < 7 ) | ( u32 ) simm32 ;
}
static inline u32 EncodeGU ( Opcode32 opcode , RiscVReg rd , s32 simm32 ) {
_assert_msg_ ( IsGPR ( rd ) , " I instruction rd must be GPR " ) ;
return EncodeU ( opcode , rd , simm32 ) ;
2022-08-24 17:12:49 +00:00
}
static inline u32 EncodeJ ( Opcode32 opcode , RiscVReg rd , s32 simm21 ) {
2022-08-27 15:55:53 +00:00
_assert_msg_ ( SignReduce32 ( simm21 , 21 ) = = simm21 , " J immediate must be signed s20.0: %d " , simm21 ) ;
2022-08-24 17:12:49 +00:00
_assert_msg_ ( ( simm21 & 1 ) = = 0 , " J immediate must be even " ) ;
2022-08-27 15:55:53 +00:00
u32 imm11 = ImmBit32 ( simm21 , 11 ) ;
u32 imm20 = ImmBit32 ( simm21 , 20 ) ;
u32 imm10_1 = ImmBits32 ( simm21 , 1 , 10 ) ;
u32 imm19_12 = ImmBits32 ( simm21 , 12 , 8 ) ;
2022-08-24 17:12:49 +00:00
// This encoding scheme tries to keep the bits from B in the same places, plus sign.
u32 imm20_10_1_11_19_12 = ( imm20 < < 19 ) | ( imm10_1 < < 9 ) | ( imm11 < < 8 ) | imm19_12 ;
2022-08-27 15:55:53 +00:00
return ( u32 ) opcode | ( ( u32 ) DecodeReg ( rd ) < < 7 ) | ( imm20_10_1_11_19_12 < < 12 ) ;
2022-08-25 02:44:29 +00:00
}
static inline u32 EncodeGJ ( Opcode32 opcode , RiscVReg rd , s32 simm21 ) {
_assert_msg_ ( IsGPR ( rd ) , " J instruction rd must be GPR " ) ;
return EncodeJ ( opcode , rd , simm21 ) ;
2022-08-24 17:12:49 +00:00
}
2022-08-27 22:14:22 +00:00
static inline u16 EncodeCR ( Opcode16 op , RiscVReg rs2 , RiscVReg rd , Funct4 funct4 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
return ( u16 ) op | ( ( u16 ) rs2 < < 2 ) | ( ( u16 ) rd < < 7 ) | ( ( u16 ) funct4 < < 12 ) ;
}
static inline u16 EncodeCI ( Opcode16 op , u8 uimm6 , RiscVReg rd , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( uimm6 < = 0x3F , " CI immediate overflow: %04x " , uimm6 ) ;
u16 imm4_0 = ImmBits16 ( uimm6 , 0 , 5 ) ;
u16 imm5 = ImmBit16 ( uimm6 , 5 ) ;
return ( u16 ) op | ( imm4_0 < < 2 ) | ( ( u16 ) rd < < 7 ) | ( imm5 < < 12 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCSS ( Opcode16 op , RiscVReg rs2 , u8 uimm6 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( uimm6 < = 0x3F , " CI immediate overflow: %04x " , uimm6 ) ;
return ( u16 ) op | ( ( u16 ) rs2 < < 2 ) | ( ( u16 ) uimm6 < < 7 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCIW ( Opcode16 op , RiscCReg rd , u8 uimm8 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
return ( u16 ) op | ( ( u16 ) rd < < 2 ) | ( ( u16 ) uimm8 < < 5 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCL ( Opcode16 op , RiscCReg rd , u8 uimm2 , RiscCReg rs1 , u8 uimm3 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( uimm2 < = 3 , " CL immediate1 overflow: %04x " , uimm2 ) ;
_assert_msg_ ( uimm3 < = 7 , " CL immediate2 overflow: %04x " , uimm3 ) ;
return ( u16 ) op | ( ( u16 ) rd < < 2 ) | ( ( u16 ) uimm2 < < 5 ) | ( ( u16 ) rs1 < < 7 ) | ( ( u16 ) uimm3 < < 10 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCL8 ( Opcode16 op , RiscCReg rd , RiscCReg rs1 , u8 uimm8 , Funct3 funct3 ) {
_assert_msg_ ( ( uimm8 & 0xF8 ) = = uimm8 , " CL immediate must fit in 8 bits and be a multiple of 8: %d " , ( int ) uimm8 ) ;
u8 imm7_6 = ImmBits8 ( uimm8 , 6 , 2 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm8 , 3 , 3 ) ;
return EncodeCL ( op , rd , imm7_6 , rs1 , imm5_4_3 , funct3 ) ;
}
static inline u16 EncodeCL4 ( Opcode16 op , RiscCReg rd , RiscCReg rs1 , u8 uimm7 , Funct3 funct3 ) {
_assert_msg_ ( ( uimm7 & 0x7C ) = = uimm7 , " CL immediate must fit in 7 bits and be a multiple of 4: %d " , ( int ) uimm7 ) ;
u8 imm2_6 = ( ImmBit8 ( uimm7 , 2 ) < < 1 ) | ImmBit8 ( uimm7 , 6 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm7 , 3 , 3 ) ;
return EncodeCL ( op , rd , imm2_6 , rs1 , imm5_4_3 , funct3 ) ;
}
static inline u16 EncodeCS ( Opcode16 op , RiscCReg rs2 , u8 uimm2 , RiscCReg rs1 , u8 uimm3 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( uimm2 < = 3 , " CS immediate1 overflow: %04x " , uimm2 ) ;
_assert_msg_ ( uimm3 < = 7 , " CS immediate2 overflow: %04x " , uimm3 ) ;
return ( u16 ) op | ( ( u16 ) rs2 < < 2 ) | ( ( u16 ) uimm2 < < 5 ) | ( ( u16 ) rs1 < < 7 ) | ( ( u16 ) uimm3 < < 10 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCS8 ( Opcode16 op , RiscCReg rd , RiscCReg rs1 , u8 uimm8 , Funct3 funct3 ) {
_assert_msg_ ( ( uimm8 & 0xF8 ) = = uimm8 , " CS immediate must fit in 8 bits and be a multiple of 8: %d " , ( int ) uimm8 ) ;
u8 imm7_6 = ImmBits8 ( uimm8 , 6 , 2 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm8 , 3 , 3 ) ;
return EncodeCS ( op , rd , imm7_6 , rs1 , imm5_4_3 , funct3 ) ;
}
static inline u16 EncodeCS4 ( Opcode16 op , RiscCReg rd , RiscCReg rs1 , u8 uimm7 , Funct3 funct3 ) {
_assert_msg_ ( ( uimm7 & 0x7C ) = = uimm7 , " CS immediate must fit in 7 bits and be a multiple of 4: %d " , ( int ) uimm7 ) ;
u8 imm2_6 = ( ImmBit8 ( uimm7 , 2 ) < < 1 ) | ImmBit8 ( uimm7 , 6 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm7 , 3 , 3 ) ;
return EncodeCS ( op , rd , imm2_6 , rs1 , imm5_4_3 , funct3 ) ;
}
static inline u16 EncodeCA ( Opcode16 op , RiscCReg rs2 , Funct2 funct2a , RiscCReg rd , Funct6 funct6 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
return ( u16 ) op | ( ( u16 ) rs2 < < 2 ) | ( ( u16 ) funct2a < < 5 ) | ( ( u16 ) rd < < 7 ) | ( ( u16 ) funct6 < < 10 ) ;
}
static inline u16 EncodeCB ( Opcode16 op , u8 uimm6 , RiscCReg rd , Funct2 funct2 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( uimm6 < = 0x3F , " CI immediate overflow: %04x " , uimm6 ) ;
u16 imm4_0 = ImmBits16 ( uimm6 , 0 , 5 ) ;
u16 imm5 = ImmBit16 ( uimm6 , 5 ) ;
return ( u16 ) op | ( imm4_0 < < 2 ) | ( ( u16 ) rd < < 7 ) | ( ( u16 ) funct2 < < 10 ) | ( imm5 < < 12 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCB ( Opcode16 op , s32 simm9 , RiscCReg rs1 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( SignReduce32 ( simm9 , 9 ) = = simm9 , " CB immediate must be signed s8.0: %d " , simm9 ) ;
_assert_msg_ ( ( simm9 & 1 ) = = 0 , " CB immediate must be even: %d " , simm9 ) ;
u16 imm76_21_5 = ( ImmBits16 ( simm9 , 6 , 2 ) < < 3 ) | ( ImmBits16 ( simm9 , 1 , 2 ) < < 1 ) | ImmBit16 ( simm9 , 5 ) ;
u16 imm8_43 = ( ImmBit16 ( simm9 , 8 ) < < 2 ) | ImmBits16 ( simm9 , 3 , 2 ) ;
return ( u16 ) op | ( imm76_21_5 < < 2 ) | ( ( u16 ) rs1 < < 7 ) | ( imm8_43 < < 10 ) | ( ( u16 ) funct3 < < 13 ) ;
}
static inline u16 EncodeCJ ( Opcode16 op , s32 simm12 , Funct3 funct3 ) {
_assert_msg_ ( SupportsCompressed ( ) , " Compressed instructions unsupported " ) ;
_assert_msg_ ( SignReduce32 ( simm12 , 12 ) = = simm12 , " CJ immediate must be signed s11.0: %d " , simm12 ) ;
_assert_msg_ ( ( simm12 & 1 ) = = 0 , " CJ immediate must be even: %d " , simm12 ) ;
u16 imm7_3_2_1_5 = ( ImmBit16 ( simm12 , 7 ) < < 4 ) | ( ImmBits16 ( simm12 , 1 , 3 ) < < 1 ) | ImmBit16 ( simm12 , 5 ) ;
u16 imm9_8_10_6 = ( ImmBits16 ( simm12 , 8 , 2 ) < < 2 ) | ( ImmBit16 ( simm12 , 10 ) < < 1 ) | ImmBit16 ( simm12 , 6 ) ;
u16 imm11_4 = ( ImmBit16 ( simm12 , 11 ) < < 1 ) | ImmBit16 ( simm12 , 4 ) ;
u16 imm11_4_9_8_10_6_7_3_2_1_5 = ( imm11_4 < < 9 ) | ( imm9_8_10_6 < < 5 ) | imm7_3_2_1_5 ;
return ( u16 ) op | ( imm11_4_9_8_10_6_7_3_2_1_5 < < 2 ) | ( ( u16 ) funct3 < < 13 ) ;
}
2022-08-26 02:26:15 +00:00
static inline Funct3 BitsToFunct3 ( int bits , bool useFloat = false ) {
int bitsSupported = useFloat ? FloatBitsSupported ( ) : BitsSupported ( ) ;
_assert_msg_ ( bitsSupported > = bits , " Cannot use funct3 width %d, only have %d " , bits , bitsSupported ) ;
2022-08-25 05:58:00 +00:00
switch ( bits ) {
case 32 :
return Funct3 : : LS_W ;
case 64 :
return Funct3 : : LS_D ;
default :
_assert_msg_ ( false , " Invalid funct3 width %d " , bits ) ;
return Funct3 : : LS_W ;
}
}
2022-08-26 02:26:15 +00:00
static inline Funct2 BitsToFunct2 ( int bits ) {
_assert_msg_ ( FloatBitsSupported ( ) > = bits , " Cannot use funct2 width %d, only have %d " , bits , FloatBitsSupported ( ) ) ;
switch ( bits ) {
case 32 :
return Funct2 : : S ;
case 64 :
return Funct2 : : D ;
case 128 :
return Funct2 : : Q ;
default :
_assert_msg_ ( false , " Invalid funct2 width %d " , bits ) ;
return Funct2 : : S ;
}
}
static inline int FConvToFloatBits ( FConv c ) {
switch ( c ) {
case FConv : : W :
case FConv : : WU :
case FConv : : L :
case FConv : : LU :
break ;
case FConv : : S :
return 32 ;
case FConv : : D :
return 64 ;
case FConv : : Q :
return 128 ;
}
return 0 ;
}
static inline int FConvToIntegerBits ( FConv c ) {
switch ( c ) {
case FConv : : S :
case FConv : : D :
case FConv : : Q :
break ;
case FConv : : W :
case FConv : : WU :
return 32 ;
case FConv : : L :
case FConv : : LU :
return 64 ;
}
return 0 ;
}
2022-08-24 17:12:49 +00:00
RiscVEmitter : : RiscVEmitter ( const u8 * ptr , u8 * writePtr ) {
SetCodePointer ( ptr , writePtr ) ;
}
void RiscVEmitter : : SetCodePointer ( const u8 * ptr , u8 * writePtr ) {
code_ = ptr ;
writable_ = writePtr ;
lastCacheFlushEnd_ = ptr ;
}
const u8 * RiscVEmitter : : GetCodePointer ( ) const {
return code_ ;
}
u8 * RiscVEmitter : : GetWritableCodePtr ( ) {
return writable_ ;
}
void RiscVEmitter : : ReserveCodeSpace ( u32 bytes ) {
_assert_msg_ ( ( bytes & 1 ) = = 0 , " Code space should be aligned " ) ;
_assert_msg_ ( ( bytes & 3 ) = = 0 | | SupportsCompressed ( ) , " Code space should be aligned (no compressed) " ) ;
for ( u32 i = 0 ; i < bytes / 4 ; i + + )
EBREAK ( ) ;
if ( bytes & 2 )
Write16 ( 0 ) ;
}
const u8 * RiscVEmitter : : AlignCode16 ( ) {
int c = int ( ( u64 ) code_ & 15 ) ;
if ( c )
ReserveCodeSpace ( 16 - c ) ;
return code_ ;
}
const u8 * RiscVEmitter : : AlignCodePage ( ) {
int page_size = GetMemoryProtectPageSize ( ) ;
int c = int ( ( u64 ) code_ & ( page_size - 1 ) ) ;
if ( c )
ReserveCodeSpace ( page_size - c ) ;
return code_ ;
}
void RiscVEmitter : : FlushIcache ( ) {
FlushIcacheSection ( lastCacheFlushEnd_ , code_ ) ;
lastCacheFlushEnd_ = code_ ;
}
void RiscVEmitter : : FlushIcacheSection ( const u8 * start , const u8 * end ) {
# if PPSSPP_ARCH(RISCV64)
2022-09-15 14:50:57 +00:00
__builtin___clear_cache ( ( void * ) start , ( void * ) end ) ;
2022-08-24 17:12:49 +00:00
# endif
}
2022-08-26 02:31:46 +00:00
FixupBranch : : ~ FixupBranch ( ) {
_assert_msg_ ( ptr = = nullptr , " FixupBranch never set (left infinite loop) " ) ;
}
void RiscVEmitter : : SetJumpTarget ( FixupBranch & branch ) {
2022-08-24 17:12:49 +00:00
SetJumpTarget ( branch , code_ ) ;
}
2022-08-26 02:31:46 +00:00
void RiscVEmitter : : SetJumpTarget ( FixupBranch & branch , const void * dst ) {
_assert_msg_ ( branch . ptr ! = nullptr , " Invalid FixupBranch (SetJumpTarget twice?) " ) ;
2022-08-24 17:12:49 +00:00
const intptr_t srcp = ( intptr_t ) branch . ptr ;
const intptr_t dstp = ( intptr_t ) dst ;
const ptrdiff_t writable_delta = writable_ - code_ ;
2022-08-26 02:31:46 +00:00
u32 * writableSrc = ( u32 * ) ( branch . ptr + writable_delta ) ;
2022-08-27 22:14:22 +00:00
// If compressed, this may be an unaligned 32-bit value, so we modify a copy.
2022-08-26 02:31:46 +00:00
u32 fixup ;
2022-08-27 22:14:22 +00:00
u16 fixup16 ;
2022-08-24 17:12:49 +00:00
_assert_msg_ ( ( dstp & 1 ) = = 0 , " Destination should be aligned " ) ;
_assert_msg_ ( ( dstp & 3 ) = = 0 | | SupportsCompressed ( ) , " Destination should be aligned (no compressed) " ) ;
ptrdiff_t distance = dstp - srcp ;
_assert_msg_ ( ( distance & 1 ) = = 0 , " Distance should be aligned " ) ;
_assert_msg_ ( ( distance & 3 ) = = 0 | | SupportsCompressed ( ) , " Distance should be aligned (no compressed) " ) ;
switch ( branch . type ) {
case FixupBranchType : : B :
_assert_msg_ ( BInRange ( branch . ptr , dst ) , " B destination is too far away (%p -> %p) " , branch . ptr , dst ) ;
2022-08-27 22:14:22 +00:00
memcpy ( & fixup , writableSrc , sizeof ( u32 ) ) ;
2022-08-26 02:31:46 +00:00
fixup = ( fixup & 0x01FFF07F ) | EncodeB ( Opcode32 : : ZERO , Funct3 : : ZERO , R_ZERO , R_ZERO , ( s32 ) distance ) ;
2022-08-27 22:14:22 +00:00
memcpy ( writableSrc , & fixup , sizeof ( u32 ) ) ;
2022-08-24 17:12:49 +00:00
break ;
case FixupBranchType : : J :
_assert_msg_ ( JInRange ( branch . ptr , dst ) , " J destination is too far away (%p -> %p) " , branch . ptr , dst ) ;
2022-08-27 22:14:22 +00:00
memcpy ( & fixup , writableSrc , sizeof ( u32 ) ) ;
2022-08-26 02:31:46 +00:00
fixup = ( fixup & 0x00000FFF ) | EncodeJ ( Opcode32 : : ZERO , R_ZERO , ( s32 ) distance ) ;
2022-08-27 22:14:22 +00:00
memcpy ( writableSrc , & fixup , sizeof ( u32 ) ) ;
break ;
case FixupBranchType : : CB :
_assert_msg_ ( CBInRange ( branch . ptr , dst ) , " C.B destination is too far away (%p -> %p) " , branch . ptr , dst ) ;
memcpy ( & fixup16 , writableSrc , sizeof ( u16 ) ) ;
fixup16 = ( fixup16 & 0xE383 ) | EncodeCB ( Opcode16 : : C0 , ( s32 ) distance , RiscCReg : : X8 , Funct3 : : ZERO ) ;
memcpy ( writableSrc , & fixup16 , sizeof ( u16 ) ) ;
break ;
case FixupBranchType : : CJ :
_assert_msg_ ( CJInRange ( branch . ptr , dst ) , " C.J destination is too far away (%p -> %p) " , branch . ptr , dst ) ;
memcpy ( & fixup16 , writableSrc , sizeof ( u16 ) ) ;
fixup16 = ( fixup16 & 0xE003 ) | EncodeCJ ( Opcode16 : : C0 , ( s32 ) distance , Funct3 : : ZERO ) ;
memcpy ( writableSrc , & fixup16 , sizeof ( u16 ) ) ;
2022-08-24 17:12:49 +00:00
break ;
}
2022-08-26 02:31:46 +00:00
branch . ptr = nullptr ;
2022-08-24 17:12:49 +00:00
}
bool RiscVEmitter : : BInRange ( const void * func ) const {
return BInRange ( code_ , func ) ;
}
bool RiscVEmitter : : JInRange ( const void * func ) const {
return JInRange ( code_ , func ) ;
}
2022-08-27 22:14:22 +00:00
bool RiscVEmitter : : CBInRange ( const void * func ) const {
return CBInRange ( code_ , func ) ;
}
2022-08-24 17:12:49 +00:00
2022-08-27 22:14:22 +00:00
bool RiscVEmitter : : CJInRange ( const void * func ) const {
return CJInRange ( code_ , func ) ;
}
static inline bool BJInRange ( const void * src , const void * dst , int bits ) {
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) src ;
2022-08-27 02:09:41 +00:00
// Get rid of bits and sign extend to validate range.
2022-08-27 22:14:22 +00:00
s32 encodable = SignReduce32 ( ( s32 ) distance , bits ) ;
2022-08-27 02:09:41 +00:00
return distance = = encodable ;
2022-08-24 17:12:49 +00:00
}
2022-08-27 22:14:22 +00:00
bool RiscVEmitter : : BInRange ( const void * src , const void * dst ) const {
return BJInRange ( src , dst , 13 ) ;
}
2022-08-24 17:12:49 +00:00
bool RiscVEmitter : : JInRange ( const void * src , const void * dst ) const {
2022-08-27 22:14:22 +00:00
return BJInRange ( src , dst , 21 ) ;
}
2022-08-24 17:12:49 +00:00
2022-08-27 22:14:22 +00:00
bool RiscVEmitter : : CBInRange ( const void * src , const void * dst ) const {
return BJInRange ( src , dst , 9 ) ;
}
bool RiscVEmitter : : CJInRange ( const void * src , const void * dst ) const {
return BJInRange ( src , dst , 12 ) ;
2022-08-27 02:09:41 +00:00
}
void RiscVEmitter : : SetRegToImmediate ( RiscVReg rd , uint64_t value , RiscVReg temp ) {
int64_t svalue = ( int64_t ) value ;
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( temp ) , " SetRegToImmediate only supports GPRs " ) ;
_assert_msg_ ( rd ! = temp , " SetRegToImmediate cannot use same register for temp and rd " ) ;
2022-08-27 15:55:53 +00:00
_assert_msg_ ( SignReduce64 ( svalue , 32 ) = = svalue | | ( value & 0xFFFFFFFF ) = = value | | BitsSupported ( ) > = 64 , " 64-bit immediate unsupported " ) ;
2022-08-27 02:09:41 +00:00
2022-08-27 15:55:53 +00:00
if ( SignReduce64 ( svalue , 12 ) = = svalue ) {
2022-08-27 02:09:41 +00:00
// Nice and simple, small immediate fits in a single ADDI against zero.
ADDI ( rd , R_ZERO , ( s32 ) svalue ) ;
return ;
}
auto useUpper = [ & ] ( int64_t v , void ( RiscVEmitter : : * upperOp ) ( RiscVReg , s32 ) , bool force = false ) {
2022-08-27 15:55:53 +00:00
if ( SignReduce64 ( v , 32 ) = = v | | force ) {
int32_t lower = ( int32_t ) SignReduce64 ( svalue , 12 ) ;
2022-08-27 02:09:41 +00:00
int32_t upper = ( ( v - lower ) > > 12 ) < < 12 ;
_assert_msg_ ( force | | upper + lower = = v , " Upper + ADDI immediate math mistake? " ) ;
// Should be fused on some processors.
( this - > * upperOp ) ( rd , upper ) ;
if ( lower ! = 0 )
ADDI ( rd , rd , lower ) ;
return true ;
}
return false ;
} ;
// If this is a simple 32-bit immediate, we can use LUI + ADDI.
if ( useUpper ( svalue , & RiscVEmitter : : LUI , BitsSupported ( ) = = 32 ) )
return ;
_assert_msg_ ( BitsSupported ( ) > 32 , " Should have stopped at LUI + ADDI on 32-bit " ) ;
// Common case, within 32 bits of PC, use AUIPC + ADDI.
intptr_t pc = ( intptr_t ) GetCodePointer ( ) ;
if ( sizeof ( pc ) < = 8 & & useUpper ( svalue - ( int64_t ) pc , & RiscVEmitter : : AUIPC ) )
return ;
// Check if it's just a shifted 32 bit immediate, those are cheap.
for ( uint32_t start = 1 ; start < = 32 ; + + start ) {
// Take the value (shifted by start) and extend sign from 32 bits.
int32_t simm32 = ( int32_t ) ( svalue > > start ) ;
if ( ( ( int64_t ) simm32 < < start ) = = svalue ) {
LI ( rd , simm32 ) ;
SLLI ( rd , rd , start ) ;
return ;
}
}
// If this is just a 32-bit unsigned value, use a wall to mask.
if ( ( svalue > > 32 ) = = 0 ) {
LI ( rd , ( int32_t ) ( svalue & 0xFFFFFFFF ) ) ;
SLLI ( rd , rd , BitsSupported ( ) - 32 ) ;
SRLI ( rd , rd , BitsSupported ( ) - 32 ) ;
return ;
}
// If we have a temporary, let's use it to shorten.
if ( temp ! = R_ZERO ) {
2022-08-27 15:55:53 +00:00
int32_t lower = ( int32_t ) svalue ;
2022-08-27 02:09:41 +00:00
int32_t upper = ( svalue - lower ) > > 32 ;
2022-08-27 22:14:22 +00:00
_assert_msg_ ( ( ( int64_t ) upper < < 32 ) + lower = = svalue , " LI + SLLI + LI + ADD immediate math mistake? " ) ;
2022-08-27 02:09:41 +00:00
// This could be a bit more optimal, in case a different shamt could simplify an LI.
LI ( rd , ( int64_t ) upper ) ;
SLLI ( rd , rd , 32 ) ;
LI ( temp , ( int64_t ) lower ) ;
ADD ( rd , rd , temp ) ;
return ;
}
// Okay, let's just start with the upper 32 bits and add the rest via ORI.
int64_t upper = svalue > > 32 ;
LI ( rd , upper ) ;
uint32_t remaining = svalue & 0xFFFFFFFF ;
uint32_t shifted = 0 ;
while ( remaining ! = 0 ) {
// Skip any zero bits, just set the first ones actually needed.
uint32_t zeroBits = clz32_nonzero ( remaining ) ;
// We do chunks of 11 to avoid compensating for sign.
uint32_t targetShift = std : : min ( zeroBits + 11 , 32U ) ;
uint32_t sourceShift = 32 - targetShift ;
int32_t chunk = ( remaining > > sourceShift ) & 0x07FF ;
SLLI ( rd , rd , targetShift - shifted ) ;
ORI ( rd , rd , chunk ) ;
// Okay, increase shift and clear the bits we've deposited.
shifted = targetShift ;
remaining & = ~ ( chunk < < sourceShift ) ;
}
// Move into place in case the lowest bits weren't set.
if ( shifted < 32 )
SLLI ( rd , rd , 32 - shifted ) ;
2022-08-24 17:12:49 +00:00
}
2022-08-25 01:01:03 +00:00
void RiscVEmitter : : LUI ( RiscVReg rd , s32 simm32 ) {
2022-08-25 02:19:32 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & rd ! = R_SP & & simm32 ! = 0 & & SignReduce32 ( simm32 & 0x0003F000 , 18 ) = = simm32 ) {
C_LUI ( rd , simm32 ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGU ( Opcode32 : : LUI , rd , simm32 ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : AUIPC ( RiscVReg rd , s32 simm32 ) {
2022-08-25 02:19:32 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGU ( Opcode32 : : AUIPC , rd , simm32 ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : JAL ( RiscVReg rd , const void * dst ) {
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CJInRange ( GetCodePointer ( ) , dst ) ) {
if ( BitsSupported ( ) = = 32 & & rd = = R_RA ) {
C_JAL ( dst ) ;
return ;
} else if ( rd = = R_ZERO ) {
C_J ( dst ) ;
return ;
}
}
2022-08-25 01:01:03 +00:00
_assert_msg_ ( JInRange ( GetCodePointer ( ) , dst ) , " JAL destination is too far away (%p -> %p) " , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 1 ) = = 0 , " JAL destination should be aligned " ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " JAL destination should be aligned (no compressed) " ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGJ ( Opcode32 : : JAL , rd , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : JALR ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & rs1 ! = R_ZERO & & simm12 = = 0 ) {
if ( rd = = R_ZERO ) {
C_JR ( rs1 ) ;
return ;
} else if ( rd = = R_RA ) {
C_JALR ( rs1 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : JALR , rd , Funct3 : : ZERO , rs1 , simm12 ) ) ;
2022-08-25 01:01:03 +00:00
}
FixupBranch RiscVEmitter : : JAL ( RiscVReg rd ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : J } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGJ ( Opcode32 : : JAL , rd , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
void RiscVEmitter : : BEQ ( RiscVReg rs1 , RiscVReg rs2 , const void * dst ) {
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CBInRange ( GetCodePointer ( ) , dst ) ) {
if ( rs2 = = R_ZERO ) {
C_BEQZ ( rs1 , dst ) ;
return ;
} else if ( rs1 = = R_ZERO ) {
C_BEQZ ( rs2 , dst ) ;
return ;
}
}
2022-08-25 01:01:03 +00:00
_assert_msg_ ( BInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " %s destination should be aligned (no compressed) " , __func__ ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BEQ , rs1 , rs2 , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : BNE ( RiscVReg rs1 , RiscVReg rs2 , const void * dst ) {
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CBInRange ( GetCodePointer ( ) , dst ) ) {
if ( rs2 = = R_ZERO ) {
C_BNEZ ( rs1 , dst ) ;
return ;
} else if ( rs1 = = R_ZERO ) {
C_BNEZ ( rs2 , dst ) ;
return ;
}
}
2022-08-25 01:01:03 +00:00
_assert_msg_ ( BInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " %s destination should be aligned (no compressed) " , __func__ ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BNE , rs1 , rs2 , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : BLT ( RiscVReg rs1 , RiscVReg rs2 , const void * dst ) {
_assert_msg_ ( BInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " %s destination should be aligned (no compressed) " , __func__ ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BLT , rs1 , rs2 , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : BGE ( RiscVReg rs1 , RiscVReg rs2 , const void * dst ) {
_assert_msg_ ( BInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " %s destination should be aligned (no compressed) " , __func__ ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BGE , rs1 , rs2 , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : BLTU ( RiscVReg rs1 , RiscVReg rs2 , const void * dst ) {
_assert_msg_ ( BInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " %s destination should be aligned (no compressed) " , __func__ ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BLTU , rs1 , rs2 , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
void RiscVEmitter : : BGEU ( RiscVReg rs1 , RiscVReg rs2 , const void * dst ) {
_assert_msg_ ( BInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 3 ) = = 0 | | SupportsCompressed ( ) , " %s destination should be aligned (no compressed) " , __func__ ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BGEU , rs1 , rs2 , ( s32 ) distance ) ) ;
2022-08-25 01:01:03 +00:00
}
FixupBranch RiscVEmitter : : BEQ ( RiscVReg rs1 , RiscVReg rs2 ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : B } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BEQ , rs1 , rs2 , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
FixupBranch RiscVEmitter : : BNE ( RiscVReg rs1 , RiscVReg rs2 ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : B } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BNE , rs1 , rs2 , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
FixupBranch RiscVEmitter : : BLT ( RiscVReg rs1 , RiscVReg rs2 ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : B } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BLT , rs1 , rs2 , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
FixupBranch RiscVEmitter : : BGE ( RiscVReg rs1 , RiscVReg rs2 ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : B } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BGE , rs1 , rs2 , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
FixupBranch RiscVEmitter : : BLTU ( RiscVReg rs1 , RiscVReg rs2 ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : B } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BLTU , rs1 , rs2 , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
FixupBranch RiscVEmitter : : BGEU ( RiscVReg rs1 , RiscVReg rs2 ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : B } ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGB ( Opcode32 : : BRANCH , Funct3 : : BGEU , rs1 , rs2 , 0 ) ) ;
2022-08-25 01:01:03 +00:00
return fixup ;
}
2022-08-25 02:19:32 +00:00
void RiscVEmitter : : LB ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_B , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : LH ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_H , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : LW ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) ) {
if ( CanCompress ( rd ) & & CanCompress ( rs1 ) & & ( simm12 & 0x7C ) = = simm12 ) {
C_LW ( rd , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( rd ! = R_ZERO & & rs1 = = R_SP & & ( simm12 & 0xFC ) = = simm12 ) {
C_LWSP ( rd , ( u8 ) simm12 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_W , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : LBU ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_BU , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : LHU ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_HU , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SB ( RiscVReg rs2 , RiscVReg rs1 , s32 simm12 ) {
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGS ( Opcode32 : : STORE , Funct3 : : LS_B , rs1 , rs2 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SH ( RiscVReg rs2 , RiscVReg rs1 , s32 simm12 ) {
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGS ( Opcode32 : : STORE , Funct3 : : LS_H , rs1 , rs2 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SW ( RiscVReg rs2 , RiscVReg rs1 , s32 simm12 ) {
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) ) {
if ( CanCompress ( rs2 ) & & CanCompress ( rs1 ) & & ( simm12 & 0x7C ) = = simm12 ) {
C_SW ( rs2 , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( rs1 = = R_SP & & ( simm12 & 0xFC ) = = simm12 ) {
C_LWSP ( rs2 , ( u8 ) simm12 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGS ( Opcode32 : : STORE , Funct3 : : LS_W , rs1 , rs2 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : ADDI ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
// Allow NOP form of ADDI.
_assert_msg_ ( rd ! = R_ZERO | | ( rs1 = = R_ZERO & & simm12 = = 0 ) , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) ) {
if ( CanCompress ( rd ) & & rs1 = = R_SP & & simm12 ! = 0 & & ( simm12 & 0x03FC ) = = simm12 ) {
C_ADDI4SPN ( rd , ( u32 ) simm12 ) ;
return ;
} else if ( rd ! = R_ZERO & & rd = = rs1 & & simm12 ! = 0 & & SignReduce32 ( simm12 , 6 ) = = simm12 ) {
C_ADDI ( rd , ( s8 ) simm12 ) ;
return ;
} else if ( rd ! = R_ZERO & & rs1 = = R_ZERO & & SignReduce32 ( simm12 , 6 ) = = simm12 ) {
C_LI ( rd , ( s8 ) simm12 ) ;
return ;
} else if ( rd = = R_SP & & rd = = rs1 & & simm12 ! = 0 & & SignReduce32 ( simm12 & ~ 0xF , 10 ) = = simm12 ) {
C_ADDI16SP ( simm12 ) ;
return ;
} else if ( rd ! = R_ZERO & & rs1 ! = R_ZERO & & simm12 = = 0 ) {
C_MV ( rd , rs1 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : ADD , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SLTI ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : SLT , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SLTIU ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : SLTU , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : XORI ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : XOR , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : ORI ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) ) {
if ( rd ! = R_ZERO & & rs1 ! = R_ZERO & & simm12 = = 0 ) {
C_MV ( rd , rs1 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : OR , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : ANDI ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & SignReduce32 ( simm12 , 6 ) = = simm12 ) {
C_ANDI ( rd , ( s8 ) simm12 ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : AND , rs1 , simm12 ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SLLI ( RiscVReg rd , RiscVReg rs1 , u32 shamt ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
// Not sure if shamt=0 is legal or not, let's play it safe.
_assert_msg_ ( shamt > 0 & & shamt < BitsSupported ( ) , " Shift out of range " ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & rd = = rs1 & & shamt < = ( u32 ) ( BitsSupported ( ) = = 64 ? 63 : 31 ) ) {
C_SLLI ( rd , ( u8 ) shamt ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : SLL , rs1 , shamt ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SRLI ( RiscVReg rd , RiscVReg rs1 , u32 shamt ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
// Not sure if shamt=0 is legal or not, let's play it safe.
_assert_msg_ ( shamt > 0 & & shamt < BitsSupported ( ) , " Shift out of range " ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & shamt < = ( u32 ) ( BitsSupported ( ) = = 64 ? 63 : 31 ) ) {
C_SRLI ( rd , ( u8 ) shamt ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : SRL , rs1 , shamt ) ) ;
2022-08-25 02:19:32 +00:00
}
void RiscVEmitter : : SRAI ( RiscVReg rd , RiscVReg rs1 , u32 shamt ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
// Not sure if shamt=0 is legal or not, let's play it safe.
_assert_msg_ ( shamt > 0 & & shamt < BitsSupported ( ) , " Shift out of range " ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & shamt < = ( u32 ) ( BitsSupported ( ) = = 64 ? 63 : 31 ) ) {
C_SRAI ( rd , ( u8 ) shamt ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGI ( Opcode32 : : OP_IMM , rd , Funct3 : : SRL , rs1 , shamt | ( 1 < < 10 ) ) ) ;
}
void RiscVEmitter : : ADD ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) ) {
if ( rs1 ! = R_ZERO & & rs2 = = R_ZERO ) {
C_MV ( rd , rs1 ) ;
return ;
} else if ( rs1 = = R_ZERO & & rs2 ! = R_ZERO ) {
C_MV ( rd , rs2 ) ;
return ;
} else if ( rd = = rs1 & & rs2 ! = R_ZERO ) {
C_ADD ( rd , rs2 ) ;
return ;
} else if ( rd = = rs2 & & rs1 ! = R_ZERO ) {
C_ADD ( rd , rs1 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : ADD , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SUB ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & CanCompress ( rs2 ) ) {
C_SUB ( rd , rs2 ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : ADD , rs1 , rs2 , Funct7 : : SUB ) ) ;
}
void RiscVEmitter : : SLL ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : SLL , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SLT ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : SLT , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SLTU ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : SLTU , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : XOR ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & CanCompress ( rs2 ) ) {
C_XOR ( rd , rs2 ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : XOR , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SRL ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : SRL , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SRA ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : SRL , rs1 , rs2 , Funct7 : : SRA ) ) ;
}
void RiscVEmitter : : OR ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) ) {
if ( CanCompress ( rd ) & & rd = = rs1 & & CanCompress ( rs2 ) ) {
C_OR ( rd , rs2 ) ;
return ;
} else if ( rs1 ! = R_ZERO & & rs2 = = R_ZERO ) {
C_MV ( rd , rs1 ) ;
return ;
} else if ( rs1 = = R_ZERO & & rs2 ! = R_ZERO ) {
C_MV ( rd , rs2 ) ;
return ;
}
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : OR , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : AND ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & CanCompress ( rs2 ) ) {
C_AND ( rd , rs2 ) ;
return ;
}
2022-08-25 02:44:29 +00:00
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : AND , rs1 , rs2 , Funct7 : : ZERO ) ) ;
2022-08-25 02:19:32 +00:00
}
2022-08-25 03:33:36 +00:00
void RiscVEmitter : : FENCE ( Fence predecessor , Fence successor ) {
_assert_msg_ ( ( u32 ) predecessor ! = 0 & & ( u32 ) successor ! = 0 , " FENCE missing pred/succ " ) ;
s32 simm12 = ( ( u32 ) predecessor < < 4 ) | ( u32 ) successor ;
Write32 ( EncodeI ( Opcode32 : : MISC_MEM , R_ZERO , Funct3 : : FENCE , R_ZERO , simm12 ) ) ;
}
void RiscVEmitter : : FENCE_TSO ( ) {
s32 simm12 = ( 0b1000 < < 28 ) | ( ( u32 ) Fence : : RW < < 4 ) | ( u32 ) Fence : : RW ;
Write32 ( EncodeI ( Opcode32 : : MISC_MEM , R_ZERO , Funct3 : : FENCE , R_ZERO , simm12 ) ) ;
}
void RiscVEmitter : : ECALL ( ) {
Write32 ( EncodeI ( Opcode32 : : SYSTEM , R_ZERO , Funct3 : : PRIV , R_ZERO , Funct12 : : ECALL ) ) ;
}
void RiscVEmitter : : EBREAK ( ) {
Write32 ( EncodeI ( Opcode32 : : SYSTEM , R_ZERO , Funct3 : : PRIV , R_ZERO , Funct12 : : EBREAK ) ) ;
}
void RiscVEmitter : : LWU ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 , " %s is only valid with R64I " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_WU , rs1 , simm12 ) ) ;
}
void RiscVEmitter : : LD ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 , " %s is only valid with R64I " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & ( BitsSupported ( ) = = 64 | | BitsSupported ( ) = = 128 ) ) {
if ( CanCompress ( rd ) & & CanCompress ( rs1 ) & & ( simm12 & 0xF8 ) = = simm12 ) {
C_LD ( rd , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( rd ! = R_ZERO & & rs1 = = R_SP & & ( simm12 & 0x01F8 ) = = simm12 ) {
C_LDSP ( rd , ( u8 ) simm12 ) ;
return ;
}
}
2022-08-25 03:33:36 +00:00
Write32 ( EncodeGI ( Opcode32 : : LOAD , rd , Funct3 : : LS_D , rs1 , simm12 ) ) ;
}
void RiscVEmitter : : SD ( RiscVReg rs2 , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 , " %s is only valid with R64I " , __func__ ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & ( BitsSupported ( ) = = 64 | | BitsSupported ( ) = = 128 ) ) {
if ( CanCompress ( rs2 ) & & CanCompress ( rs1 ) & & ( simm12 & 0xF8 ) = = simm12 ) {
C_SD ( rs2 , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( rs1 = = R_SP & & ( simm12 & 0x01F8 ) = = simm12 ) {
C_SDSP ( rs2 , ( u8 ) simm12 ) ;
return ;
}
}
2022-08-25 03:33:36 +00:00
Write32 ( EncodeGS ( Opcode32 : : STORE , Funct3 : : LS_D , rs1 , rs2 , simm12 ) ) ;
}
void RiscVEmitter : : ADDIW ( RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
ADDI ( rd , rs1 , simm12 ) ;
return ;
}
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & rd ! = R_ZERO & & rd = = rs1 & & SignReduce32 ( simm12 , 6 ) = = simm12 ) {
C_ADDIW ( rd , ( s8 ) simm12 ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : OP_IMM_32 , rd , Funct3 : : ADD , rs1 , simm12 ) ) ;
}
void RiscVEmitter : : SLLIW ( RiscVReg rd , RiscVReg rs1 , u32 shamt ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SLLI ( rd , rs1 , shamt ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
// Not sure if shamt=0 is legal or not, let's play it safe.
_assert_msg_ ( shamt > 0 & & shamt < 32 , " Shift out of range " ) ;
Write32 ( EncodeGI ( Opcode32 : : OP_IMM_32 , rd , Funct3 : : SLL , rs1 , shamt ) ) ;
}
void RiscVEmitter : : SRLIW ( RiscVReg rd , RiscVReg rs1 , u32 shamt ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SRLI ( rd , rs1 , shamt ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
// Not sure if shamt=0 is legal or not, let's play it safe.
_assert_msg_ ( shamt > 0 & & shamt < 32 , " Shift out of range " ) ;
Write32 ( EncodeGI ( Opcode32 : : OP_IMM_32 , rd , Funct3 : : SRL , rs1 , shamt ) ) ;
}
void RiscVEmitter : : SRAIW ( RiscVReg rd , RiscVReg rs1 , u32 shamt ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SRAI ( rd , rs1 , shamt ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
// Not sure if shamt=0 is legal or not, let's play it safe.
_assert_msg_ ( shamt > 0 & & shamt < 32 , " Shift out of range " ) ;
Write32 ( EncodeGI ( Opcode32 : : OP_IMM_32 , rd , Funct3 : : SRL , rs1 , shamt | ( 1 < < 10 ) ) ) ;
}
void RiscVEmitter : : ADDW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
ADD ( rd , rs1 , rs2 ) ;
return ;
}
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & CanCompress ( rs2 ) ) {
C_ADDW ( rd , rs2 ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : ADD , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SUBW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SUB ( rd , rs1 , rs2 ) ;
return ;
}
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & rd = = rs1 & & CanCompress ( rs2 ) ) {
C_SUBW ( rd , rs2 ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : ADD , rs1 , rs2 , Funct7 : : SUB ) ) ;
}
void RiscVEmitter : : SLLW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SLL ( rd , rs1 , rs2 ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : SLL , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SRLW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SRL ( rd , rs1 , rs2 ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : SRL , rs1 , rs2 , Funct7 : : ZERO ) ) ;
}
void RiscVEmitter : : SRAW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
2022-08-27 05:32:20 +00:00
if ( BitsSupported ( ) = = 32 ) {
SRA ( rd , rs1 , rs2 ) ;
return ;
}
2022-08-25 03:33:36 +00:00
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero is a HINT " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : SRL , rs1 , rs2 , Funct7 : : SRA ) ) ;
}
2022-08-25 04:05:19 +00:00
void RiscVEmitter : : MUL ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : MUL , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : MULH ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : MULH , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : MULHSU ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : MULHSU , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : MULHU ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : MULHU , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : DIV ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : DIV , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : DIVU ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : DIVU , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : REM ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : REM , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : REMU ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( SupportsMulDiv ( ) , " %s is only valid with R32M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP , rd , Funct3 : : REMU , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : MULW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 & & SupportsMulDiv ( ) , " %s is only valid with R64M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : MUL , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : DIVW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 & & SupportsMulDiv ( ) , " %s is only valid with R64M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : DIV , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : DIVUW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 & & SupportsMulDiv ( ) , " %s is only valid with R64M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : DIVU , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : REMW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 & & SupportsMulDiv ( ) , " %s is only valid with R64M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : REM , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
void RiscVEmitter : : REMUW ( RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( BitsSupported ( ) > = 64 & & SupportsMulDiv ( ) , " %s is only valid with R64M " , __func__ ) ;
// Not explicitly a HINT, but seems sensible to restrict just in case.
_assert_msg_ ( rd ! = R_ZERO , " %s write to zero " , __func__ ) ;
Write32 ( EncodeGR ( Opcode32 : : OP_32 , rd , Funct3 : : REMU , rs1 , rs2 , Funct7 : : MULDIV ) ) ;
}
2022-08-25 05:58:00 +00:00
void RiscVEmitter : : LR ( int bits , RiscVReg rd , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
_assert_msg_ ( ordering ! = Atomic : : RELEASE , " %s should not use RELEASE ordering " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , R_ZERO , ordering , Funct5 : : LR ) ) ;
}
void RiscVEmitter : : SC ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
_assert_msg_ ( ordering ! = Atomic : : ACQUIRE , " %s should not use ACQUIRE ordering " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : SC ) ) ;
}
void RiscVEmitter : : AMOSWAP ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOSWAP ) ) ;
}
void RiscVEmitter : : AMOADD ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOADD ) ) ;
}
void RiscVEmitter : : AMOAND ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOAND ) ) ;
}
void RiscVEmitter : : AMOOR ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOOR ) ) ;
}
void RiscVEmitter : : AMOXOR ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOXOR ) ) ;
}
void RiscVEmitter : : AMOMIN ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOMIN ) ) ;
}
void RiscVEmitter : : AMOMAX ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOMAX ) ) ;
}
void RiscVEmitter : : AMOMINU ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOMINU ) ) ;
}
void RiscVEmitter : : AMOMAXU ( int bits , RiscVReg rd , RiscVReg rs2 , RiscVReg rs1 , Atomic ordering ) {
_assert_msg_ ( SupportsAtomic ( ) , " %s is only valid with R32A " , __func__ ) ;
Write32 ( EncodeAtomicR ( Opcode32 : : AMO , rd , BitsToFunct3 ( bits ) , rs1 , rs2 , ordering , Funct5 : : AMOMAXU ) ) ;
}
2022-08-26 02:26:15 +00:00
void RiscVEmitter : : FL ( int bits , RiscVReg rd , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( IsGPR ( rs1 ) & & IsFPR ( rd ) , " FL with incorrect register types " ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rd ) & & CanCompress ( rs1 ) ) {
if ( bits = = 64 & & BitsSupported ( ) < = 64 & & ( simm12 & 0xF8 ) = = simm12 ) {
C_FLD ( rd , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( bits = = 32 & & BitsSupported ( ) = = 32 & & ( simm12 & 0x7C ) = = simm12 ) {
C_FLW ( rd , rs1 , ( u8 ) simm12 ) ;
return ;
}
} else if ( AutoCompress ( ) & & rs1 = = R_SP ) {
if ( bits = = 64 & & BitsSupported ( ) < = 64 & & ( simm12 & 0x01F8 ) = = simm12 ) {
C_FLDSP ( rd , ( u32 ) simm12 ) ;
return ;
} else if ( bits = = 32 & & BitsSupported ( ) = = 32 & & ( simm12 & 0xFC ) = = simm12 ) {
C_FLWSP ( rd , ( u8 ) simm12 ) ;
return ;
}
}
2022-08-26 02:26:15 +00:00
Write32 ( EncodeI ( Opcode32 : : LOAD_FP , rd , BitsToFunct3 ( bits , true ) , rs1 , simm12 ) ) ;
}
void RiscVEmitter : : FS ( int bits , RiscVReg rs2 , RiscVReg rs1 , s32 simm12 ) {
_assert_msg_ ( IsGPR ( rs1 ) & & IsFPR ( rs2 ) , " FS with incorrect register types " ) ;
2022-08-27 22:14:22 +00:00
if ( AutoCompress ( ) & & CanCompress ( rs2 ) & & CanCompress ( rs1 ) ) {
if ( bits = = 64 & & BitsSupported ( ) < = 64 & & ( simm12 & 0xF8 ) = = simm12 ) {
C_FSD ( rs2 , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( bits = = 32 & & BitsSupported ( ) = = 32 & & ( simm12 & 0x7C ) = = simm12 ) {
C_FSW ( rs2 , rs1 , ( u8 ) simm12 ) ;
return ;
} else if ( AutoCompress ( ) & & rs1 = = R_SP ) {
if ( bits = = 64 & & BitsSupported ( ) < = 64 & & ( simm12 & 0x01F8 ) = = simm12 ) {
C_FSDSP ( rs2 , ( u32 ) simm12 ) ;
return ;
} else if ( bits = = 32 & & BitsSupported ( ) = = 32 & & ( simm12 & 0xFC ) = = simm12 ) {
C_FSWSP ( rs2 , ( u8 ) simm12 ) ;
return ;
}
}
}
2022-08-26 02:26:15 +00:00
Write32 ( EncodeS ( Opcode32 : : STORE_FP , BitsToFunct3 ( bits , true ) , rs1 , rs2 , simm12 ) ) ;
}
void RiscVEmitter : : FMADD ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , RiscVReg rs3 , Round rm ) {
Write32 ( EncodeFR4 ( Opcode32 : : FMADD , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , rs3 ) ) ;
}
void RiscVEmitter : : FMSUB ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , RiscVReg rs3 , Round rm ) {
Write32 ( EncodeFR4 ( Opcode32 : : FMSUB , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , rs3 ) ) ;
}
void RiscVEmitter : : FNMSUB ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , RiscVReg rs3 , Round rm ) {
Write32 ( EncodeFR4 ( Opcode32 : : FNMSUB , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , rs3 ) ) ;
}
void RiscVEmitter : : FNMADD ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , RiscVReg rs3 , Round rm ) {
Write32 ( EncodeFR4 ( Opcode32 : : FNMADD , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , rs3 ) ) ;
}
void RiscVEmitter : : FADD ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , Round rm ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FADD ) ) ;
}
void RiscVEmitter : : FSUB ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , Round rm ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FSUB ) ) ;
}
void RiscVEmitter : : FMUL ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , Round rm ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FMUL ) ) ;
}
void RiscVEmitter : : FDIV ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 , Round rm ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FDIV ) ) ;
}
void RiscVEmitter : : FSQRT ( int bits , RiscVReg rd , RiscVReg rs1 , Round rm ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , F0 , BitsToFunct2 ( bits ) , Funct5 : : FSQRT ) ) ;
}
void RiscVEmitter : : FSGNJ ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , Funct3 : : FSGNJ , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FSGNJ ) ) ;
}
void RiscVEmitter : : FSGNJN ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , Funct3 : : FSGNJN , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FSGNJ ) ) ;
}
void RiscVEmitter : : FSGNJX ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , Funct3 : : FSGNJX , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FSGNJ ) ) ;
}
void RiscVEmitter : : FMIN ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , Funct3 : : FMIN , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FMINMAX ) ) ;
}
void RiscVEmitter : : FMAX ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
Write32 ( EncodeFR ( Opcode32 : : OP_FP , rd , Funct3 : : FMAX , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FMINMAX ) ) ;
}
void RiscVEmitter : : FCVT ( FConv to , FConv from , RiscVReg rd , RiscVReg rs1 , Round rm ) {
int floatBits = std : : max ( FConvToFloatBits ( from ) , FConvToFloatBits ( to ) ) ;
int integerBits = std : : max ( FConvToIntegerBits ( from ) , FConvToIntegerBits ( to ) ) ;
_assert_msg_ ( floatBits > 0 , " FCVT can't be used with only GPRs " ) ;
_assert_msg_ ( integerBits < = BitsSupported ( ) , " FCVT for %d integer bits, only %d supported " , integerBits , BitsSupported ( ) ) ;
_assert_msg_ ( floatBits < = FloatBitsSupported ( ) , " FCVT for %d float bits, only %d supported " , floatBits , FloatBitsSupported ( ) ) ;
if ( integerBits = = 0 ) {
// Convert between float widths.
Funct2 fromFmt = BitsToFunct2 ( FConvToFloatBits ( from ) ) ;
Funct2 toFmt = BitsToFunct2 ( FConvToFloatBits ( to ) ) ;
2022-08-26 03:30:01 +00:00
if ( FConvToFloatBits ( to ) > FConvToFloatBits ( from ) ) {
_assert_msg_ ( rm = = Round : : DYNAMIC | | rm = = Round : : NEAREST_EVEN , " Invalid rounding mode for widening FCVT " ) ;
rm = Round : : NEAREST_EVEN ;
}
2022-08-26 02:26:15 +00:00
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , ( RiscVReg ) fromFmt , toFmt , Funct5 : : FCVT_SZ ) ) ;
} else {
Funct5 funct5 = FConvToIntegerBits ( to ) = = 0 ? Funct5 : : FCVT_FROMX : Funct5 : : FCVT_TOX ;
FConv integerFmt = FConvToIntegerBits ( to ) = = 0 ? from : to ;
Funct2 floatFmt = BitsToFunct2 ( floatBits ) ;
_assert_msg_ ( ( ( int ) integerFmt & ~ 3 ) = = 0 , " Got wrong integer bits " ) ;
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , ( Funct3 ) rm , rs1 , ( RiscVReg ) integerFmt , floatFmt , funct5 ) ) ;
}
}
void RiscVEmitter : : FMV ( FMv to , FMv from , RiscVReg rd , RiscVReg rs1 ) {
int bits = 0 ;
switch ( to = = FMv : : X ? from : to ) {
case FMv : : D : bits = 64 ; break ;
case FMv : : W : bits = 32 ; break ;
case FMv : : X : bits = 0 ; break ;
}
_assert_msg_ ( BitsSupported ( ) > = bits & & FloatBitsSupported ( ) > = bits , " FMV cannot be used for %d bits, only %d/%d supported " , bits , BitsSupported ( ) , FloatBitsSupported ( ) ) ;
_assert_msg_ ( ( to = = FMv : : X & & from ! = FMv : : X ) | | ( to ! = FMv : : X & & from = = FMv : : X ) , " %s can only transfer between FPR/GPR " , __func__ ) ;
_assert_msg_ ( to = = FMv : : X ? IsGPR ( rd ) : IsFPR ( rd ) , " %s rd of wrong type " , __func__ ) ;
_assert_msg_ ( from = = FMv : : X ? IsGPR ( rs1 ) : IsFPR ( rs1 ) , " %s rs1 of wrong type " , __func__ ) ;
Funct5 funct5 = to = = FMv : : X ? Funct5 : : FMV_TOX : Funct5 : : FMV_FROMX ;
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , Funct3 : : FMV , rs1 , F0 , BitsToFunct2 ( bits ) , funct5 ) ) ;
}
void RiscVEmitter : : FEQ ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s rd must be GPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs1 ) , " %s rs1 must be FPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " %s rs2 must be FPR " , __func__ ) ;
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , Funct3 : : FEQ , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FCMP ) ) ;
}
void RiscVEmitter : : FLT ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s rd must be GPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs1 ) , " %s rs1 must be FPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " %s rs2 must be FPR " , __func__ ) ;
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , Funct3 : : FLT , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FCMP ) ) ;
}
void RiscVEmitter : : FLE ( int bits , RiscVReg rd , RiscVReg rs1 , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s rd must be GPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs1 ) , " %s rs1 must be FPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " %s rs2 must be FPR " , __func__ ) ;
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , Funct3 : : FLE , rs1 , rs2 , BitsToFunct2 ( bits ) , Funct5 : : FCMP ) ) ;
}
void RiscVEmitter : : FCLASS ( int bits , RiscVReg rd , RiscVReg rs1 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s rd must be GPR " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs1 ) , " %s rs1 must be FPR " , __func__ ) ;
Write32 ( EncodeR ( Opcode32 : : OP_FP , rd , Funct3 : : FCLASS , rs1 , F0 , BitsToFunct2 ( bits ) , Funct5 : : FMV_TOX ) ) ;
}
2022-08-25 05:58:00 +00:00
2022-08-26 03:30:01 +00:00
void RiscVEmitter : : CSRRW ( RiscVReg rd , Csr csr , RiscVReg rs1 ) {
_assert_msg_ ( SupportsZicsr ( ) , " %s instruction not supported " , __func__ ) ;
_assert_msg_ ( ( u32 ) csr < = 0x00000FFF , " %s with invalid CSR number " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : SYSTEM , rd , Funct3 : : CSRRW , rs1 , ( Funct12 ) csr ) ) ;
}
void RiscVEmitter : : CSRRS ( RiscVReg rd , Csr csr , RiscVReg rs1 ) {
_assert_msg_ ( SupportsZicsr ( ) , " %s instruction not supported " , __func__ ) ;
_assert_msg_ ( ( u32 ) csr < = 0x00000FFF , " %s with invalid CSR number " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : SYSTEM , rd , Funct3 : : CSRRS , rs1 , ( Funct12 ) csr ) ) ;
}
void RiscVEmitter : : CSRRC ( RiscVReg rd , Csr csr , RiscVReg rs1 ) {
_assert_msg_ ( SupportsZicsr ( ) , " %s instruction not supported " , __func__ ) ;
_assert_msg_ ( ( u32 ) csr < = 0x00000FFF , " %s with invalid CSR number " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : SYSTEM , rd , Funct3 : : CSRRC , rs1 , ( Funct12 ) csr ) ) ;
}
void RiscVEmitter : : CSRRWI ( RiscVReg rd , Csr csr , u8 uimm5 ) {
_assert_msg_ ( SupportsZicsr ( ) , " %s instruction not supported " , __func__ ) ;
_assert_msg_ ( ( u32 ) csr < = 0x00000FFF , " %s with invalid CSR number " , __func__ ) ;
_assert_msg_ ( ( u32 ) uimm5 < = 0x1F , " %s can only specify lowest 5 bits " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : SYSTEM , rd , Funct3 : : CSRRWI , ( RiscVReg ) uimm5 , ( Funct12 ) csr ) ) ;
}
void RiscVEmitter : : CSRRSI ( RiscVReg rd , Csr csr , u8 uimm5 ) {
_assert_msg_ ( SupportsZicsr ( ) , " %s instruction not supported " , __func__ ) ;
_assert_msg_ ( ( u32 ) csr < = 0x00000FFF , " %s with invalid CSR number " , __func__ ) ;
_assert_msg_ ( ( u32 ) uimm5 < = 0x1F , " %s can only set lowest 5 bits " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : SYSTEM , rd , Funct3 : : CSRRSI , ( RiscVReg ) uimm5 , ( Funct12 ) csr ) ) ;
}
void RiscVEmitter : : CSRRCI ( RiscVReg rd , Csr csr , u8 uimm5 ) {
_assert_msg_ ( SupportsZicsr ( ) , " %s instruction not supported " , __func__ ) ;
_assert_msg_ ( ( u32 ) csr < = 0x00000FFF , " %s with invalid CSR number " , __func__ ) ;
_assert_msg_ ( ( u32 ) uimm5 < = 0x1F , " %s can only clear lowest 5 bits " , __func__ ) ;
Write32 ( EncodeGI ( Opcode32 : : SYSTEM , rd , Funct3 : : CSRRCI , ( RiscVReg ) uimm5 , ( Funct12 ) csr ) ) ;
}
2022-08-27 22:14:22 +00:00
bool RiscVEmitter : : AutoCompress ( ) const {
return SupportsCompressed ( ) & & autoCompress_ ;
}
void RiscVEmitter : : C_ADDI4SPN ( RiscVReg rd , u32 uimm10 ) {
_assert_msg_ ( IsGPR ( rd ) & & CanCompress ( rd ) , " %s requires rd as GPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( ( uimm10 & 0x03FC ) = = uimm10 & & uimm10 ! = 0 , " %s offset must fit in 10 bits and be a non-zero multiple of 4: %d " , __func__ , ( int ) uimm10 ) ;
u8 imm2_3 = ( ImmBit8 ( uimm10 , 2 ) < < 1 ) | ImmBit8 ( uimm10 , 3 ) ;
u8 imm9_8_7_6 = ImmBits8 ( uimm10 , 6 , 4 ) ;
u8 imm5_4 = ImmBits8 ( uimm10 , 4 , 2 ) ;
u8 imm_5_4_9_8_7_6_2_3 = ( imm5_4 < < 6 ) | ( imm9_8_7_6 < < 2 ) | imm2_3 ;
Write16 ( EncodeCIW ( Opcode16 : : C0 , CompressReg ( rd ) , imm_5_4_9_8_7_6_2_3 , Funct3 : : C_ADDI4SPN ) ) ;
}
void RiscVEmitter : : C_FLD ( RiscVReg rd , RiscVReg rs1 , u8 uimm8 ) {
_assert_msg_ ( BitsSupported ( ) < = 64 & & FloatBitsSupported ( ) = = 64 , " %s is only valid with RV32DC/RV64DC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rd ) & & CanCompress ( rd ) , " %s requires rd as FPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCL8 ( Opcode16 : : C0 , CompressReg ( rd ) , CompressReg ( rs1 ) , uimm8 , Funct3 : : C_FLD ) ) ;
}
void RiscVEmitter : : C_LW ( RiscVReg rd , RiscVReg rs1 , u8 uimm7 ) {
_assert_msg_ ( IsGPR ( rd ) & & CanCompress ( rd ) , " %s requires rd as GPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCL4 ( Opcode16 : : C0 , CompressReg ( rd ) , CompressReg ( rs1 ) , uimm7 , Funct3 : : C_LW ) ) ;
}
void RiscVEmitter : : C_FLW ( RiscVReg rd , RiscVReg rs1 , u8 uimm7 ) {
_assert_msg_ ( BitsSupported ( ) = = 32 & & FloatBitsSupported ( ) > = 32 , " %s is only valid with RV32FC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rd ) & & CanCompress ( rd ) , " %s requires rd as FPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCL4 ( Opcode16 : : C0 , CompressReg ( rd ) , CompressReg ( rs1 ) , uimm7 , Funct3 : : C_FLW ) ) ;
}
void RiscVEmitter : : C_LD ( RiscVReg rd , RiscVReg rs1 , u8 uimm8 ) {
_assert_msg_ ( BitsSupported ( ) = = 64 | | BitsSupported ( ) = = 128 , " %s is only valid with RV64/RV128 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rd ) & & CanCompress ( rd ) , " %s requires rd as GPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCL8 ( Opcode16 : : C0 , CompressReg ( rd ) , CompressReg ( rs1 ) , uimm8 , Funct3 : : C_LD ) ) ;
}
void RiscVEmitter : : C_FSD ( RiscVReg rs2 , RiscVReg rs1 , u8 uimm8 ) {
_assert_msg_ ( BitsSupported ( ) < = 64 & & FloatBitsSupported ( ) = = 64 , " %s is only valid with RV32DC/RV64DC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) & & CanCompress ( rs2 ) , " %s requires rs2 as FPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCL8 ( Opcode16 : : C0 , CompressReg ( rs2 ) , CompressReg ( rs1 ) , uimm8 , Funct3 : : C_FSD ) ) ;
}
void RiscVEmitter : : C_SW ( RiscVReg rs2 , RiscVReg rs1 , u8 uimm7 ) {
_assert_msg_ ( IsGPR ( rs2 ) & & CanCompress ( rs2 ) , " %s requires rs2 as GPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCS4 ( Opcode16 : : C0 , CompressReg ( rs2 ) , CompressReg ( rs1 ) , uimm7 , Funct3 : : C_SW ) ) ;
}
void RiscVEmitter : : C_FSW ( RiscVReg rs2 , RiscVReg rs1 , u8 uimm7 ) {
_assert_msg_ ( BitsSupported ( ) = = 32 & & FloatBitsSupported ( ) > = 32 , " %s is only valid with RV32FC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) & & CanCompress ( rs2 ) , " %s requires rs2 as FPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCS4 ( Opcode16 : : C0 , CompressReg ( rs2 ) , CompressReg ( rs1 ) , uimm7 , Funct3 : : C_FSW ) ) ;
}
void RiscVEmitter : : C_SD ( RiscVReg rs2 , RiscVReg rs1 , u8 uimm8 ) {
_assert_msg_ ( BitsSupported ( ) = = 64 | | BitsSupported ( ) = = 128 , " %s is only valid with RV64/RV128 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs2 ) & & CanCompress ( rs2 ) , " %s requires rs2 as GPR between X8 and X15 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs1 ) & & CanCompress ( rs1 ) , " %s requires rs1 as GPR between X8 and X15 " , __func__ ) ;
Write16 ( EncodeCS8 ( Opcode16 : : C0 , CompressReg ( rs2 ) , CompressReg ( rs1 ) , uimm8 , Funct3 : : C_SD ) ) ;
}
void RiscVEmitter : : C_NOP ( ) {
Write16 ( EncodeCI ( Opcode16 : : C1 , 0 , R_ZERO , Funct3 : : C_ADDI ) ) ;
}
void RiscVEmitter : : C_ADDI ( RiscVReg rd , s8 simm6 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( simm6 ! = 0 & & SignReduce32 ( simm6 , 6 ) = = ( s32 ) simm6 , " %s immediate must be non-zero and s5.0: %d " , __func__ , simm6 ) ;
Write16 ( EncodeCI ( Opcode16 : : C1 , ImmBits8 ( simm6 , 0 , 6 ) , rd , Funct3 : : C_ADDI ) ) ;
}
void RiscVEmitter : : C_JAL ( const void * dst ) {
_assert_msg_ ( BitsSupported ( ) = = 32 , " %s is only valid with RV32C " , __func__ ) ;
_assert_msg_ ( CJInRange ( GetCodePointer ( ) , dst ) , " C_JAL destination is too far away (%p -> %p) " , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 1 ) = = 0 , " C_JAL destination should be aligned " ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
Write32 ( EncodeCJ ( Opcode16 : : C1 , ( s32 ) distance , Funct3 : : C_JAL ) ) ;
}
FixupBranch RiscVEmitter : : C_JAL ( ) {
_assert_msg_ ( BitsSupported ( ) = = 32 , " %s is only valid with RV32C " , __func__ ) ;
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : CJ } ;
Write16 ( EncodeCJ ( Opcode16 : : C1 , 0 , Funct3 : : C_JAL ) ) ;
return fixup ;
}
void RiscVEmitter : : C_ADDIW ( RiscVReg rd , s8 simm6 ) {
if ( BitsSupported ( ) = = 32 ) {
C_ADDI ( rd , simm6 ) ;
return ;
}
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( SignReduce32 ( simm6 , 6 ) = = ( s32 ) simm6 , " %s immediate must be s5.0: %d " , __func__ , simm6 ) ;
Write16 ( EncodeCI ( Opcode16 : : C1 , ImmBits8 ( simm6 , 0 , 6 ) , rd , Funct3 : : C_ADDIW ) ) ;
}
void RiscVEmitter : : C_LI ( RiscVReg rd , s8 simm6 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( SignReduce32 ( simm6 , 6 ) = = ( s32 ) simm6 , " %s immediate must be s5.0: %d " , __func__ , simm6 ) ;
Write16 ( EncodeCI ( Opcode16 : : C1 , ImmBits8 ( simm6 , 0 , 6 ) , rd , Funct3 : : C_LI ) ) ;
}
void RiscVEmitter : : C_ADDI16SP ( s32 simm10 ) {
_assert_msg_ ( simm10 ! = 0 & & SignReduce32 ( simm10 , 10 ) = = simm10 , " %s immediate must be non-zero and s9.0: %d " , __func__ , simm10 ) ;
_assert_msg_ ( ( simm10 & 0xF ) = = 0 , " %s immediate must be multiple of 16: %d " , __func__ , simm10 ) ;
u8 imm8_7_5 = ( ImmBits8 ( simm10 , 7 , 2 ) < < 1 ) | ImmBit8 ( simm10 , 5 ) ;
u8 imm4_6 = ( ImmBit8 ( simm10 , 4 ) < < 1 ) | ImmBit8 ( simm10 , 6 ) ;
u8 imm9_4_6_8_7_5 = ( ImmBit8 ( simm10 , 9 ) < < 5 ) | ( imm4_6 < < 3 ) | imm8_7_5 ;
Write16 ( EncodeCI ( Opcode16 : : C1 , imm9_4_6_8_7_5 , R_SP , Funct3 : : C_LUI ) ) ;
}
void RiscVEmitter : : C_LUI ( RiscVReg rd , s32 simm18 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO & & rd ! = R_SP , " %s must write to GPR other than X0/X2 " , __func__ ) ;
_assert_msg_ ( simm18 ! = 0 & & SignReduce32 ( simm18 , 18 ) = = simm18 , " %s immediate must be non-zero and s17.0: %d " , __func__ , simm18 ) ;
_assert_msg_ ( ( simm18 & 0x0FFF ) = = 0 , " %s immediate must not have lower 12 bits set: %d " , __func__ , simm18 ) ;
u8 imm17_12 = ImmBits8 ( simm18 , 12 , 6 ) ;
Write16 ( EncodeCI ( Opcode16 : : C1 , imm17_12 , rd , Funct3 : : C_LUI ) ) ;
}
void RiscVEmitter : : C_SRLI ( RiscVReg rd , u8 uimm6 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s must write to GPR " , __func__ ) ;
_assert_msg_ ( uimm6 ! = 0 & & uimm6 < = ( BitsSupported ( ) = = 64 ? 63 : 31 ) , " %s immediate must be between 1 and %d: %d " , __func__ , BitsSupported ( ) = = 64 ? 63 : 31 , uimm6 ) ;
Write16 ( EncodeCB ( Opcode16 : : C1 , uimm6 , CompressReg ( rd ) , Funct2 : : C_SRLI , Funct3 : : C_ARITH ) ) ;
}
void RiscVEmitter : : C_SRAI ( RiscVReg rd , u8 uimm6 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s must write to GPR " , __func__ ) ;
_assert_msg_ ( uimm6 ! = 0 & & uimm6 < = ( BitsSupported ( ) = = 64 ? 63 : 31 ) , " %s immediate must be between 1 and %d: %d " , __func__ , BitsSupported ( ) = = 64 ? 63 : 31 , uimm6 ) ;
Write16 ( EncodeCB ( Opcode16 : : C1 , uimm6 , CompressReg ( rd ) , Funct2 : : C_SRAI , Funct3 : : C_ARITH ) ) ;
}
void RiscVEmitter : : C_ANDI ( RiscVReg rd , s8 simm6 ) {
_assert_msg_ ( IsGPR ( rd ) , " %s must write to GPR " , __func__ ) ;
// It seems like a mistake that this allows simm6 == 0 when c.li can be used...
_assert_msg_ ( SignReduce32 ( simm6 , 6 ) = = ( s32 ) simm6 , " %s immediate must be s5.0: %d " , __func__ , simm6 ) ;
Write16 ( EncodeCB ( Opcode16 : : C1 , ImmBits8 ( simm6 , 0 , 6 ) , CompressReg ( rd ) , Funct2 : : C_ANDI , Funct3 : : C_ARITH ) ) ;
}
void RiscVEmitter : : C_SUB ( RiscVReg rd , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( rs2 ) , " %s must use GPRs " , __func__ ) ;
Write16 ( EncodeCA ( Opcode16 : : C1 , CompressReg ( rs2 ) , Funct2 : : C_SUB , CompressReg ( rd ) , Funct6 : : C_OP ) ) ;
}
void RiscVEmitter : : C_XOR ( RiscVReg rd , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( rs2 ) , " %s must use GPRs " , __func__ ) ;
Write16 ( EncodeCA ( Opcode16 : : C1 , CompressReg ( rs2 ) , Funct2 : : C_XOR , CompressReg ( rd ) , Funct6 : : C_OP ) ) ;
}
void RiscVEmitter : : C_OR ( RiscVReg rd , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( rs2 ) , " %s must use GPRs " , __func__ ) ;
Write16 ( EncodeCA ( Opcode16 : : C1 , CompressReg ( rs2 ) , Funct2 : : C_OR , CompressReg ( rd ) , Funct6 : : C_OP ) ) ;
}
void RiscVEmitter : : C_AND ( RiscVReg rd , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( rs2 ) , " %s must use GPRs " , __func__ ) ;
Write16 ( EncodeCA ( Opcode16 : : C1 , CompressReg ( rs2 ) , Funct2 : : C_AND , CompressReg ( rd ) , Funct6 : : C_OP ) ) ;
}
void RiscVEmitter : : C_SUBW ( RiscVReg rd , RiscVReg rs2 ) {
if ( BitsSupported ( ) = = 32 ) {
C_SUB ( rd , rs2 ) ;
return ;
}
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( rs2 ) , " %s must use GPRs " , __func__ ) ;
Write16 ( EncodeCA ( Opcode16 : : C1 , CompressReg ( rs2 ) , Funct2 : : C_SUBW , CompressReg ( rd ) , Funct6 : : C_OP_32 ) ) ;
}
void RiscVEmitter : : C_ADDW ( RiscVReg rd , RiscVReg rs2 ) {
if ( BitsSupported ( ) = = 32 ) {
C_ADD ( rd , rs2 ) ;
return ;
}
_assert_msg_ ( IsGPR ( rd ) & & IsGPR ( rs2 ) , " %s must use GPRs " , __func__ ) ;
Write16 ( EncodeCA ( Opcode16 : : C1 , CompressReg ( rs2 ) , Funct2 : : C_ADDW , CompressReg ( rd ) , Funct6 : : C_OP_32 ) ) ;
}
void RiscVEmitter : : C_J ( const void * dst ) {
_assert_msg_ ( CJInRange ( GetCodePointer ( ) , dst ) , " C_J destination is too far away (%p -> %p) " , GetCodePointer ( ) , dst ) ;
_assert_msg_ ( ( ( intptr_t ) dst & 1 ) = = 0 , " C_J destination should be aligned " ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
Write16 ( EncodeCJ ( Opcode16 : : C1 , ( s32 ) distance , Funct3 : : C_J ) ) ;
}
void RiscVEmitter : : C_BEQZ ( RiscVReg rs1 , const void * dst ) {
_assert_msg_ ( IsGPR ( rs1 ) , " %s must use a GPR " , __func__ ) ;
_assert_msg_ ( CBInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
Write16 ( EncodeCB ( Opcode16 : : C1 , ( s32 ) distance , CompressReg ( rs1 ) , Funct3 : : C_BEQZ ) ) ;
}
void RiscVEmitter : : C_BNEZ ( RiscVReg rs1 , const void * dst ) {
_assert_msg_ ( IsGPR ( rs1 ) , " %s must use a GPR " , __func__ ) ;
_assert_msg_ ( CBInRange ( GetCodePointer ( ) , dst ) , " %s destination is too far away (%p -> %p) " , __func__ , GetCodePointer ( ) , dst ) ;
ptrdiff_t distance = ( intptr_t ) dst - ( intptr_t ) GetCodePointer ( ) ;
Write16 ( EncodeCB ( Opcode16 : : C1 , ( s32 ) distance , CompressReg ( rs1 ) , Funct3 : : C_BNEZ ) ) ;
}
FixupBranch RiscVEmitter : : C_J ( ) {
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : CJ } ;
Write16 ( EncodeCJ ( Opcode16 : : C1 , 0 , Funct3 : : C_J ) ) ;
return fixup ;
}
FixupBranch RiscVEmitter : : C_BEQZ ( RiscVReg rs1 ) {
_assert_msg_ ( IsGPR ( rs1 ) , " %s must use a GPR " , __func__ ) ;
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : CB } ;
Write16 ( EncodeCB ( Opcode16 : : C1 , 0 , CompressReg ( rs1 ) , Funct3 : : C_BEQZ ) ) ;
return fixup ;
}
FixupBranch RiscVEmitter : : C_BNEZ ( RiscVReg rs1 ) {
_assert_msg_ ( IsGPR ( rs1 ) , " %s must use a GPR " , __func__ ) ;
FixupBranch fixup { GetCodePointer ( ) , FixupBranchType : : CB } ;
Write16 ( EncodeCB ( Opcode16 : : C1 , 0 , CompressReg ( rs1 ) , Funct3 : : C_BNEZ ) ) ;
return fixup ;
}
void RiscVEmitter : : C_SLLI ( RiscVReg rd , u8 uimm6 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( uimm6 ! = 0 & & uimm6 < = ( BitsSupported ( ) = = 64 ? 63 : 31 ) , " %s immediate must be between 1 and %d: %d " , __func__ , BitsSupported ( ) = = 64 ? 63 : 31 , uimm6 ) ;
Write16 ( EncodeCI ( Opcode16 : : C2 , uimm6 , rd , Funct3 : : C_SLLI ) ) ;
}
void RiscVEmitter : : C_FLDSP ( RiscVReg rd , u32 uimm9 ) {
_assert_msg_ ( BitsSupported ( ) < = 64 & & FloatBitsSupported ( ) = = 64 , " %s is only valid with RV32DC/RV64DC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rd ) , " %s must write to FPR " , __func__ ) ;
_assert_msg_ ( ( uimm9 & 0x01F8 ) = = uimm9 , " %s offset must fit in 9 bits and be a multiple of 8: %d " , __func__ , ( int ) uimm9 ) ;
u8 imm8_7_6 = ImmBits8 ( uimm9 , 6 , 3 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm9 , 3 , 3 ) ;
u8 imm5_4_3_8_7_6 = ( imm5_4_3 < < 3 ) | imm8_7_6 ;
Write16 ( EncodeCI ( Opcode16 : : C2 , imm5_4_3_8_7_6 , rd , Funct3 : : C_FLDSP ) ) ;
}
void RiscVEmitter : : C_LWSP ( RiscVReg rd , u8 uimm8 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( ( uimm8 & 0xFC ) = = uimm8 , " %s offset must fit in 8 bits and be a multiple of 4: %d " , __func__ , ( int ) uimm8 ) ;
u8 imm7_6 = ImmBits8 ( uimm8 , 6 , 2 ) ;
u8 imm5_4_3_2 = ImmBits8 ( uimm8 , 2 , 4 ) ;
u8 imm5_4_3_2_7_6 = ( imm5_4_3_2 < < 2 ) | imm7_6 ;
Write16 ( EncodeCI ( Opcode16 : : C2 , imm5_4_3_2_7_6 , rd , Funct3 : : C_LWSP ) ) ;
}
void RiscVEmitter : : C_FLWSP ( RiscVReg rd , u8 uimm8 ) {
_assert_msg_ ( BitsSupported ( ) = = 32 & & FloatBitsSupported ( ) > = 32 , " %s is only valid with RV32FC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rd ) , " %s must write to FPR " , __func__ ) ;
_assert_msg_ ( ( uimm8 & 0xFC ) = = uimm8 , " %s offset must fit in 8 bits and be a multiple of 4: %d " , __func__ , ( int ) uimm8 ) ;
u8 imm7_6 = ImmBits8 ( uimm8 , 6 , 2 ) ;
u8 imm5_4_3_2 = ImmBits8 ( uimm8 , 2 , 4 ) ;
u8 imm5_4_3_2_7_6 = ( imm5_4_3_2 < < 2 ) | imm7_6 ;
Write16 ( EncodeCI ( Opcode16 : : C2 , imm5_4_3_2_7_6 , rd , Funct3 : : C_FLWSP ) ) ;
}
void RiscVEmitter : : C_LDSP ( RiscVReg rd , u32 uimm9 ) {
_assert_msg_ ( BitsSupported ( ) = = 64 | | BitsSupported ( ) = = 128 , " %s is only valid with RV64/RV128 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( ( uimm9 & 0x01F8 ) = = uimm9 , " %s offset must fit in 9 bits and be a multiple of 8: %d " , __func__ , ( int ) uimm9 ) ;
u8 imm8_7_6 = ImmBits8 ( uimm9 , 6 , 3 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm9 , 3 , 3 ) ;
u8 imm5_4_3_8_7_6 = ( imm5_4_3 < < 3 ) | imm8_7_6 ;
Write16 ( EncodeCI ( Opcode16 : : C2 , imm5_4_3_8_7_6 , rd , Funct3 : : C_LDSP ) ) ;
}
void RiscVEmitter : : C_JR ( RiscVReg rs1 ) {
_assert_msg_ ( IsGPR ( rs1 ) & & rs1 ! = R_ZERO , " %s must read from GPR other than X0 " , __func__ ) ;
Write16 ( EncodeCR ( Opcode16 : : C2 , R_ZERO , rs1 , Funct4 : : C_JR ) ) ;
}
void RiscVEmitter : : C_MV ( RiscVReg rd , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs2 ) & & rs2 ! = R_ZERO , " %s must read from GPR other than X0 " , __func__ ) ;
Write16 ( EncodeCR ( Opcode16 : : C2 , rs2 , rd , Funct4 : : C_MV ) ) ;
}
void RiscVEmitter : : C_EBREAK ( ) {
Write16 ( EncodeCR ( Opcode16 : : C2 , R_ZERO , R_ZERO , Funct4 : : C_JALR ) ) ;
}
void RiscVEmitter : : C_JALR ( RiscVReg rs1 ) {
_assert_msg_ ( IsGPR ( rs1 ) & & rs1 ! = R_ZERO , " %s must read from GPR other than X0 " , __func__ ) ;
Write16 ( EncodeCR ( Opcode16 : : C2 , R_ZERO , rs1 , Funct4 : : C_JALR ) ) ;
}
void RiscVEmitter : : C_ADD ( RiscVReg rd , RiscVReg rs2 ) {
_assert_msg_ ( IsGPR ( rd ) & & rd ! = R_ZERO , " %s must write to GPR other than X0 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs2 ) & & rs2 ! = R_ZERO , " %s must read from a GPR other than X0 " , __func__ ) ;
Write16 ( EncodeCR ( Opcode16 : : C2 , rs2 , rd , Funct4 : : C_ADD ) ) ;
}
void RiscVEmitter : : C_FSDSP ( RiscVReg rs2 , u32 uimm9 ) {
_assert_msg_ ( BitsSupported ( ) < = 64 & & FloatBitsSupported ( ) = = 64 , " %s is only valid with RV32DC/RV64DC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " %s must read from FPR " , __func__ ) ;
_assert_msg_ ( ( uimm9 & 0x01F8 ) = = uimm9 , " %s offset must fit in 9 bits and be a multiple of 8: %d " , __func__ , ( int ) uimm9 ) ;
u8 imm8_7_6 = ImmBits8 ( uimm9 , 6 , 3 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm9 , 3 , 3 ) ;
u8 imm5_4_3_8_7_6 = ( imm5_4_3 < < 3 ) | imm8_7_6 ;
Write16 ( EncodeCSS ( Opcode16 : : C2 , rs2 , imm5_4_3_8_7_6 , Funct3 : : C_FSDSP ) ) ;
}
void RiscVEmitter : : C_SWSP ( RiscVReg rs2 , u8 uimm8 ) {
_assert_msg_ ( IsGPR ( rs2 ) , " %s must read from GPR " , __func__ ) ;
_assert_msg_ ( ( uimm8 & 0xFC ) = = uimm8 , " %s offset must fit in 8 bits and be a multiple of 4: %d " , __func__ , ( int ) uimm8 ) ;
u8 imm7_6 = ImmBits8 ( uimm8 , 6 , 2 ) ;
u8 imm5_4_3_2 = ImmBits8 ( uimm8 , 2 , 4 ) ;
u8 imm5_4_3_2_7_6 = ( imm5_4_3_2 < < 2 ) | imm7_6 ;
Write16 ( EncodeCSS ( Opcode16 : : C2 , rs2 , imm5_4_3_2_7_6 , Funct3 : : C_SWSP ) ) ;
}
void RiscVEmitter : : C_FSWSP ( RiscVReg rs2 , u8 uimm8 ) {
_assert_msg_ ( BitsSupported ( ) = = 32 & & FloatBitsSupported ( ) > = 32 , " %s is only valid with RV32FC " , __func__ ) ;
_assert_msg_ ( IsFPR ( rs2 ) , " %s must read from FPR " , __func__ ) ;
_assert_msg_ ( ( uimm8 & 0xFC ) = = uimm8 , " %s offset must fit in 8 bits and be a multiple of 4: %d " , __func__ , ( int ) uimm8 ) ;
u8 imm7_6 = ImmBits8 ( uimm8 , 6 , 2 ) ;
u8 imm5_4_3_2 = ImmBits8 ( uimm8 , 2 , 4 ) ;
u8 imm5_4_3_2_7_6 = ( imm5_4_3_2 < < 2 ) | imm7_6 ;
Write16 ( EncodeCSS ( Opcode16 : : C2 , rs2 , imm5_4_3_2_7_6 , Funct3 : : C_FSWSP ) ) ;
}
void RiscVEmitter : : C_SDSP ( RiscVReg rs2 , u32 uimm9 ) {
_assert_msg_ ( BitsSupported ( ) = = 64 | | BitsSupported ( ) = = 128 , " %s is only valid with RV64/RV128 " , __func__ ) ;
_assert_msg_ ( IsGPR ( rs2 ) , " %s must read from GPR " , __func__ ) ;
_assert_msg_ ( ( uimm9 & 0x01F8 ) = = uimm9 , " %s offset must fit in 9 bits and be a multiple of 8: %d " , __func__ , ( int ) uimm9 ) ;
u8 imm8_7_6 = ImmBits8 ( uimm9 , 6 , 3 ) ;
u8 imm5_4_3 = ImmBits8 ( uimm9 , 3 , 3 ) ;
u8 imm5_4_3_8_7_6 = ( imm5_4_3 < < 3 ) | imm8_7_6 ;
Write16 ( EncodeCSS ( Opcode16 : : C2 , rs2 , imm5_4_3_8_7_6 , Funct3 : : C_SDSP ) ) ;
}
2022-08-24 17:12:49 +00:00
} ;