Repository: dotnet/runtime
Pull request #114150: [RISC-V] Introduce Zbb
Author: login: tomeksowi
Labels: name: area-CodeGen-coreclr
description: CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
name: community-contribution
description: Indicates that the PR has been added by a community member
name: arch-riscv
description: Related to the RISC-V architecture
Created: 2025-04-02T13:09:21Z | Merged: 2025-04-17T22:11:47Z

Accelerate some codegens with Zbb instructions.

Part of #84834, cc @dotnet/samsung


Diff:
diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp
index 6ca6564379a748..9be48ea01507a8 100644
--- a/src/coreclr/jit/codegenriscv64.cpp
+++ b/src/coreclr/jit/codegenriscv64.cpp
@@ -1187,7 +1187,7 @@ void CodeGen::genCodeForMulHi(GenTreeOp* treeNode)
     genProduceReg(treeNode);
 }
 
-// Generate code for ADD, SUB, MUL, AND, AND_NOT, OR and XOR
+// Generate code for ADD, SUB, MUL, AND, AND_NOT, OR, OR_NOT, XOR, and XOR_NOT
 // This method is expected to have called genConsumeOperands() before calling it.
 void CodeGen::genCodeForBinary(GenTreeOp* treeNode)
 {
@@ -1195,7 +1195,7 @@ 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_XOR));
+    assert(treeNode->OperIs(GT_ADD, GT_SUB, GT_MUL, GT_AND, GT_AND_NOT, GT_OR, GT_OR_NOT, GT_XOR, GT_XOR_NOT));
 
     GenTree*    op1 = treeNode->gtGetOp1();
     GenTree*    op2 = treeNode->gtGetOp2();
@@ -1827,7 +1827,25 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
 //
 void CodeGen::genCodeForBswap(GenTree* tree)
 {
-    NYI_RISCV64("genCodeForBswap-----unimplemented on RISCV64 yet----");
+    assert(tree->OperIs(GT_BSWAP, GT_BSWAP16));
+    var_types type = tree->gtGetOp1()->TypeGet();
+    emitAttr  size = emitTypeSize(type);
+    regNumber dest = tree->GetRegNum();
+    regNumber src  = genConsumeReg(tree->gtGetOp1());
+
+    assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+    emitter& emit = *GetEmitter();
+    emit.emitIns_R_R(INS_rev8, size, dest, src);
+    if (size < EA_PTRSIZE)
+    {
+        int shiftAmount = tree->OperIs(GT_BSWAP16) ? 48 : 32;
+        // TODO: we need to right-shift the byte-reversed register anyway. Remove the cast (in Lowering::LowerCast?)
+        // wrapping GT_BSWAP16 and pass the exact destination type here, so that this codegen could leave the register
+        // properly extended.
+        emit.emitIns_R_R_I(INS_srli, size, dest, dest, shiftAmount);
+    }
+
+    genProduceReg(tree);
 }
 
 //------------------------------------------------------------------------
@@ -2637,7 +2655,9 @@ instruction CodeGen::genGetInsForOper(GenTree* treeNode)
                 break;
 
             case GT_AND_NOT:
-                NYI_RISCV64("GT_AND_NOT-----unimplemented/unused on RISCV64 yet----");
+                assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+                assert(!isImmed(treeNode));
+                ins = INS_andn;
                 break;
 
             case GT_OR:
@@ -2652,6 +2672,12 @@ instruction CodeGen::genGetInsForOper(GenTree* treeNode)
                 }
                 break;
 
+            case GT_OR_NOT:
+                assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+                assert(!isImmed(treeNode));
+                ins = INS_orn;
+                break;
+
             case GT_LSH:
                 isImm = isImmed(treeNode);
                 if (isImm)
@@ -2749,6 +2775,12 @@ instruction CodeGen::genGetInsForOper(GenTree* treeNode)
                 }
                 break;
 
+            case GT_XOR_NOT:
+                assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+                assert(!isImmed(treeNode));
+                ins = INS_xnor;
+                break;
+
             default:
                 NO_WAY("Unhandled oper in genGetInsForOper() - integer");
                 break;
@@ -4301,6 +4333,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
         case GT_XOR:
         case GT_AND:
         case GT_AND_NOT:
+        case GT_OR_NOT:
+        case GT_XOR_NOT:
             assert(varTypeIsIntegralOrI(treeNode));
 
             FALLTHROUGH;
@@ -5336,48 +5370,81 @@ void CodeGen::genCodeForShift(GenTree* tree)
     GenTree* operand = tree->gtGetOp1();
     GenTree* shiftBy = tree->gtGetOp2();
 
+    unsigned immWidth = emitter::getBitWidth(size); // For RISCV64, immWidth will be set to 32 or 64
+
     if (tree->OperIs(GT_ROR, GT_ROL))
     {
-        regNumber tempReg  = internalRegisters.GetSingle(tree);
-        unsigned  immWidth = emitter::getBitWidth(size); // For RISCV64, immWidth will be set to 32 or 64
-        if (!shiftBy->IsCnsIntOrI())
+        if (compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb))
         {
-            regNumber shiftRight = tree->OperIs(GT_ROR) ? shiftBy->GetRegNum() : tempReg;
-            regNumber shiftLeft  = tree->OperIs(GT_ROR) ? tempReg : shiftBy->GetRegNum();
-            GetEmitter()->emitIns_R_R_I(INS_addi, size, tempReg, REG_R0, immWidth);
-            GetEmitter()->emitIns_R_R_R(INS_sub, size, tempReg, tempReg, shiftBy->GetRegNum());
-            if (size == EA_8BYTE)
+            bool is4 = (size == EA_4BYTE);
+            bool isR = tree->OperIs(GT_ROR);
+            if (!shiftBy->IsCnsIntOrI())
             {
-                GetEmitter()->emitIns_R_R_R(INS_srl, size, REG_RA, operand->GetRegNum(), shiftRight);
-                GetEmitter()->emitIns_R_R_R(INS_sll, size, tempReg, operand->GetRegNum(), shiftLeft);
+                instruction ins;
+                if (isR)
+                {
+                    ins = is4 ? INS_rorw : INS_ror;
+                }
+                else
+                {
+                    ins = is4 ? INS_rolw : INS_rol;
+                }
+                GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftBy->GetRegNum());
             }
             else
             {
-                GetEmitter()->emitIns_R_R_R(INS_srlw, size, REG_RA, operand->GetRegNum(), shiftRight);
-                GetEmitter()->emitIns_R_R_R(INS_sllw, size, tempReg, operand->GetRegNum(), shiftLeft);
+                unsigned shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal;
+                assert(shiftByImm < immWidth);
+                if (!isR)
+                {
+                    shiftByImm = immWidth - shiftByImm;
+                }
+                instruction ins = is4 ? INS_roriw : INS_rori;
+                GetEmitter()->emitIns_R_R_I(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftByImm);
             }
         }
         else
         {
-            unsigned shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal;
-            if (shiftByImm >= 32 && shiftByImm < 64)
+            regNumber tempReg = internalRegisters.GetSingle(tree);
+            if (!shiftBy->IsCnsIntOrI())
             {
-                immWidth = 64;
-            }
-            unsigned shiftRight = tree->OperIs(GT_ROR) ? shiftByImm : immWidth - shiftByImm;
-            unsigned shiftLeft  = tree->OperIs(GT_ROR) ? immWidth - shiftByImm : shiftByImm;
-            if ((shiftByImm >= 32 && shiftByImm < 64) || size == EA_8BYTE)
-            {
-                GetEmitter()->emitIns_R_R_I(INS_srli, size, REG_RA, operand->GetRegNum(), shiftRight);
-                GetEmitter()->emitIns_R_R_I(INS_slli, size, tempReg, operand->GetRegNum(), shiftLeft);
+                regNumber shiftRight = tree->OperIs(GT_ROR) ? shiftBy->GetRegNum() : tempReg;
+                regNumber shiftLeft  = tree->OperIs(GT_ROR) ? tempReg : shiftBy->GetRegNum();
+                GetEmitter()->emitIns_R_R_I(INS_addi, size, tempReg, REG_R0, immWidth);
+                GetEmitter()->emitIns_R_R_R(INS_sub, size, tempReg, tempReg, shiftBy->GetRegNum());
+                if (size == EA_8BYTE)
+                {
+                    GetEmitter()->emitIns_R_R_R(INS_srl, size, REG_RA, operand->GetRegNum(), shiftRight);
+                    GetEmitter()->emitIns_R_R_R(INS_sll, size, tempReg, operand->GetRegNum(), shiftLeft);
+                }
+                else
+                {
+                    GetEmitter()->emitIns_R_R_R(INS_srlw, size, REG_RA, operand->GetRegNum(), shiftRight);
+                    GetEmitter()->emitIns_R_R_R(INS_sllw, size, tempReg, operand->GetRegNum(), shiftLeft);
+                }
             }
             else
             {
-                GetEmitter()->emitIns_R_R_I(INS_srliw, size, REG_RA, operand->GetRegNum(), shiftRight);
-                GetEmitter()->emitIns_R_R_I(INS_slliw, size, tempReg, operand->GetRegNum(), shiftLeft);
+                unsigned shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal;
+                if (shiftByImm >= 32 && shiftByImm < 64)
+                {
+                    immWidth = 64;
+                }
+                unsigned shiftRight = tree->OperIs(GT_ROR) ? shiftByImm : immWidth - shiftByImm;
+                unsigned shiftLeft  = tree->OperIs(GT_ROR) ? immWidth - shiftByImm : shiftByImm;
+                if ((shiftByImm >= 32 && shiftByImm < 64) || size == EA_8BYTE)
+                {
+                    GetEmitter()->emitIns_R_R_I(INS_srli, size, REG_RA, operand->GetRegNum(), shiftRight);
+                    GetEmitter()->emitIns_R_R_I(INS_slli, size, tempReg, operand->GetRegNum(), shiftLeft);
+                }
+                else
+                {
+                    GetEmitter()->emitIns_R_R_I(INS_srliw, size, REG_RA, operand->GetRegNum(), shiftRight);
+                    GetEmitter()->emitIns_R_R_I(INS_slliw, size, tempReg, operand->GetRegNum(), shiftLeft);
+                }
             }
+            GetEmitter()->emitIns_R_R_R(INS_or, size, tree->GetRegNum(), REG_RA, tempReg);
         }
-        GetEmitter()->emitIns_R_R_R(INS_or, size, tree->GetRegNum(), REG_RA, tempReg);
     }
     else
     {
@@ -5392,7 +5459,6 @@ void CodeGen::genCodeForShift(GenTree* tree)
             unsigned    shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal;
 
             // should check shiftByImm for riscv64-ins.
-            unsigned immWidth = emitter::getBitWidth(size); // For RISCV64, immWidth will be set to 32 or 64
             shiftByImm &= (immWidth - 1);
 
             if (ins == INS_slliw && shiftByImm >= 32)
@@ -6329,28 +6395,37 @@ void CodeGen::genIntToIntCast(GenTreeCast* cast)
             case GenIntCastDesc::ZERO_EXTEND_SMALL_INT:
                 if (desc.ExtendSrcSize() == 1)
                 {
-                    emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstReg, srcReg, 64 - 8);
-                    emit->emitIns_R_R_I(INS_srli, EA_PTRSIZE, dstReg, dstReg, 64 - 8);
-                }
-                else
-                {
-
-                    emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstReg, srcReg, 64 - 16);
-                    emit->emitIns_R_R_I(INS_srli, EA_PTRSIZE, dstReg, dstReg, 64 - 16);
+                    emit->emitIns_R_R_I(INS_andi, EA_PTRSIZE, dstReg, srcReg, 0xff);
+                    break;
                 }
-                break;
+                FALLTHROUGH;
             case GenIntCastDesc::SIGN_EXTEND_SMALL_INT:
-                if (desc.ExtendSrcSize() == 1)
+            {
+                bool isSignExtend = (desc.ExtendKind() == GenIntCastDesc::SIGN_EXTEND_SMALL_INT);
+                if (compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb))
                 {
-                    emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstReg, srcReg, 64 - 8);
-                    emit->emitIns_R_R_I(INS_srai, EA_PTRSIZE, dstReg, dstReg, 64 - 8);
+                    instruction extend = INS_none;
+                    bool        isHalf = (desc.ExtendSrcSize() == 2);
+                    if (isSignExtend)
+                    {
+                        extend = isHalf ? INS_sext_h : INS_sext_b;
+                    }
+                    else
+                    {
+                        assert(isHalf);
+                        extend = INS_zext_h;
+                    }
+                    emit->emitIns_R_R(extend, EA_PTRSIZE, dstReg, srcReg);
                 }
                 else
                 {
-                    emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstReg, srcReg, 64 - 16);
-                    emit->emitIns_R_R_I(INS_srai, EA_PTRSIZE, dstReg, dstReg, 64 - 16);
+                    instruction shiftRight  = isSignExtend ? INS_srai : INS_srli;
+                    unsigned    shiftAmount = 64 - desc.ExtendSrcSize() * 8;
+                    emit->emitIns_R_R_I(INS_slli, EA_PTRSIZE, dstReg, srcReg, shiftAmount);
+                    emit->emitIns_R_R_I(shiftRight, EA_PTRSIZE, dstReg, dstReg, shiftAmount);
                 }
                 break;
+            }
 
             case GenIntCastDesc::ZERO_EXTEND_INT:
 
diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp
index a67f125c90b84f..3784cd7e6cc437 100644
--- a/src/coreclr/jit/emitriscv64.cpp
+++ b/src/coreclr/jit/emitriscv64.cpp
@@ -650,7 +650,7 @@ void emitter::emitIns_R_R(
 {
     code_t code = emitInsCode(ins);
 
-    if (INS_mov == ins || INS_sext_w == ins || (INS_clz <= ins && ins <= INS_cpopw))
+    if (INS_mov == ins || INS_sext_w == ins || (INS_clz <= ins && ins <= INS_rev8))
     {
         assert(isGeneralRegisterOrR0(reg1));
         assert(isGeneralRegisterOrR0(reg2));
@@ -728,7 +728,7 @@ 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_flw == ins || INS_rori == ins || INS_roriw == ins)
     {
         assert(isGeneralRegister(reg2));
         code |= (reg1 & 0x1f) << 7; // rd
@@ -827,7 +827,7 @@ 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_min <= ins && ins <= INS_maxu))
+        (INS_rol <= ins && ins <= INS_maxu))
     {
 #ifdef DEBUG
         switch (ins)
@@ -915,6 +915,13 @@ void emitter::emitIns_R_R_R(
             case INS_amomaxu_w:
             case INS_amomaxu_d:
 
+            case INS_rol:
+            case INS_rolw:
+            case INS_ror:
+            case INS_rorw:
+            case INS_xnor:
+            case INS_orn:
+            case INS_andn:
             case INS_min:
             case INS_minu:
             case INS_max:
@@ -3843,16 +3850,17 @@ void emitter::emitDispInsName(
                 case 0x1:
                 {
                     unsigned funct6 = (imm12 >> 6) & 0x3f;
-                    unsigned shamt  = imm12 & 0x3f; // 6 BITS for SHAMT in RISCV64
+                    unsigned shamt  = imm12 & 0x3f; // 6 BITS for SHAMT in RISCV6
                     switch (funct6)
                     {
                         case 0b011000:
                         {
-                            static const char* names[] = {"clz", "ctz", "cpop"};
+                            static const char* names[] = {"clz", "ctz", "cpop", nullptr, "sext.b", "sext.h"};
                             // shift amount is treated as additional funct opcode
-                            if (shamt >= ARRAY_SIZE(names))
+                            if (shamt >= ARRAY_SIZE(names) || shamt == 3)
                                 return emitDispIllegalInstruction(code);
 
+                            assert(names[shamt] != nullptr);
                             printLength  = printf("%s", names[shamt]);
                             hasImmediate = false;
                             break;
@@ -3874,21 +3882,41 @@ void emitter::emitDispInsName(
                     printLength = printf("sltiu");
                     break;
                 case 0x4: // XORI
-                    printLength = printf("xori");
+                    if (imm12 == -1)
+                    {
+                        printLength  = printf("not");
+                        hasImmediate = false;
+                    }
+                    else
+                    {
+                        printLength = printf("xori");
+                    }
                     break;
                 case 0x5: // SRLI & SRAI
                 {
-                    static constexpr unsigned kLogicalShiftFunct6    = 0b000000;
-                    static constexpr unsigned kArithmeticShiftFunct6 = 0b010000;
-
-                    unsigned funct6         = (imm12 >> 6) & 0x3f;
-                    bool     isLogicalShift = funct6 == kLogicalShiftFunct6;
-                    if ((!isLogicalShift) && (funct6 != kArithmeticShiftFunct6))
+                    unsigned funct6 = (imm12 >> 6) & 0x3f;
+                    imm12 &= 0x3f; // 6BITS for SHAMT in RISCV64
+                    switch (funct6)
                     {
-                        return emitDispIllegalInstruction(code);
+                        case 0b000000:
+                            printLength = printf("srli");
+                            break;
+                        case 0b010000:
+                            printLength = printf("srai");
+                            break;
+                        case 0b011000:
+                            printLength = printf("rori");
+                            break;
+                        case 0b011010:
+                            if (imm12 != 0b111000) // shift amount is treated as additional funct opcode
+                                return emitDispIllegalInstruction(code);
+
+                            printLength  = printf("rev8");
+                            hasImmediate = false;
+                            break;
+                        default:
+                            return emitDispIllegalInstruction(code);
                     }
-                    printLength = printf(isLogicalShift ? "srli" : "srai");
-                    imm12 &= 0x3f; // 6BITS for SHAMT in RISCV64
                 }
                 break;
                 case 0x6: // ORI
@@ -3969,21 +3997,21 @@ void emitter::emitDispInsName(
                     return;
                 case 0x5: // SRLIW & SRAIW
                 {
-                    static constexpr unsigned kLogicalShiftFunct7    = 0b0000000;
-                    static constexpr unsigned kArithmeticShiftFunct7 = 0b0100000;
-
                     unsigned funct7 = (imm12 >> 5) & 0x7f;
-                    if (funct7 == kLogicalShiftFunct7)
-                    {
-                        printf("srliw          %s, %s, %d\n", rd, rs1, imm12 & 0x1f); // 5BITS for SHAMT in RISCV64
-                    }
-                    else if (funct7 == kArithmeticShiftFunct7)
-                    {
-                        printf("sraiw          %s, %s, %d\n", rd, rs1, imm12 & 0x1f); // 5BITS for SHAMT in RISCV64
-                    }
-                    else
+                    imm12 &= 0x1f; // 5BITS for SHAMT in RISCV64
+                    switch (funct7)
                     {
-                        emitDispIllegalInstruction(code);
+                        case 0b0000000:
+                            printf("srliw          %s, %s, %d\n", rd, rs1, imm12);
+                            return;
+                        case 0b0100000:
+                            printf("sraiw          %s, %s, %d\n", rd, rs1, imm12);
+                            return;
+                        case 0b0110000:
+                            printf("roriw          %s, %s, %d\n", rd, rs1, imm12);
+                            return;
+                        default:
+                            return emitDispIllegalInstruction(code);
                     }
                 }
                     return;
@@ -4038,9 +4066,18 @@ void emitter::emitDispInsName(
                         case 0x0: // SUB
                             printf("sub            %s, %s, %s\n", rd, rs1, rs2);
                             return;
+                        case 0x4: // XNOR
+                            printf("xnor           %s, %s, %s\n", rd, rs1, rs2);
+                            return;
                         case 0x5: // SRA
                             printf("sra            %s, %s, %s\n", rd, rs1, rs2);
                             return;
+                        case 0x6: // ORN
+                            printf("orn            %s, %s, %s\n", rd, rs1, rs2);
+                            return;
+                        case 0x7: // ANDN
+                            printf("andn           %s, %s, %s\n", rd, rs1, rs2);
+                            return;
                         default:
                             return emitDispIllegalInstruction(code);
                     }
@@ -4076,6 +4113,19 @@ void emitter::emitDispInsName(
                             return emitDispIllegalInstruction(code);
                     }
                     return;
+                case 0b0110000:
+                    switch (opcode3)
+                    {
+                        case 0b001:
+                            printf("rol            %s, %s, %s\n", rd, rs1, rs2);
+                            return;
+                        case 0b101:
+                            printf("ror            %s, %s, %s\n", rd, rs1, rs2);
+                            return;
+                        default:
+                            return emitDispIllegalInstruction(code);
+                    }
+                    return;
                 case 0b0000101:
                 {
                     if ((opcode3 >> 2) != 1) // clmul[h] unsupported
@@ -4093,9 +4143,10 @@ void emitter::emitDispInsName(
         {
             unsigned int opcode2 = (code >> 25) & 0x7f;
             unsigned int opcode3 = (code >> 12) & 0x7;
+            unsigned int rs2Num  = (code >> 20) & 0x1f;
             const char*  rd      = RegNames[(code >> 7) & 0x1f];
             const char*  rs1     = RegNames[(code >> 15) & 0x1f];
-            const char*  rs2     = RegNames[(code >> 20) & 0x1f];
+            const char*  rs2     = RegNames[rs2Num];
 
             switch (opcode2)
             {
@@ -4150,6 +4201,28 @@ void emitter::emitDispInsName(
                             return emitDispIllegalInstruction(code);
                     }
                     return;
+                case 0b0110000:
+                    switch (opcode3)
+                    {
+                        case 0b001:
+                            printf("rolw           %s, %s, %s\n", rd, rs1, rs2);
+                            return;
+                        case 0b101:
+                            printf("rorw          %s, %s, %s\n", rd, rs1, rs2);
+                            return;
+                        default:
+                            return emitDispIllegalInstruction(code);
+                    }
+                    return;
+                case 0b0000100:
+                    // Currently only zext.h for this opcode2.
+                    // Note: zext.h is encoded as a pseudo for 'packw rd, rs1, zero' which is not in Zbb.
+                    if (opcode3 != 0b100 || rs2Num != REG_ZERO)
+                        return emitDispIllegalInstruction(code);
+
+                    printf("zext.h         %s, %s\n", rd, rs1);
+                    return;
+
                 default:
                     return emitDispIllegalInstruction(code);
             }
@@ -5325,7 +5398,9 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst,
             case GT_AND:
             case GT_AND_NOT:
             case GT_OR:
+            case GT_OR_NOT:
             case GT_XOR:
+            case GT_XOR_NOT:
             {
                 emitIns_R_R_R(ins, attr, dstReg, src1Reg, src2Reg);
 
diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index 2dd1ebd574a93b..ae3989f2f2d22c 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -4668,9 +4668,11 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE    clsHnd,
                 {
                     case CorInfoType::CORINFO_TYPE_SHORT:
                     case CorInfoType::CORINFO_TYPE_USHORT:
+                    {
                         retNode = gtNewCastNode(TYP_INT, gtNewOperNode(GT_BSWAP16, TYP_INT, impPopStack().val), false,
                                                 callType);
                         break;
+                    }
 
                     case CorInfoType::CORINFO_TYPE_INT:
                     case CorInfoType::CORINFO_TYPE_UINT:
@@ -10772,19 +10774,22 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
         {
             namespaceName += 1;
 
-#if defined(TARGET_XARCH) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64)
+#if defined(TARGET_XARCH) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
             if (strcmp(namespaceName, "Buffers.Binary") == 0)
             {
                 if (strcmp(className, "BinaryPrimitives") == 0)
                 {
                     if (strcmp(methodName, "ReverseEndianness") == 0)
                     {
-                        result = NI_System_Buffers_Binary_BinaryPrimitives_ReverseEndianness;
+                        RISCV64_ONLY(if (compOpportunisticallyDependsOn(InstructionSet_Zbb)))
+                        {
+                            result = NI_System_Buffers_Binary_BinaryPrimitives_ReverseEndianness;
+                        }
                     }
                 }
             }
             else
-#endif // defined(TARGET_XARCH) || defined(TARGET_ARM64)
+#endif // defined(TARGET_XARCH) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
                 if (strcmp(namespaceName, "Collections.Generic") == 0)
                 {
                     if (strcmp(className, "Comparer`1") == 0)
diff --git a/src/coreclr/jit/instrsriscv64.h b/src/coreclr/jit/instrsriscv64.h
index 1f72938548b451..fe643015e11e79 100644
--- a/src/coreclr/jit/instrsriscv64.h
+++ b/src/coreclr/jit/instrsriscv64.h
@@ -269,13 +269,28 @@ INST(ctz,           "ctz",            0,   0x60101013)
 INST(ctzw,          "ctzw",           0,   0x6010101b)
 INST(cpop,          "cpop",           0,   0x60201013)
 INST(cpopw,         "cpopw",          0,   0x6020101b)
+INST(sext_b,        "sext.b",         0,   0x60401013)
+INST(sext_h,        "sext.h",         0,   0x60501013)
+INST(zext_h,        "zext.h",         0,   0x0800403b)
+INST(rev8,          "rev8",           0,   0x6b805013)
 
 //// R_R_R
+INST(rol,           "rol",            0,   0x60001033)
+INST(rolw,          "rolw",           0,   0x6000103b)
+INST(ror,           "ror",            0,   0x60005033)
+INST(rorw,          "rorw",           0,   0x6000503b)
+INST(xnor,          "xnor",           0,   0x40004033)
+INST(orn,           "orn",            0,   0x40006033)
+INST(andn,          "andn",           0,   0x40007033)
 INST(min,           "min",            0,   0x0a004033)
 INST(minu,          "minu",           0,   0x0a005033)
 INST(max,           "max",            0,   0x0a006033)
 INST(maxu,          "maxu",           0,   0x0a007033)
 
+//// R_R_I
+INST(rori,          "rori",           0,   0x60005013)
+INST(roriw,         "roriw",          0,   0x6000501b)
+
 // clang-format on
 /*****************************************************************************/
 #undef INST
diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp
index 9784dd6d55bd5d..b5acc593c337ef 100644
--- a/src/coreclr/jit/lower.cpp
+++ b/src/coreclr/jit/lower.cpp
@@ -730,7 +730,6 @@ GenTree* Lowering::LowerNode(GenTree* node)
         case GT_MDARR_LENGTH:
         case GT_MDARR_LOWER_BOUND:
             return LowerArrLength(node->AsArrCommon());
-            break;
 
         default:
             break;
diff --git a/src/coreclr/jit/lowerriscv64.cpp b/src/coreclr/jit/lowerriscv64.cpp
index 6a1cffd5ca0426..5c7db04953a836 100644
--- a/src/coreclr/jit/lowerriscv64.cpp
+++ b/src/coreclr/jit/lowerriscv64.cpp
@@ -187,6 +187,73 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue)
 //
 GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp)
 {
+    if (comp->opts.OptimizationEnabled())
+    {
+        GenTree*& op1 = binOp->gtOp1;
+        GenTree*& op2 = binOp->gtOp2;
+
+        bool isOp1Negated = op1->OperIs(GT_NOT);
+        bool isOp2Negated = op2->OperIs(GT_NOT);
+        if (binOp->OperIs(GT_AND, GT_OR, GT_XOR) && (isOp1Negated || isOp2Negated))
+        {
+            if ((isOp1Negated && isOp2Negated) || comp->compOpportunisticallyDependsOn(InstructionSet_Zbb))
+            {
+                if (isOp1Negated)
+                {
+                    BlockRange().Remove(op1);
+                    op1 = op1->AsUnOp()->gtGetOp1();
+                }
+                if (isOp2Negated)
+                {
+                    BlockRange().Remove(op2);
+                    op2 = op2->AsUnOp()->gtGetOp1();
+                }
+
+                if (isOp1Negated != isOp2Negated)
+                {
+                    assert(comp->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+                    if (isOp1Negated)
+                        std::swap(op1, op2);
+
+                    genTreeOps operNot = GT_NONE;
+                    switch (binOp->OperGet())
+                    {
+                        case GT_AND:
+                            operNot = GT_AND_NOT;
+                            break;
+                        case GT_OR:
+                            operNot = GT_OR_NOT;
+                            break;
+                        default:
+                            assert(binOp->OperIs(GT_XOR));
+                            operNot = GT_XOR_NOT;
+                            break;
+                    }
+                    binOp->ChangeOper(operNot);
+                }
+                else if (binOp->OperIs(GT_AND, GT_OR)) // XOR is good after negation removal, (~a ^ ~b) == (a ^ b)
+                {
+                    assert(isOp1Negated && isOp2Negated);
+                    LIR::Use use;
+                    if (BlockRange().TryGetUse(binOp, &use))
+                    {
+                        // (~a | ~b) == ~(a & b),  (~a & ~b) == ~(a | b)
+                        genTreeOps reverseOper = binOp->OperIs(GT_AND) ? GT_OR : GT_AND;
+                        binOp->ChangeOper(reverseOper);
+
+                        GenTreeUnOp* negation = comp->gtNewOperNode(GT_NOT, binOp->gtType, binOp);
+                        BlockRange().InsertAfter(binOp, negation);
+                        use.ReplaceWith(negation);
+                    }
+                    else
+                    {
+                        binOp->SetUnusedValue();
+                    }
+                }
+            }
+        }
+    }
+
     ContainCheckBinary(binOp);
 
     return binOp->gtNext;
diff --git a/src/coreclr/jit/lsrariscv64.cpp b/src/coreclr/jit/lsrariscv64.cpp
index c307148b17769b..19da9096bfc790 100644
--- a/src/coreclr/jit/lsrariscv64.cpp
+++ b/src/coreclr/jit/lsrariscv64.cpp
@@ -261,7 +261,7 @@ int LinearScan::BuildNode(GenTree* tree)
         case GT_RSZ:
         case GT_ROR:
         case GT_ROL:
-            if (tree->OperIs(GT_ROR, GT_ROL))
+            if (tree->OperIs(GT_ROR, GT_ROL) && !compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb))
                 buildInternalIntRegisterDefForNode(tree);
             srcCount = BuildBinaryUses(tree->AsOp());
             buildInternalRegisterUses();


Reviews:
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:10:31Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:13:06Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:13:43Z
user: login: tomeksowi
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:29:35Z
user: login: tomeksowi
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:38:06Z
user: login: jakobbotsch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T14:56:19Z
user: login: BruceForstall
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T22:11:35Z

Review comments:
diff_hunk: @@ -188,6 +188,68 @@ GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue)
 //
 GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp)
 {
+    if (comp->opts.OptimizationEnabled())
+    {
+        GenTree*& op1 = binOp->gtOp1;
+        GenTree*& op2 = binOp->gtOp2;
+
+        bool isOp1Negated = op1->OperIs(GT_NOT);
+        bool isOp2Negated = op2->OperIs(GT_NOT);
+        if (binOp->OperIs(GT_AND, GT_OR, GT_XOR) && (isOp1Negated || isOp2Negated))
+        {
+            if ((isOp1Negated && isOp2Negated) || comp->compOpportunisticallyDependsOn(InstructionSet_Zbb))
+            {
+                if (isOp1Negated)
+                {
+                    BlockRange().Remove(op1);
+                    op1 = op1->AsUnOp()->gtGetOp1();
+                }
+                if (isOp2Negated)
+                {
+                    BlockRange().Remove(op2);
+                    op2 = op2->AsUnOp()->gtGetOp1();
+                }
+
+                if (isOp1Negated != isOp2Negated)
+                {
+                    assert(comp->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+                    if (isOp1Negated)
+                        std::swap(op1, op2);
+
+                    genTreeOps operNot = GT_NONE;
+                    switch (binOp->OperGet())
+                    {
+                        case GT_AND:
+                            operNot = GT_AND_NOT;
+                            break;
+                        case GT_OR:
+                            operNot = GT_OR_NOT;
+                            break;
+                        default:
+                            assert(binOp->OperIs(GT_XOR));
+                            operNot = GT_XOR_NOT;
+                            break;
+                    }
+                    binOp->ChangeOper(operNot);
+                }
+                else if (binOp->OperIs(GT_AND, GT_OR)) // XOR is good after negation removal, (~a ^ ~b) == (a ^ b)
+                {
+                    assert(isOp1Negated && isOp2Negated);
+
+                    // (~a | ~b) == ~(a & b),  (~a & ~b) == ~(a | b)
+                    genTreeOps reverseOper = binOp->OperIs(GT_AND) ? GT_OR : GT_AND;
+                    binOp->ChangeOper(reverseOper);
+                    GenTreeUnOp* negation = comp->gtNewOperNode(GT_NOT, binOp->gtType, binOp);
+
+                    GenTree** use = nullptr;
+                    binOp->gtGetParent(&use);
path: src/coreclr/jit/lowerriscv64.cpp
user: login: jakobbotsch
body: This should use `BlockRange().TryGetUse`. `gtGetParent` is only for HIR.
created_at: 2025-04-02T14:10:31Z
author_association: MEMBER
diff_hunk: @@ -1844,7 +1844,25 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
 //
 void CodeGen::genCodeForBswap(GenTree* tree)
 {
-    NYI_RISCV64("genCodeForBswap-----unimplemented on RISCV64 yet----");
+    assert(tree->OperIs(GT_BSWAP, GT_BSWAP16));
+    var_types type = tree->gtGetOp1()->TypeGet();
+    emitAttr  size = emitTypeSize(type);
+    regNumber dest = tree->GetRegNum();
+    regNumber src  = genConsumeReg(tree->gtGetOp1());
+
+    assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+    emitter& emit = *GetEmitter();
+    emit.emitIns_R_R(INS_rev8, size, dest, src);
+    if (size < EA_PTRSIZE)
+    {
+        int shiftAmount = tree->OperIs(GT_BSWAP16) ? 48 : 32;
+        // TODO: we need to right-shift the byte-reversed register anyway. Remove the cast (in Lowering::LowerCast?)
+        // wrapping GT_BSWAP16 and pass the exact destination type here, so that this codegen could leave the register
+        // properly extended.
+        emit.emitIns_R_R_I(INS_srai, size, dest, dest, shiftAmount);
+    }
path: src/coreclr/jit/codegenriscv64.cpp
user: login: jakobbotsch
body: Emitting `rev8` for both BSWAP16 and BSWAP is suspicious. How does it differentiate between `BSWAP16(int)` and `BSWAP(int)`?
created_at: 2025-04-02T14:13:06Z
author_association: MEMBER
diff_hunk: @@ -1844,7 +1844,25 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
 //
 void CodeGen::genCodeForBswap(GenTree* tree)
 {
-    NYI_RISCV64("genCodeForBswap-----unimplemented on RISCV64 yet----");
+    assert(tree->OperIs(GT_BSWAP, GT_BSWAP16));
+    var_types type = tree->gtGetOp1()->TypeGet();
+    emitAttr  size = emitTypeSize(type);
+    regNumber dest = tree->GetRegNum();
+    regNumber src  = genConsumeReg(tree->gtGetOp1());
+
+    assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+    emitter& emit = *GetEmitter();
+    emit.emitIns_R_R(INS_rev8, size, dest, src);
+    if (size < EA_PTRSIZE)
+    {
+        int shiftAmount = tree->OperIs(GT_BSWAP16) ? 48 : 32;
+        // TODO: we need to right-shift the byte-reversed register anyway. Remove the cast (in Lowering::LowerCast?)
+        // wrapping GT_BSWAP16 and pass the exact destination type here, so that this codegen could leave the register
+        // properly extended.
+        emit.emitIns_R_R_I(INS_srai, size, dest, dest, shiftAmount);
path: src/coreclr/jit/codegenriscv64.cpp
user: login: jakobbotsch
body: Is this sign extending for BSWAP16? BSWAP16 should zero extend.
created_at: 2025-04-02T14:13:42Z
author_association: MEMBER
diff_hunk: @@ -1844,7 +1844,25 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
 //
 void CodeGen::genCodeForBswap(GenTree* tree)
 {
-    NYI_RISCV64("genCodeForBswap-----unimplemented on RISCV64 yet----");
+    assert(tree->OperIs(GT_BSWAP, GT_BSWAP16));
+    var_types type = tree->gtGetOp1()->TypeGet();
+    emitAttr  size = emitTypeSize(type);
+    regNumber dest = tree->GetRegNum();
+    regNumber src  = genConsumeReg(tree->gtGetOp1());
+
+    assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+    emitter& emit = *GetEmitter();
+    emit.emitIns_R_R(INS_rev8, size, dest, src);
+    if (size < EA_PTRSIZE)
+    {
+        int shiftAmount = tree->OperIs(GT_BSWAP16) ? 48 : 32;
+        // TODO: we need to right-shift the byte-reversed register anyway. Remove the cast (in Lowering::LowerCast?)
+        // wrapping GT_BSWAP16 and pass the exact destination type here, so that this codegen could leave the register
+        // properly extended.
+        emit.emitIns_R_R_I(INS_srai, size, dest, dest, shiftAmount);
+    }
path: src/coreclr/jit/codegenriscv64.cpp
user: login: tomeksowi
body: There's only one `rev8` instruction that reverses the whole register, reversing smaller integers requires right-shifting the reversed register (the shift amount differs BSWAP vs BSWAP16).
created_at: 2025-04-02T14:29:34Z
author_association: MEMBER
diff_hunk: @@ -1844,7 +1844,25 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
 //
 void CodeGen::genCodeForBswap(GenTree* tree)
 {
-    NYI_RISCV64("genCodeForBswap-----unimplemented on RISCV64 yet----");
+    assert(tree->OperIs(GT_BSWAP, GT_BSWAP16));
+    var_types type = tree->gtGetOp1()->TypeGet();
+    emitAttr  size = emitTypeSize(type);
+    regNumber dest = tree->GetRegNum();
+    regNumber src  = genConsumeReg(tree->gtGetOp1());
+
+    assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+    emitter& emit = *GetEmitter();
+    emit.emitIns_R_R(INS_rev8, size, dest, src);
+    if (size < EA_PTRSIZE)
+    {
+        int shiftAmount = tree->OperIs(GT_BSWAP16) ? 48 : 32;
+        // TODO: we need to right-shift the byte-reversed register anyway. Remove the cast (in Lowering::LowerCast?)
+        // wrapping GT_BSWAP16 and pass the exact destination type here, so that this codegen could leave the register
+        // properly extended.
+        emit.emitIns_R_R_I(INS_srai, size, dest, dest, shiftAmount);
path: src/coreclr/jit/codegenriscv64.cpp
user: login: tomeksowi
body: [Yes](https://github.com/riscv/riscv-isa-manual/blob/600b757e543a19b07d79b82120bd10b84f19912e/src/b-st-ext.adoc?plain=1#L2555-L2558). I can put a logical shift but the proper type extension of the result is done anyway by the cast:
https://github.com/dotnet/runtime/blob/4b2fe3c0fa1bf47d37419dcefd1ad6d7b7bcf569/src/coreclr/jit/importercalls.cpp#L4667-L4670
created_at: 2025-04-02T14:38:04Z
author_association: MEMBER
diff_hunk: @@ -1844,7 +1844,25 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
 //
 void CodeGen::genCodeForBswap(GenTree* tree)
 {
-    NYI_RISCV64("genCodeForBswap-----unimplemented on RISCV64 yet----");
+    assert(tree->OperIs(GT_BSWAP, GT_BSWAP16));
+    var_types type = tree->gtGetOp1()->TypeGet();
+    emitAttr  size = emitTypeSize(type);
+    regNumber dest = tree->GetRegNum();
+    regNumber src  = genConsumeReg(tree->gtGetOp1());
+
+    assert(compiler->compOpportunisticallyDependsOn(InstructionSet_Zbb));
+    emitter& emit = *GetEmitter();
+    emit.emitIns_R_R(INS_rev8, size, dest, src);
+    if (size < EA_PTRSIZE)
+    {
+        int shiftAmount = tree->OperIs(GT_BSWAP16) ? 48 : 32;
+        // TODO: we need to right-shift the byte-reversed register anyway. Remove the cast (in Lowering::LowerCast?)
+        // wrapping GT_BSWAP16 and pass the exact destination type here, so that this codegen could leave the register
+        // properly extended.
+        emit.emitIns_R_R_I(INS_srai, size, dest, dest, shiftAmount);
path: src/coreclr/jit/codegenriscv64.cpp
user: login: jakobbotsch
body: You cannot rely on this cast. `BSWAP16` is defined to zero extend and optimizations in the JIT depend on that behavior. E.g. the JIT might remove that normalizing cast because it is unnecessary under the assumption that `BSWAP16` normalizes correctly. See #67903.
created_at: 2025-04-02T14:56:18Z
author_association: MEMBER

PR comments:
user: login: dotnet-policy-service[bot]
created_at: 2025-04-02T13:10:01Z
body: Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in [area-owners.md](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you want to be subscribed.
<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
author_association: CONTRIBUTOR
user: login: risc-vv
created_at: 2025-04-02T13:11:15Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9528 / 9548 (99.79%)</summary>


```
=======================
      passed: 9528
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9654
 TOTAL tests: 9654
   REAL time: 2h 9min 8s 138ms
=======================

```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/591ea2d570f52850576e287b07c0c582/raw/80049323068fb0819554cb52aef45987155a1a13/Release-CLR-VF2-e01bb45dfd0eee487a3c6f273f16a8303568ff3d.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/f5703a5c6737800b0a01f6e847324fef/raw/7244ac0ddac1d2562fe46fdd21ec385a7db6d816/Release-CLR-VF2-e01bb45dfd0eee487a3c6f273f16a8303568ff3d.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/135/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `e01bb45dfd0eee487a3c6f273f16a8303568ff3d`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9528 / 9548 (99.79%)</summary>


```
=======================
      passed: 9528
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9654
 TOTAL tests: 9654
   REAL time: 2h 47min 57s 710ms
=======================

```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/9bad7ed0b952a33d7a18618219afc4e0/raw/8f20fdee3a20117fd9117b2b3156079b7f629bbe/Release-CLR-QEMU-e01bb45dfd0eee487a3c6f273f16a8303568ff3d.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/bb8e76f9239fde8816e2f5d61d1f32c1/raw/c8123a5adfb89c16d8c76511d11b7b299116336c/Release-CLR-QEMU-e01bb45dfd0eee487a3c6f273f16a8303568ff3d.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/135/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `e01bb45dfd0eee487a3c6f273f16a8303568ff3d`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-VF2: 456456 / 498016 (91.65%)</summary>


```
=======================
      passed: 456456
      failed: 672
     skipped: 1419
      killed: 40888
------------------------
  TOTAL libs: 258
 TOTAL tests: 499435
   REAL time: 2h 57min 22s 132ms
=======================

```
[Release-FX-VF2.md](https://gist.githubusercontent.com/risc-vv/f8db60c9513d6f45bfff778ed918981d/raw/488cd831ec103fd10e4d2f7eeeb6c02ea02b276d/Release-FX-VF2-e01bb45dfd0eee487a3c6f273f16a8303568ff3d.md), [Release-FX-VF2.xml](http://127.0.0.1/pipelines/Release-FX-VF2/133/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-VF2/133/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `e01bb45dfd0eee487a3c6f273f16a8303568ff3d`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-QEMU: 713206 / 741249 (96.22%)</summary>


```
=======================
      passed: 713206
      failed: 874
     skipped: 1462
      killed: 27169
------------------------
  TOTAL libs: 258
 TOTAL tests: 742711
   REAL time: 2h 29min 46s 41ms
=======================

```
[Release-FX-QEMU.md](https://gist.githubusercontent.com/risc-vv/adb1fd9c91c4a428eecad16c35137079/raw/9fffa4c1d59cd90992537185850643cede55c94b/Release-FX-QEMU-e01bb45dfd0eee487a3c6f273f16a8303568ff3d.md), [Release-FX-QEMU.xml](http://127.0.0.1/pipelines/Release-FX-QEMU/130/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-QEMU/130/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `e01bb45dfd0eee487a3c6f273f16a8303568ff3d`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE
user: login: risc-vv
created_at: 2025-04-02T15:11:08Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9528 / 9548 (99.79%)</summary>


```
=======================
      passed: 9528
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9654
 TOTAL tests: 9654
   REAL time: 2h 13min 8s 619ms
=======================

```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/17c8640a2f1ab4c05460b7cb06665792/raw/a53927ab430453125fdaf9dde2e6b053e2a3819f/Release-CLR-VF2-ee068fe115138648b12f5b081880c61ab845fe09.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/b0cfcb8c1c88cf90d77ea22c0aca1f12/raw/23a7359b0a090947a20921fd1a957707daf92135/Release-CLR-VF2-ee068fe115138648b12f5b081880c61ab845fe09.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/136/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `ee068fe115138648b12f5b081880c61ab845fe09`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-VF2: 434315 / 469482 (92.51%)</summary>


```
=======================
      passed: 434315
      failed: 678
     skipped: 1487
      killed: 34489
------------------------
  TOTAL libs: 258
 TOTAL tests: 470969
   REAL time: 2h 54min 7s 347ms
=======================

```
[Release-FX-VF2.md](https://gist.githubusercontent.com/risc-vv/c33170caca0ddc7b88f0ccd67f979b7f/raw/f68f5bdf7e1839582ab047e61b74e5e205f00563/Release-FX-VF2-ee068fe115138648b12f5b081880c61ab845fe09.md), [Release-FX-VF2.xml](http://127.0.0.1/pipelines/Release-FX-VF2/134/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-VF2/134/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `ee068fe115138648b12f5b081880c61ab845fe09`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9528 / 9548 (99.79%)</summary>


```
=======================
      passed: 9528
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9654
 TOTAL tests: 9654
   REAL time: 2h 47min 57s 603ms
=======================

```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/acc97873c22d4be6378375474693232a/raw/a72e4a5f36cd0932c0c006a0ecdb8037a752935a/Release-CLR-QEMU-ee068fe115138648b12f5b081880c61ab845fe09.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/e9c54fdbf6c1ece797563283833b3bdd/raw/96873211a227c77d6b085c29a9016281304c3c72/Release-CLR-QEMU-ee068fe115138648b12f5b081880c61ab845fe09.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/136/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `ee068fe115138648b12f5b081880c61ab845fe09`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE
user: login: risc-vv
created_at: 2025-04-04T08:55:59Z
body: <details><summary>69200b10 is being scheduled for building and testing</summary>

GIT: `69200b102398c3264330336b11f46de89ed0da46`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: zbb</details>
author_association: NONE
user: login: tomeksowi
created_at: 2025-04-04T09:01:42Z
body: No regressions, I'll look what's the missed context

Diffs are based on <span style="color:#1460aa">171,584</span> contexts (<span style="color:#1460aa">22,709</span> MinOpts, <span style="color:#1460aa">148,875</span> FullOpts).

<span style="color:#d35400">MISSED</span> contexts: base: <span style="color:green">0 (0.00%)</span>, diff: <span style="color:#d35400">1 (0.00%)</span>


<details>
<summary>Overall (<span style="color:green">-486,920</span> bytes)</summary>
<div style="margin-left:1em">

|Collection|Base size (bytes)|Diff size (bytes)|PerfScore in Diffs
|---|--:|--:|--:|
|linux.riscv64.Checked.mch|123,874,100|<span style="color:green">-486,920</span>|<span style="color:green">-0.72%</span>|


</div></details>

<details>
<summary>MinOpts (<span style="color:green">-90,700</span> bytes)</summary>
<div style="margin-left:1em">

|Collection|Base size (bytes)|Diff size (bytes)|PerfScore in Diffs
|---|--:|--:|--:|
|linux.riscv64.Checked.mch|47,531,640|<span style="color:green">-90,700</span>|<span style="color:green">-0.32%</span>|


</div></details>

<details>
<summary>FullOpts (<span style="color:green">-396,220</span> bytes)</summary>
<div style="margin-left:1em">

|Collection|Base size (bytes)|Diff size (bytes)|PerfScore in Diffs
|---|--:|--:|--:|
|linux.riscv64.Checked.mch|76,342,460|<span style="color:green">-396,220</span>|<span style="color:green">-0.80%</span>|


</div></details>

<details>
<summary>Example diffs</summary>
<div style="margin-left:1em">


<details>
<summary>linux.riscv64.Checked.mch</summary>
<div style="margin-left:1em">


<details>
<summary><span style="color:green">-16</span> (<span style="color:green">-30.77%</span>) : 41224.dasm - Internal.VersionResilientHashCode:RotateLeft(int,int):int (FullOpts)</summary>
<div style="margin-left:1em">

```diff
@@ -22,19 +22,15 @@ G_M25405_IG01:        ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref,
             mv             fp, sp, 
 						;; size=16 bbWeight=1 PerfScore 9.00
 G_M25405_IG02:        ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0000 {}, byref
-            addi           a2, zero, 0xD1FFAB1E
-            sub            a2, a2, a1
-            srlw           ra, a0, a2
-            sllw           a2, a0, a1
-            or             a0, ra, a2
-						;; size=20 bbWeight=1 PerfScore 2.50
+            rolw           a0, a0, a1
+						;; size=4 bbWeight=1 PerfScore 0.50
 G_M25405_IG03:        ; bbWeight=1, epilog, nogc, extend
             ld             ra, 8(sp)
             ld             fp, 0(sp)
             addi           sp, sp, 16
             ret						;; size=16 bbWeight=1 PerfScore 7.50
 
-; Total bytes of code 52, prolog size 16, PerfScore 19.00, instruction count 13, allocated bytes for code 52 (MethodHash=d2d19cc2) for method Internal.VersionResilientHashCode:RotateLeft(int,int):int (FullOpts)
+; Total bytes of code 36, prolog size 16, PerfScore 17.00, instruction count 9, allocated bytes for code 36 (MethodHash=d2d19cc2) for method Internal.VersionResilientHashCode:RotateLeft(int,int):int (FullOpts)
 ; ============================================================
 
 Unwind Info:
@@ -45,7 +41,7 @@ Unwind Info:
   E bit             : 0
   X bit             : 0
   Vers              : 0
-  Function Length   : 13 (0x0000d) Actual length = 52 (0x000034)
+  Function Length   : 9 (0x00009) Actual length = 36 (0x000024)
   ---- Epilog scopes ----
   ---- Scope 0
   Epilog Start Offset        : 3523193630 (0xd1ffab1e) Actual offset = 3523193630 (0xd1ffab1e) Offset from main function begin = 3523193630 (0xd1ffab1e)
```

</div></details>

<details>
<summary><span style="color:green">-16</span> (<span style="color:green">-28.57%</span>) : 12453.dasm - System.Numerics.Tensors.TensorPrimitives+RotateRightOperator`1[int]:Invoke(int):int:this (FullOpts)</summary>
<div style="margin-left:1em">

```diff
@@ -26,19 +26,15 @@ G_M45139_IG02:        ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0400 {a0}, byre
             ; byrRegs +[a0]
             lw             a0, 0xD1FFAB1E(a0)
             ; byrRegs -[a0]
-            addi           a2, zero, 0xD1FFAB1E
-            sub            a2, a2, a0
-            srlw           ra, a1, a0
-            sllw           a2, a1, a2
-            or             a0, ra, a2
-						;; size=24 bbWeight=1 PerfScore 4.50
+            rorw          a0, a1, a0
+						;; size=8 bbWeight=1 PerfScore 2.50
 G_M45139_IG03:        ; bbWeight=1, epilog, nogc, extend
             ld             ra, 8(sp)
             ld             fp, 0(sp)
             addi           sp, sp, 16
             ret						;; size=16 bbWeight=1 PerfScore 7.50
 
-; Total bytes of code 56, prolog size 16, PerfScore 21.00, instruction count 14, allocated bytes for code 56 (MethodHash=f0874fac) for method System.Numerics.Tensors.TensorPrimitives+RotateRightOperator`1[int]:Invoke(int):int:this (FullOpts)
+; Total bytes of code 40, prolog size 16, PerfScore 19.00, instruction count 10, allocated bytes for code 40 (MethodHash=f0874fac) for method System.Numerics.Tensors.TensorPrimitives+RotateRightOperator`1[int]:Invoke(int):int:this (FullOpts)
 ; ============================================================
 
 Unwind Info:
@@ -49,7 +45,7 @@ Unwind Info:
   E bit             : 0
   X bit             : 0
   Vers              : 0
-  Function Length   : 14 (0x0000e) Actual length = 56 (0x000038)
+  Function Length   : 10 (0x0000a) Actual length = 40 (0x000028)
   ---- Epilog scopes ----
   ---- Scope 0
   Epilog Start Offset        : 3523193630 (0xd1ffab1e) Actual offset = 3523193630 (0xd1ffab1e) Offset from main function begin = 3523193630 (0xd1ffab1e)
```

</div></details>

<details>
<summary><span style="color:green">-16</span> (<span style="color:green">-28.57%</span>) : 12454.dasm - System.Numerics.Tensors.TensorPrimitives+RotateRightOperator`1[long]:Invoke(long):long:this (FullOpts)</summary>
<div style="margin-left:1em">

```diff
@@ -26,19 +26,15 @@ G_M38666_IG02:        ; bbWeight=1, gcrefRegs=0000 {}, byrefRegs=0400 {a0}, byre
             ; byrRegs +[a0]
             lw             a0, 0xD1FFAB1E(a0)
             ; byrRegs -[a0]
-            addi           a2, zero, 0xD1FFAB1E
-            sub            a2, a2, a0
-            srl            ra, a1, a0
-            sll            a2, a1, a2
-            or             a0, ra, a2
-						;; size=24 bbWeight=1 PerfScore 4.50
+            ror            a0, a1, a0
+						;; size=8 bbWeight=1 PerfScore 2.50
 G_M38666_IG03:        ; bbWeight=1, epilog, nogc, extend
             ld             ra, 8(sp)
             ld             fp, 0(sp)
             addi           sp, sp, 16
             ret						;; size=16 bbWeight=1 PerfScore 7.50
 
-; Total bytes of code 56, prolog size 16, PerfScore 21.00, instruction count 14, allocated bytes for code 56 (MethodHash=676968f5) for method System.Numerics.Tensors.TensorPrimitives+RotateRightOperator`1[long]:Invoke(long):long:this (FullOpts)
+; Total bytes of code 40, prolog size 16, PerfScore 19.00, instruction count 10, allocated bytes for code 40 (MethodHash=676968f5) for method System.Numerics.Tensors.TensorPrimitives+RotateRightOperator`1[long]:Invoke(long):long:this (FullOpts)
 ; ============================================================
 
 Unwind Info:
@@ -49,7 +45,7 @@ Unwind Info:
   E bit             : 0
   X bit             : 0
   Vers              : 0
-  Function Length   : 14 (0x0000e) Actual length = 56 (0x000038)
+  Function Length   : 10 (0x0000a) Actual length = 40 (0x000028)
   ---- Epilog scopes ----
   ---- Scope 0
   Epilog Start Offset        : 3523193630 (0xd1ffab1e) Actual offset = 3523193630 (0xd1ffab1e) Offset from main function begin = 3523193630 (0xd1ffab1e)
```

</div></details>

<details>
<summary>+0 (0.00%) : 171536.dasm - Generated442:StructConstrainedInterfaceCallsTest() (FullOpts)</summary>
<div style="margin-left:1em">

No diffs found?

</div></details>

<details>
<summary>+0 (0.00%) : 171472.dasm - ValueNumberingCheckedCastsOfConstants:<TestCastingUInt64ToUInt32>g__ConfirmUInt64OneDecrementUnderUInt64MaxValueCastToUInt32Overflows|97_24() (FullOpts)</summary>
<div style="margin-left:1em">

No diffs found?

</div></details>

<details>
<summary>+0 (0.00%) : 171440.dasm - ValueNumberingCheckedCastsOfConstants:<TestCastingUInt64ToInt32>g__ConfirmUInt32MaxValueCastToInt32Overflows|96_17() (FullOpts)</summary>
<div style="margin-left:1em">

No diffs found?

</div></details>


</div></details>


</div></details>

<details>
<summary>Details</summary>
<div style="margin-left:1em">

#### Size improvements/regressions per collection

|Collection|Contexts with diffs|Improvements|Regressions|Same size|Improvements (bytes)|Regressions (bytes)|
|---|--:|--:|--:|--:|--:|--:|
|linux.riscv64.Checked.mch|44,460|<span style="color:green">35,552</span>|<span style="color:red">0</span>|<span style="color:blue">8,908</span>|<span style="color:green">-486,920</span>|<span style="color:red">+0</span>|

---

#### PerfScore improvements/regressions per collection

|Collection|Contexts with diffs|Improvements|Regressions|Same PerfScore|Improvements (PerfScore)|Regressions (PerfScore)|PerfScore Overall in FullOpts|
|---|--:|--:|--:|--:|--:|--:|--:|
|linux.riscv64.Checked.mch|44,460|<span style="color:green">34,781</span>|<span style="color:red">0</span>|<span style="color:blue">9,679</span>|<span style="color:green">-0.92%</span>|0.00%|<span style="color:green">-0.1990%</span>|

---

#### Context information

|Collection|Diffed contexts|MinOpts|FullOpts|Missed, base|Missed, diff|
|---|--:|--:|--:|--:|--:|
|linux.riscv64.Checked.mch|171,584|22,709|148,875|0 (0.00%)|1 (0.00%)|


---

#### jit-analyze output


</div></details>

author_association: MEMBER
user: login: risc-vv
created_at: 2025-04-04T09:16:18Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9529 / 9549 (99.79%)</summary>


```
=======================
      passed: 9529
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9655
 TOTAL tests: 9655
   REAL time: 2h 12min 33s 685ms
=======================

```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/92c3b2b12708505764d00b17c6a66fcd/raw/de6cd29ea2d6143ad281e4bb9dbd5569a748b2b6/Release-CLR-VF2-52b8a0c046dad3b0187169373bba0972175e3592.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/cf7c8d3200998ce9fd0a4496955a838c/raw/9b7a726ee7229084f332a1f6c072b7c9519e6355/Release-CLR-VF2-52b8a0c046dad3b0187169373bba0972175e3592.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/141/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `52b8a0c046dad3b0187169373bba0972175e3592`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-QEMU: 631076 / 660256 (95.58%)</summary>


```
=======================
      passed: 631076
      failed: 1639
     skipped: 1462
      killed: 27541
------------------------
  TOTAL libs: 259
 TOTAL tests: 661718
   REAL time: 2h 30min 30s 104ms
=======================

```
[Release-FX-QEMU.md](https://gist.githubusercontent.com/risc-vv/d2038b22f2820c1251d7b5e001a72bb1/raw/ebc79da259eab34ccda8fd96a339f234e55fbc71/Release-FX-QEMU-52b8a0c046dad3b0187169373bba0972175e3592.md), [Release-FX-QEMU.xml](http://127.0.0.1/pipelines/Release-FX-QEMU/135/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-QEMU/135/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `52b8a0c046dad3b0187169373bba0972175e3592`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-VF2: 636810 / 664988 (95.76%)</summary>


```
=======================
      passed: 636810
      failed: 1445
     skipped: 1486
      killed: 26733
------------------------
  TOTAL libs: 259
 TOTAL tests: 666474
   REAL time: 2h 40min 1s 578ms
=======================

```
[Release-FX-VF2.md](https://gist.githubusercontent.com/risc-vv/6137e0198a97a79cfce7f30ca4ee5bcd/raw/8c115398e0ea7963fe74217c95cffb34b9463d3c/Release-FX-VF2-52b8a0c046dad3b0187169373bba0972175e3592.md), [Release-FX-VF2.xml](http://127.0.0.1/pipelines/Release-FX-VF2/138/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-VF2/138/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `52b8a0c046dad3b0187169373bba0972175e3592`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9529 / 9549 (99.79%)</summary>


```
=======================
      passed: 9529
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9655
 TOTAL tests: 9655
   REAL time: 2h 47min 4s 398ms
=======================

```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/292c7642e098d7635d141326c2a9fb82/raw/d6133c350fc080046ee351b125e9781095a6180b/Release-CLR-QEMU-52b8a0c046dad3b0187169373bba0972175e3592.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/3bdfb250804089817c2138e73ffab068/raw/60c1d67645261e3fe0763521472e7610223470c8/Release-CLR-QEMU-52b8a0c046dad3b0187169373bba0972175e3592.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/140/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `52b8a0c046dad3b0187169373bba0972175e3592`
CI: `a8426a46d8575dfcb3b5fec0d7d0b7a7c118d690`
REPO: [tomeksowi/runtime](https://github.com/tomeksowi/runtime)
BRANCH: `zbb`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE
user: login: risc-vv
created_at: 2025-04-09T12:51:05Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9532 / 9552 (99.79%)</summary>


```
=======================
      passed: 9532
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9658
 TOTAL tests: 9658
   REAL time: 2h 10min 58s 528ms
=======================

```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/687ad84f1cf29747af741039460fd38d/raw/ff0a6a3ee4826db68acea4db8e3a7de4ddda0bc8/Release-CLR-VF2-db6bc0884114c1d71887af4fd01270bce167699f.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/b30b3d5b5c8787e35e257cc45b36ba34/raw/50488caae629157316e66a50b7d3975d71b68405/Release-CLR-VF2-db6bc0884114c1d71887af4fd01270bce167699f.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/153/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `db6bc0884114c1d71887af4fd01270bce167699f`
CI: `09909bfe3d23ad26455327811013bcbb48915255`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-QEMU: 633735 / 662830 (95.61%)</summary>


```
=======================
      passed: 633735
      failed: 1540
     skipped: 1463
      killed: 27555
------------------------
  TOTAL libs: 259
 TOTAL tests: 664293
   REAL time: 2h 33min 2s 576ms
=======================

```
[Release-FX-QEMU.md](https://gist.githubusercontent.com/risc-vv/6ad7719c46192b68d795e2ac42671fb7/raw/c27bddcd6e92831f503a8242cf388dc9bcd7a080/Release-FX-QEMU-db6bc0884114c1d71887af4fd01270bce167699f.md), [Release-FX-QEMU.xml](http://127.0.0.1/pipelines/Release-FX-QEMU/144/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-QEMU/144/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `db6bc0884114c1d71887af4fd01270bce167699f`
CI: `09909bfe3d23ad26455327811013bcbb48915255`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9532 / 9552 (99.79%)</summary>


```
=======================
      passed: 9532
      failed: 3
     skipped: 106
      killed: 17
------------------------
  TOTAL libs: 9658
 TOTAL tests: 9658
   REAL time: 2h 48min 14s 760ms
=======================

```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/0aa395487837cd9142886e6d20d9eab8/raw/d6b586da4f4545422f0e94f6e4a278f81c8681bd/Release-CLR-QEMU-db6bc0884114c1d71887af4fd01270bce167699f.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/283f35f8453581133710086b9d446a66/raw/dce4ce3e2e0c3da89a02fa4ff1a2ace95af6e1e3/Release-CLR-QEMU-db6bc0884114c1d71887af4fd01270bce167699f.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/150/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `db6bc0884114c1d71887af4fd01270bce167699f`
CI: `09909bfe3d23ad26455327811013bcbb48915255`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE
user: login: risc-vv
created_at: 2025-04-11T13:41:10Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9540 / 9589 (99.49%)</summary>


```

=======================
      passed: 9540
      failed: 29
     skipped: 70
      killed: 20
------------------------
  TOTAL libs: 9659
 TOTAL tests: 9659
   REAL time: 2h 34min 19s 526ms
=======================
```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/3f18fff7e7be10cffbacd41609866b40/raw/10f5ac35682ef162f45cecd39c394dd75edc39e5/Release-CLR-VF2-4db78f46a51ee6b38c802d148f30163b8c2d5154.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/b3aa853cb60ccefbfa6cb24928a68e00/raw/7191e8ba5113999125978856bdd67ce59aa02009/Release-CLR-VF2-4db78f46a51ee6b38c802d148f30163b8c2d5154.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/160/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `4db78f46a51ee6b38c802d148f30163b8c2d5154`
CI: `396638dc6f3cc259b01119150e078a456a35e7da`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-QEMU: 644845 / 669056 (96.38%)</summary>


```

=======================
      passed: 644845
      failed: 1564
     skipped: 1617
      killed: 22647
------------------------
  TOTAL libs: 259
 TOTAL tests: 670673
   REAL time: 2h 34min 35s 845ms
=======================
```
[Release-FX-QEMU.md](https://gist.githubusercontent.com/risc-vv/c8b90fdca8fe5af74591f093eff9825a/raw/117380d3b96a187a9daa5e3623f3eb3cf9d056b8/Release-FX-QEMU-4db78f46a51ee6b38c802d148f30163b8c2d5154.md), [Release-FX-QEMU.xml](http://127.0.0.1/pipelines/Release-FX-QEMU/149/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-QEMU/149/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `4db78f46a51ee6b38c802d148f30163b8c2d5154`
CI: `396638dc6f3cc259b01119150e078a456a35e7da`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9541 / 9589 (99.50%)</summary>


```

=======================
      passed: 9541
      failed: 28
     skipped: 70
      killed: 20
------------------------
  TOTAL libs: 9659
 TOTAL tests: 9659
   REAL time: 3h 19min 14s 340ms
=======================
```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/583b156acafa3ceccac0e0d88555700e/raw/6e062d5f8d6851a1493bc33c96eb804d418eba39/Release-CLR-QEMU-4db78f46a51ee6b38c802d148f30163b8c2d5154.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/e56d6d1c2604f68e58f323c5d7bf9693/raw/b5012b7afbd06ab7085114f4db8031aa1f9e2c5e/Release-CLR-QEMU-4db78f46a51ee6b38c802d148f30163b8c2d5154.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/156/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `4db78f46a51ee6b38c802d148f30163b8c2d5154`
CI: `396638dc6f3cc259b01119150e078a456a35e7da`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE
user: login: am11
created_at: 2025-04-13T05:35:36Z
body: Interesting that 4 days ago:
```
      failed: 3
     skipped: 106
```
and in the next run 2 days ago:
```
      failed: 29
     skipped: 70
```

Is this a flakiness in test orchestration that it can sometimes run the skipped tests or were there as many tests enabled in two days? 👀

@tomeksowi if you could rerun the tests and it goes back to 99.79%, then it's former and something which should be looked at from runtime infra viewpoint. We can open an issue with build+test commands executed by risc-vv as steps to repro.
author_association: MEMBER
user: login: tomeksowi
created_at: 2025-04-13T07:48:41Z
body: > @tomeksowi if you could rerun the tests and it goes back to 99.79%, then it's former and something which should be looked at from runtime infra viewpoint. We can open an issue with build+test commands executed by risc-vv as steps to repro.

Let's try. But risc-vv is running tests **after** merging with latest main (the report could be clearer about that) so it could be a regression. I fixed some varargs not supported tests e.g. in #112399, the number of tests increased 9552 to 9589 so it maybe similar this time, I'll check on Monday.
author_association: MEMBER
user: login: am11
created_at: 2025-04-13T09:08:42Z
body: > the report could be clearer about that

The markdown report could also include build and test commands. Infra is constantly undergoing refactoring, so we can test those commands during that type of work to avoid breakage.
author_association: MEMBER
user: login: risc-vv
created_at: 2025-04-14T01:01:06Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9542 / 9590 (99.50%)</summary>


```

=======================
      passed: 9542
      failed: 28
     skipped: 70
      killed: 20
------------------------
  TOTAL libs: 9660
 TOTAL tests: 9660
   REAL time: 2h 37min 38s 912ms
=======================
```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/63b92d438cf716b9e130c3f70e6dcd93/raw/f18cb0bca3e779500d3c0f1f76edb1dbe5a9f8d7/Release-CLR-VF2-6cb870602a753c6cbc6e311f13e6db3dbe126f2d.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/dc569f85f2ffb4cf6db182846c917f43/raw/80bdd91a6f08df633f87a10bd7de17893a81f418/Release-CLR-VF2-6cb870602a753c6cbc6e311f13e6db3dbe126f2d.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/161/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `6cb870602a753c6cbc6e311f13e6db3dbe126f2d`
CI: `396638dc6f3cc259b01119150e078a456a35e7da`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9542 / 9590 (99.50%)</summary>


```

=======================
      passed: 9542
      failed: 28
     skipped: 70
      killed: 20
------------------------
  TOTAL libs: 9660
 TOTAL tests: 9660
   REAL time: 3h 50min 37s 136ms
=======================
```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/df110343bf15d0ea2a09ddfad451ad8d/raw/4ff597ef4baa9cf09d1876b6c0fe8b4dd57564d6/Release-CLR-QEMU-6cb870602a753c6cbc6e311f13e6db3dbe126f2d.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/96219b2ee632a16ec8efbb798bc14c9b/raw/4c0dcc2176084303fd8c90c64648e3ad4b3c3de5/Release-CLR-QEMU-6cb870602a753c6cbc6e311f13e6db3dbe126f2d.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/157/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `6cb870602a753c6cbc6e311f13e6db3dbe126f2d`
CI: `396638dc6f3cc259b01119150e078a456a35e7da`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-QEMU: 633600 / 657795 (96.32%)</summary>


```

=======================
      passed: 633600
      failed: 1599
     skipped: 1469
      killed: 22596
------------------------
  TOTAL libs: 259
 TOTAL tests: 659264
   REAL time: 2h 45min 7s 330ms
=======================
```
[Release-FX-QEMU.md](https://gist.githubusercontent.com/risc-vv/0a2c9cde8cab43d7be1831b6272071da/raw/c53929ce3be7a1063462b7b1c66e7cf772ed68ab/Release-FX-QEMU-6cb870602a753c6cbc6e311f13e6db3dbe126f2d.md), [Release-FX-QEMU.xml](http://127.0.0.1/pipelines/Release-FX-QEMU/150/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-QEMU/150/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `6cb870602a753c6cbc6e311f13e6db3dbe126f2d`
CI: `396638dc6f3cc259b01119150e078a456a35e7da`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE
user: login: risc-vv
created_at: 2025-04-15T13:16:25Z
body: <details><summary>7b78b545 is being scheduled for building and testing</summary>

GIT: `7b78b545a4c016f10164ab9ef8a54eece8cbf552`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: main</details>
author_association: NONE
user: login: tomeksowi
created_at: 2025-04-15T13:17:41Z
body: >       passed: 9542
>       failed: 28
>      skipped: 70
>       killed: 20

Probably our CI script ignores some entries from issues.targets (@sirntar is working on it). I ran `src/tests/run.sh` locally and the problem didn't repeat.
author_association: MEMBER
user: login: risc-vv
created_at: 2025-04-17T08:06:59Z
body: <details>
<summary>RISC-V Release-CLR-VF2: 9702 / 9750 (99.51%)</summary>


```

=======================
      passed: 9702
      failed: 28
     skipped: 70
      killed: 20
------------------------
  TOTAL libs: 9820
 TOTAL tests: 9820
   REAL time: 1h 57min 27s 220ms
=======================
```
[Release-CLR-VF2.md](https://gist.githubusercontent.com/risc-vv/6af119333eef095f06b5ae84356fd812/raw/f22620d92e27d8acf34d06cfaa88d82e83a16c01/Release-CLR-VF2-034a8b200f6fdf89e2f764dc817a867285eab8a4.md), [Release-CLR-VF2.xml](https://gist.githubusercontent.com/risc-vv/5f81b44c28c23777eeaad79a395b0bed/raw/6c68bde975e4970300baa2ad2a0520c4ddc410e1/Release-CLR-VF2-034a8b200f6fdf89e2f764dc817a867285eab8a4.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-VF2/167/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `034a8b200f6fdf89e2f764dc817a867285eab8a4`
CI: `2d916d20de463f9bba05ae71b3d1f37d439a8cb1`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-CLR-QEMU: 9702 / 9750 (99.51%)</summary>


```

=======================
      passed: 9702
      failed: 28
     skipped: 70
      killed: 20
------------------------
  TOTAL libs: 9820
 TOTAL tests: 9820
   REAL time: 3h 22min 34s 278ms
=======================
```
[Release-CLR-QEMU.md](https://gist.githubusercontent.com/risc-vv/87022ccedc5b61fd7305a83e180848cc/raw/6d928c25ce2e209f525fc7488de87c3aa8103ff6/Release-CLR-QEMU-034a8b200f6fdf89e2f764dc817a867285eab8a4.md), [Release-CLR-QEMU.xml](https://gist.githubusercontent.com/risc-vv/3be2890423a130b48335f30142030d52/raw/f25ef535814a9d941c6c99f3351e84c60eecd99f/Release-CLR-QEMU-034a8b200f6fdf89e2f764dc817a867285eab8a4.xml), [testclr_output.tar.gz](http://127.0.0.1/pipelines/Release-CLR-QEMU/163/run-tests/1/run-tests/testoutput/testclr_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `034a8b200f6fdf89e2f764dc817a867285eab8a4`
CI: `2d916d20de463f9bba05ae71b3d1f37d439a8cb1`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
<details>
<summary>RISC-V Release-FX-QEMU: 720592 / 744909 (96.74%)</summary>


```

=======================
      passed: 720592
      failed: 1616
     skipped: 1677
      killed: 22701
------------------------
  TOTAL libs: 259
 TOTAL tests: 746586
   REAL time: 2h 28min 38s 599ms
=======================
```
[Release-FX-QEMU.md](https://gist.githubusercontent.com/risc-vv/2b4d269c95dfc9919c2bf959dacdb6e6/raw/438e42dd93bec93c752d7e3345090356232a8888/Release-FX-QEMU-034a8b200f6fdf89e2f764dc817a867285eab8a4.md), [Release-FX-QEMU.xml](http://127.0.0.1/pipelines/Release-FX-QEMU/156/run-tests/1/run-tests/testoutput/report.xml.gz), [testfx_output.tar.gz](http://127.0.0.1/pipelines/Release-FX-QEMU/156/run-tests/1/run-tests/testoutput/testfx_details.Release.tar.gz)
</details><details>
<summary>Build information and commands</summary>

GIT: `034a8b200f6fdf89e2f764dc817a867285eab8a4`
CI: `2d916d20de463f9bba05ae71b3d1f37d439a8cb1`
REPO: [dotnet/runtime](https://github.com/dotnet/runtime)
BRANCH: `main`
CONFIG: `Release`
LIB_CONFIG: `Release`

</details>
author_association: NONE