@@ -1329,9 +1329,7 @@ void Llvm::buildStoreLocalField(GenTreeLclFld* lclFld)
1329
1329
1330
1330
if (lclFld->TypeIs (TYP_STRUCT) && genActualTypeIsInt (data))
1331
1331
{
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);
1335
1333
}
1336
1334
else
1337
1335
{
@@ -1931,8 +1929,7 @@ void Llvm::buildStoreBlk(GenTreeBlk* blockOp)
1931
1929
// Check for the "initblk" operation ("dataNode" is either INIT_VAL or constant zero).
1932
1930
if (blockOp->OperIsInitBlkOp ())
1933
1931
{
1934
- Value* fillValue = consumeInitVal (dataNode);
1935
- _builder.CreateMemSet (addrValue, fillValue, _builder.getInt32 (layout->GetSize ()), llvm::Align ());
1932
+ consumeInitValAndEmitInitBlk (dataNode, addrValue, layout);
1936
1933
return ;
1937
1934
}
1938
1935
@@ -2467,19 +2464,33 @@ bool Llvm::isAddressAligned(GenTree* addr, unsigned alignment)
2467
2464
return alignment == 1 ; // Any address is aligned to one byte.
2468
2465
}
2469
2466
2470
- Value* Llvm::consumeInitVal (GenTree* initVal)
2467
+ Value* Llvm::consumeInitVal (GenTree* initVal, uint8_t * pValue )
2471
2468
{
2472
2469
assert (initVal->isContained ());
2473
2470
if (initVal->IsIntegralConst ())
2474
2471
{
2475
2472
assert (initVal->IsIntegralConst (0 ));
2476
- return _builder.getInt8 (0 );
2473
+ *pValue = 0 ;
2474
+ return nullptr ;
2477
2475
}
2478
2476
2479
2477
assert (initVal->OperIsInitVal ());
2480
2478
return consumeValue (initVal->gtGetOp1 (), Type::getInt8Ty (m_context->Context ));
2481
2479
}
2482
2480
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
+
2483
2494
void Llvm::storeObjAtAddress (Value* baseAddress, Value* data, StructDesc* structDesc)
2484
2495
{
2485
2496
size_t fieldCount = structDesc->getFieldCount ();
@@ -2553,6 +2564,66 @@ unsigned Llvm::buildMemCpy(Value* baseAddress, unsigned startOffset, unsigned en
2553
2564
return size;
2554
2565
}
2555
2566
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
+
2556
2627
void Llvm::emitJumpToThrowHelper (Value* jumpCondValue, CorInfoHelpFunc helperFunc DEBUGARG (GenTree* nodeThrowing))
2557
2628
{
2558
2629
bool shadowTailCalledThrowHelper = false ;
@@ -3251,6 +3322,21 @@ Value* Llvm::gepOrAddrInBounds(Value* addr, unsigned offset)
3251
3322
return _builder.CreateInBoundsGEP (Type::getInt8Ty (m_context->Context ), addr, _builder.getInt32 (offset));
3252
3323
}
3253
3324
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
+
3254
3340
Value* Llvm::getShadowStack ()
3255
3341
{
3256
3342
if (getCurrentLlvmFunctionIndex () == ROOT_FUNC_IDX)
0 commit comments