Skip to content
3 changes: 2 additions & 1 deletion src/coreclr/jit/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,14 @@ var_types ABIPassingSegment::GetRegisterType() const
//
// Parameters:
// layout - The layout of the class that this segment is part of
// or nullptr if there is no layout
//
// Return Value:
// A type that matches ABIPassingSegment::Size and the register.
//
var_types ABIPassingSegment::GetRegisterType(ClassLayout* layout) const
{
if (genIsValidIntReg(GetRegister()))
if ((layout != nullptr) && (genIsValidIntReg(GetRegister())))
{
assert(Offset < layout->GetSize());
if (((Offset % TARGET_POINTER_SIZE) == 0) && (Size == TARGET_POINTER_SIZE))
Expand Down
20 changes: 19 additions & 1 deletion src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1961,7 +1961,25 @@ void CodeGen::genGenerateCode(void** codePtr, uint32_t* nativeSizeOfCode)
m_compiler->compGetHelperFtn((CorInfoHelpFunc)i);
}
}
#endif

#if defined(TARGET_WASM)
// Allow the JIT to fail R2R at this point, so we can skip over methods
// that compile without assert but then have Wasm validation errors
//
static ConfigMethodRange JitR2RUnsupportedRange;
JitR2RUnsupportedRange.EnsureInit(JitConfig.JitR2RUnsupportedRange());
assert(!JitR2RUnsupportedRange.Error());
const unsigned hash = m_compiler->impInlineRoot()->info.compMethodHash();
const bool inRange = !JitR2RUnsupportedRange.IsEmpty() && JitR2RUnsupportedRange.Contains(hash);

if (inRange)
{
JITDUMP("Failing R2R codegen because of JitR2RUnsupportedRange. Hash is 0x%08x, range is ", hash);
JITDUMPEXEC(JitR2RUnsupportedRange.Dump());
implReadyToRunUnsupported();
}
#endif // defined(TARGET_WASM)
#endif // DEBUG
}

//----------------------------------------------------------------------
Expand Down
79 changes: 65 additions & 14 deletions src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,9 @@ void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
GetEmitter()->emitIns_I(is64BitOp ? INS_i64_const : INS_i32_const, size, is64BitOp ? INT64_MIN : INT32_MIN);
GetEmitter()->emitIns(is64BitOp ? INS_i64_eq : INS_i32_eq);

GetEmitter()->emitIns(is64BitOp ? INS_i64_and : INS_i32_and);
// Wasm relops always produce i32 results
//
GetEmitter()->emitIns(INS_i32_and);
genJumpToThrowHlpBlk(SCK_ARITH_EXCPN);
}
}
Expand Down Expand Up @@ -1477,6 +1479,14 @@ void CodeGen::genCodeForShift(GenTree* tree)
// different types. The shift operand width in IR is always TYP_INT; the WASM operations have the same widths
// for both the shift and shiftee. So the shift may need to be extended (zero-extended) for TYP_LONG.

if (treeNode->TypeIs(TYP_LONG))
{
assert(treeNode->gtGetOp2()->TypeIs(TYP_INT));
// Zero-extend the shift amount to 64 bits for long shifts/rotates.
// Wasteful if the amount was a constant, perhaps we should contain it if so.
GetEmitter()->emitIns(INS_i64_extend_u_i32);
}

instruction ins;
switch (PackOperAndType(treeNode->OperGet(), treeNode->TypeGet()))
{
Expand Down Expand Up @@ -1821,6 +1831,8 @@ void CodeGen::genIntrinsic(GenTreeIntrinsic* treeNode)
// Handle intrinsics that can be implemented by target-specific instructions
instruction ins = INS_invalid;

bool canHaveMixedTypes = false;

switch (PackIntrinsicAndType(treeNode->gtIntrinsicName, treeNode->TypeGet()))
{
case PackIntrinsicAndType(NI_System_Math_Abs, TYP_FLOAT):
Expand Down Expand Up @@ -1884,33 +1896,72 @@ void CodeGen::genIntrinsic(GenTreeIntrinsic* treeNode)
break;

case PackIntrinsicAndType(NI_PRIMITIVE_LeadingZeroCount, TYP_INT):
ins = INS_i32_clz;
break;
case PackIntrinsicAndType(NI_PRIMITIVE_LeadingZeroCount, TYP_LONG):
ins = INS_i64_clz;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_TrailingZeroCount, TYP_INT):
ins = INS_i32_ctz;
break;
case PackIntrinsicAndType(NI_PRIMITIVE_TrailingZeroCount, TYP_LONG):
ins = INS_i64_ctz;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_PopCount, TYP_INT):
ins = INS_i32_popcnt;
break;
case PackIntrinsicAndType(NI_PRIMITIVE_PopCount, TYP_LONG):
ins = INS_i64_popcnt;
canHaveMixedTypes = true;
break;

default:
assert(!"genIntrinsic: Unsupported intrinsic");
unreached();
}

bool needsTruncation = false;
bool needsExtension = false;

if (canHaveMixedTypes)
{
var_types treeType = treeNode->TypeGet();
var_types operandType = genActualType(treeNode->gtGetOp1()->TypeGet());

needsTruncation = (operandType == TYP_LONG) && (treeType == TYP_INT);
needsExtension = (operandType == TYP_INT) && (treeType == TYP_LONG);

switch (PackIntrinsicAndType(treeNode->gtIntrinsicName, operandType))
{
case PackIntrinsicAndType(NI_PRIMITIVE_LeadingZeroCount, TYP_INT):
ins = INS_i32_clz;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_LeadingZeroCount, TYP_LONG):
ins = INS_i64_clz;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_TrailingZeroCount, TYP_INT):
ins = INS_i32_ctz;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_TrailingZeroCount, TYP_LONG):
ins = INS_i64_ctz;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_PopCount, TYP_INT):
ins = INS_i32_popcnt;
break;

case PackIntrinsicAndType(NI_PRIMITIVE_PopCount, TYP_LONG):
ins = INS_i64_popcnt;
break;

default:
unreached();
}
}

GetEmitter()->emitIns(ins);

if (needsTruncation)
{
GetEmitter()->emitIns(INS_i32_wrap_i64);
}
else if (needsExtension)
{
GetEmitter()->emitIns(INS_i64_extend_u_i32);
}

WasmProduceReg(treeNode);
}

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,9 @@ CONFIG_INTEGER(JitDispIns, "JitDispIns", 0)
#if defined(TARGET_WASM)
// Set this to 1 to turn NYI_WASM into R2R unsupported failures instead of asserts.
CONFIG_INTEGER(JitWasmNyiToR2RUnsupported, "JitWasmNyiToR2RUnsupported", 0)
// Specify methods that will fail with R2R unsupported after codegen.
// Useful for bypassing methods that compile cleanly but have invalid Wasm codegen.
CONFIG_STRING(JitR2RUnsupportedRange, "JitR2RUnsupportedRange")
#endif // defined(TARGET_WASM)

// Allow to enregister locals with struct type.
Expand Down
7 changes: 2 additions & 5 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2428,11 +2428,8 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg)
{
if (seg.IsPassedInRegister())
{
var_types regType = seg.GetRegisterType();
// If passed in a float reg then keep that type; otherwise let
// createSlotAccess get the type from the layout.
var_types slotType = varTypeUsesFloatReg(regType) ? regType : TYP_UNDEF;
GenTree* access = createSlotAccess(seg.Offset, slotType);
var_types regType = seg.GetRegisterType(layout);
GenTree* access = createSlotAccess(seg.Offset, regType);

newArg->AsFieldList()->AddField(this, access, seg.Offset, access->TypeGet());
}
Expand Down
17 changes: 14 additions & 3 deletions src/coreclr/tools/Common/JitInterface/WasmLowering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

using ILCompiler;
using ILCompiler.DependencyAnalysis.Wasm;

using Internal.TypeSystem;
Expand Down Expand Up @@ -156,8 +156,9 @@ public static WasmFuncType GetSignature(MethodDesc method)
returnIsVoid = true;
}

// Reserve space for potential implicit this, stack pointer parameter, portable entrypoint parameter, and return buffer
ArrayBuilder<WasmValueType> result = new(signature.Length + 4);
// Reserve space for potential implicit this, stack pointer parameter, portable entrypoint parameter,
// generic context, async continuation, and return buffer
ArrayBuilder<WasmValueType> result = new(signature.Length + 6);

if (!signature.IsStatic)
{
Expand Down Expand Up @@ -191,6 +192,16 @@ public static WasmFuncType GetSignature(MethodDesc method)
}
}

if (method.RequiresInstMethodDescArg() || method.RequiresInstMethodTableArg())
{
result.Add(pointerType); // generic context
}

if (method.IsAsyncCall())
{
result.Add(pointerType); // async continuation
}

for (int i = explicitThis ? 1 : 0; i < signature.Length; i++)
{
result.Add(LowerType(signature[i]));
Expand Down
Loading