@@ -421,6 +421,110 @@ static llvm::Value *computeExtraTagBytes(IRGenFunction &IGF, IRBuilder &Builder,
421
421
return phi;
422
422
}
423
423
424
+ // / Emit a specialized memory operation for a \p size of 0, 1, 2 or
425
+ // / 4 bytes.
426
+ // / \p emitMemOpFn will be called in a basic block where \p size is
427
+ // / a known constant value passed as a parameter to the function.
428
+ static void emitSpecializedMemOperation (
429
+ IRGenFunction &IGF,
430
+ llvm::function_ref<void (IRBuilder &, Size)> emitMemOpFn,
431
+ llvm::Value *size) {
432
+ auto &Ctx = IGF.IGM .getLLVMContext ();
433
+ auto &Builder = IGF.Builder ;
434
+
435
+ // Sizes to try. Tested in order.
436
+ const auto sizes = std::array<Size, 4 >{
437
+ Size (0 ),
438
+ Size (1 ),
439
+ Size (2 ),
440
+ Size (4 ),
441
+ };
442
+
443
+ // Block to jump to after successful match.
444
+ auto *returnBB = llvm::BasicBlock::Create (Ctx);
445
+
446
+ // Test all the sizes in turn, generating code similar to:
447
+ //
448
+ // if (size == 0) {
449
+ // <op>
450
+ // } else if (size == 1) {
451
+ // <op>
452
+ // } else if (size == 2) {
453
+ // <op>
454
+ // } else if (size == 4) {
455
+ // <op>
456
+ // } else {
457
+ // <unreachable>
458
+ // }
459
+ //
460
+ for (const Size &s : sizes) {
461
+ auto *matchBB = llvm::BasicBlock::Create (Ctx);
462
+ auto *nextBB = llvm::BasicBlock::Create (Ctx);
463
+
464
+ // Check if size matches.
465
+ auto *imm = Builder.getInt32 (s.getValue ());
466
+ auto *cmp = Builder.CreateICmpEQ (size, imm);
467
+ Builder.CreateCondBr (cmp, matchBB, nextBB);
468
+
469
+ // Size matches: execute sized operation.
470
+ Builder.emitBlock (matchBB);
471
+ emitMemOpFn (Builder, s);
472
+ Builder.CreateBr (returnBB);
473
+
474
+ // Size does not match: try next size.
475
+ Builder.emitBlock (nextBB);
476
+ }
477
+ // No size matched. Should never happen.
478
+ Builder.CreateUnreachable ();
479
+
480
+ // Continue.
481
+ Builder.emitBlock (returnBB);
482
+ }
483
+
484
+ // / Emit a load of a \p size byte integer value zero extended to 4 bytes.
485
+ // / \p size may be 0, 1, 2 or 4.
486
+ static llvm::Value *emitGetTag (IRGenFunction &IGF,
487
+ Address from,
488
+ llvm::Value *size) {
489
+ auto *phi = llvm::PHINode::Create (IGF.IGM .Int32Ty , 4 );
490
+ emitSpecializedMemOperation (IGF,
491
+ [=](IRBuilder &B, Size s) {
492
+ if (s == Size (0 )) {
493
+ // If the size is 0 bytes return 0.
494
+ phi->addIncoming (B.getInt32 (0 ), B.GetInsertBlock ());
495
+ return ;
496
+ }
497
+ // Generate a load of size bytes and zero-extend it to 32-bits.
498
+ auto *type = B.getIntNTy (s.getValueInBits ());
499
+ Address addr = B.CreateBitCast (from, type->getPointerTo ());
500
+ auto *val = B.CreateZExtOrTrunc (B.CreateLoad (addr), B.getInt32Ty ());
501
+ phi->addIncoming (val, B.GetInsertBlock ());
502
+ },
503
+ size);
504
+ IGF.Builder .Insert (phi);
505
+ return phi;
506
+ }
507
+
508
+ // / Emit a store of \p val truncated to \p size bytes.
509
+ // / \p size may be 0, 1, 2 or 4.
510
+ static void emitSetTag (IRGenFunction &IGF,
511
+ Address to, llvm::Value *val,
512
+ llvm::Value *size) {
513
+ emitSpecializedMemOperation (IGF,
514
+ [=](IRBuilder &B, Size s) {
515
+ if (s == Size (0 )) {
516
+ // Nothing to store.
517
+ return ;
518
+ }
519
+ // Store value truncated to size bytes.
520
+ auto *type = B.getIntNTy (s.getValueInBits ());
521
+ auto *trunc = B.CreateZExtOrTrunc (val, type);
522
+ Address addr = B.CreateBitCast (to, type->getPointerTo ());
523
+ B.CreateStore (trunc, addr);
524
+ },
525
+ size);
526
+ }
527
+
424
528
llvm::Value *FixedTypeInfo::getEnumTagSinglePayload (IRGenFunction &IGF,
425
529
llvm::Value *numEmptyCases,
426
530
Address enumAddr,
@@ -467,26 +571,21 @@ llvm::Value *irgen::getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
467
571
468
572
// There are extra tag bits to check.
469
573
Builder.emitBlock (extraTagBitsBB);
470
- Address extraTagBitsSlot = IGF.createAlloca (IGM.Int32Ty , Alignment (4 ));
471
- Builder.CreateStore (zero, extraTagBitsSlot);
472
574
473
575
// Compute the number of extra tag bytes.
474
576
auto *emptyCases = Builder.CreateSub (numEmptyCases, numExtraInhabitants);
475
577
auto *numExtraTagBytes =
476
578
computeExtraTagBytes (IGF, Builder, fixedSize, emptyCases);
477
579
478
- // Read the extra tag bytes.
580
+ // Read the value stored in the extra tag bytes.
479
581
auto *valueAddr =
480
582
Builder.CreateBitOrPointerCast (enumAddr.getAddress (), IGM.Int8PtrTy );
481
583
auto *extraTagBitsAddr =
482
584
Builder.CreateConstInBoundsGEP1_32 (IGM.Int8Ty , valueAddr,
483
- fixedSize.getValue ());
484
-
485
- // TODO: big endian.
486
- Builder.CreateMemCpy (
487
- Builder.CreateBitCast (extraTagBitsSlot, IGM.Int8PtrTy ).getAddress (), 1 ,
488
- extraTagBitsAddr, 1 , numExtraTagBytes);
489
- auto extraTagBits = Builder.CreateLoad (extraTagBitsSlot);
585
+ fixedSize.getValue ());
586
+ auto *extraTagBits = emitGetTag (IGF,
587
+ Address (extraTagBitsAddr, Alignment (1 )),
588
+ numExtraTagBytes);
490
589
491
590
extraTagBitsBB = llvm::BasicBlock::Create (Ctx);
492
591
Builder.CreateCondBr (Builder.CreateICmpEQ (extraTagBits, zero),
@@ -497,20 +596,25 @@ llvm::Value *irgen::getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
497
596
Builder.emitBlock (extraTagBitsBB);
498
597
499
598
auto *truncSize = Builder.CreateZExtOrTrunc (size, IGM.Int32Ty );
500
- Address caseIndexFromValueSlot = IGF.createAlloca (IGM.Int32Ty , Alignment (4 ));
501
- Builder.CreateStore (zero, caseIndexFromValueSlot);
502
599
503
600
auto *caseIndexFromExtraTagBits = Builder.CreateSelect (
504
601
Builder.CreateICmpUGE (truncSize, four), zero,
505
602
Builder.CreateShl (Builder.CreateSub (extraTagBits, one),
506
603
Builder.CreateMul (eight, truncSize)));
507
604
508
- // TODO: big endian.
509
- Builder.CreateMemCpy (
510
- Builder.CreateBitCast (caseIndexFromValueSlot, IGM.Int8PtrTy ),
511
- Address (valueAddr, Alignment (1 )),
512
- std::min (Size (4U ), fixedSize));
513
- auto caseIndexFromValue = Builder.CreateLoad (caseIndexFromValueSlot);
605
+ llvm::Value *caseIndexFromValue = zero;
606
+ if (fixedSize > Size (0 )) {
607
+ // Read up to one pointer-sized 'chunk' of the payload.
608
+ // The size of the chunk does not have to be a power of 2.
609
+ Size limit = IGM.getPointerSize ();
610
+ auto *caseIndexType = llvm::IntegerType::get (Ctx,
611
+ std::min (limit, fixedSize).getValueInBits ());
612
+ auto *caseIndexAddr = Builder.CreateBitCast (valueAddr,
613
+ caseIndexType->getPointerTo ());
614
+ caseIndexFromValue = Builder.CreateZExtOrTrunc (
615
+ Builder.CreateLoad (Address (caseIndexAddr, Alignment (1 ))),
616
+ IGM.Int32Ty );
617
+ }
514
618
515
619
auto *result1 = Builder.CreateAdd (
516
620
numExtraInhabitants,
@@ -544,72 +648,6 @@ llvm::Value *irgen::getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
544
648
return Builder.CreateAdd (result, llvm::ConstantInt::get (IGM.Int32Ty , 1 ));
545
649
}
546
650
547
- // / Emit a speciaize memory operation for a \p size of 0 to 4 bytes.
548
- static void emitSpecializedMemOperation (
549
- IRGenFunction &IGF,
550
- llvm::function_ref<void (IRBuilder &, Size)> emitMemOpFn,
551
- llvm::Value *size) {
552
- auto &IGM = IGF.IGM ;
553
- auto &Ctx = IGF.IGM .getLLVMContext ();
554
- auto &Builder = IGF.Builder ;
555
- auto *returnBB = llvm::BasicBlock::Create (Ctx);
556
- auto *oneBB = llvm::BasicBlock::Create (Ctx);
557
- auto *twoBB = llvm::BasicBlock::Create (Ctx);
558
- auto *fourBB = llvm::BasicBlock::Create (Ctx);
559
- auto *int32Ty = IGM.Int32Ty ;
560
- auto *zero = llvm::ConstantInt::get (int32Ty, 0U );
561
- auto *one = llvm::ConstantInt::get (int32Ty, 1U );
562
- auto *two = llvm::ConstantInt::get (int32Ty, 2U );
563
-
564
- auto *continueBB = llvm::BasicBlock::Create (Ctx);
565
- auto *isZero = Builder.CreateICmpEQ (size, zero);
566
- Builder.CreateCondBr (isZero, returnBB, continueBB);
567
-
568
- Builder.emitBlock (continueBB);
569
- continueBB = llvm::BasicBlock::Create (Ctx);
570
- auto *isOne = Builder.CreateICmpEQ (size, one);
571
- Builder.CreateCondBr (isOne, oneBB, continueBB);
572
-
573
- Builder.emitBlock (continueBB);
574
- auto *isTwo = Builder.CreateICmpEQ (size, two);
575
- Builder.CreateCondBr (isTwo, twoBB, fourBB);
576
-
577
- Builder.emitBlock (oneBB);
578
- emitMemOpFn (Builder, Size (1 ));
579
- Builder.CreateBr (returnBB);
580
-
581
- Builder.emitBlock (twoBB);
582
- emitMemOpFn (Builder, Size (2 ));
583
- Builder.CreateBr (returnBB);
584
-
585
- Builder.emitBlock (fourBB);
586
- emitMemOpFn (Builder, Size (4 ));
587
- Builder.CreateBr (returnBB);
588
-
589
- Builder.emitBlock (returnBB);
590
- }
591
-
592
- // / Emit a memset of zero operation for a \p size of 0 to 4 bytes.
593
- static void emitMemZero (IRGenFunction &IGF, Address addr,
594
- llvm::Value *size) {
595
- auto *zeroByte = llvm::ConstantInt::get (IGF.IGM .Int8Ty , 0U );
596
- emitSpecializedMemOperation (IGF,
597
- [=](IRBuilder &B, Size numBytes) {
598
- B.CreateMemSet (addr, zeroByte, numBytes);
599
- },
600
- size);
601
- }
602
-
603
- // / Emit a memcpy operation for a \p size of 0 to 4 bytes.
604
- static void emitMemCpy (IRGenFunction &IGF, Address to, Address from,
605
- llvm::Value *size) {
606
- emitSpecializedMemOperation (IGF,
607
- [=](IRBuilder &B, Size numBytes) {
608
- B.CreateMemCpy (to, from, numBytes);
609
- },
610
- size);
611
- }
612
-
613
651
void FixedTypeInfo::storeEnumTagSinglePayload (IRGenFunction &IGF,
614
652
llvm::Value *whichCase,
615
653
llvm::Value *numEmptyCases,
@@ -679,7 +717,7 @@ void irgen::storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
679
717
// We are the payload or fit within the extra inhabitants.
680
718
Builder.emitBlock (isPayloadOrInhabitantCaseBB);
681
719
// Zero the tag bits.
682
- emitMemZero (IGF, extraTagBitsAddr, numExtraTagBytes);
720
+ emitSetTag (IGF, extraTagBitsAddr, zero , numExtraTagBytes);
683
721
isPayloadOrInhabitantCaseBB = Builder.GetInsertBlock ();
684
722
auto *storeInhabitantBB = llvm::BasicBlock::Create (Ctx);
685
723
auto *returnBB = llvm::BasicBlock::Create (Ctx);
@@ -729,21 +767,28 @@ void irgen::storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
729
767
payloadIndex->addIncoming (caseIndex, payloadGE4BB);
730
768
payloadIndex->addIncoming (payloadIndex0, payloadLT4BB);
731
769
732
- Address payloadIndexAddr = IGF.createAlloca (int32Ty, Alignment (4 ));
733
- Builder.CreateStore (payloadIndex, payloadIndexAddr);
734
- Address extraTagIndexAddr = IGF.createAlloca (int32Ty, Alignment (4 ));
735
- Builder.CreateStore (extraTagIndex, extraTagIndexAddr);
736
- // TODO: big endian
737
- Builder.CreateMemCpy (
738
- valueAddr,
739
- Builder.CreateBitCast (payloadIndexAddr, IGM.Int8PtrTy ),
740
- std::min (Size (4U ), fixedSize));
741
- Address extraZeroAddr = Builder.CreateConstByteArrayGEP (valueAddr, Size (4 ));
742
- if (fixedSize > Size (4 ))
743
- Builder.CreateMemSet (
744
- extraZeroAddr, llvm::ConstantInt::get (IGM.Int8Ty , 0 ),
745
- Builder.CreateSub (size, llvm::ConstantInt::get (size->getType (), 4 )));
746
- emitMemCpy (IGF, extraTagBitsAddr, extraTagIndexAddr, numExtraTagBytes);
770
+ if (fixedSize > Size (0 )) {
771
+ // Write the value into the first pointer-sized (or smaller)
772
+ // 'chunk' of the payload.
773
+ // The size of the chunk does not have to be a power of 2.
774
+ Size limit = IGM.getPointerSize ();
775
+ auto *chunkType = Builder.getIntNTy (
776
+ std::min (fixedSize, limit).getValueInBits ());
777
+ Builder.CreateStore (
778
+ Builder.CreateZExtOrTrunc (payloadIndex, chunkType),
779
+ Builder.CreateBitCast (valueAddr, chunkType->getPointerTo ()));
780
+
781
+ // Zero the remainder of the payload.
782
+ if (fixedSize > limit) {
783
+ auto zeroAddr = Builder.CreateConstByteArrayGEP (valueAddr, limit);
784
+ auto zeroSize = Builder.CreateSub (
785
+ size,
786
+ llvm::ConstantInt::get (size->getType (), limit.getValue ()));
787
+ Builder.CreateMemSet (zeroAddr, Builder.getInt8 (0 ), zeroSize);
788
+ }
789
+ }
790
+ // Write to the extra tag bytes, if any.
791
+ emitSetTag (IGF, extraTagBitsAddr, extraTagIndex, numExtraTagBytes);
747
792
Builder.CreateBr (returnBB);
748
793
749
794
Builder.emitBlock (returnBB);
0 commit comments