Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 11 additions & 5 deletions src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2176,9 +2176,8 @@ void CodeGen::genCodeForConstant(GenTree* treeNode)
icon = treeNode->AsIntConCommon();
if (icon->IsIconHandle())
{
// Wasm has no absolute-address literals; every handle is materialized as a module-base-
// relative constant and relocated. compReloc is always on for a real AOT compile, so a
// handle only reaches here without needing a reloc under a cross-VM SuperPMI replay.
// Handles need linker relocations for NativeAOT or image-relative relocations for R2R.
// A handle only reaches here without needing a reloc under a cross-VM SuperPMI replay.
assert(icon->ImmedValNeedsReloc(m_compiler) || m_compiler->RunningSuperPmiReplay());
GetEmitter()->emitAddressConstant((void*)icon->IntegralValue());
WasmProduceReg(treeNode);
Expand Down Expand Up @@ -3150,11 +3149,18 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree)

if (addr->isContained() && !addr->OperIs(GT_LEA))
{
// A contained address constant folds into the memarg offset, so emit just the image base here.
// A contained address constant folds into the memarg offset, so emit just the address base here.
//
assert(addr->IsIconHandle() && !tree->TypeIs(TYP_SIMD12));
assert(addr->AsIntConCommon()->ImmedValNeedsReloc(m_compiler));
GetEmitter()->emitImageBase();
if (m_compiler->IsNativeAot())
{
GetEmitter()->emitIns_I(INS_i32_const, EA_PTRSIZE, 0);
}
else
{
GetEmitter()->emitImageBase();
}
GetEmitter()->emitIns_MemargAddress(ins_Load(type), emitActualTypeSize(type),
(void*)addr->AsIntConCommon()->IntegralValue());
}
Expand Down
54 changes: 33 additions & 21 deletions src/coreclr/jit/emitwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,25 @@ bool emitter::emitInsIsStore(instruction ins)
//
void emitter::emitImageBase()
{
assert(!m_compiler->IsNativeAot());
emitIns_I(INS_global_get, EA_HANDLE_CNS_RELOC,
(cnsval_ssize_t)(size_t)m_compiler->eeGetWasmWellKnownGlobals()->imageBase);
}

//------------------------------------------------------------------------
// emitAddressConstant: Emit a memory address constant, like an indirection cell.
// This will automatically make use of relocations and the module base (imageBase).
// NativeAOT uses linker-relocated absolute addresses; R2R adds the module base.
void emitter::emitAddressConstant(void* address)
{
// Load our module base from the image base global, then load our address constant, then sum them.
emitImageBase();
if (!m_compiler->IsNativeAot())
{
emitImageBase();
}
emitIns_I(INS_i32_const_address, EA_SET_FLG(EA_PTRSIZE, EA_CNS_RELOC_FLG), (cnsval_ssize_t)address);
emitIns(INS_i32_add);
if (!m_compiler->IsNativeAot())
{
emitIns(INS_i32_add);
}
}

//------------------------------------------------------------------------
Expand All @@ -219,12 +225,13 @@ void emitter::emitAddressConstant(void* address)
// Arguments:
// ins - the load or store instruction
// attr - emit attributes
// address - the address constant, relocated relative to the module base
// address - the relocatable address constant
//
// Notes:
// The module base must already be on the stack; see emitImageBase. This folds the addition that
// emitAddressConstant would otherwise emit into the memarg offset. The memarg offset is always a
// relocation, never a raw address, so the caller must only reach here when relocating.
// The memory-address base (zero for NativeAOT, image base for R2R) must already be on the stack.
// This folds the addition that emitAddressConstant would otherwise emit into the memarg offset.
// The memarg offset is always a relocation, never a raw address, so the caller must only reach here
// when relocating.
//
void emitter::emitIns_MemargAddress(instruction ins, emitAttr attr, void* address)
{
Expand Down Expand Up @@ -252,9 +259,7 @@ void emitter::emitFuncletAddressConstant(cnsval_ssize_t funcletId)
// emitDataOffsetConstant: Emit a constant whose value is the linear-memory
// address of an entry in this method's JIT-emitted data (constants) section.
//
// The encoding mirrors emitAddressConstant: we load the image base global
// (the module image base), emit a relocated i32.const for the entry's offset,
// then add them. At output time the reloc target is resolved to the host
// The encoding mirrors emitAddressConstant. At output time the reloc target is resolved to the host
// pointer of the data section entry, which crossgen2 maps to the per-method
// read-only data symbol + offset.
//
Expand All @@ -264,16 +269,21 @@ void emitter::emitFuncletAddressConstant(cnsval_ssize_t funcletId)
//
void emitter::emitDataOffsetConstant(UNATIVE_OFFSET dataOffs)
{
emitIns_I(INS_global_get, EA_HANDLE_CNS_RELOC,
(cnsval_ssize_t)(size_t)m_compiler->eeGetWasmWellKnownGlobals()->imageBase);
if (!m_compiler->IsNativeAot())
{
emitImageBase();
}

instrDesc* id = emitNewInstrSC(EA_SET_FLG(EA_PTRSIZE, EA_CNS_RELOC_FLG), (cnsval_ssize_t)dataOffs);
id->idIns(INS_i32_const_dataoffs);
id->idInsFmt(IF_DATAOFFS);
dispIns(id);
appendToCurIG(id);

emitIns(INS_i32_add);
if (!m_compiler->IsNativeAot())
{
emitIns(INS_i32_add);
}
}

/*****************************************************************************
Expand Down Expand Up @@ -1007,9 +1017,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_MEMADDR:
{
dst += emitOutputOpcode(dst, ins);
// TODO-WASM: The below reloc we're emitting here is specific to R2R and assumes the address we want
// is an offset from __image_base
dst += emitOutputConstant(dst, id, SIGNED, CorInfoReloc::WASM_MEMORY_ADDR_REL_SLEB);
CorInfoReloc reloc = m_compiler->IsNativeAot() ? CorInfoReloc::WASM_MEMORY_ADDR_SLEB
: CorInfoReloc::WASM_MEMORY_ADDR_REL_SLEB;
dst += emitOutputConstant(dst, id, SIGNED, reloc);
Comment thread
MichalStrehovsky marked this conversation as resolved.
Resolved
break;
}
case IF_FUNCLETIDX:
Expand Down Expand Up @@ -1038,7 +1048,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutputOpcode(dst, ins);
UNATIVE_OFFSET dataOffs = (UNATIVE_OFFSET)emitGetInsSC(id);
BYTE* target = emitDataOffsetToPtr(dataOffs);
emitRecordRelocation(dst, target, CorInfoReloc::WASM_MEMORY_ADDR_REL_SLEB);
CorInfoReloc reloc = m_compiler->IsNativeAot() ? CorInfoReloc::WASM_MEMORY_ADDR_SLEB
: CorInfoReloc::WASM_MEMORY_ADDR_REL_SLEB;
emitRecordRelocation(dst, target, reloc);
dst += emitOutputPaddedReloc(dst);
break;
}
Expand Down Expand Up @@ -1102,9 +1114,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
assert(align <= UINT32_MAX); // spec says memarg alignment is u32
assert(align < 64); // spec says align > 2^6 produces a memidx for multiple memories.
dst += emitOutputULEB128(dst, align);
// TODO-WASM: as with IF_MEMADDR, this reloc is specific to R2R and assumes the address we want is an
// offset from __image_base.
dst += emitOutputConstant(dst, id, UNSIGNED, CorInfoReloc::WASM_MEMORY_ADDR_REL_LEB);
CorInfoReloc reloc =
m_compiler->IsNativeAot() ? CorInfoReloc::WASM_MEMORY_ADDR_LEB : CorInfoReloc::WASM_MEMORY_ADDR_REL_LEB;
dst += emitOutputConstant(dst, id, UNSIGNED, reloc);
break;
}
case IF_LOCAL_DECL:
Expand Down
13 changes: 6 additions & 7 deletions src/coreclr/jit/lowerwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,15 +580,14 @@ void Lowering::ContainCheckIndir(GenTreeIndir* indirNode)

// Contain a relocatable address constant so it folds into the load's memarg offset.
//
// Codegen for such a constant is "global.get $imageBase; i32.const <reloc>; i32.add"; containing it lets
// genCodeForIndir emit just the image base and put the relocated address in the memarg instead. Only loads
// can do this: the parent emits the base in place of the address, and a store cannot because its value
// operand has already been pushed. A multiply-used address is excluded because codegen re-materializes it
// from a register that would no longer hold the full address.
// The load emits the address base and puts the relocated address in the memarg. A store cannot contain
// its address because its value operand has already been pushed. Multiply-used addresses are excluded
// because codegen re-materializes them from registers that must still hold the full address.
//
GenTree* addr = indirNode->Addr();
GenTree* addr = indirNode->Addr();
bool isNativeFunctionAddress = m_compiler->IsNativeAot() && addr->IsIconHandle(GTF_ICON_FTN_ADDR);
if (indirNode->OperIs(GT_IND) && !indirNode->TypeIs(TYP_SIMD12) && addr->IsIconHandle() &&
addr->AsIntConCommon()->ImmedValNeedsReloc(m_compiler) &&
!isNativeFunctionAddress && addr->AsIntConCommon()->ImmedValNeedsReloc(m_compiler) &&
((addr->gtLIRFlags & LIR::Flags::MultiplyUsed) == LIR::Flags::None))
{
MakeSrcContained(indirNode, addr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ private unsafe int WriteRelocationEntries(SectionDataEmitter section, int conten
RelocType.WASM_TABLE_INDEX_I32 => WasmRelocationType.TableIndexI32,
RelocType.WASM_TABLE_INDEX_I64 => WasmRelocationType.TableIndexI64,
RelocType.WASM_MEMORY_ADDR_LEB => WasmRelocationType.MemoryAddrLeb,
RelocType.WASM_MEMORY_ADDR_SLEB when isFunction => WasmRelocationType.TableIndexSleb,
RelocType.WASM_MEMORY_ADDR_SLEB => WasmRelocationType.MemoryAddrSleb,
RelocType.WASM_MEMORY_ADDR_REL_SLEB when isFunction => WasmRelocationType.TableIndexSleb,
RelocType.WASM_MEMORY_ADDR_REL_SLEB => WasmRelocationType.MemoryAddrRelSleb,
Expand Down
Loading