diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 344580fe6a6e1c..ffc6f3197266c2 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -11,8 +11,8 @@ void CodeGen::genMarkLabelsForCodegen() { - // TODO-WASM: serialize fgWasmControlFlow results into codegen-level metadata/labels - // (or use them directly and leave this empty). + // No work needed here for now. + // We mark labels as needed in genEmitStartBlock. } void CodeGen::genFnEpilog(BasicBlock* block) @@ -154,7 +154,13 @@ void CodeGen::genEmitStartBlock(BasicBlock* block) while (!wasmControlFlowStack->Empty() && (wasmControlFlowStack->Top()->End() == cursor)) { instGen(INS_end); - wasmControlFlowStack->Pop(); + WasmInterval* interval = wasmControlFlowStack->Pop(); + + if (!interval->IsLoop() && !block->HasFlag(BBF_HAS_LABEL)) + { + block->SetFlags(BBF_HAS_LABEL); + genDefineTempLabel(block); + } } // Push control flow for intervals that start here or earlier, and emit @@ -179,6 +185,12 @@ void CodeGen::genEmitStartBlock(BasicBlock* block) wasmCursor++; wasmControlFlowStack->Push(interval); + if (interval->IsLoop() && !block->HasFlag(BBF_HAS_LABEL)) + { + block->SetFlags(BBF_HAS_LABEL); + genDefineTempLabel(block); + } + if (wasmCursor >= compiler->fgWasmIntervals->size()) { break; @@ -349,7 +361,7 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) BasicBlock* const caseTarget = desc->GetCase(caseNum)->getDestinationBlock(); unsigned depth = findTargetDepth(caseTarget); - GetEmitter()->emitIns_I(INS_label, EA_4BYTE, depth); + GetEmitter()->emitIns_J(INS_label, EA_4BYTE, depth, caseTarget); } } @@ -878,7 +890,7 @@ void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock) { instruction instr = emitter::emitJumpKindToIns(jmp); unsigned const depth = findTargetDepth(tgtBlock); - GetEmitter()->emitIns_I(instr, EA_4BYTE, depth); + GetEmitter()->emitIns_J(instr, EA_4BYTE, depth, tgtBlock); } void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* code)) diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index f18b84a19ca2b9..2482c1b22c6ce8 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -1729,6 +1729,7 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz) assert(info->idFinallyCall == false); assert(info->idCatchRet == false); assert(info->idCallSig == nullptr); + assert(info->idTargetBlock == nullptr); info->idNum = emitInsCount; info->idSize = sz; diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 4418dc4c2e93bb..254b144598f7c2 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -637,6 +637,7 @@ class emitter bool idFinallyCall; // Branch instruction is a call to finally 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_ARM diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index 694a572471752f..243edde19268c5 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -29,6 +29,11 @@ void emitter::emitIns(instruction ins) //------------------------------------------------------------------------ // emitIns_I: Emit an instruction with an immediate operand. // +// Arguments: +// ins - instruction to emit +// attr - emit attributes +// imm - immediate value +// void emitter::emitIns_I(instruction ins, emitAttr attr, cnsval_ssize_t imm) { instrDesc* id = emitNewInstrSC(attr, imm); @@ -41,6 +46,32 @@ void emitter::emitIns_I(instruction ins, emitAttr attr, cnsval_ssize_t imm) appendToCurIG(id); } +//------------------------------------------------------------------------ +// emitIns_J: Emit a jump instruction with an immediate operand. +// +// Arguments: +// ins - instruction to emit +// attr - emit attributes +// imm - immediate value (depth in control flow stack) +// targetBlock - block at that depth +// +void emitter::emitIns_J(instruction ins, emitAttr attr, cnsval_ssize_t imm, BasicBlock* targetBlock) +{ + instrDesc* id = emitNewInstrSC(attr, imm); + insFormat fmt = emitInsFormat(ins); + + id->idIns(ins); + id->idInsFmt(fmt); + + if (m_debugInfoSize > 0) + { + id->idDebugOnlyInfo()->idTargetBlock = targetBlock; + } + + dispIns(id); + appendToCurIG(id); +} + //------------------------------------------------------------------------ // emitIns_S: Emit a memory instruction with a stack-based address mode operand. // @@ -113,7 +144,9 @@ static unsigned GetInsOpcode(instruction ins) size_t emitter::emitSizeOfInsDsc(instrDesc* id) const { if (emitIsSmallInsDsc(id)) + { return SMALL_IDSC_SIZE; + } if (id->idIsLargeCns()) { @@ -121,6 +154,7 @@ size_t emitter::emitSizeOfInsDsc(instrDesc* id) const assert(!id->idIsLargeCall()); return sizeof(instrDescCns); } + return sizeof(instrDesc); } @@ -304,8 +338,11 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) break; } case IF_LABEL: - NYI_WASM("emitOutputInstr IF_LABEL"); + { + cnsval_ssize_t constant = emitGetInsSC(id); + dst += emitOutputULEB128(dst, (uint64_t)constant); break; + } case IF_MEMARG: { dst += emitOutputByte(dst, opcode); @@ -411,6 +448,20 @@ void emitter::emitDispIns( emitDispInst(ins); + auto dispJumpTargetIfAny = [this, id]() { + if (m_debugInfoSize > 0) + { + BasicBlock* const targetBlock = id->idDebugOnlyInfo()->idTargetBlock; + if (targetBlock != nullptr) + { + printf(" ;; "); + insGroup* const targetGroup = (insGroup*)emitCodeGetCookie(targetBlock); + assert(targetGroup != nullptr); + emitPrintLabel(targetGroup); + } + } + }; + // The reference for the following style of display is wasm-objdump output. // switch (fmt) @@ -424,6 +475,7 @@ void emitter::emitDispIns( { cnsval_ssize_t imm = emitGetInsSC(id); printf(" %llu", (uint64_t)imm); + dispJumpTargetIfAny(); } break; diff --git a/src/coreclr/jit/emitwasm.h b/src/coreclr/jit/emitwasm.h index c3d4c04ddc0815..896f7d1cea20c5 100644 --- a/src/coreclr/jit/emitwasm.h +++ b/src/coreclr/jit/emitwasm.h @@ -18,6 +18,7 @@ void emitDispInst(instruction ins); public: void emitIns(instruction ins); void emitIns_I(instruction ins, emitAttr attr, cnsval_ssize_t imm); +void emitIns_J(instruction ins, emitAttr attr, cnsval_ssize_t imm, BasicBlock* tgtBlock); void emitIns_S(instruction ins, emitAttr attr, int varx, int offs); void emitIns_R(instruction ins, emitAttr attr, regNumber reg);