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
1 change: 1 addition & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class CodeGen final : public CodeGenInterface
ArrayStack<WasmInterval*>* wasmControlFlowStack = nullptr;
unsigned wasmCursor = 0;
unsigned findTargetDepth(BasicBlock* target);
regNumber MakeOperandMultiUse(GenTree* node, GenTree* operand);
#endif

void genEmitStartBlock(BasicBlock* block);
Expand Down
158 changes: 149 additions & 9 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,12 @@ CodeGenInterface* getCodeGenerator(Compiler* comp)
return new (comp, CMK_Codegen) CodeGen(comp);
}

// TODO-WASM-Factoring: this ifdef factoring is temporary. The end factoring should look like this:
// 1. Everything shared by all codegen backends (incl. WASM) stays here.
// 2. Everything else goes into codegenlinear.cpp.
// 3. codegenlinear.cpp gets renamed to codegennative.cpp.
//
#ifndef TARGET_WASM
NodeInternalRegisters::NodeInternalRegisters(Compiler* comp)
: m_table(comp->getAllocator(CMK_LSRA))
{
}

#if HAS_FIXED_REGISTER_SET
//------------------------------------------------------------------------
// Add: Add internal allocated registers for the specified node.
//
Expand Down Expand Up @@ -174,6 +169,149 @@ unsigned NodeInternalRegisters::Count(GenTree* tree, regMaskTP mask)
regMaskTP regs;
return m_table.Lookup(tree, &regs) ? genCountBits(regs & mask) : 0;
}
#else // !HAS_FIXED_REGISTER_SET
//------------------------------------------------------------------------
// InternalRegs: construct an empty 'InternalRegs' instance.
//
InternalRegs::InternalRegs()
{
for (size_t i = 0; i < ArrLen(m_regs); i++)
{
m_regs[i] = REG_NA;
}
}

//------------------------------------------------------------------------
// IsEmpty: are there any registers in this set?
//
// Return Value:
// Whether there are any registers in this set.
//
bool InternalRegs::IsEmpty() const
{
return m_regs[0] == REG_NA;
}

//------------------------------------------------------------------------
// Count: how many registers are in this set?
//
// Return Value:
// The count of registers in this set.
//
unsigned InternalRegs::Count() const
{
unsigned count = 0;
while (count < ArrLen(m_regs))
{
if (m_regs[count] == REG_NA)
{
break;
}
count++;
}
return count;
}

//------------------------------------------------------------------------
// Add: add a register to this set.
//
// The set must not be full yet.
//
// Parameters:
// reg - The register to add
//
void InternalRegs::Add(regNumber reg)
{
assert(reg != REG_NA);
unsigned count = Count();
assert(count < ArrLen(m_regs));
m_regs[count] = reg;
}

//------------------------------------------------------------------------
// GetAt: Get a register at an index.
//
// Parameters:
// index - The index
//
// Return Value:
// The register at 'index', which must be valid.
//
regNumber InternalRegs::GetAt(unsigned index) const
{
assert(index < Count());
return m_regs[index];
}

//------------------------------------------------------------------------
// SetAt: Set a register at an index.
//
// Parameters:
// index - The index
// reg - The register, must be valid
//
void InternalRegs::SetAt(unsigned index, regNumber reg)
{
assert(index < Count());
assert(reg != REG_NA);
m_regs[index] = reg;
}

//------------------------------------------------------------------------
// Extract: Remove the last register from this set and return it.
//
// Return Value:
// The extracted register.
//
regNumber InternalRegs::Extract()
{
assert(!IsEmpty());
unsigned index = Count() - 1;
regNumber reg = m_regs[index];
m_regs[index] = REG_NA;
return reg;
}

//------------------------------------------------------------------------
// Add: Add a register to the set of ones internally allocated for this node.
//
// Parameters:
// tree - IR node to add the internal allocated register to
// reg - The register to add
//
void NodeInternalRegisters::Add(GenTree* tree, regNumber reg)
{
InternalRegs* regs = m_table.LookupPointerOrAdd(tree, InternalRegs{});
regs->Add(reg);
}

//------------------------------------------------------------------------
// GetAll: Get the internally allocated registers for the specified node.
//
// Parameters:
// tree - IR node to get the registers for
//
// Returns:
// Pointer to the registers, nullptr if there are none.
//
InternalRegs* NodeInternalRegisters::GetAll(GenTree* tree)
{
InternalRegs* regs = m_table.LookupPointer(tree);
assert((regs == nullptr) || !regs->IsEmpty());
return regs;
}

//------------------------------------------------------------------------
// Iterate: Get the iterator for the internal register table.
//
// Returns:
// A 'for'-loop compatible iterator of the table entries.
//
NodeInternalRegistersTable::KeyValueIteration NodeInternalRegisters::Iterate()
{
return NodeInternalRegistersTable::KeyValueIteration(&m_table);
}
#endif // !HAS_FIXED_REGISTER_SET

#if defined(TARGET_XARCH)
void CodeGenInterface::CopyRegisterInfo()
Expand All @@ -190,15 +328,12 @@ void CodeGenInterface::CopyRegisterInfo()
rbmMskCalleeTrash = m_compiler->rbmMskCalleeTrash;
}
#endif // TARGET_XARCH
#endif // !TARGET_WASM

// CodeGen constructor
CodeGenInterface::CodeGenInterface(Compiler* theCompiler)
: gcInfo(theCompiler)
, regSet(theCompiler, gcInfo)
#if HAS_FIXED_REGISTER_SET
, internalRegisters(theCompiler)
#endif // HAS_FIXED_REGISTER_SET
, m_compiler(theCompiler)
, treeLifeUpdater(nullptr)
#ifdef TARGET_WASM
Expand Down Expand Up @@ -268,6 +403,11 @@ CodeGen::CodeGen(Compiler* theCompiler)
#endif // TARGET_ARM64
}

// TODO-WASM-Factoring: this ifdef factoring is temporary. The end factoring should look like this:
// 1. Everything shared by all codegen backends (incl. WASM) stays here.
// 2. Everything else goes into codegenlinear.cpp.
// 3. codegenlinear.cpp gets renamed to codegennative.cpp.
//
#ifndef TARGET_WASM
#if defined(TARGET_X86) || defined(TARGET_ARM)

Expand Down
42 changes: 34 additions & 8 deletions src/coreclr/jit/codegeninterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,48 @@ class emitter;

CodeGenInterface* getCodeGenerator(Compiler* comp);

#if HAS_FIXED_REGISTER_SET
using InternalRegs = regMaskTP;
#else // !HAS_FIXED_REGISTER_SET
class InternalRegs
{
public:
static const unsigned MAX_REG_COUNT = 2;

private:
regNumber m_regs[MAX_REG_COUNT];

public:
InternalRegs();

bool IsEmpty() const;
unsigned Count() const;
void Add(regNumber reg);
regNumber GetAt(unsigned index) const;
void SetAt(unsigned index, regNumber reg);
regNumber Extract();
};
#endif // !HAS_FIXED_REGISTER_SET

using NodeInternalRegistersTable = JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, InternalRegs>;
class NodeInternalRegisters
{
typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, regMaskTP> NodeInternalRegistersTable;
NodeInternalRegistersTable m_table;
NodeInternalRegistersTable m_table;

public:
NodeInternalRegisters(Compiler* comp);

#if HAS_FIXED_REGISTER_SET
void Add(GenTree* tree, regMaskTP reg);
regNumber Extract(GenTree* tree, regMaskTP mask = static_cast<regMaskTP>(-1));
regNumber GetSingle(GenTree* tree, regMaskTP mask = static_cast<regMaskTP>(-1));
regMaskTP GetAll(GenTree* tree);
unsigned Count(GenTree* tree, regMaskTP mask = static_cast<regMaskTP>(-1));
#else // !HAS_FIXED_REGISTER_SET
void Add(GenTree* tree, regNumber reg);
InternalRegs* GetAll(GenTree* tree);
NodeInternalRegistersTable::KeyValueIteration Iterate();
#endif // !HAS_FIXED_REGISTER_SET
};

class CodeGenInterface
Expand Down Expand Up @@ -144,13 +173,10 @@ class CodeGenInterface
unsigned* mulPtr,
ssize_t* cnsPtr) = 0;

GCInfo gcInfo;
RegSet regSet;
regMaskTP calleeRegArgMaskLiveIn; // Mask of register arguments live on entry to the (root) method.

#if HAS_FIXED_REGISTER_SET
GCInfo gcInfo;
RegSet regSet;
regMaskTP calleeRegArgMaskLiveIn; // Mask of register arguments live on entry to the (root) method.
NodeInternalRegisters internalRegisters;
#endif

protected:
Compiler* m_compiler;
Expand Down
65 changes: 44 additions & 21 deletions src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,34 @@ void CodeGen::genEmitStartBlock(BasicBlock* block)
}
}

//------------------------------------------------------------------------
// MakeOperandMultiUse: Prepare an operand for multiple usages.
//
// Extracts an internal register from 'node' if 'operand' is not already
// in a register, and initializes the extracted register via "local.tee".
//
// Arguments:
// node - The parent node of 'operand', holder of the internal registers
// operand - The operand, must be on top of the value stack
//
// Return Value:
// The register to use for 'operand'.
//
regNumber CodeGen::MakeOperandMultiUse(GenTree* node, GenTree* operand)
{
if (genIsRegCandidateLocal(operand))
{
LclVarDsc* varDsc = m_compiler->lvaGetDesc(operand->AsLclVar());
assert(varDsc->lvIsInReg());
return varDsc->GetRegNum();
}

InternalRegs* regs = internalRegisters.GetAll(node);
regNumber reg = regs->Extract();
GetEmitter()->emitIns_I(INS_local_tee, emitActualTypeSize(operand), WasmRegToIndex(reg));
return reg;
}

//------------------------------------------------------------------------
// genCodeForTreeNode: codegen for a particular tree node
//
Expand Down Expand Up @@ -955,34 +983,31 @@ void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
{
genConsumeOperands(treeNode);

// wasm stack is
// divisor (top)
// dividend (next)
// ...
// TODO-WASM: To check for exception, we will have to spill these to
// internal registers along the way, like so:
//
// ... push dividend
// tee.local $temp1
// ... push divisor
// tee.local $temp2
// ... exception checks (using $temp1 and $temp2; will introduce flow)
// div/mod op

if (!varTypeIsFloating(treeNode->TypeGet()))
{
ExceptionSetFlags exSetFlags = treeNode->OperExceptions(m_compiler);
bool is64BitOp = treeNode->TypeIs(TYP_LONG);
emitAttr size = is64BitOp ? EA_8BYTE : EA_4BYTE;

// TODO-WASM:(AnyVal / 0) => DivideByZeroException
//
// (AnyVal / 0) => DivideByZeroException.
GenTree* divisor = treeNode->gtGetOp2();
regNumber divisorReg = REG_NA;
if ((exSetFlags & ExceptionSetFlags::DivideByZeroException) != ExceptionSetFlags::None)
{
divisorReg = MakeOperandMultiUse(treeNode, divisor);
GetEmitter()->emitIns(is64BitOp ? INS_i64_eqz : INS_i32_eqz);
genJumpToThrowHlpBlk(SCK_DIV_BY_ZERO);
}

// TODO-WASM: (MinInt / -1) => ArithmeticException
//
// (MinInt / -1) => ArithmeticException.
if ((exSetFlags & ExceptionSetFlags::ArithmeticException) != ExceptionSetFlags::None)
{
// TODO-WASM: implement overflow checking.
}

if (divisorReg != REG_NA)
{
GetEmitter()->emitIns_I(INS_local_get, size, WasmRegToIndex(divisorReg));
}
}

Expand Down Expand Up @@ -1024,9 +1049,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
break;

default:
ins = INS_none;
NYI_WASM("genCodeForDivMod");
break;
unreached();
}

GetEmitter()->emitIns(ins);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/emitwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ void emitter::emitDispIns(
BasicBlock* const targetBlock = id->idDebugOnlyInfo()->idTargetBlock;
if (targetBlock != nullptr)
{
printf(" ;;");
printf(" ;; ");
insGroup* const targetGroup = (insGroup*)emitCodeGetCookie(targetBlock);
assert(targetGroup != nullptr);
emitPrintLabel(targetGroup);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/instrswasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ INST(drop, "drop", 0, IF_OPCODE, 0x1A)

INST(local_get, "local.get", 0, IF_ULEB128, 0x20)
INST(local_set, "local.set", 0, IF_ULEB128, 0x21)
INST(local_tee, "local.tee", 0, IF_ULEB128, 0x22)
INST(i32_load, "i32.load", 0, IF_MEMARG, 0x28)
INST(i64_load, "i64.load", 0, IF_MEMARG, 0x29)
INST(f32_load, "f32.load", 0, IF_MEMARG, 0x2A)
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/jithashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ class JitHashTable
{
return m_val;
}

Value& GetValueRef()
{
return m_val;
}
};

//------------------------------------------------------------------------
Expand Down
Loading
Loading