Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e93e57d
Revert wasm method stub method in crossgen to allow invoking the actu…
adamperlin Dec 9, 2025
4b991da
WIP add args as locals to the beginning of method epilog in Wasm codegen
adamperlin Dec 10, 2025
5933e67
Multiple fixes for emitting local declarations for incoming args
adamperlin Dec 11, 2025
7b8e339
jit-format
adamperlin Dec 11, 2025
78b7c70
Merge branch 'main' of github.com:dotnet/runtime into adamperlin/wasm…
adamperlin Dec 11, 2025
9fbfb86
Generate locals only for non-args
adamperlin Dec 11, 2025
7d12af0
Update src/coreclr/jit/emit.h
adamperlin Dec 11, 2025
4b91b3a
Update src/coreclr/jit/emitfmtswasm.h
adamperlin Dec 11, 2025
183851f
Update src/coreclr/jit/codegencommon.cpp
adamperlin Dec 11, 2025
c9d3046
Update src/coreclr/jit/emitwasm.cpp
adamperlin Dec 11, 2025
0482ee3
Remove incorrect noway_asserts
adamperlin Dec 11, 2025
dfb0627
Remove empty ifdef block
adamperlin Dec 11, 2025
b237c17
Apply some copilot review suggestions
adamperlin Dec 11, 2025
19c9eaf
Address some review feedback
adamperlin Dec 12, 2025
76a15f2
Finish addressing review feedback
adamperlin Dec 12, 2025
d32f695
Fix instGen placement
adamperlin Dec 12, 2025
f3e2f82
Add block->IsLast() guard for emitting end instruction in Wasm genFnE…
adamperlin Dec 13, 2025
0820a24
Emit correct local count for current state of Wasm codegen
adamperlin Dec 13, 2025
78945a3
Address some more review feedback
adamperlin Dec 16, 2025
9a3c21a
Merge branch 'main' of github.com:dotnet/runtime into wasm-arg-initia…
adamperlin Dec 16, 2025
ddb4801
Address additional review feedback
adamperlin Dec 17, 2025
704a4a7
Merge branch 'main' of github.com:dotnet/runtime into wasm-arg-initia…
adamperlin Dec 17, 2025
7bb7cfc
Apply suggestion from @SingleAccretion
adamperlin Dec 17, 2025
06207d5
Address additional review feedback; properly guard access to wasm-spe…
adamperlin Dec 17, 2025
c52da98
Address additional review feedback
adamperlin Dec 17, 2025
9373181
Fix condition for `end` generation in src/coreclr/jit/codegenwasm.cpp
adamperlin Dec 17, 2025
29a82df
Update src/coreclr/jit/codegenwasm.cpp
adamperlin Dec 17, 2025
afc4638
Update src/coreclr/jit/emit.h
adamperlin Dec 17, 2025
5a32a13
Address additional review feedback
adamperlin Dec 17, 2025
ef2c690
Fix bug in jitutil.py determine_jit_name logic (cherry-pick from #122…
adamperlin Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Multiple fixes for emitting local declarations for incoming args
  • Loading branch information
adamperlin committed Dec 11, 2025
commit 5933e67ea2812f916456d28e07dc1499c4e09504
5 changes: 1 addition & 4 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
#include "compiler.h" // temporary??
#include "regset.h"
#include "jitgcinfo.h"

#include "wasmtypes.h"
#include "vartype.h"
#include "wasmtypesdef.h"

class CodeGen final : public CodeGenInterface
{
Expand Down Expand Up @@ -594,7 +592,6 @@ class CodeGen final : public CodeGenInterface
void genFnProlog();
#if defined(TARGET_WASM)
void genWasmArgsAsLocals();
instWasmValueType genWasmTypeFromVarType(var_types type);
#endif
void genFnEpilog(BasicBlock* block);

Expand Down
31 changes: 3 additions & 28 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

#include "jitstd/algorithm.h"

#if defined(TARGET_WASM)
#include "vartypedef.h"
#include "wasmtypes.h"
#endif

/*****************************************************************************/

void CodeGenInterface::setFramePointerRequiredEH(bool value)
Expand Down Expand Up @@ -5657,34 +5652,14 @@ void CodeGen::genFnProlog()
#else // defined(TARGET_WASM)
// TODO-WASM: proper local count, local declarations, and shadow stack maintenance
GetEmitter()->emitIns_I(INS_local_cnt, EA_8BYTE, compiler->info.compArgsCount);
genWasmArgsAsLocals();
GetEmitter()->emitMarkPrologEnd();
#endif // !defined(TARGET_WASM)

GetEmitter()->emitEndProlog();
}

#if defined(TARGET_WASM)
//------------------------------------------------------------------------
// genWasmTypeFromVarType: map var_type to wasm type
//
instWasmValueType CodeGen::genWasmTypeFromVarType(var_types type)
{
switch (type)
{
case TYP_INT:
case TYP_REF:
case TYP_BYREF:
return instWasmValueType ;
case TYP_LONG:
return instWasmValueType::I64;
case TYP_FLOAT:
return instWasmValueType::F32;
case TYP_DOUBLE:
return instWasmValueType::F64;
default:
unreached();
}
}

//------------------------------------------------------------------------
// genWasmArgsAsLocals: generate wasm locals for all incoming arguments
Expand All @@ -5695,8 +5670,8 @@ void CodeGen::genWasmArgsAsLocals()
{
LclVarDsc* varDsc = compiler->lvaGetDesc(i);
assert(varDsc->lvIsParam);
instWasmValueType type = genWasmTypeFromVarType(varDsc->TypeGet());
GetEmitter()->emitIns_I_Ty(INS_local_decl, emitTypeSize(varDsc->TypeGet()), type);
emitter::instWasmValueType type = GetEmitter()->genWasmTypeFromVarType(varDsc->TypeGet());
GetEmitter()->emitIns_I_Ty(INS_local_decl, 1, type);
}
}
#endif
Expand Down
37 changes: 24 additions & 13 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ class emitter
CORINFO_SIG_INFO* idCallSig; // Used to report native call site signatures to the EE
};

#if defined(TARGET_WASM)
#include "wasmtypesdef.h"
#endif

#ifdef TARGET_ARM
unsigned insEncodeSetFlags(insFlags sf);

Expand Down Expand Up @@ -892,6 +896,9 @@ class emitter
unsigned _idLclFPBase : 1; // access a local on stack - SP based offset
insOpts _idInsOpt : 3; // options for Load/Store instructions
#endif
#ifdef TARGET_WASM
unsigned _idLclDecl : 1; // is this a local declaration?
#endif

////////////////////////////////////////////////////////////////////////
// Space taken up to here:
Expand Down Expand Up @@ -919,7 +926,7 @@ class emitter
#elif defined(TARGET_AMD64)
#define ID_EXTRA_BITFIELD_BITS (20)
#elif defined(TARGET_WASM)
#define ID_EXTRA_BITFIELD_BITS (-4)
#define ID_EXTRA_BITFIELD_BITS (-3)
#else
#error Unsupported or unset target architecture
#endif
Expand Down Expand Up @@ -1296,6 +1303,18 @@ class emitter
assert(reg == _idReg1);
}

#ifdef TARGET_WASM
bool idIsLclVarDecl() const
{
return (_idLclDecl != 0);
}

void idSetIsLclVarDecl(bool isDecl)
{
_idLclDecl = isDecl ? 1 : 0;
}
#endif

#ifdef TARGET_ARM64
GCtype idGCrefReg2() const
{
Expand Down Expand Up @@ -2335,9 +2354,7 @@ class emitter
};
#endif

#ifdef TARGET_WASM
#include "wasmtypes.h"

#if defined(TARGET_WASM)
struct instrDescLclVarDecl : instrDesc
{
instrDescLclVarDecl() = delete;
Expand Down Expand Up @@ -3316,7 +3333,7 @@ class emitter
instrDesc* emitNewInstrCnsDsp(emitAttr attr, target_ssize_t cns, int dsp);

#ifdef TARGET_WASM
instrDesc* emitNewInstrLclVarDecl(emitAttr attr, cnsval_ssize_t localCount, instWasmValueType type);

#endif

#ifdef TARGET_ARM
Expand Down Expand Up @@ -4135,16 +4152,10 @@ inline emitter::instrDesc* emitter::emitNewInstrSC(emitAttr attr, cnsval_ssize_t
}

#ifdef TARGET_WASM
#include "wasmtypes.h"
#include "wasmtypesdef.h"


inline emitter::instrDesc* emitter::emitNewInstrLclVarDecl(emitAttr attr, cnsval_ssize_t localCount, instWasmValueType type)
{
instrDescLclVarDecl* id = static_cast<instrDescLclVarDecl*>(emitAllocAnyInstr(sizeof(instrDescLclVarDecl), attr));
id->idLclCnt(localCount);
id->idLclType(type);

return id;
}
#endif

#ifdef TARGET_ARM
Expand Down
65 changes: 59 additions & 6 deletions src/coreclr/jit/emitwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,20 @@ bool emitter::emitInsIsStore(instruction ins)
return false;
}

//------------------------------------------------------------------------
// emitIns_I: Emit an instruction with an immediate operand and an encoded valye type
emitter::instrDesc* emitter::emitNewInstrLclVarDecl(emitAttr attr, cnsval_ssize_t localCount, instWasmValueType type)
{
instrDescLclVarDecl* id = static_cast<instrDescLclVarDecl*>(emitAllocAnyInstr(sizeof(instrDescLclVarDecl), attr));
id->idSetIsLclVarDecl(true);
id->idLclCnt(localCount);
id->idLclType(type);

return id;
}

//-----------------------------------------------------------------------------------
// emitIns_I: Emit an instruction with an immediate operand and an encoded value type
//
void emitter::emitIns_I_Ty(instruction ins, cnsval_ssize_t imm, instWasmValueType valType)
void emitter::emitIns_I_Ty(instruction ins, cnsval_ssize_t imm, emitter::instWasmValueType valType)
{
instrDesc* id = this->emitNewInstrLclVarDecl(EA_8BYTE, imm, valType);
insFormat fmt = this->emitInsFormat(ins);
Expand All @@ -100,6 +110,26 @@ void emitter::emitIns_I_Ty(instruction ins, cnsval_ssize_t imm, instWasmValueTyp
this->appendToCurIG(id);
}

emitter::instWasmValueType emitter::emitGetLclVarDeclType(instrDesc* id)
{
if (!id->idIsLclVarDecl())
{
noway_assert("not a LclVarDecl instrDesc");
}

return static_cast<instrDescLclVarDecl*>(id)->lclType;
}

cnsval_ssize_t emitter::emitGetLclVarDeclCount(instrDesc* id)
{
if (!id->idIsLclVarDecl())
{
noway_assert("not a LclVarDecl instrDesc");
}

return static_cast<instrDescLclVarDecl*>(id)->lclCnt;
}

emitter::insFormat emitter::emitInsFormat(instruction ins)
{
static_assert(IF_COUNT < 255);
Expand Down Expand Up @@ -136,6 +166,12 @@ size_t emitter::emitSizeOfInsDsc(instrDesc* id) const
assert(!id->idIsLargeCall());
return sizeof(instrDescCns);
}

if (id->idIsLclVarDecl())
{
return sizeof(instrDescLclVarDecl);
}

return sizeof(instrDesc);
}

Expand Down Expand Up @@ -185,6 +221,13 @@ unsigned emitter::instrDesc::idCodeSize() const
assert(!idIsCnsReloc());
size = SizeOfULEB128(emitGetInsSC(this));
break;
case IF_LOCAL_DECL:
{
assert(idIsLclVarDecl());
instrDescLclVarDecl* idl = static_cast<instrDescLclVarDecl*>(const_cast<instrDesc*>(this));
size = SizeOfULEB128(idl->lclCnt) + sizeof(emitter::instWasmValueType);
break;
}
case IF_ULEB128:
size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this));
break;
Expand Down Expand Up @@ -341,11 +384,13 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
}
case IF_LOCAL_DECL:
{
cnsval_ssize_t constant = emitGetInsSC(id);
dst += emitOutputULEB128(dst, (uint64_t)constant);
assert(id->idIsLclVarDecl());
cnsval_ssize_t count = emitGetLclVarDeclCount(id);
instWasmValueType valType = emitGetLclVarDeclType(id);
dst += emitOutputULEB128(dst, (uint64_t)count);
// TODO-WASM: currently assuming all locals are numtypes which are single byte encoded.
// vec types are also single byte encoded. If we end up using reftypes, we'll need to handle the more complex encoding.
dst += emitOutputByte(dst, static_cast<uint8_t>(instWasmValueType::I32));
dst += emitOutputByte(dst, static_cast<uint8_t>(valType));
break;
}
default:
Expand Down Expand Up @@ -459,6 +504,14 @@ void emitter::emitDispIns(
}
break;

case IF_LOCAL_DECL:
{
cnsval_ssize_t imm = emitGetLclVarDeclCount(id);
instWasmValueType valType = emitGetLclVarDeclType(id);
printf(" %llu %s", (uint64_t)imm, instWasmValueTypeToStr(valType));
}
break;

case IF_SLEB128:
{
cnsval_ssize_t imm = emitGetInsSC(id);
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/jit/emitwasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* Debug-only routines to display instructions */
/************************************************************************/

#include "wasmtypes.h"
#include "wasmtypesdef.h"

#if defined(DEBUG) || defined(LATE_DISASM)
void getInsSveExecutionCharacteristics(instrDesc* id, insExecutionCharacteristics& result);
Expand Down Expand Up @@ -35,6 +35,10 @@ static unsigned SizeOfSLEB128(int64_t value);

static unsigned emitGetAlignHintLog2(const instrDesc* id);

instrDesc* emitNewInstrLclVarDecl(emitAttr attr, cnsval_ssize_t localCount, instWasmValueType type);
static instWasmValueType emitGetLclVarDeclType(instrDesc* id);
static cnsval_ssize_t emitGetLclVarDeclCount(instrDesc* id);

/************************************************************************/
/* Private members that deal with target-dependent instr. descriptors */
/************************************************************************/
Expand Down
22 changes: 0 additions & 22 deletions src/coreclr/jit/wasmtypes.h

This file was deleted.

62 changes: 62 additions & 0 deletions src/coreclr/jit/wasmtypesdef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

/*****************************************************************************/
#ifndef _WASMTYPESDEF_H_
#define _WASMTYPESDEF_H_
/*****************************************************************************/

#include <cstdint>
#include "vartypesdef.h"

#if defined(TARGET_WASM)
enum class instWasmValueType : uint8_t
{
F64 = 0x7C,
F32 = 0x7D,
I64 = 0x7E,
I32 = 0x7F,
};

const char *const wasmValueTypeNames[4] = {
"f64",
"f32",
"i64",
"i32",
};

//------------------------------------------------------------------------
// wasmValueTypeToStr: map wasm type to string
const char *const instWasmValueTypeToStr(instWasmValueType type)
{
assert((type >= instWasmValueType::F64) && (type <= instWasmValueType::I32));
return wasmValueTypeNames[static_cast<uint8_t>(type) - static_cast<uint8_t>(instWasmValueType::F64)];
}

//------------------------------------------------------------------------
// genWasmTypeFromVarType: map var_type to wasm type
//
instWasmValueType genWasmTypeFromVarType(var_types type)
{
switch (type)
{
case TYP_INT:
case TYP_REF:
case TYP_BYREF:
return instWasmValueType::I32;
case TYP_LONG:
return instWasmValueType::I64;
case TYP_FLOAT:
return instWasmValueType::F32;
case TYP_DOUBLE:
return instWasmValueType::F64;
default:
unreached();
}
}
#endif

/*****************************************************************************/
#endif // _WASMTYPESDEF_H_
/*****************************************************************************/