Skip to content

Commit cbf8308

Browse files
[NativeAOT-LLVM] Work around poor inlined memset code quality in LLVM (#3183)
* wasmjit-diff fixups * Work around poor inlined memset code quality in LLVM
1 parent d226778 commit cbf8308

File tree

3 files changed

+99
-9
lines changed

3 files changed

+99
-9
lines changed

src/coreclr/jit/llvm.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,9 +626,11 @@ class Llvm
626626
void emitAlignmentCheckForAddress(GenTree* addr, Value* addrValue, unsigned alignment DEBUGARG(GenTree* indir));
627627
bool isAddressAligned(GenTree* addr, unsigned alignment);
628628

629-
Value* consumeInitVal(GenTree* initVal);
629+
Value* consumeInitVal(GenTree* initVal, uint8_t* pValue);
630+
void consumeInitValAndEmitInitBlk(GenTree* initVal, Value* addrValue, ClassLayout* layout);
630631
void storeObjAtAddress(Value* baseAddress, Value* data, StructDesc* structDesc);
631632
unsigned buildMemCpy(Value* baseAddress, unsigned startOffset, unsigned endOffset, Value* srcAddress);
633+
void emitMemSet(Value* addr, uint8_t value, unsigned size);
632634

633635
void emitJumpToThrowHelper(Value* jumpCondValue, CorInfoHelpFunc helperFunc DEBUGARG(GenTree* nodeThrowing));
634636
Value* emitCheckedArithmeticOperation(
@@ -666,6 +668,7 @@ class Llvm
666668

667669
Value* gepOrAddr(Value* addr, unsigned offset);
668670
Value* gepOrAddrInBounds(Value* addr, unsigned offset);
671+
Value* emitAddLoadStoreOffset(Value* addr, unsigned offset);
669672
llvm::Constant* getIntPtrConst(target_size_t value, Type* llvmType = nullptr);
670673
Value* getShadowStack();
671674
Value* getShadowStackForCallee(bool isTailCall = false);

src/coreclr/jit/llvmcodegen.cpp

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,9 +1329,7 @@ void Llvm::buildStoreLocalField(GenTreeLclFld* lclFld)
13291329

13301330
if (lclFld->TypeIs(TYP_STRUCT) && genActualTypeIsInt(data))
13311331
{
1332-
Value* fillValue = consumeInitVal(data);
1333-
Value* sizeValue = _builder.getInt32(layout->GetSize());
1334-
_builder.CreateMemSet(addrValue, fillValue, sizeValue, llvm::MaybeAlign());
1332+
consumeInitValAndEmitInitBlk(data, addrValue, layout);
13351333
}
13361334
else
13371335
{
@@ -1931,8 +1929,7 @@ void Llvm::buildStoreBlk(GenTreeBlk* blockOp)
19311929
// Check for the "initblk" operation ("dataNode" is either INIT_VAL or constant zero).
19321930
if (blockOp->OperIsInitBlkOp())
19331931
{
1934-
Value* fillValue = consumeInitVal(dataNode);
1935-
_builder.CreateMemSet(addrValue, fillValue, _builder.getInt32(layout->GetSize()), llvm::Align());
1932+
consumeInitValAndEmitInitBlk(dataNode, addrValue, layout);
19361933
return;
19371934
}
19381935

@@ -2467,19 +2464,33 @@ bool Llvm::isAddressAligned(GenTree* addr, unsigned alignment)
24672464
return alignment == 1; // Any address is aligned to one byte.
24682465
}
24692466

2470-
Value* Llvm::consumeInitVal(GenTree* initVal)
2467+
Value* Llvm::consumeInitVal(GenTree* initVal, uint8_t* pValue)
24712468
{
24722469
assert(initVal->isContained());
24732470
if (initVal->IsIntegralConst())
24742471
{
24752472
assert(initVal->IsIntegralConst(0));
2476-
return _builder.getInt8(0);
2473+
*pValue = 0;
2474+
return nullptr;
24772475
}
24782476

24792477
assert(initVal->OperIsInitVal());
24802478
return consumeValue(initVal->gtGetOp1(), Type::getInt8Ty(m_context->Context));
24812479
}
24822480

2481+
void Llvm::consumeInitValAndEmitInitBlk(GenTree* initVal, Value* addrValue, ClassLayout* layout)
2482+
{
2483+
uint8_t constInitValue;
2484+
Value* initValue = consumeInitVal(initVal, &constInitValue);
2485+
if (initValue != nullptr)
2486+
{
2487+
_builder.CreateMemSet(addrValue, initValue, layout->GetSize(), llvm::MaybeAlign());
2488+
return;
2489+
}
2490+
2491+
emitMemSet(addrValue, constInitValue, layout->GetSize());
2492+
}
2493+
24832494
void Llvm::storeObjAtAddress(Value* baseAddress, Value* data, StructDesc* structDesc)
24842495
{
24852496
size_t fieldCount = structDesc->getFieldCount();
@@ -2553,6 +2564,66 @@ unsigned Llvm::buildMemCpy(Value* baseAddress, unsigned startOffset, unsigned en
25532564
return size;
25542565
}
25552566

2567+
void Llvm::emitMemSet(Value* addr, uint8_t value, unsigned size)
2568+
{
2569+
static const unsigned LLVM_MAX_UNROLL_SIZE = 64;
2570+
2571+
llvm::Align align(1);
2572+
if (size > LLVM_MAX_UNROLL_SIZE)
2573+
{
2574+
_builder.CreateMemSet(addr, _builder.getInt8(value), size, align);
2575+
return;
2576+
}
2577+
2578+
// TODO-LLVM: remove this manual unrolling once https://github.com/llvm/llvm-project/issues/79692 is fixed.
2579+
unsigned offset = 0;
2580+
Value* int64Value = nullptr;
2581+
for (; size - offset >= 8; offset += 8)
2582+
{
2583+
if (int64Value == nullptr)
2584+
{
2585+
int64Value = _builder.getInt64(0x0101010101010101ULL * value);
2586+
}
2587+
Value* addrAtOffset = emitAddLoadStoreOffset(addr, offset);
2588+
_builder.CreateAlignedStore(int64Value, addrAtOffset, llvm::commonAlignment(align, offset));
2589+
}
2590+
2591+
Value* int32Value = nullptr;
2592+
for (; size - offset >= 4; offset += 4)
2593+
{
2594+
if (int32Value == nullptr)
2595+
{
2596+
int32Value = _builder.getInt32(0x01010101u * value);
2597+
}
2598+
Value* addrAtOffset = emitAddLoadStoreOffset(addr, offset);
2599+
_builder.CreateAlignedStore(int32Value, addrAtOffset, llvm::commonAlignment(align, offset));
2600+
}
2601+
2602+
Value* int16Value = nullptr;
2603+
for (; size - offset >= 2; offset += 2)
2604+
{
2605+
if (int16Value == nullptr)
2606+
{
2607+
int16Value = _builder.getInt16(0x0101 * value);
2608+
}
2609+
Value* addrAtOffset = emitAddLoadStoreOffset(addr, offset);
2610+
_builder.CreateAlignedStore(int16Value, addrAtOffset, llvm::commonAlignment(align, offset));
2611+
}
2612+
2613+
Value* int8Value = nullptr;
2614+
for (; size - offset >= 1; offset += 1)
2615+
{
2616+
if (int8Value == nullptr)
2617+
{
2618+
int8Value = _builder.getInt8(value);
2619+
}
2620+
Value* addrAtOffset = emitAddLoadStoreOffset(addr, offset);
2621+
_builder.CreateAlignedStore(int8Value, addrAtOffset, llvm::commonAlignment(align, offset));
2622+
}
2623+
2624+
assert(offset == size);
2625+
}
2626+
25562627
void Llvm::emitJumpToThrowHelper(Value* jumpCondValue, CorInfoHelpFunc helperFunc DEBUGARG(GenTree* nodeThrowing))
25572628
{
25582629
bool shadowTailCalledThrowHelper = false;
@@ -3251,6 +3322,21 @@ Value* Llvm::gepOrAddrInBounds(Value* addr, unsigned offset)
32513322
return _builder.CreateInBoundsGEP(Type::getInt8Ty(m_context->Context), addr, _builder.getInt32(offset));
32523323
}
32533324

3325+
Value* Llvm::emitAddLoadStoreOffset(Value* addr, unsigned offset)
3326+
{
3327+
// TODO-LLVM: replace this with getelementptr 'nusw' once we move to LLVM 20+.
3328+
assert(addr->getType()->isPointerTy());
3329+
if (offset == 0)
3330+
{
3331+
return addr;
3332+
}
3333+
3334+
addr = _builder.CreatePtrToInt(addr, getIntPtrLlvmType());
3335+
addr = _builder.CreateNUWAdd(addr, getIntPtrConst(offset));
3336+
addr = _builder.CreateIntToPtr(addr, getPtrLlvmType());
3337+
return addr;
3338+
}
3339+
32543340
Value* Llvm::getShadowStack()
32553341
{
32563342
if (getCurrentLlvmFunctionIndex() == ROOT_FUNC_IDX)

src/tests/nativeaot/SmokeTests/HelloWasm/wasmjit-diff.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,15 @@ if ($Analyze -or $Summary)
140140

141141
if ($Llvm)
142142
{
143-
$LlvmSummaryLineRegex = [Regex]::New('define.*@"?([^"]*)"?\(.*\).*{', "Compiled")
143+
$LlvmSummaryLineRegex = [Regex]::New('define.*@"?([^"]*?)"?\(.*\).*{', "Compiled")
144144
function ParseLlvmSummary($ObjDirectory, $SummaryName)
145145
{
146146
Write-Host -NoNewLine "Analysing ${SummaryName}"
147147

148148
# Use the results file to be resilient against stale bitcode files.
149149
$SummaryList = [Collections.Generic.Dictionary[string, object]]::new()
150150
$BitcodeFiles = Get-Content "$ObjDirectory/$TestProjectName.results.txt"
151+
$BitcodeFiles = $BitcodeFiles | Where-Object { $_.EndsWith(".bc") }
151152

152153
# The results file in the 'base' directory will refer to the original ('diff') files. Fix this up.
153154
for ($i = 0; $i -lt $BitcodeFiles.Length; $i++)

0 commit comments

Comments
 (0)