return opcode | (rd << 7) | (funct3 << 12) | (rs1 << 15) | (rs2 << 20) | (funct7 << 25);
}
+static unsigned UTypeInstr(unsigned opcode, unsigned rd, int imm20)
+{
+ _ASSERTE(!(opcode >> 7));
+ _ASSERTE(!(rd >> 5));
+ _ASSERTE(StubLinkerCPU::isValidUimm20(imm20));
+ return opcode | (rd << 7) | (imm20 << 12);
+}
+
+static unsigned BTypeInstr(unsigned opcode, unsigned funct3, unsigned rs1, unsigned rs2, int imm13)
+{
+ _ASSERTE(!(opcode >> 7));
+ _ASSERTE(!(funct3 >> 3));
+ _ASSERTE(!(rs1 >> 5));
+ _ASSERTE(!(rs2 >> 5));
+ _ASSERTE(StubLinkerCPU::isValidSimm13(imm13));
+ _ASSERTE(IS_ALIGNED(imm13, 2));
+ int immLo1 = (imm13 >> 11) & 0x1;
+ int immLo4 = (imm13 >> 1) & 0xf;
+ int immHi6 = (imm13 >> 5) & 0x3f;
+ int immHi1 = (imm13 >> 12) & 0x1;
+ return opcode | (immLo4 << 8) | (funct3 << 12) | (rs1 << 15) | (rs2 << 20) | (immHi6 << 25) | (immLo1 << 7) | (immHi1 << 31);
+}
+
void StubLinkerCPU::EmitLoad(IntReg dest, IntReg srcAddr, int offset)
{
Emit32(ITypeInstr(0x3, 0x3, dest, srcAddr, offset)); // ld
//
// Allocation of dynamic helpers
//
-
#define DYNAMIC_HELPER_ALIGNMENT sizeof(TADDR)
#define BEGIN_DYNAMIC_HELPER_EMIT(size) \
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
-#define END_DYNAMIC_HELPER_EMIT() \
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
+ SIZE_T cb = size; \
+ SIZE_T cbAligned = ALIGN_UP(cb, DYNAMIC_HELPER_ALIGNMENT); \
+ BYTE * pStartRX = (BYTE *)(void*)pAllocator->GetDynamicHelpersHeap()->AllocAlignedMem(cbAligned, DYNAMIC_HELPER_ALIGNMENT); \
+ ExecutableWriterHolder<BYTE> startWriterHolder(pStartRX, cbAligned); \
+ BYTE * pStart = startWriterHolder.GetRW(); \
+ size_t rxOffset = pStartRX - pStart; \
+ BYTE * p = pStart;
+#define END_DYNAMIC_HELPER_EMIT() \
+ _ASSERTE(pStart + cb == p); \
+ while (p < pStart + cbAligned) { *(DWORD*)p = 0xffffff0f/*badcode*/; p += 4; }\
+ ClrFlushInstructionCache(pStart, cbAligned); \
+ return (PCODE)pStart
// Uses x8 as scratch register to store address of data label
// After load x8 is increment to point to next data
// only accepts positive offsets
PCODE DynamicHelpers::CreateHelper(LoaderAllocator * pAllocator, TADDR arg, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(32);
+
+ EmitHelperWithArg(p, rxOffset, pAllocator, arg, target);
+
+ END_DYNAMIC_HELPER_EMIT();
}
// Caller must ensure sufficient byte are allocated including padding (if applicable)
void DynamicHelpers::EmitHelperWithArg(BYTE*& p, size_t rxOffset, LoaderAllocator * pAllocator, TADDR arg, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
+ STANDARD_VM_CONTRACT;
+
+ const IntReg RegR0 = 0, RegT0 = 5, RegA0 = 10;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegT0, 16);// ld a0, 16(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT0, RegT0, 24);;// ld t0, 24(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegT0, 0);// jalr zero, 0(t0)
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+ // target
+ *(PCODE*)p = target;
+ p += 8;
}
PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(32);
+
+ EmitHelperWithArg(p, rxOffset, pAllocator, arg, target);
+
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateHelper(LoaderAllocator * pAllocator, TADDR arg, TADDR arg2, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(48);
+
+ const IntReg RegR0 = 0, RegT0 = 5, RegA0 = 10, RegA1 = 11;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegT0, 24);// ld a0, 24(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA1, RegT0, 32);// ld a1, 32(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT0, RegT0, 40);// ld t0, 40(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegT0, 0);// jalr x0, 0(t0)
+ p += 4;
+
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegR0, RegR0, 0);// nop, padding to make 8 byte aligned
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+ // arg2
+ *(TADDR*)p = arg2;
+ p += 8;
+ // target
+ *(TADDR*)p = target;
+ p += 8;
+
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateHelperArgMove(LoaderAllocator * pAllocator, TADDR arg, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(40);
+
+ const IntReg RegR0 = 0, RegT0 = 5, RegA0 = 10, RegA1 = 11;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegA1, RegA0, 0);// addi a1, a0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegT0, 24);// ld a0, 24(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT0, RegT0, 32);// ld t0, 32(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegT0, 0);// jalr x0, 0(t0)
+ p += 4;
+
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegR0, RegR0, 0);// nop, padding to make 8 byte aligned
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+ // target
+ *(TADDR*)p = target;
+ p += 8;
+
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateReturn(LoaderAllocator * pAllocator)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(4);
+
+ const IntReg RegR0 = 0, RegRa = 1;
+
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegRa, 0);// ret
+ p += 4;
+
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateReturnConst(LoaderAllocator * pAllocator, TADDR arg)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(24);
+
+ const IntReg RegR0 = 0, RegRa = 1, RegT0 = 5, RegA0 = 10;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegT0, 16);// ld a0, 16(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegRa, 0);// ret
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegR0, RegR0, 0);// nop, padding to make 8 byte aligned
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateReturnIndirConst(LoaderAllocator * pAllocator, TADDR arg, INT8 offset)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(32);
+
+ const IntReg RegR0 = 0, RegRa = 1, RegT0 = 5, RegA0 = 10;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegT0, 24);// ld a0, 24(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegA0, 0);// ld a0,0(a0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegA0, RegA0, offset & 0xfff);// addi a0, a0, offset
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegRa, 0);// ret
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegR0, RegR0, 0);// nop, padding to make 8 byte aligned
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(32);
+
+ const IntReg RegR0 = 0, RegT0 = 5, RegA2 = 12;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA2, RegT0, 16);// ld a2,16(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT0, RegT0, 24);// ld t0,24(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegT0, 0);// jalr x0, 0(t0)
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+
+ // target
+ *(TADDR*)p = target;
+ p += 8;
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, TADDR arg2, PCODE target)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(48);
+
+ const IntReg RegR0 = 0, RegT0 = 5, RegA2 = 12, RegA3 = 1;
+
+ *(DWORD*)p = UTypeInstr(0x17, RegT0, 0);// auipc t0, 0
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA2, RegT0, 24);// ld a2,24(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA3, RegT0, 32);// ld a3,32(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT0, RegT0, 40);;// ld t0,40(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegT0, 0);// jalr x0, 0(t0)
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegR0, RegR0, 0);// nop, padding to make 8 byte aligned
+ p += 4;
+
+ // label:
+ // arg
+ *(TADDR*)p = arg;
+ p += 8;
+ // arg2
+ *(TADDR*)p = arg2;
+ p += 8;
+ // target
+ *(TADDR*)p = target;
+ p += 8;
+ END_DYNAMIC_HELPER_EMIT();
}
PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup, DWORD dictionaryIndexAndSlot, Module * pModule)
{
- _ASSERTE(!"RISCV64: not implementation on riscv64!!!");
- return NULL;
+ STANDARD_VM_CONTRACT;
+ const IntReg RegR0 = 0, RegA0 = 10, RegT2 = 7, RegT4 = 29, RegT5 = 30;
+
+ PCODE helperAddress = (pLookup->helper == CORINFO_HELP_RUNTIMEHANDLE_METHOD ?
+ GetEEFuncEntryPoint(JIT_GenericHandleMethodWithSlotAndModule) :
+ GetEEFuncEntryPoint(JIT_GenericHandleClassWithSlotAndModule));
+
+ GenericHandleArgs * pArgs = (GenericHandleArgs *)(void *)pAllocator->GetDynamicHelpersHeap()->AllocAlignedMem(sizeof(GenericHandleArgs), DYNAMIC_HELPER_ALIGNMENT);
+ ExecutableWriterHolder<GenericHandleArgs> argsWriterHolder(pArgs, sizeof(GenericHandleArgs));
+ argsWriterHolder.GetRW()->dictionaryIndexAndSlot = dictionaryIndexAndSlot;
+ argsWriterHolder.GetRW()->signature = pLookup->signature;
+ argsWriterHolder.GetRW()->module = (CORINFO_MODULE_HANDLE)pModule;
+
+ WORD slotOffset = (WORD)(dictionaryIndexAndSlot & 0xFFFF) * sizeof(Dictionary*);
+
+ // It's available only via the run-time helper function
+ if (pLookup->indirections == CORINFO_USEHELPER)
+ {
+ BEGIN_DYNAMIC_HELPER_EMIT(32);
+
+ // a0 already contains generic context parameter
+ // reuse EmitHelperWithArg for below two operations
+ // a1 <- pArgs
+ // branch to helperAddress
+ EmitHelperWithArg(p, rxOffset, pAllocator, (TADDR)pArgs, helperAddress);
+
+ END_DYNAMIC_HELPER_EMIT();
+ }
+ else
+ {
+ int codeSize = 0;
+ int indirectionsDataSize = 0;
+ if (pLookup->testForNull || pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK)
+ {
+ //mv t2, a0
+ codeSize += 4;
+ }
+
+ for (WORD i = 0; i < pLookup->indirections; i++) {
+ _ASSERTE(pLookup->offsets[i] >= 0);
+ if (i == pLookup->indirections - 1 && pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK)
+ {
+ codeSize += (pLookup->sizeOffset > 2047 ? 24 : 16);
+ indirectionsDataSize += (pLookup->sizeOffset > 2047 ? 4 : 0);
+ }
+
+ codeSize += (pLookup->offsets[i] > 2047 ? 12 : 4); // if( > 2047) (12 bytes) else 4 bytes for instructions.
+ indirectionsDataSize += (pLookup->offsets[i] > 2047 ? 4 : 0); // 4 bytes for storing indirection offset values
+ }
+
+ codeSize += indirectionsDataSize ? 4 : 0; // auipc
+
+ if (pLookup->testForNull)
+ {
+ codeSize += 12; // beq-ret-addi
+
+ //padding for 8-byte align (required by EmitHelperWithArg)
+ codeSize = ALIGN_UP(codeSize, 8);
+
+ codeSize += 32; // size of EmitHelperWithArg
+ }
+ else
+ {
+ codeSize += 4; /* jalr */
+ }
+
+ // the offset value of data_label.
+ uint dataOffset = codeSize;
+
+ codeSize += indirectionsDataSize;
+
+ BEGIN_DYNAMIC_HELPER_EMIT(codeSize);
+
+ BYTE * old_p = p;
+
+ if (indirectionsDataSize)
+ {
+ _ASSERTE(codeSize < 2047);
+
+ //auipc t4, 0
+ *(DWORD*)p = UTypeInstr(0x17, RegT4, 0);
+ p += 4;
+ }
+
+ if (pLookup->testForNull || pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK)
+ {
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegT2, RegA0, 0);// addi t2, a0, 0
+ p += 4;
+ }
+
+ BYTE* pBLTCall = NULL;
+
+ for (WORD i = 0; i < pLookup->indirections; i++)
+ {
+ if (i == pLookup->indirections - 1 && pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK)
+ {
+ _ASSERTE(pLookup->testForNull && i > 0);
+
+ if (pLookup->sizeOffset > 2047)
+ {
+ *(DWORD*)p = ITypeInstr(0x3, 0x2, RegT4, RegT4, dataOffset);// lw t4, dataOffset(t4)
+ p += 4;
+ *(DWORD*)p = RTypeInstr(0x33, 0, 0, RegT5, RegA0, RegT4);// add t5, a0, t4
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT5, RegT5, 0);// ld t5, 0(t5)
+ p += 4;
+
+ // move to next indirection offset data
+ dataOffset += 4;
+ }
+ else
+ {
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegT5, RegA0, (UINT32)pLookup->sizeOffset);// ld t5, #(pLookup->sizeOffset)(a0)
+ p += 4;
+ }
+ // lui t4, (slotOffset&0xfffff000)>>12
+ *(DWORD*)p = UTypeInstr(0x37, RegT4, (((UINT32)slotOffset & 0xfffff000) >> 12));
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegT4, RegT4, slotOffset & 0xfff);// addi t4, t4, (slotOffset&0xfff)
+ p += 4;
+ // blt t4, t5, CALL HELPER
+ pBLTCall = p; // Offset filled later
+ p += 4;
+ }
+
+ if (pLookup->offsets[i] > 2047)
+ {
+ _ASSERTE(dataOffset < 2047);
+ *(DWORD*)p = ITypeInstr(0x3, 0x2, RegT4, RegT4, dataOffset & 0xfff);// lw t4, dataOffset(t4)
+ p += 4;
+ *(DWORD*)p = RTypeInstr(0x33, 0, 0, RegA0, RegA0, RegT4);// add a0, a0, t4
+ p += 4;
+ *(DWORD*)p = ITypeInstr(0x3, 0x2, RegA0, RegA0, 0);// lw a0, 0(a0)
+ p += 4;
+ // move to next indirection offset data
+ dataOffset += 4; // add 4 as next data is at 4 bytes from previous data
+ }
+ else
+ {
+ // offset must be 8 byte aligned
+ _ASSERTE((pLookup->offsets[i] & 0x7) == 0);
+ *(DWORD*)p = ITypeInstr(0x3, 0x3, RegA0, RegA0, (UINT32)pLookup->offsets[i]);// ld a0, #(pLookup->offsets[i])(a0)
+ p += 4;
+ }
+ }
+
+ // No null test required
+ if (!pLookup->testForNull)
+ {
+ _ASSERTE(pLookup->sizeOffset == CORINFO_NO_SIZE_CHECK);
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegRa, 0);// ret
+ p += 4;
+ }
+ else
+ {
+ // beq a0, x0, CALL HELPER:
+ *(DWORD*)p = BTypeInstr(0x63, 0, RegA0, RegR0, 8);
+ p += 4;
+
+ *(DWORD*)p = ITypeInstr(0x67, 0, RegR0, RegRa, 0);// ret
+ p += 4;
+
+ // CALL HELPER:
+ if (pBLTCall != NULL)
+ *(DWORD*)pBLTCall = BTypeInstr(0x63, 0x4, RegT4, RegT5, (UINT32)(p - pBLTCall));
+
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegA0, RegT2, 0);// addi a0, t2, 0
+ p += 4;
+ if ((uintptr_t)(p - old_p) & 0x7)
+ {
+ // nop, padding for 8-byte align (required by EmitHelperWithArg)
+ *(DWORD*)p = ITypeInstr(0x13, 0, RegR0, RegR0, 0);
+ p += 4;
+ }
+
+ // reuse EmitHelperWithArg for below two operations
+ // a1 <- pArgs
+ // branch to helperAddress
+ EmitHelperWithArg(p, rxOffset, pAllocator, (TADDR)pArgs, helperAddress);
+ }
+
+ // data_label:
+ for (WORD i = 0; i < pLookup->indirections; i++)
+ {
+ if (i == pLookup->indirections - 1 && pLookup->sizeOffset != CORINFO_NO_SIZE_CHECK && pLookup->sizeOffset > 2047)
+ {
+ *(UINT32*)p = (UINT32)pLookup->sizeOffset;
+ p += 4;
+ }
+ if (pLookup->offsets[i] > 2047)
+ {
+ *(UINT32*)p = (UINT32)pLookup->offsets[i];
+ p += 4;
+ }
+ }
+
+ END_DYNAMIC_HELPER_EMIT();
+ }
}
#endif // FEATURE_READYTORUN