@@ -1904,6 +1904,21 @@ enum Nf {
#undef INSN
+#define INSN(NAME, op, width, umop, mop, mew, nf) \
+ void NAME(VectorRegister Vd_or_Vs3, Register Rs1, VectorMask vm = unmasked) { \
+ patch_VLdSt(op, Vd_or_Vs3, width, Rs1, umop, vm, mop, mew, nf); \
+ }
+
+ // Vector Unit-Stride Segment Load Instructions
+ INSN(vlseg3e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g3);
+ INSN(vlseg4e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g4);
+
+ // Vector Unit-Stride Segment Store Instructions
+ INSN(vsseg3e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g3);
+ INSN(vsseg4e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g4);
+
+#undef INSN
+
#define INSN(NAME, op, width, mop, mew) \
void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked, Nf nf = g1) { \
patch_VLdSt(op, Vd, width, Rs1, Vs2->raw_encoding(), vm, mop, mew, nf); \
@@ -5260,6 +5260,502 @@ class StubGenerator: public StubCodeGenerator {
return (address) start;
}
+ /**
+ * vector registers:
+ * input VectorRegister's: intputV1-V3, for m2 they could be v2, v4, v6, for m1 they could be v1, v2, v3
+ * index VectorRegister's: idxV1-V4, for m2 they could be v8, v10, v12, v14, for m1 they could be v4, v5, v6, v7
+ * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v8, v9, v10, v11
+ *
+ * NOTE: each field will occupy a vector register group
+ */
+ void base64_vector_encode_round(Register src, Register dst, Register codec,
+ Register size, Register stepSrc, Register stepDst,
+ VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3,
+ VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4,
+ VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3, VectorRegister outputV4,
+ Assembler::LMUL lmul) {
+ // set vector register type/len
+ __ vsetvli(x0, size, Assembler::e8, lmul);
+
+ // segmented load src into v registers: mem(src) => vr(3)
+ __ vlseg3e8_v(inputV1, src);
+
+ // src = src + register_group_len_bytes * 3
+ __ add(src, src, stepSrc);
+
+ // encoding
+ // 1. compute index into lookup table: vr(3) => vr(4)
+ __ vsrl_vi(idxV1, inputV1, 2);
+
+ __ vsrl_vi(idxV2, inputV2, 2);
+ __ vsll_vi(inputV1, inputV1, 6);
+ __ vor_vv(idxV2, idxV2, inputV1);
+ __ vsrl_vi(idxV2, idxV2, 2);
+
+ __ vsrl_vi(idxV3, inputV3, 4);
+ __ vsll_vi(inputV2, inputV2, 4);
+ __ vor_vv(idxV3, inputV2, idxV3);
+ __ vsrl_vi(idxV3, idxV3, 2);
+
+ __ vsll_vi(idxV4, inputV3, 2);
+ __ vsrl_vi(idxV4, idxV4, 2);
+
+ // 2. indexed load: vr(4) => vr(4)
+ __ vluxei8_v(outputV1, codec, idxV1);
+ __ vluxei8_v(outputV2, codec, idxV2);
+ __ vluxei8_v(outputV3, codec, idxV3);
+ __ vluxei8_v(outputV4, codec, idxV4);
+
+ // segmented store encoded data in v registers back to dst: vr(4) => mem(dst)
+ __ vsseg4e8_v(outputV1, dst);
+
+ // dst = dst + register_group_len_bytes * 4
+ __ add(dst, dst, stepDst);
+ }
+
+ /**
+ * void j.u.Base64.Encoder.encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL)
+ *
+ * Input arguments:
+ * c_rarg0 - src, source array
+ * c_rarg1 - sp, src start offset
+ * c_rarg2 - sl, src end offset
+ * c_rarg3 - dst, dest array
+ * c_rarg4 - dp, dst start offset
+ * c_rarg5 - isURL, Base64 or URL character set
+ */
+ address generate_base64_encodeBlock() {
+ alignas(64) static const char toBase64[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+
+ alignas(64) static const char toBase64URL[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+ };
+
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "encodeBlock");
+ address start = __ pc();
+ __ enter();
+
+ Register src = c_rarg0;
+ Register soff = c_rarg1;
+ Register send = c_rarg2;
+ Register dst = c_rarg3;
+ Register doff = c_rarg4;
+ Register isURL = c_rarg5;
+
+ Register codec = c_rarg6;
+ Register length = c_rarg7; // total length of src data in bytes
+
+ Label ProcessData, Exit;
+
+ // length should be multiple of 3
+ __ sub(length, send, soff);
+ // real src/dst to process data
+ __ add(src, src, soff);
+ __ add(dst, dst, doff);
+
+ // load the codec base address
+ __ la(codec, ExternalAddress((address) toBase64));
+ __ beqz(isURL, ProcessData);
+ __ la(codec, ExternalAddress((address) toBase64URL));
+ __ BIND(ProcessData);
+
+ // vector version
+ if (UseRVV) {
+ Label ProcessM2, ProcessM1, ProcessScalar;
+
+ Register size = soff;
+ Register stepSrcM1 = send;
+ Register stepSrcM2 = doff;
+ Register stepDst = isURL;
+
+ __ mv(size, MaxVectorSize * 2);
+ __ mv(stepSrcM1, MaxVectorSize * 3);
+ __ slli(stepSrcM2, stepSrcM1, 1);
+ __ mv(stepDst, MaxVectorSize * 2 * 4);
+
+ __ blt(length, stepSrcM2, ProcessM1);
+
+ __ BIND(ProcessM2);
+ base64_vector_encode_round(src, dst, codec,
+ size, stepSrcM2, stepDst,
+ v2, v4, v6, // inputs
+ v8, v10, v12, v14, // indexes
+ v16, v18, v20, v22, // outputs
+ Assembler::m2);
+
+ __ sub(length, length, stepSrcM2);
+ __ bge(length, stepSrcM2, ProcessM2);
+
+ __ BIND(ProcessM1);
+ __ blt(length, stepSrcM1, ProcessScalar);
+
+ __ srli(size, size, 1);
+ __ srli(stepDst, stepDst, 1);
+ base64_vector_encode_round(src, dst, codec,
+ size, stepSrcM1, stepDst,
+ v1, v2, v3, // inputs
+ v4, v5, v6, v7, // indexes
+ v8, v9, v10, v11, // outputs
+ Assembler::m1);
+ __ sub(length, length, stepSrcM1);
+
+ __ BIND(ProcessScalar);
+ }
+
+ // scalar version
+ {
+ Register byte1 = soff, byte0 = send, byte2 = doff;
+ Register combined24Bits = isURL;
+
+ __ beqz(length, Exit);
+
+ Label ScalarLoop;
+ __ BIND(ScalarLoop);
+ {
+ // plain: [byte0[7:0] : byte1[7:0] : byte2[7:0]] =>
+ // encoded: [byte0[7:2] : byte0[1:0]+byte1[7:4] : byte1[3:0]+byte2[7:6] : byte2[5:0]]
+
+ // load 3 bytes src data
+ __ lbu(byte0, Address(src, 0));
+ __ lbu(byte1, Address(src, 1));
+ __ lbu(byte2, Address(src, 2));
+ __ addi(src, src, 3);
+
+ // construct 24 bits from 3 bytes
+ __ slliw(byte0, byte0, 16);
+ __ slliw(byte1, byte1, 8);
+ __ orr(combined24Bits, byte0, byte1);
+ __ orr(combined24Bits, combined24Bits, byte2);
+
+ // get codec index and encode(ie. load from codec by index)
+ __ slliw(byte0, combined24Bits, 8);
+ __ srliw(byte0, byte0, 26);
+ __ add(byte0, codec, byte0);
+ __ lbu(byte0, byte0);
+
+ __ slliw(byte1, combined24Bits, 14);
+ __ srliw(byte1, byte1, 26);
+ __ add(byte1, codec, byte1);
+ __ lbu(byte1, byte1);
+
+ __ slliw(byte2, combined24Bits, 20);
+ __ srliw(byte2, byte2, 26);
+ __ add(byte2, codec, byte2);
+ __ lbu(byte2, byte2);
+
+ __ andi(combined24Bits, combined24Bits, 0x3f);
+ __ add(combined24Bits, codec, combined24Bits);
+ __ lbu(combined24Bits, combined24Bits);
+
+ // store 4 bytes encoded data
+ __ sb(byte0, Address(dst, 0));
+ __ sb(byte1, Address(dst, 1));
+ __ sb(byte2, Address(dst, 2));
+ __ sb(combined24Bits, Address(dst, 3));
+
+ __ sub(length, length, 3);
+ __ addi(dst, dst, 4);
+ // loop back
+ __ bnez(length, ScalarLoop);
+ }
+ }
+
+ __ BIND(Exit);
+
+ __ leave();
+ __ ret();
+
+ return (address) start;
+ }
+
+ /**
+ * vector registers:
+ * input VectorRegister's: intputV1-V4, for m2 they could be v2, v4, v6, for m1 they could be v2, v4, v6, v8
+ * index VectorRegister's: idxV1-V3, for m2 they could be v8, v10, v12, v14, for m1 they could be v10, v12, v14, v16
+ * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v18, v20, v22
+ *
+ * NOTE: each field will occupy a single vector register group
+ */
+ void base64_vector_decode_round(Register src, Register dst, Register codec,
+ Register size, Register stepSrc, Register stepDst, Register failedIdx,
+ VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3, VectorRegister inputV4,
+ VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4,
+ VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3,
+ Assembler::LMUL lmul) {
+ // set vector register type/len
+ __ vsetvli(x0, size, Assembler::e8, lmul, Assembler::ma, Assembler::ta);
+
+ // segmented load src into v registers: mem(src) => vr(4)
+ __ vlseg4e8_v(inputV1, src);
+
+ // src = src + register_group_len_bytes * 4
+ __ add(src, src, stepSrc);
+
+ // decoding
+ // 1. indexed load: vr(4) => vr(4)
+ __ vluxei8_v(idxV1, codec, inputV1);
+ __ vluxei8_v(idxV2, codec, inputV2);
+ __ vluxei8_v(idxV3, codec, inputV3);
+ __ vluxei8_v(idxV4, codec, inputV4);
+
+ // 2. check wrong data
+ __ vor_vv(outputV1, idxV1, idxV2);
+ __ vor_vv(outputV2, idxV3, idxV4);
+ __ vor_vv(outputV1, outputV1, outputV2);
+ __ vmseq_vi(v0, outputV1, -1);
+ __ vfirst_m(failedIdx, v0);
+ Label NoFailure, FailureAtIdx0;
+ // valid value can only be -1 when < 0
+ __ bltz(failedIdx, NoFailure);
+ // when the first data (at index 0) fails, no need to process data anymore
+ __ beqz(failedIdx, FailureAtIdx0);
+ __ vsetvli(x0, failedIdx, Assembler::e8, lmul, Assembler::mu, Assembler::tu);
+ __ slli(stepDst, failedIdx, 1);
+ __ add(stepDst, failedIdx, stepDst);
+ __ BIND(NoFailure);
+
+ // 3. compute the decoded data: vr(4) => vr(3)
+ __ vsll_vi(idxV1, idxV1, 2);
+ __ vsrl_vi(outputV1, idxV2, 4);
+ __ vor_vv(outputV1, outputV1, idxV1);
+
+ __ vsll_vi(idxV2, idxV2, 4);
+ __ vsrl_vi(outputV2, idxV3, 2);
+ __ vor_vv(outputV2, outputV2, idxV2);
+
+ __ vsll_vi(idxV3, idxV3, 6);
+ __ vor_vv(outputV3, idxV4, idxV3);
+
+ // segmented store encoded data in v registers back to dst: vr(3) => mem(dst)
+ __ vsseg3e8_v(outputV1, dst);
+
+ // dst = dst + register_group_len_bytes * 3
+ __ add(dst, dst, stepDst);
+ __ BIND(FailureAtIdx0);
+ }
+
+ /**
+ * int j.u.Base64.Decoder.decodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL, boolean isMIME)
+ *
+ * Input arguments:
+ * c_rarg0 - src, source array
+ * c_rarg1 - sp, src start offset
+ * c_rarg2 - sl, src end offset
+ * c_rarg3 - dst, dest array
+ * c_rarg4 - dp, dst start offset
+ * c_rarg5 - isURL, Base64 or URL character set
+ * c_rarg6 - isMIME, Decoding MIME block
+ */
+ address generate_base64_decodeBlock() {
+
+ static const uint8_t fromBase64[256] = {
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u,
+ 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u,
+ 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u,
+ 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ };
+
+ static const uint8_t fromBase64URL[256] = {
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u,
+ 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u,
+ 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 63u,
+ 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u,
+ 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+ };
+
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "decodeBlock");
+ address start = __ pc();
+ __ enter();
+
+ Register src = c_rarg0;
+ Register soff = c_rarg1;
+ Register send = c_rarg2;
+ Register dst = c_rarg3;
+ Register doff = c_rarg4;
+ Register isURL = c_rarg5;
+ Register isMIME = c_rarg6;
+
+ Register codec = c_rarg7;
+ Register dstBackup = x31;
+ Register length = x28; // t3, total length of src data in bytes
+
+ Label ProcessData, Exit;
+ Label ProcessScalar, ScalarLoop;
+
+ // passed in length (send - soff) is guaranteed to be > 4,
+ // and in this intrinsic we only process data of length in multiple of 4,
+ // it's not guaranteed to be multiple of 4 by java level, so do it explicitly
+ __ sub(length, send, soff);
+ __ andi(length, length, -4);
+ // real src/dst to process data
+ __ add(src, src, soff);
+ __ add(dst, dst, doff);
+ // backup of dst, used to calculate the return value at exit
+ __ mv(dstBackup, dst);
+
+ // load the codec base address
+ __ la(codec, ExternalAddress((address) fromBase64));
+ __ beqz(isURL, ProcessData);
+ __ la(codec, ExternalAddress((address) fromBase64URL));
+ __ BIND(ProcessData);
+
+ // vector version
+ if (UseRVV) {
+ // for MIME case, it has a default length limit of 76 which could be
+ // different(smaller) from (send - soff), so in MIME case, we go through
+ // the scalar code path directly.
+ __ bnez(isMIME, ScalarLoop);
+
+ Label ProcessM1, ProcessM2;
+
+ Register failedIdx = soff;
+ Register stepSrcM1 = send;
+ Register stepSrcM2 = doff;
+ Register stepDst = isURL;
+ Register size = x29; // t4
+
+ __ mv(size, MaxVectorSize * 2);
+ __ mv(stepSrcM1, MaxVectorSize * 4);
+ __ slli(stepSrcM2, stepSrcM1, 1);
+ __ mv(stepDst, MaxVectorSize * 2 * 3);
+
+ __ blt(length, stepSrcM2, ProcessM1);
+
+
+ // Assembler::m2
+ __ BIND(ProcessM2);
+ base64_vector_decode_round(src, dst, codec,
+ size, stepSrcM2, stepDst, failedIdx,
+ v2, v4, v6, v8, // inputs
+ v10, v12, v14, v16, // indexes
+ v18, v20, v22, // outputs
+ Assembler::m2);
+ __ sub(length, length, stepSrcM2);
+
+ // error check
+ // valid value of failedIdx can only be -1 when < 0
+ __ bgez(failedIdx, Exit);
+
+ __ bge(length, stepSrcM2, ProcessM2);
+
+
+ // Assembler::m1
+ __ BIND(ProcessM1);
+ __ blt(length, stepSrcM1, ProcessScalar);
+
+ __ srli(size, size, 1);
+ __ srli(stepDst, stepDst, 1);
+ base64_vector_decode_round(src, dst, codec,
+ size, stepSrcM1, stepDst, failedIdx,
+ v1, v2, v3, v4, // inputs
+ v5, v6, v7, v8, // indexes
+ v9, v10, v11, // outputs
+ Assembler::m1);
+ __ sub(length, length, stepSrcM1);
+
+ // error check
+ // valid value of failedIdx can only be -1 when < 0
+ __ bgez(failedIdx, Exit);
+
+ __ BIND(ProcessScalar);
+ __ beqz(length, Exit);
+ }
+
+ // scalar version
+ {
+ Register byte0 = soff, byte1 = send, byte2 = doff, byte3 = isURL;
+ Register combined32Bits = x29; // t5
+
+ // encoded: [byte0[5:0] : byte1[5:0] : byte2[5:0]] : byte3[5:0]] =>
+ // plain: [byte0[5:0]+byte1[5:4] : byte1[3:0]+byte2[5:2] : byte2[1:0]+byte3[5:0]]
+ __ BIND(ScalarLoop);
+
+ // load 4 bytes encoded src data
+ __ lbu(byte0, Address(src, 0));
+ __ lbu(byte1, Address(src, 1));
+ __ lbu(byte2, Address(src, 2));
+ __ lbu(byte3, Address(src, 3));
+ __ addi(src, src, 4);
+
+ // get codec index and decode (ie. load from codec by index)
+ __ add(byte0, codec, byte0);
+ __ add(byte1, codec, byte1);
+ __ lb(byte0, Address(byte0, 0));
+ __ lb(byte1, Address(byte1, 0));
+ __ add(byte2, codec, byte2);
+ __ add(byte3, codec, byte3);
+ __ lb(byte2, Address(byte2, 0));
+ __ lb(byte3, Address(byte3, 0));
+ __ slliw(byte0, byte0, 18);
+ __ slliw(byte1, byte1, 12);
+ __ orr(byte0, byte0, byte1);
+ __ orr(byte0, byte0, byte3);
+ __ slliw(byte2, byte2, 6);
+ // For performance consideration, `combined32Bits` is constructed for 2 purposes at the same time,
+ // 1. error check below
+ // 2. decode below
+ __ orr(combined32Bits, byte0, byte2);
+
+ // error check
+ __ bltz(combined32Bits, Exit);
+
+ // store 3 bytes decoded data
+ __ sraiw(byte0, combined32Bits, 16);
+ __ sraiw(byte1, combined32Bits, 8);
+ __ sb(byte0, Address(dst, 0));
+ __ sb(byte1, Address(dst, 1));
+ __ sb(combined32Bits, Address(dst, 2));
+
+ __ sub(length, length, 4);
+ __ addi(dst, dst, 3);
+ // loop back
+ __ bnez(length, ScalarLoop);
+ }
+
+ __ BIND(Exit);
+ __ sub(c_rarg0, dst, dstBackup);
+
+ __ leave();
+ __ ret();
+
+ return (address) start;
+ }
+
void adler32_process_bytes(Register buff, Register s1, Register s2, VectorRegister vtable,
VectorRegister vzero, VectorRegister vbytes, VectorRegister vs1acc, VectorRegister vs2acc,
Register temp0, Register temp1, Register temp2, Register temp3,
@@ -6128,6 +6624,11 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB");
}
+ if (UseBASE64Intrinsics) {
+ StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock();
+ StubRoutines::_base64_decodeBlock = generate_base64_decodeBlock();
+ }
+
if (UseAdler32Intrinsics) {
StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32();
}
@@ -311,6 +311,11 @@ void VM_Version::c2_initialize() {
FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false);
}
+ // Base64
+ if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) {
+ FLAG_SET_DEFAULT(UseBASE64Intrinsics, true);
+ }
+
if (UseRVV) {
if (FLAG_IS_DEFAULT(MaxVectorSize)) {
MaxVectorSize = _initial_vector_length;