@@ -612,6 +612,118 @@ Instruction *emitSpecConstantRecursive(Type *Ty, Instruction *InsertBefore,
612
612
613
613
} // namespace
614
614
615
+ // / Function creates load instruction from the given Buffer by the given Offset.
616
+ // / Function returns the value of load instruction.
617
+ static Value *createLoadFromBuffer (CallInst *CI, Value *Buffer, size_t Offset,
618
+ Type *SCType) {
619
+ LLVMContext &C = CI->getContext ();
620
+ Type *Int8Ty = Type::getInt8Ty (C);
621
+ Type *Int32Ty = Type::getInt32Ty (C);
622
+ GetElementPtrInst *GEP = GetElementPtrInst::Create (
623
+ Int8Ty, Buffer, {ConstantInt::get (Int32Ty, Offset, false )}, " gep" , CI);
624
+
625
+ Instruction *BitCast = nullptr ;
626
+ if (SCType->isIntegerTy (1 )) // No bitcast to i1 before load
627
+ BitCast = GEP;
628
+ else
629
+ BitCast = new BitCastInst (
630
+ GEP, PointerType::get (SCType, GEP->getAddressSpace ()), " bc" , CI);
631
+
632
+ // When we encounter i1 spec constant, we still load the whole byte
633
+ Value *Load = new LoadInst (SCType->isIntegerTy (1 ) ? Int8Ty : SCType, BitCast,
634
+ " load" , CI);
635
+ if (SCType->isIntegerTy (1 )) // trunc back to i1 if necessary
636
+ Load = CastInst::CreateIntegerCast (Load, SCType, /* IsSigned */ false ,
637
+ " tobool" , CI);
638
+
639
+ return Load;
640
+ }
641
+
642
+ // / Function tries to dig out the initializer from the given CallInst to
643
+ // / SpecConst function. ArgIndex is the expected index of the function operand
644
+ // / leading to the initializer.
645
+ // /
646
+ // / Examples:
647
+ // / 1)
648
+ // / %"spec_id" = type { i32 }
649
+ // / @value = internal addrspace(1) constant %"spec_id" { i32 123 }, align 4
650
+ // / call spir_func i32 @sycl_getScalar2020SpecConst(%1, @value, %2)
651
+ // /
652
+ // / 2)
653
+ // / %"spec_id" = type { %A }
654
+ // / %A = type { i32 }
655
+ // / @value = constant %"spec_id" { %A { i32 1 } }, align 4
656
+ // / call spir_func void @getCompositeSpecConst(%1, %2, @value, %3)
657
+ static Constant *tryGetSpecConstInitializerFromCI (CallInst *CI,
658
+ unsigned ArgIndex) {
659
+ assert (CI->getNumOperands () > ArgIndex && " ArgIndex is out of boundary" );
660
+ auto *GV = dyn_cast<GlobalVariable>(
661
+ CI->getArgOperand (ArgIndex)->stripPointerCasts ());
662
+ if (!GV)
663
+ return nullptr ;
664
+
665
+ // Go through global variable if the argument was not null.
666
+ assert (GV->hasInitializer () && " GV is expected to have initializer" );
667
+ Constant *Initializer = GV->getInitializer ();
668
+ assert ((isa<ConstantAggregate>(Initializer) || Initializer->isZeroValue ()) &&
669
+ " expected specialization_id instance" );
670
+ // specialization_id structure contains a single field which is the
671
+ // default value of corresponding specialization constant.
672
+ return Initializer->getAggregateElement (0u );
673
+ }
674
+
675
+ // / Function replaces last Metadata node in the given vector with new
676
+ // / node which contains given Padding.
677
+ static void
678
+ updatePaddingInLastMDNode (LLVMContext &Ctx,
679
+ MapVector<StringRef, MDNode *> &SCMetadata,
680
+ unsigned Padding) {
681
+ // The spec constant map can't be empty as the first offset is 0
682
+ // and so it can't be misaligned.
683
+ assert (!SCMetadata.empty () && " Cannot add padding to first spec constant" );
684
+
685
+ // To communicate the padding to the runtime, update the metadata
686
+ // node of the previous spec constant to append a padding node. It
687
+ // can't be added in front of the current spec constant, as doing
688
+ // so would require the spec constant node to have a non-zero
689
+ // CompositeOffset which breaks accessing it in the runtime.
690
+ auto Last = SCMetadata.back ();
691
+
692
+ // Emulated spec constants don't use composite so should
693
+ // always be formatted as (SymID, ID, Offset, Size), except when
694
+ // they include padding, but since padding is added at insertion
695
+ // of the next element, the last element of the map can never be
696
+ // padded.
697
+ assert (Last.second ->getNumOperands () == 4 &&
698
+ " Incorrect emulated spec constant format" );
699
+
700
+ Type *Int32Ty = Type::getInt32Ty (Ctx);
701
+ SmallVector<Metadata *, 16 > MDOps;
702
+
703
+ // Copy the existing metadata.
704
+ MDOps.push_back (Last.second ->getOperand (0 ));
705
+ MDOps.push_back (Last.second ->getOperand (1 ));
706
+ MDOps.push_back (Last.second ->getOperand (2 ));
707
+ auto &SizeOp = Last.second ->getOperand (3 );
708
+ MDOps.push_back (SizeOp);
709
+
710
+ // Extract the size of the previous node to use as CompositeOffset
711
+ // for the padding node.
712
+ auto PrevSize = mdconst::extract<ConstantInt>(SizeOp)->getValue ();
713
+
714
+ // The max value is a magic value used for padding that the
715
+ // runtime knows to skip.
716
+ MDOps.push_back (ConstantAsMetadata::get (Constant::getIntegerValue (
717
+ Int32Ty, APInt (32 , std::numeric_limits<unsigned >::max ()))));
718
+ MDOps.push_back (
719
+ ConstantAsMetadata::get (Constant::getIntegerValue (Int32Ty, PrevSize)));
720
+ MDOps.push_back (ConstantAsMetadata::get (
721
+ Constant::getIntegerValue (Int32Ty, APInt (32 , Padding))));
722
+
723
+ // Replace the last metadata node with the node including the padding.
724
+ SCMetadata[Last.first ] = MDNode::get (Ctx, MDOps);
725
+ }
726
+
615
727
PreservedAnalyses SpecConstantsPass::run (Module &M,
616
728
ModuleAnalysisManager &MAM) {
617
729
ID NextID = {0 , false };
@@ -627,6 +739,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
627
739
// setting (see below).
628
740
bool IRModified = false ;
629
741
742
+ LLVMContext &Ctx = M.getContext ();
630
743
for (Function &F : M) {
631
744
if (!F.isDeclaration ())
632
745
continue ;
@@ -665,23 +778,8 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
665
778
StringRef SymID = getStringLiteralArg (CI, NameArgNo, DelInsts);
666
779
Value *Replacement = nullptr ;
667
780
668
- Constant *DefaultValue = nullptr ;
669
- // There is a mechanism to specify the default value in SYCL 2020.
670
- // It is stored as an initializer of a global variable referenced by
671
- // the second argument of the intrinsic.
672
- auto *GV = dyn_cast<GlobalVariable>(
673
- CI->getArgOperand (NameArgNo + 1 )->stripPointerCasts ());
674
- // Go through global variable if the second argument was not null.
675
- if (GV) {
676
- assert (GV->hasInitializer () && " expected initializer" );
677
- auto *Initializer = GV->getInitializer ();
678
- assert ((isa<ConstantAggregate>(Initializer) ||
679
- Initializer->isZeroValue ()) &&
680
- " expected specialization_id instance" );
681
- // specialization_id structure contains a single field which is the
682
- // default value of corresponding specialization constant.
683
- DefaultValue = Initializer->getAggregateElement (0u );
684
- }
781
+ Constant *DefaultValue =
782
+ tryGetSpecConstInitializerFromCI (CI, NameArgNo + 1 );
685
783
686
784
bool IsNewSpecConstant = false ;
687
785
unsigned Padding = 0 ;
@@ -743,54 +841,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
743
841
OffsetMap[SymID] = NextOffset;
744
842
745
843
assert (CurrentOffset % Align == 0 && " Alignment calculation error" );
746
-
747
- // The spec constant map can't be empty as the first offset is 0
748
- // and so it can't be misaligned.
749
- assert (!SCMetadata.empty () &&
750
- " Cannot add padding to first spec constant" );
751
-
752
- // To communicate the padding to the runtime, update the metadata
753
- // node of the previous spec constant to append a padding node. It
754
- // can't be added in front of the current spec constant, as doing
755
- // so would require the spec constant node to have a non-zero
756
- // CompositeOffset which breaks accessing it in the runtime.
757
- auto Prev = SCMetadata.back ();
758
-
759
- // Emulated spec constants don't use composite so should
760
- // always be formatted as (SymID, ID, Offset, Size), except when
761
- // they include padding, but since padding is added at insertion
762
- // of the next element, the last element of the map can never be
763
- // padded.
764
- assert (Prev.second ->getNumOperands () == 4 &&
765
- " Incorrect emulated spec constant format" );
766
-
767
- LLVMContext &Ctx = M.getContext ();
768
- auto *Int32Ty = Type::getInt32Ty (Ctx);
769
- SmallVector<Metadata *, 16 > MDOps;
770
-
771
- // Copy the existing metadata.
772
- MDOps.push_back (Prev.second ->getOperand (0 ));
773
- MDOps.push_back (Prev.second ->getOperand (1 ));
774
- MDOps.push_back (Prev.second ->getOperand (2 ));
775
- auto &SizeOp = Prev.second ->getOperand (3 );
776
- MDOps.push_back (SizeOp);
777
-
778
- // Extract the size of the previous node to use as CompositeOffset
779
- // for the padding node.
780
- auto PrevSize = mdconst::extract<ConstantInt>(SizeOp)->getValue ();
781
-
782
- // The max value is a magic value used for padding that the
783
- // runtime knows to skip.
784
- MDOps.push_back (ConstantAsMetadata::get (Constant::getIntegerValue (
785
- Int32Ty, APInt (32 , std::numeric_limits<unsigned >::max ()))));
786
- MDOps.push_back (ConstantAsMetadata::get (
787
- Constant::getIntegerValue (Int32Ty, PrevSize)));
788
- MDOps.push_back (ConstantAsMetadata::get (
789
- Constant::getIntegerValue (Int32Ty, APInt (32 , Padding))));
790
-
791
- // Replace previous metadata node with the node including the
792
- // padding.
793
- SCMetadata[Prev.first ] = MDNode::get (Ctx, MDOps);
844
+ updatePaddingInLastMDNode (Ctx, SCMetadata, Padding);
794
845
}
795
846
796
847
SCMetadata[SymID] = generateSpecConstantMetadata (
@@ -800,31 +851,12 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
800
851
NextOffset += Size;
801
852
}
802
853
803
- Type *Int8Ty = Type::getInt8Ty (CI->getContext ());
804
- Type *Int32Ty = Type::getInt32Ty (CI->getContext ());
805
- GetElementPtrInst *GEP = GetElementPtrInst::Create (
806
- Int8Ty, RTBuffer, {ConstantInt::get (Int32Ty, CurrentOffset, false )},
807
- " gep" , CI);
808
-
809
- Instruction *BitCast = nullptr ;
810
- if (SCTy->isIntegerTy (1 )) // No bitcast to i1 before load
811
- BitCast = GEP;
812
- else
813
- BitCast = new BitCastInst (
814
- GEP, PointerType::get (SCTy, GEP->getAddressSpace ()), " bc" , CI);
815
-
816
- // When we encounter i1 spec constant, we still load the whole byte
817
- Replacement = new LoadInst (SCTy->isIntegerTy (1 ) ? Int8Ty : SCTy,
818
- BitCast, " load" , CI);
819
- if (SCTy->isIntegerTy (1 )) // trunc back to i1 if necessary
820
- Replacement = CastInst::CreateIntegerCast (
821
- Replacement, SCTy, /* IsSigned */ false , " tobool" , CI);
854
+ Replacement = createLoadFromBuffer (CI, RTBuffer, CurrentOffset, SCTy);
822
855
}
823
856
824
857
if (IsNewSpecConstant && DefaultValue) {
825
858
if (Padding != 0 ) {
826
859
// Initialize the padding with null data
827
- LLVMContext &Ctx = DefaultValue->getContext ();
828
860
auto PadTy = ArrayType::get (Type::getInt8Ty (Ctx), Padding);
829
861
DefaultsMetadata.push_back (MDNode::get (
830
862
Ctx,
0 commit comments