@@ -376,6 +376,10 @@ std::optional<StaticSampler> RootSignatureParser::parseStaticSampler() {
376
376
377
377
Sampler.Reg = Params->Reg .value ();
378
378
379
+ // Fill in optional values
380
+ if (Params->MipLODBias .has_value ())
381
+ Sampler.MipLODBias = Params->MipLODBias .value ();
382
+
379
383
if (consumeExpectedToken (TokenKind::pu_r_paren,
380
384
diag::err_hlsl_unexpected_end_of_params,
381
385
/* param of=*/ TokenKind::kw_StaticSampler))
@@ -661,6 +665,23 @@ RootSignatureParser::parseStaticSamplerParams() {
661
665
return std::nullopt;
662
666
Params.Reg = Reg;
663
667
}
668
+
669
+ // `mipLODBias` `=` NUMBER
670
+ if (tryConsumeExpectedToken (TokenKind::kw_mipLODBias)) {
671
+ if (Params.MipLODBias .has_value ()) {
672
+ getDiags ().Report (CurToken.TokLoc , diag::err_hlsl_rootsig_repeat_param)
673
+ << CurToken.TokKind ;
674
+ return std::nullopt;
675
+ }
676
+
677
+ if (consumeExpectedToken (TokenKind::pu_equal))
678
+ return std::nullopt;
679
+
680
+ auto MipLODBias = parseFloatParam ();
681
+ if (!MipLODBias.has_value ())
682
+ return std::nullopt;
683
+ Params.MipLODBias = MipLODBias;
684
+ }
664
685
} while (tryConsumeExpectedToken (TokenKind::pu_comma));
665
686
666
687
return Params;
@@ -709,6 +730,39 @@ std::optional<Register> RootSignatureParser::parseRegister() {
709
730
return Reg;
710
731
}
711
732
733
+ std::optional<float > RootSignatureParser::parseFloatParam () {
734
+ assert (CurToken.TokKind == TokenKind::pu_equal &&
735
+ " Expects to only be invoked starting at given keyword" );
736
+ // Consume sign modifier
737
+ bool Signed =
738
+ tryConsumeExpectedToken ({TokenKind::pu_plus, TokenKind::pu_minus});
739
+ bool Negated = Signed && CurToken.TokKind == TokenKind::pu_minus;
740
+
741
+ // DXC will treat a postive signed integer as unsigned
742
+ if (!Negated && tryConsumeExpectedToken (TokenKind::int_literal)) {
743
+ std::optional<uint32_t > UInt = handleUIntLiteral ();
744
+ if (!UInt.has_value ())
745
+ return std::nullopt;
746
+ return float (UInt.value ());
747
+ }
748
+
749
+ if (Negated && tryConsumeExpectedToken (TokenKind::int_literal)) {
750
+ std::optional<int32_t > Int = handleIntLiteral (Negated);
751
+ if (!Int.has_value ())
752
+ return std::nullopt;
753
+ return float (Int.value ());
754
+ }
755
+
756
+ if (tryConsumeExpectedToken (TokenKind::float_literal)) {
757
+ std::optional<float > Float = handleFloatLiteral (Negated);
758
+ if (!Float.has_value ())
759
+ return std::nullopt;
760
+ return Float.value ();
761
+ }
762
+
763
+ return std::nullopt;
764
+ }
765
+
712
766
std::optional<llvm::hlsl::rootsig::ShaderVisibility>
713
767
RootSignatureParser::parseShaderVisibility () {
714
768
assert (CurToken.TokKind == TokenKind::pu_equal &&
@@ -819,22 +873,121 @@ std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() {
819
873
PP.getSourceManager (), PP.getLangOpts (),
820
874
PP.getTargetInfo (), PP.getDiagnostics ());
821
875
if (Literal.hadError )
822
- return true ; // Error has already been reported so just return
876
+ return std::nullopt ; // Error has already been reported so just return
823
877
824
- assert (Literal.isIntegerLiteral () && " IsNumberChar will only support digits" );
878
+ assert (Literal.isIntegerLiteral () &&
879
+ " NumSpelling can only consist of digits" );
825
880
826
- llvm::APSInt Val = llvm::APSInt (32 , false );
881
+ llvm::APSInt Val (32 , /* IsUnsigned= */ true );
827
882
if (Literal.GetIntegerValue (Val)) {
828
883
// Report that the value has overflowed
829
884
PP.getDiagnostics ().Report (CurToken.TokLoc ,
830
885
diag::err_hlsl_number_literal_overflow)
831
- << 0 << CurToken. NumSpelling ;
886
+ << /* integer type */ 0 << /* is signed */ 0 ;
832
887
return std::nullopt;
833
888
}
834
889
835
890
return Val.getExtValue ();
836
891
}
837
892
893
+ std::optional<int32_t > RootSignatureParser::handleIntLiteral (bool Negated) {
894
+ // Parse the numeric value and do semantic checks on its specification
895
+ clang::NumericLiteralParser Literal (CurToken.NumSpelling , CurToken.TokLoc ,
896
+ PP.getSourceManager (), PP.getLangOpts (),
897
+ PP.getTargetInfo (), PP.getDiagnostics ());
898
+ if (Literal.hadError )
899
+ return std::nullopt; // Error has already been reported so just return
900
+
901
+ assert (Literal.isIntegerLiteral () &&
902
+ " NumSpelling can only consist of digits" );
903
+
904
+ llvm::APSInt Val (32 , /* IsUnsigned=*/ true );
905
+ // GetIntegerValue will overwrite Val from the parsed Literal and return
906
+ // true if it overflows as a 32-bit unsigned int
907
+ bool Overflowed = Literal.GetIntegerValue (Val);
908
+
909
+ // So we then need to check that it doesn't overflow as a 32-bit signed int:
910
+ int64_t MaxNegativeMagnitude = -int64_t (std::numeric_limits<int32_t >::min ());
911
+ Overflowed |= (Negated && MaxNegativeMagnitude < Val.getExtValue ());
912
+
913
+ int64_t MaxPositiveMagnitude = int64_t (std::numeric_limits<int32_t >::max ());
914
+ Overflowed |= (!Negated && MaxPositiveMagnitude < Val.getExtValue ());
915
+
916
+ if (Overflowed) {
917
+ // Report that the value has overflowed
918
+ PP.getDiagnostics ().Report (CurToken.TokLoc ,
919
+ diag::err_hlsl_number_literal_overflow)
920
+ << /* integer type*/ 0 << /* is signed*/ 1 ;
921
+ return std::nullopt;
922
+ }
923
+
924
+ if (Negated)
925
+ Val = -Val;
926
+
927
+ return int32_t (Val.getExtValue ());
928
+ }
929
+
930
+ std::optional<float > RootSignatureParser::handleFloatLiteral (bool Negated) {
931
+ // Parse the numeric value and do semantic checks on its specification
932
+ clang::NumericLiteralParser Literal (CurToken.NumSpelling , CurToken.TokLoc ,
933
+ PP.getSourceManager (), PP.getLangOpts (),
934
+ PP.getTargetInfo (), PP.getDiagnostics ());
935
+ if (Literal.hadError )
936
+ return std::nullopt; // Error has already been reported so just return
937
+
938
+ assert (Literal.isFloatingLiteral () &&
939
+ " NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
940
+ " will be caught and reported by NumericLiteralParser." );
941
+
942
+ // DXC used `strtod` to convert the token string to a float which corresponds
943
+ // to:
944
+ auto DXCSemantics = llvm::APFloat::Semantics::S_IEEEdouble;
945
+ auto DXCRoundingMode = llvm::RoundingMode::NearestTiesToEven;
946
+
947
+ llvm::APFloat Val (llvm::APFloat::EnumToSemantics (DXCSemantics));
948
+ llvm::APFloat::opStatus Status (Literal.GetFloatValue (Val, DXCRoundingMode));
949
+
950
+ // Note: we do not error when opStatus::opInexact by itself as this just
951
+ // denotes that rounding occured but not that it is invalid
952
+ assert (!(Status & llvm::APFloat::opStatus::opInvalidOp) &&
953
+ " NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
954
+ " will be caught and reported by NumericLiteralParser." );
955
+
956
+ assert (!(Status & llvm::APFloat::opStatus::opDivByZero) &&
957
+ " It is not possible for a division to be performed when "
958
+ " constructing an APFloat from a string" );
959
+
960
+ if (Status & llvm::APFloat::opStatus::opUnderflow) {
961
+ // Report that the value has underflowed
962
+ PP.getDiagnostics ().Report (CurToken.TokLoc ,
963
+ diag::err_hlsl_number_literal_underflow);
964
+ return std::nullopt;
965
+ }
966
+
967
+ if (Status & llvm::APFloat::opStatus::opOverflow) {
968
+ // Report that the value has overflowed
969
+ PP.getDiagnostics ().Report (CurToken.TokLoc ,
970
+ diag::err_hlsl_number_literal_overflow)
971
+ << /* float type*/ 1 ;
972
+ return std::nullopt;
973
+ }
974
+
975
+ if (Negated)
976
+ Val = -Val;
977
+
978
+ double DoubleVal = Val.convertToDouble ();
979
+ double FloatMax = double (std::numeric_limits<float >::max ());
980
+ if (FloatMax < DoubleVal || DoubleVal < -FloatMax) {
981
+ // Report that the value has overflowed
982
+ PP.getDiagnostics ().Report (CurToken.TokLoc ,
983
+ diag::err_hlsl_number_literal_overflow)
984
+ << /* float type*/ 1 ;
985
+ return std::nullopt;
986
+ }
987
+
988
+ return static_cast <float >(DoubleVal);
989
+ }
990
+
838
991
bool RootSignatureParser::verifyZeroFlag () {
839
992
assert (CurToken.TokKind == TokenKind::int_literal);
840
993
auto X = handleUIntLiteral ();
0 commit comments