Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
ca72510
Detect Zbs
tomeksowi May 6, 2025
96762df
Emitter
tomeksowi May 6, 2025
53d04b3
Test
tomeksowi May 6, 2025
2eb54ac
bseti, binvi
tomeksowi May 6, 2025
d66c4ef
Fix IntrinsicConstants Zbs flag
tomeksowi May 7, 2025
8bf36ca
Remove brace indent in JITEEVersionIdentifier
tomeksowi May 7, 2025
90aa3ee
Fix test
tomeksowi May 7, 2025
2c35e03
binvi
tomeksowi May 7, 2025
7a4fd78
Simplify ExtractShift test
tomeksowi May 7, 2025
4c3a319
Simple bexti lowering
tomeksowi May 7, 2025
10e542f
Revert "Remove brace indent in JITEEVersionIdentifier"
tomeksowi May 7, 2025
2ea339b
remove debug log
tomeksowi May 8, 2025
6455785
Make GT_BIT_EXTRACT TYP_INT as it is 0 or 1
tomeksowi May 8, 2025
5fa51b2
Lower to bexti also for log2 < 11
tomeksowi May 8, 2025
81d70a5
Bit extract patterns where the argument is shifted right by constant
tomeksowi May 8, 2025
8056db9
bset, bclr
tomeksowi May 9, 2025
6ff88fb
Merge branch 'main' into zbs
tomeksowi May 9, 2025
e0ca030
Merge branch 'main' into zbs
tomeksowi May 12, 2025
3e8fb2f
bclr
tomeksowi May 12, 2025
e6555f0
bext
tomeksowi May 12, 2025
4dbd2d7
Lower a & (1 << b) != 0 to bext
tomeksowi May 13, 2025
12a163a
Fix ClearNeg
tomeksowi May 13, 2025
e246937
Simplify assigning shamt in bset, bclr, binv
tomeksowi May 13, 2025
282f679
Wrap shift amount in bset/binv/bclr
tomeksowi May 13, 2025
49e731f
Prevent bit index overflow in bexti
tomeksowi May 14, 2025
fc387d3
Don't add log2 to variable bit index in bext because it may exceed 32…
tomeksowi May 14, 2025
dee3557
Fix assertion
tomeksowi May 14, 2025
aca58ec
Fix bext shift amount wrapping to 32 bits
tomeksowi May 15, 2025
701f346
Fix right shift so the bool value is not sign-extended
tomeksowi May 15, 2025
102edd8
Pull (a & bit) == bit => (a & bit) != 0 transformation out of Zbs block
tomeksowi May 16, 2025
9385a83
Pull (a & bit) != 0 => (a >> log2(bit)) & 1 out of Zbs lowering
tomeksowi May 19, 2025
2407778
Don't emit bexti 0 because andi 1 can do
tomeksowi May 19, 2025
ced90c7
Pull transformation a & (1 << N) => (a >> N) & 1 out of Zbs
tomeksowi May 19, 2025
b0c8882
Insert wrapping shamt to 5 bits in a single place
tomeksowi May 19, 2025
bd77263
Clean up constant bit branch
tomeksowi May 19, 2025
8e1e1c6
Don't emit bext for 32-bit types because it needs andi 31 to wrap the…
tomeksowi May 20, 2025
fb5375e
Expand (a & C) == C transformation to any constant, block (a & bit) !…
tomeksowi May 20, 2025
6e21193
Don't change the sign bit with bseti/bclri/binvi as it affects sign e…
tomeksowi May 20, 2025
08c7bff
Merge branch 'main' into zbs
tomeksowi May 20, 2025
9f974c7
Fix (a & bit) == bit transformation
tomeksowi May 21, 2025
781ea58
Fix maxBitIndex assertion
tomeksowi May 21, 2025
ce82ba3
Merge branch 'main' into zbs
tomeksowi May 23, 2025
2d81f1f
Merge branch 'main' into zbs
tomeksowi May 27, 2025
a1b3e7b
Merge branch 'main' into zbs
tomeksowi Jun 4, 2025
c89c962
Merge branch 'main' into zbs
tomeksowi Jun 12, 2025
8f2330d
Merge branch 'main' into zbs
tomeksowi Jun 13, 2025
8edd7ba
Merge branch 'main' into zbs
tomeksowi Jun 24, 2025
269b114
Remove GT_BIT_EXTRACT
tomeksowi Jun 24, 2025
1041040
Clear containment when lowered to negated bin ops
tomeksowi Jun 25, 2025
f92829c
Simplify lowering for variable bit index, fix corner cases when both …
tomeksowi Jun 25, 2025
4aead69
Remove BIT_EXTRACT tests
tomeksowi Jun 25, 2025
848c99e
Merge branch 'main' into zbs
tomeksowi Jul 3, 2025
332906e
Merge branch 'main' into zbs
tomeksowi Jul 9, 2025
5a67429
Merge branch 'main' into zbs
tomeksowi Jul 25, 2025
04294c4
Merge branch 'main' into zbs
tomeksowi Aug 8, 2025
396de73
Merge branch 'main' into zbs (resolve conflicts)
tomeksowi Aug 21, 2025
6f64593
Merge branch 'main' into zbs (resolve conflicts)
tomeksowi Aug 22, 2025
090266d
Merge branch 'main' into zbs (resolve conflicts)
tomeksowi Sep 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Sve2, W("EnableArm64Sv
#elif defined(TARGET_RISCV64)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zba, W("EnableRiscV64Zba"), 1, "Allows RiscV64 Zba hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbb, W("EnableRiscV64Zbb"), 1, "Allows RiscV64 Zbb hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbs, W("EnableRiscV64Zbs"), 1, "Allows RiscV64 Zbs hardware intrinsics to be disabled")
#endif

// Runtime-async
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/inc/corinfoinstructionset.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum CORINFO_InstructionSet
InstructionSet_RiscV64Base=1,
InstructionSet_Zba=2,
InstructionSet_Zbb=3,
InstructionSet_Zbs=4,
#endif // TARGET_RISCV64
#ifdef TARGET_AMD64
InstructionSet_X86Base=1,
Expand Down Expand Up @@ -383,6 +384,8 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins
resultflags.RemoveInstructionSet(InstructionSet_Zbb);
if (resultflags.HasInstructionSet(InstructionSet_Zba) && !resultflags.HasInstructionSet(InstructionSet_RiscV64Base))
resultflags.RemoveInstructionSet(InstructionSet_Zba);
if (resultflags.HasInstructionSet(InstructionSet_Zbs) && !resultflags.HasInstructionSet(InstructionSet_RiscV64Base))
resultflags.RemoveInstructionSet(InstructionSet_Zbs);
#endif // TARGET_RISCV64
#ifdef TARGET_AMD64
if (resultflags.HasInstructionSet(InstructionSet_X86Base) && !resultflags.HasInstructionSet(InstructionSet_X86Base_X64))
Expand Down Expand Up @@ -653,6 +656,8 @@ inline const char *InstructionSetToString(CORINFO_InstructionSet instructionSet)
return "Zba";
case InstructionSet_Zbb :
return "Zbb";
case InstructionSet_Zbs :
return "Zbs";
#endif // TARGET_RISCV64
#ifdef TARGET_AMD64
case InstructionSet_X86Base :
Expand Down Expand Up @@ -844,6 +849,7 @@ inline CORINFO_InstructionSet InstructionSetFromR2RInstructionSet(ReadyToRunInst
case READYTORUN_INSTRUCTION_RiscV64Base: return InstructionSet_RiscV64Base;
case READYTORUN_INSTRUCTION_Zba: return InstructionSet_Zba;
case READYTORUN_INSTRUCTION_Zbb: return InstructionSet_Zbb;
case READYTORUN_INSTRUCTION_Zbs: return InstructionSet_Zbs;
#endif // TARGET_RISCV64
#ifdef TARGET_AMD64
case READYTORUN_INSTRUCTION_X86Base: return InstructionSet_X86Base;
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@

#include <minipal/guid.h>

constexpr GUID JITEEVersionIdentifier = { /* 3d2bdd20-eced-4a07-b9fb-227ce7f55fcd */
0x3d2bdd20,
0xeced,
0x4a07,
{0xb9, 0xfb, 0x22, 0x7c, 0xe7, 0xf5, 0x5f, 0xcd}
constexpr GUID JITEEVersionIdentifier = { /* 2ee48f01-3119-484e-931a-ed38f69e9829 */
0x2ee48f01,
0x3119,
0x484e,
{0x93, 0x1a, 0xed, 0x38, 0xf6, 0x9e, 0x98, 0x29}
};

#endif // JIT_EE_VERSIONING_GUID_H
1 change: 1 addition & 0 deletions src/coreclr/inc/readytoruninstructionset.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ enum ReadyToRunInstructionSet
READYTORUN_INSTRUCTION_Avx512Vp2intersect_VL=81,
READYTORUN_INSTRUCTION_Avx512Vpopcntdq=82,
READYTORUN_INSTRUCTION_Avx512Vpopcntdq_VL=83,
READYTORUN_INSTRUCTION_Zbs=84,

};

Expand Down
21 changes: 20 additions & 1 deletion src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,8 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode)
regNumber targetReg = treeNode->GetRegNum();
emitter* emit = GetEmitter();

assert(treeNode->OperIs(GT_ADD, GT_SUB, GT_MUL, GT_AND, GT_AND_NOT, GT_OR, GT_OR_NOT, GT_XOR, GT_XOR_NOT));
assert(treeNode->OperIs(GT_ADD, GT_SUB, GT_MUL, GT_AND, GT_AND_NOT, GT_OR, GT_OR_NOT, GT_XOR, GT_XOR_NOT,
GT_BIT_SET, GT_BIT_CLEAR, GT_BIT_INVERT));

GenTree* op1 = treeNode->gtGetOp1();
GenTree* op2 = treeNode->gtGetOp2();
Expand Down Expand Up @@ -2702,6 +2703,21 @@ instruction CodeGen::genGetInsForOper(GenTree* treeNode)
ins = INS_xnor;
break;

case GT_BIT_SET:
assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbs));
ins = isImmed(treeNode) ? INS_bseti : INS_bset;
break;

case GT_BIT_CLEAR:
assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbs));
ins = isImmed(treeNode) ? INS_bclri : INS_bclr;
break;

case GT_BIT_INVERT:
assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbs));
ins = isImmed(treeNode) ? INS_binvi : INS_binv;
break;

default:
NO_WAY("Unhandled oper in genGetInsForOper() - integer");
break;
Expand Down Expand Up @@ -4139,6 +4155,9 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
case GT_AND_NOT:
case GT_OR_NOT:
case GT_XOR_NOT:
case GT_BIT_SET:
case GT_BIT_CLEAR:
case GT_BIT_INVERT:
assert(varTypeIsIntegralOrI(treeNode));

FALLTHROUGH;
Expand Down
71 changes: 64 additions & 7 deletions src/coreclr/jit/emitriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,8 @@ void emitter::emitIns_R_R_I(

if ((INS_addi <= ins && INS_srai >= ins) || (INS_addiw <= ins && INS_sraiw >= ins) ||
(INS_lb <= ins && INS_lhu >= ins) || INS_ld == ins || INS_lw == ins || INS_jalr == ins || INS_fld == ins ||
INS_flw == ins || INS_slli_uw == ins || INS_rori == ins || INS_roriw == ins)
INS_flw == ins || INS_slli_uw == ins || INS_rori == ins || INS_roriw == ins ||
(INS_bseti <= ins && ins <= INS_binvi))
{
assert(isGeneralRegister(reg2));
code |= (reg1 & 0x1f) << 7; // rd
Expand Down Expand Up @@ -841,7 +842,8 @@ void emitter::emitIns_R_R_R(
(INS_addw <= ins && ins <= INS_sraw) || (INS_fadd_s <= ins && ins <= INS_fmax_s) ||
(INS_fadd_d <= ins && ins <= INS_fmax_d) || (INS_feq_s <= ins && ins <= INS_fle_s) ||
(INS_feq_d <= ins && ins <= INS_fle_d) || (INS_lr_w <= ins && ins <= INS_amomaxu_d) ||
(INS_sh1add <= ins && ins <= INS_sh3add_uw) || (INS_rol <= ins && ins <= INS_maxu))
(INS_sh1add <= ins && ins <= INS_sh3add_uw) || (INS_rol <= ins && ins <= INS_maxu) ||
(INS_bset <= ins && ins <= INS_binv))
{
#ifdef DEBUG
switch (ins)
Expand Down Expand Up @@ -948,6 +950,11 @@ void emitter::emitIns_R_R_R(
case INS_minu:
case INS_max:
case INS_maxu:

case INS_bset:
case INS_bclr:
case INS_bext:
case INS_binv:
break;
default:
NYI_RISCV64("illegal ins within emitIns_R_R_R!");
Expand Down Expand Up @@ -3778,7 +3785,7 @@ void emitter::emitDispInsName(
case 0x1:
{
unsigned funct6 = (imm12 >> 6) & 0x3f;
unsigned shamt = imm12 & 0x3f; // 6 BITS for SHAMT in RISCV6
unsigned shamt = imm12 & 0x3f; // 6 BITS for SHAMT in RISCV64
switch (funct6)
{
case 0b011000:
Expand All @@ -3795,12 +3802,20 @@ void emitter::emitDispInsName(
}
case 0b000000:
printLength = printf("slli");
imm12 = shamt;
break;

case 0b001010:
printLength = printf("bseti");
break;
case 0b010010:
printLength = printf("bclri");
break;
case 0b011010:
printLength = printf("binvi");
break;
default:
return emitDispIllegalInstruction(code);
}
imm12 = shamt;
}
break;
case 0x2: // SLTI
Expand All @@ -3820,7 +3835,7 @@ void emitter::emitDispInsName(
printLength = printf("xori");
}
break;
case 0x5: // SRLI & SRAI
case 0x5:
{
unsigned funct6 = (imm12 >> 6) & 0x3f;
imm12 &= 0x3f; // 6BITS for SHAMT in RISCV64
Expand All @@ -3835,6 +3850,9 @@ void emitter::emitDispInsName(
case 0b011000:
printLength = printf("rori");
break;
case 0b010010:
printLength = printf("bexti");
break;
case 0b011010:
if (imm12 != 0b111000) // shift amount is treated as additional funct opcode
return emitDispIllegalInstruction(code);
Expand Down Expand Up @@ -4085,6 +4103,28 @@ void emitter::emitDispInsName(
printf("%s %s, %s, %s\n", names[opcode3 & 0b11], rd, rs1, rs2);
return;
}
case 0b0010100:
if (opcode3 != 0b001)
return emitDispIllegalInstruction(code);
printf("bset %s, %s, %s\n", rd, rs1, rs2);
return;
case 0b0100100:
switch (opcode3)
{
case 0b001:
printf("bclr %s, %s, %s\n", rd, rs1, rs2);
return;
case 0b101:
printf("bext %s, %s, %s\n", rd, rs1, rs2);
return;
default:
return emitDispIllegalInstruction(code);
}
case 0b0110100:
if (opcode3 != 0b001)
return emitDispIllegalInstruction(code);
printf("binv %s, %s, %s\n", rd, rs1, rs2);
return;
default:
return emitDispIllegalInstruction(code);
}
Expand Down Expand Up @@ -5325,8 +5365,22 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst,
ins = INS_addiw;
imm = -imm;
}
else if (ins == INS_bseti || ins == INS_bclri || ins == INS_bexti || ins == INS_binvi)
{
// Use base instructions where possible:
// "bexti rd, rs, 0" is equivalent to "andi rd, rs, 1"
// "bseti/bclri/binvi rd, rs, imm" are equivalent to "ori/andi/xori rd, rs, (~)(1 << imm)" for imm < 11
int minBitIndex = (ins == INS_bexti) ? 1 : 11;
int maxBitIndex = emitActualTypeSize(src1) * 8;
if (ins != INS_bexti && attr == EA_4BYTE)
maxBitIndex--; // can't touch the sign bit alone, it affects sign extension

assert(imm >= minBitIndex);
assert(imm < maxBitIndex);
}

assert(ins == INS_addi || ins == INS_addiw || ins == INS_andi || ins == INS_ori || ins == INS_xori);
assert(ins == INS_addi || ins == INS_addiw || ins == INS_andi || ins == INS_ori || ins == INS_xori ||
ins == INS_bseti || ins == INS_bclri || ins == INS_bexti || ins == INS_binvi);

regNumber tempReg = needCheckOv ? codeGen->internalRegisters.Extract(dst) : REG_NA;

Expand Down Expand Up @@ -5474,6 +5528,9 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst,
case GT_OR_NOT:
case GT_XOR:
case GT_XOR_NOT:
case GT_BIT_SET:
case GT_BIT_CLEAR:
case GT_BIT_INVERT:
{
emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg);

Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/jit/gtlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@ GTNODE(SH3ADD_UW , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(ADD_UW , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// Maps to riscv64 slli.uw instruction. Computes result = zext(op1[31..0]) << imm.
GTNODE(SLLI_UW , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)

// Maps to bset/bseti instruction. Computes result = op1 | (1 << op2)
GTNODE(BIT_SET , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// Maps to bclr/bclri instruction. Computes result = op1 & ~(1 << op2)
GTNODE(BIT_CLEAR , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// Maps to binv/binvi instruction. Computes result = op1 ^ (1 << op2)
GTNODE(BIT_INVERT , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
#endif

//-----------------------------------------------------------------------------
Expand Down
13 changes: 13 additions & 0 deletions src/coreclr/jit/instrsriscv64.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,19 @@ INST(sh2add_uw, "sh2add_uw", 0, 0x2000403b)
INST(sh3add_uw, "sh3add_uw", 0, 0x2000603b)
INST(slli_uw, "slli_uw", 0, 0x0800101b)

// Zbs (RV32 + RV64)
//// R_R_R
INST(bset, "bset", 0, 0x28001033)
INST(bclr, "bclr", 0, 0x48001033)
INST(bext, "bext", 0, 0x48005033)
INST(binv, "binv", 0, 0x68001033)

//// R_R_I
INST(bseti, "bseti", 0, 0x28001013)
INST(bclri, "bclri", 0, 0x48001013)
INST(bexti, "bexti", 0, 0x48005013)
INST(binvi, "binvi", 0, 0x68001013)

// RVC
INST(c_mv, "c.mv", 0, 0x00008002)
INST(c_add, "c.add", 0, 0x00009002)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ RELEASE_CONFIG_INTEGER(EnableArm64Sve2, "EnableArm64Sve2",
#elif defined(TARGET_RISCV64)
RELEASE_CONFIG_INTEGER(EnableRiscV64Zba, "EnableRiscV64Zba", 1) // Allows RiscV64 Zba hardware intrinsics to be disabled
RELEASE_CONFIG_INTEGER(EnableRiscV64Zbb, "EnableRiscV64Zbb", 1) // Allows RiscV64 Zbb hardware intrinsics to be disabled
RELEASE_CONFIG_INTEGER(EnableRiscV64Zbs, "EnableRiscV64Zbs", 1) // Allows RiscV64 Zbs hardware intrinsics to be disabled
#endif

RELEASE_CONFIG_INTEGER(EnableEmbeddedBroadcast, "EnableEmbeddedBroadcast", 1) // Allows embedded broadcasts to be disabled
Expand Down
Loading
Loading