-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[Wasm RyuJIT] Add Instruction Encoding for Local Var Declarations and Emit Local Declarations #122425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[Wasm RyuJIT] Add Instruction Encoding for Local Var Declarations and Emit Local Declarations #122425
Changes from 24 commits
e93e57d
4b991da
5933e67
7b8e339
78b7c70
9fbfb86
7d12af0
4b91b3a
183851f
c9d3046
0482ee3
dfb0627
b237c17
19c9eaf
76a15f2
d32f695
f3e2f82
0820a24
78945a3
9a3c21a
ddb4801
704a4a7
7bb7cfc
06207d5
c52da98
9373181
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -638,6 +638,9 @@ class emitter | |||||
| bool idCatchRet; // Instruction is for a catch 'return' | ||||||
| CORINFO_SIG_INFO* idCallSig; // Used to report native call site signatures to the EE | ||||||
| BasicBlock* idTargetBlock; // Target block for branches | ||||||
| #ifdef TARGET_WASM | ||||||
| int lclOffset; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| #endif | ||||||
| }; | ||||||
|
|
||||||
| #ifdef TARGET_ARM | ||||||
|
|
@@ -1296,6 +1299,13 @@ class emitter | |||||
| assert(reg == _idReg1); | ||||||
| } | ||||||
|
|
||||||
| #ifdef TARGET_WASM | ||||||
| bool idIsLclVarDecl() const | ||||||
| { | ||||||
| return _idInsFmt == IF_LOCAL_DECL; | ||||||
| } | ||||||
| #endif | ||||||
|
|
||||||
| #ifdef TARGET_ARM64 | ||||||
| GCtype idGCrefReg2() const | ||||||
| { | ||||||
|
|
@@ -2335,6 +2345,25 @@ class emitter | |||||
| }; | ||||||
| #endif | ||||||
|
|
||||||
| #if defined(TARGET_WASM) | ||||||
| struct instrDescLclVarDecl : instrDesc | ||||||
| { | ||||||
| instrDescLclVarDecl() = delete; | ||||||
| cnsval_ssize_t lclCnt; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is technically larger than necessary since the local count can't really exceed 32 bits (and (Using an unsigned integer might also get rid of some casts) |
||||||
| WasmValueType lclType; | ||||||
|
|
||||||
| void idLclType(WasmValueType type) | ||||||
| { | ||||||
| lclType = type; | ||||||
| } | ||||||
|
|
||||||
| void idLclCnt(cnsval_ssize_t cnt) | ||||||
| { | ||||||
| lclCnt = cnt; | ||||||
| } | ||||||
| }; | ||||||
| #endif // TARGET_WASM | ||||||
|
|
||||||
| #ifdef TARGET_RISCV64 | ||||||
| struct instrDescLoadImm : instrDescCns | ||||||
| { | ||||||
|
|
@@ -3293,6 +3322,7 @@ class emitter | |||||
| instrDesc* emitNewInstrCns(emitAttr attr, cnsval_ssize_t cns); | ||||||
| instrDesc* emitNewInstrDsp(emitAttr attr, target_ssize_t dsp); | ||||||
| instrDesc* emitNewInstrCnsDsp(emitAttr attr, target_ssize_t cns, int dsp); | ||||||
|
|
||||||
| #ifdef TARGET_ARM | ||||||
| instrDesc* emitNewInstrReloc(emitAttr attr, BYTE* addr); | ||||||
| #endif // TARGET_ARM | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -116,6 +116,62 @@ bool emitter::emitInsIsStore(instruction ins) | |||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| emitter::instrDesc* emitter::emitNewInstrLclVarDecl(emitAttr attr, | ||||||
| cnsval_ssize_t localCount, | ||||||
| WasmValueType type, | ||||||
| int lclOffset) | ||||||
| { | ||||||
| instrDescLclVarDecl* id = static_cast<instrDescLclVarDecl*>(emitAllocAnyInstr(sizeof(instrDescLclVarDecl), attr)); | ||||||
| id->idLclCnt(localCount); | ||||||
| id->idLclType(type); | ||||||
|
|
||||||
| if (m_debugInfoSize > 0) | ||||||
| { | ||||||
| id->idDebugOnlyInfo()->lclOffset = lclOffset; | ||||||
| } | ||||||
|
|
||||||
| return id; | ||||||
| } | ||||||
|
|
||||||
| //----------------------------------------------------------------------------------- | ||||||
| // emitIns_I_Ty: Emit an instruction for a local variable declaration, encoding both | ||||||
| // a count (immediate) and a value type. This is specifically used for local variable | ||||||
| // declarations that require both the number of locals and their type to be encoded. | ||||||
| // | ||||||
| // Arguments: | ||||||
| // ins - instruction to emit | ||||||
| // imm - immediate value (local count) | ||||||
| // valType - value type of the local variable | ||||||
| // offs - local variable offset (= count of preceding locals) for debug info | ||||||
| void emitter::emitIns_I_Ty(instruction ins, cnsval_ssize_t imm, WasmValueType valType, int offs) | ||||||
| { | ||||||
| instrDesc* id = emitNewInstrLclVarDecl(EA_8BYTE, imm, valType, offs); | ||||||
| insFormat fmt = emitInsFormat(ins); | ||||||
|
|
||||||
| id->idIns(ins); | ||||||
| id->idInsFmt(fmt); | ||||||
|
|
||||||
| if (m_debugInfoSize > 0) | ||||||
| { | ||||||
| id->idDebugOnlyInfo()->lclOffset = offs; | ||||||
| } | ||||||
|
|
||||||
| dispIns(id); | ||||||
| appendToCurIG(id); | ||||||
| } | ||||||
|
|
||||||
| WasmValueType emitter::emitGetLclVarDeclType(instrDesc* id) | ||||||
| { | ||||||
| assert(id->idIsLclVarDecl()); | ||||||
| return static_cast<instrDescLclVarDecl*>(id)->lclType; | ||||||
| } | ||||||
|
|
||||||
| cnsval_ssize_t emitter::emitGetLclVarDeclCount(instrDesc* id) | ||||||
| { | ||||||
| assert(id->idIsLclVarDecl()); | ||||||
| return static_cast<instrDescLclVarDecl*>(id)->lclCnt; | ||||||
| } | ||||||
|
|
||||||
| emitter::insFormat emitter::emitInsFormat(instruction ins) | ||||||
| { | ||||||
| static_assert(IF_COUNT < 255); | ||||||
|
|
@@ -155,6 +211,11 @@ size_t emitter::emitSizeOfInsDsc(instrDesc* id) const | |||||
| return sizeof(instrDescCns); | ||||||
| } | ||||||
|
|
||||||
| if (id->idIsLclVarDecl()) | ||||||
| { | ||||||
| return sizeof(instrDescLclVarDecl); | ||||||
| } | ||||||
|
|
||||||
| return sizeof(instrDesc); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -181,6 +242,23 @@ unsigned emitter::SizeOfSLEB128(int64_t value) | |||||
| return (x * 37) >> 8; | ||||||
| } | ||||||
|
|
||||||
| static uint8_t GetWasmValueTypeCode(WasmValueType type) | ||||||
| { | ||||||
| // clang-format off | ||||||
| static const uint8_t typecode_mapping[] = { | ||||||
| 0x00, // WasmValueType::Invalid = 0, | ||||||
| 0x7C, // WasmValueType::F64 = 1, | ||||||
| 0x7D, // WasmValueType::F32 = 2, | ||||||
| 0x7E, // WasmValueType::I64 = 3, | ||||||
| 0x7F, // WasmValueType::I32 = 4, | ||||||
| }; | ||||||
| static const int WASM_TYP_COUNT = ArrLen(typecode_mapping); | ||||||
| static_assert(ArrLen(typecode_mapping) == (int)WasmValueType::Count); | ||||||
| // clang-format on | ||||||
|
|
||||||
| return typecode_mapping[static_cast<unsigned>(type)]; | ||||||
| } | ||||||
|
|
||||||
| unsigned emitter::instrDesc::idCodeSize() const | ||||||
| { | ||||||
| #ifdef TARGET_WASM32 | ||||||
|
|
@@ -199,10 +277,18 @@ unsigned emitter::instrDesc::idCodeSize() const | |||||
| case IF_BLOCK: | ||||||
| size += 1; | ||||||
| break; | ||||||
| case IF_LABEL: | ||||||
| case IF_RAW_ULEB128: | ||||||
| assert(!idIsCnsReloc()); | ||||||
| size = SizeOfULEB128(emitGetInsSC(this)); | ||||||
| break; | ||||||
| case IF_LOCAL_DECL: | ||||||
| { | ||||||
| assert(idIsLclVarDecl()); | ||||||
| instrDescLclVarDecl* idl = static_cast<instrDescLclVarDecl*>(const_cast<instrDesc*>(this)); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Avoid the Or you could use the |
||||||
| uint8_t typeCode = GetWasmValueTypeCode(idl->lclType); | ||||||
| size = SizeOfULEB128(idl->lclCnt) + sizeof(typeCode); | ||||||
| break; | ||||||
| } | ||||||
| case IF_ULEB128: | ||||||
| size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this)); | ||||||
| break; | ||||||
|
|
@@ -337,7 +423,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) | |||||
| dst += emitRawBytes(dst, &bits, sizeof(cnsval_ssize_t)); | ||||||
| break; | ||||||
| } | ||||||
| case IF_LABEL: | ||||||
| case IF_RAW_ULEB128: | ||||||
| { | ||||||
| cnsval_ssize_t constant = emitGetInsSC(id); | ||||||
| dst += emitOutputULEB128(dst, (uint64_t)constant); | ||||||
|
|
@@ -354,6 +440,15 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) | |||||
| dst += emitOutputULEB128(dst, offset); | ||||||
| break; | ||||||
| } | ||||||
| case IF_LOCAL_DECL: | ||||||
| { | ||||||
| assert(id->idIsLclVarDecl()); | ||||||
| cnsval_ssize_t count = emitGetLclVarDeclCount(id); | ||||||
| uint8_t valType = GetWasmValueTypeCode(emitGetLclVarDeclType(id)); | ||||||
| dst += emitOutputULEB128(dst, (uint64_t)count); | ||||||
| dst += emitOutputByte(dst, valType); | ||||||
| break; | ||||||
| } | ||||||
| default: | ||||||
| NYI_WASM("emitOutputInstr"); | ||||||
| break; | ||||||
|
|
@@ -470,7 +565,7 @@ void emitter::emitDispIns( | |||||
| case IF_BLOCK: | ||||||
| break; | ||||||
|
|
||||||
| case IF_LABEL: | ||||||
| case IF_RAW_ULEB128: | ||||||
| case IF_ULEB128: | ||||||
| { | ||||||
| cnsval_ssize_t imm = emitGetInsSC(id); | ||||||
|
|
@@ -479,6 +574,34 @@ void emitter::emitDispIns( | |||||
| } | ||||||
| break; | ||||||
|
|
||||||
| case IF_LOCAL_DECL: | ||||||
| { | ||||||
| cnsval_ssize_t count = emitGetLclVarDeclCount(id); | ||||||
| WasmValueType valType = emitGetLclVarDeclType(id); | ||||||
| int offs = id->idDebugOnlyInfo()->lclOffset; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would move this down to the |
||||||
| assert(count > 0); // we should not be declaring a local entry with zero count | ||||||
|
|
||||||
| if (m_debugInfoSize > 0) | ||||||
| { | ||||||
| // With debug info: print the local offsets being declared | ||||||
| if (count > 1) | ||||||
| { | ||||||
| printf("[%llu..%llu] type=%s", offs, offs + (uint64_t)count - 1, WasmValueTypeName(valType)); | ||||||
| } | ||||||
| else // single local case | ||||||
| { | ||||||
| printf("[%llu] type=%s", offs, WasmValueTypeName(valType)); | ||||||
| } | ||||||
| } | ||||||
| else | ||||||
| { | ||||||
| // No debug info case: just print the count and type of the locals | ||||||
| printf(" count=%llu type=%s", (uint64_t)count, WasmValueTypeName(valType)); | ||||||
| break; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
| } | ||||||
| break; | ||||||
|
|
||||||
| case IF_SLEB128: | ||||||
| { | ||||||
| cnsval_ssize_t imm = emitGetInsSC(id); | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,7 +26,9 @@ | |||||||||||||
| // | ||||||||||||||
| INST(invalid, "INVALID", 0, IF_NONE, BAD_CODE) | ||||||||||||||
| INST(unreachable, "unreachable", 0, IF_OPCODE, 0x00) | ||||||||||||||
| INST(label, "label", 0, IF_LABEL, 0x00) | ||||||||||||||
| INST(label, "label", 0, IF_RAW_ULEB128, 0x00) | ||||||||||||||
| INST(local_cnt, "local.cnt", 0, IF_RAW_ULEB128, 0x00) | ||||||||||||||
| INST(local_decl, "local", 0, IF_LOCAL_DECL, 0x00) | ||||||||||||||
|
Comment on lines
+29
to
+31
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Technically the ambition is to have all these aligned across all the instructions but we can make that happen after the list settles down a bit. |
||||||||||||||
| INST(nop, "nop", 0, IF_OPCODE, 0x01) | ||||||||||||||
| INST(block, "block", 0, IF_BLOCK, 0x02) | ||||||||||||||
| INST(loop, "loop", 0, IF_BLOCK, 0x03) | ||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.