-
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 all 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
29a82df
afc4638
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -116,6 +116,70 @@ bool emitter::emitInsIsStore(instruction ins) | |||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| //----------------------------------------------------------------------------- | ||||||
| // emitNewInstrLclVarDecl: Construct an instrDesc corresponding to a wasm local | ||||||
| // declaration. | ||||||
| // | ||||||
| // Arguments: | ||||||
| // attr - emit attributes | ||||||
| // localCount - the count of locals in this declaration | ||||||
| // type - the type of local in the declaration | ||||||
| // lclOffset - used to provide the starting index of this local | ||||||
| // | ||||||
| // Notes: | ||||||
| // `lclOffset` is stored as debug info attached to the instruction, | ||||||
| // so the offset will only be used if m_debugInfoSize > 0 | ||||||
| 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); | ||||||
|
|
||||||
| 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 +219,11 @@ size_t emitter::emitSizeOfInsDsc(instrDesc* id) const | |||||
| return sizeof(instrDescCns); | ||||||
| } | ||||||
|
|
||||||
| if (id->idIsLclVarDecl()) | ||||||
| { | ||||||
| return sizeof(instrDescLclVarDecl); | ||||||
| } | ||||||
|
|
||||||
| return sizeof(instrDesc); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -181,6 +250,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 +285,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 +431,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 +448,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 +573,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 +582,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.
This is technically larger than necessary since the local count can't really exceed 32 bits (and
cnsval_ssize_tis a signed 64 bit number). BaseinstrDescis 16 bytes, this desc is going to be 32 bytes (due to alignment), but if this field is made to be 32 bits, it can fit into 24 bytes.(Using an unsigned integer might also get rid of some casts)