[clang] [HLSL] Add support for a simplified version of precise (PR #232534)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 15 15:48:11 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-hlsl
Author: Sarah Spall (spall)
<details>
<summary>Changes</summary>
Add support for a simplified version of precise; if precise appears anywhere in the translation unit then use IEEE-strict math mode.
Assisted by Claude Opus 5.5 and GTP Sol 6.1
Closes #<!-- -->232058
---
Patch is 27.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/232534.diff
22 Files Affected:
- (modified) clang/include/clang/AST/ASTContext.h (+5)
- (modified) clang/include/clang/Basic/Attr.td (+7)
- (modified) clang/include/clang/Basic/AttrDocs.td (+17)
- (modified) clang/include/clang/Basic/LangOptions.def (+1)
- (modified) clang/include/clang/Basic/LangOptions.h (+12-1)
- (modified) clang/include/clang/Basic/TokenKinds.def (+1)
- (modified) clang/include/clang/Sema/SemaHLSL.h (+1)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+3)
- (modified) clang/include/clang/Serialization/ASTReader.h (+3)
- (modified) clang/lib/CodeGen/ModuleBuilder.cpp (+94-2)
- (modified) clang/lib/Parse/ParseDecl.cpp (+4)
- (modified) clang/lib/Parse/ParseTentative.cpp (+2-1)
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+3)
- (modified) clang/lib/Sema/SemaHLSL.cpp (+8)
- (modified) clang/lib/Serialization/ASTReader.cpp (+10)
- (modified) clang/lib/Serialization/ASTWriter.cpp (+6)
- (added) clang/test/CodeGenHLSL/precise-pch.hlsl (+34)
- (added) clang/test/CodeGenHLSL/precise.hlsl (+59)
- (added) clang/test/ParserHLSL/precise-keyword.hlsl (+6)
- (added) clang/test/SemaHLSL/precise-ast.hlsl (+34)
- (added) clang/test/SemaHLSL/precise-errors.hlsl (+4)
- (modified) clang/unittests/Basic/LangOptionsTest.cpp (+32)
``````````diff
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 1349637273d1e7..ba78877ddf4948 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -325,6 +325,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::ContextualFoldingSet<HLSLAttributedResourceType, ASTContext &>
HLSLAttributedResourceTypes;
llvm::FoldingSet<HLSLInlineSpirvType> HLSLInlineSpirvTypes;
+ /// Whether the HLSL `precise` keyword appears in this translation unit.
+ bool HLSLPreciseUsed = false;
mutable llvm::FoldingSet<CountAttributedType> CountAttributedTypes;
@@ -2103,6 +2105,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
uint32_t Alignment,
ArrayRef<SpirvOperand> Operands);
+ void setHLSLPreciseUsed() { HLSLPreciseUsed = true; }
+ bool isHLSLPreciseUsed() const { return HLSLPreciseUsed; }
+
QualType getSubstTemplateTypeParmType(QualType Replacement,
Decl *AssociatedDecl, unsigned Index,
UnsignedOrNone PackIndex,
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index f8bd097733529a..5b4074fa184d3f 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5396,6 +5396,13 @@ def HLSLInterpolationModifier : InheritableAttr {
let Documentation = [HLSLInterpolationModifierDocs];
}
+def HLSLPrecise : InheritableAttr {
+ let Spellings = [CustomKeyword<"precise">];
+ let Subjects = SubjectList<[Var, Field, Function], ErrorDiag>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLPreciseDocs];
+}
+
def HLSLParamModifier : ParameterABIAttr {
let Spellings = [CustomKeyword<"in">, CustomKeyword<"inout">, CustomKeyword<"out">];
let Accessors = [Accessor<"isIn", [CustomKeyword<"in">]>,
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index e8ce3c3dea7f3b..a6798322c52b72 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -9434,6 +9434,23 @@ interpolation mode; their interpolation modifiers are ignored.
}];
}
+def HLSLPreciseDocs : Documentation {
+ let Category = DocCatVariable;
+ let Heading = "precise";
+ let Content = [{
+The HLSL ``precise`` keyword can be applied to variables, parameters, fields,
+and function return values to request that floating-point computations
+contributing to their values are performed with IEEE-strict semantics.
+
+Clang currently implements a simplified version of ``precise``: if the keyword
+is used anywhere in a translation unit, the whole translation unit is compiled
+in IEEE-strict floating-point mode, as if ``-Gis`` (``-ffp-model=strict``) had
+been specified.
+
+The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-syntax
+ }];
+}
+
def HLSLParamQualifierDocs : Documentation {
let Category = DocCatVariable;
let Heading = "HLSL Parameter Modifiers";
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 155d365771b836..71a59b2e4abc50 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -246,6 +246,7 @@ LANGOPT(OpenMPTargetAtomicReduction , 1, 0, NotCompatible, "Use atomic operation
LANGOPT(NoGPULib , 1, 0, NotCompatible, "Indicate a build without the standard GPU libraries.")
LANGOPT(HLSL, 1, 0, NotCompatible, "HLSL")
+LANGOPT(HLSLPrecise, 1, 0, Benign, "TU-wide HLSL precise floating-point mode")
ENUM_LANGOPT(HLSLVersion, HLSLLangStd, 16, HLSL_Unset, NotCompatible, "HLSL Version")
LANGOPT(HLSLStrictAvailability, 1, 0, NotCompatible,
"Strict availability diagnostic mode for HLSL built-in functions.")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 160c53fed49350..5253d29c18e383 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -1090,7 +1090,18 @@ class FPOptionsOverride {
}
FPOptions applyOverrides(const LangOptions &LO) {
- return applyOverrides(FPOptions(LO));
+ FPOptions Result = applyOverrides(FPOptions(LO));
+ if (LO.HLSLPrecise) {
+ // TU-wide HLSL precise mode takes precedence over unsafe FP pragmas.
+ Result.setFPContractMode(LangOptions::FPM_Off);
+ Result.setAllowFPReassociate(false);
+ Result.setNoHonorNaNs(false);
+ Result.setNoHonorInfs(false);
+ Result.setNoSignedZero(false);
+ Result.setAllowReciprocal(false);
+ Result.setAllowApproxFunc(false);
+ }
+ return Result;
}
bool operator==(FPOptionsOverride other) const {
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 528825ad68b8dc..318584cbd26df2 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -550,6 +550,7 @@ KEYWORD(centroid , KEYHLSL)
KEYWORD(noperspective , KEYHLSL)
KEYWORD(sample , KEYHLSL)
KEYWORD(center , KEYHLSL)
+KEYWORD(precise , KEYHLSL)
KEYWORD(in , KEYHLSL)
KEYWORD(inout , KEYHLSL)
KEYWORD(out , KEYHLSL)
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 3d62f47dfde691..01ade1295a8670 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -192,6 +192,7 @@ class SemaHLSL : public SemaBase {
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
void handleInterpolationModifierAttr(Decl *D, const ParsedAttr &AL);
+ void handlePreciseAttr(Decl *D, const ParsedAttr &AL);
Attr *buildMatrixLayoutTypeAttr(QualType T, const ParsedAttr &AL);
bool diagnoseMatrixLayoutInstantiation(attr::Kind K, QualType T,
SourceLocation Loc);
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index ae3a2fad6ebe7f..e05bd1d9191438 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -754,6 +754,9 @@ enum ASTRecordTypes {
/// Record code for the OpenMP 'requires' directives seen in the TU.
OMP_REQUIRES_DECLS = 81,
+
+ /// Whether the HLSL 'precise' keyword was used in the TU.
+ HLSL_PRECISE_USED = 82,
};
/// Record types used within a source manager block.
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 275383d40cf808..d10fb6c64aed78 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -983,6 +983,9 @@ class ASTReader : public ExternalPreprocessorSource,
/// The floating point pragma option settings.
SmallVector<uint64_t, 1> FPPragmaOptions;
+ /// Whether any loaded AST file used the HLSL 'precise' keyword.
+ bool HLSLPreciseUsed = false;
+
/// The pragma clang optimize location (if the pragma state is "off").
SourceLocation OptimizeOffPragmaLocation;
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index 0b00362487d2af..8803ef910dff45 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -26,6 +26,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <memory>
@@ -66,6 +67,22 @@ namespace {
std::unique_ptr<CodeGen::CodeGenModule> Builder;
SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
+ /// HLSL defers all code generation to the end of the translation unit
+ /// because a use of the `precise` keyword anywhere in it changes the
+ /// floating-point mode of the whole translation unit. The deferred
+ /// callbacks are replayed in their original order.
+ struct DeferredHLSLDecl {
+ enum KindTy { TopLevel, InlineFunction, StaticMemberVar } Kind;
+ DeclGroupRef DG;
+ };
+ SmallVector<DeferredHLSLDecl, 0> DeferredHLSLDecls;
+ bool EmittingDeferredHLSLDecls = false;
+
+ bool shouldDeferForHLSL() const {
+ return Ctx && Ctx->getLangOpts().HLSL && !IRGenFinished &&
+ !EmittingDeferredHLSLDecls;
+ }
+
static llvm::StringRef ExpandModuleName(llvm::StringRef ModuleName,
const CodeGenOptions &CGO) {
if (ModuleName == "-" && !CGO.MainFileName.empty())
@@ -182,6 +199,12 @@ namespace {
if (Diags.hasErrorOccurred())
return;
+ if (shouldDeferForHLSL()) {
+ DeferredHLSLDecls.push_back(
+ {DeferredHLSLDecl::StaticMemberVar, DeclGroupRef(VD)});
+ return;
+ }
+
Builder->HandleCXXStaticMemberVarInstantiation(VD);
}
@@ -194,13 +217,72 @@ namespace {
if (Diags.hasUnrecoverableErrorOccurred())
return true;
+ if (shouldDeferForHLSL()) {
+ DeferredHLSLDecls.push_back({DeferredHLSLDecl::TopLevel, DG});
+ return true;
+ }
+
+ EmitTopLevelDeclGroup(DG);
+ return true;
+ }
+
+ void EmitTopLevelDeclGroup(DeclGroupRef DG) {
HandlingTopLevelDeclRAII HandlingDecl(*this);
// Make sure to emit all elements of a Decl.
for (auto &I : DG)
Builder->EmitTopLevelDecl(I);
+ }
- return true;
+ /// Clang implements a simplified version of the HLSL `precise` keyword: if
+ /// it is used anywhere in the translation unit, the whole translation unit
+ /// is compiled in IEEE-strict mode, matching -Gis (-ffp-model=strict).
+ void applyHLSLPreciseFPMode() {
+ if (!Ctx->isHLSLPreciseUsed())
+ return;
+ // ASTContext refers to the CompilerInvocation's mutable LangOptions.
+ LangOptions &LO = const_cast<LangOptions &>(Ctx->getLangOpts());
+ LO.HLSLPrecise = true;
+ LO.FastMath = false;
+ LO.UnsafeFPMath = false;
+ LO.AllowFPReassoc = false;
+ LO.NoHonorNaNs = false;
+ LO.NoHonorInfs = false;
+ LO.NoSignedZero = false;
+ LO.AllowRecip = false;
+ LO.ApproxFunc = false;
+ LO.setDefaultFPContractMode(LangOptions::FPM_Off);
+ LO.setComplexRange(LangOptions::CX_Full);
+ // Like CompilerInstance::createTarget, only enable the rounding and
+ // exception modes on targets that support them.
+ if (Ctx->getTargetInfo().hasStrictFP() || LO.ExpStrictFP) {
+ LO.RoundingMath = true;
+ LO.setFPExceptionMode(LangOptions::FPE_Strict);
+ }
+ }
+
+ void EmitDeferredHLSLDecls() {
+ // Callbacks triggered while emitting are handled directly.
+ llvm::SaveAndRestore Emitting(EmittingDeferredHLSLDecls, true);
+ for (DeferredHLSLDecl &D : DeferredHLSLDecls) {
+ if (Diags.hasUnrecoverableErrorOccurred())
+ return;
+ switch (D.Kind) {
+ case DeferredHLSLDecl::TopLevel:
+ EmitTopLevelDeclGroup(D.DG);
+ break;
+ case DeferredHLSLDecl::InlineFunction:
+ DeferredInlineMemberFuncDefs.push_back(
+ cast<FunctionDecl>(D.DG.getSingleDecl()));
+ break;
+ case DeferredHLSLDecl::StaticMemberVar:
+ Builder->HandleCXXStaticMemberVarInstantiation(
+ cast<VarDecl>(D.DG.getSingleDecl()));
+ break;
+ }
+ }
+ DeferredHLSLDecls.clear();
+ EmitDeferredDecls();
}
void EmitDeferredDecls() {
@@ -230,7 +312,11 @@ namespace {
// void bar();
// void foo() { bar(); }
// } A;
- DeferredInlineMemberFuncDefs.push_back(D);
+ if (shouldDeferForHLSL())
+ DeferredHLSLDecls.push_back(
+ {DeferredHLSLDecl::InlineFunction, DeclGroupRef(D)});
+ else
+ DeferredInlineMemberFuncDefs.push_back(D);
// Provide some coverage mapping even for methods that aren't emitted.
// Don't do this for templated classes though, as they may not be
@@ -310,6 +396,12 @@ namespace {
}
void HandleTranslationUnit(ASTContext &Ctx) override {
+ if (!Diags.hasUnrecoverableErrorOccurred() && Builder &&
+ shouldDeferForHLSL()) {
+ applyHLSLPreciseFPMode();
+ EmitDeferredHLSLDecls();
+ }
+
// Release the Builder when there is no error.
if (!Diags.hasUnrecoverableErrorOccurred() && Builder)
Builder->Release();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 40249287184446..6ed82d5cdc49ff 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4702,6 +4702,7 @@ void Parser::ParseDeclarationSpecifiers(
case tok::kw_noperspective:
case tok::kw_sample:
case tok::kw_center:
+ case tok::kw_precise:
case tok::kw_groupshared:
case tok::kw_in:
case tok::kw_inout:
@@ -5873,6 +5874,7 @@ bool Parser::isTypeSpecifierQualifier(const Token &Tok) {
case tok::kw_noperspective:
case tok::kw_sample:
case tok::kw_center:
+ case tok::kw_precise:
case tok::kw_groupshared:
case tok::kw_in:
case tok::kw_inout:
@@ -6167,6 +6169,7 @@ bool Parser::isDeclarationSpecifier(
case tok::kw_noperspective:
case tok::kw_sample:
case tok::kw_center:
+ case tok::kw_precise:
case tok::kw_row_major:
case tok::kw_column_major:
return getLangOpts().HLSL;
@@ -6419,6 +6422,7 @@ void Parser::ParseTypeQualifierListOpt(
case tok::kw_noperspective:
case tok::kw_sample:
case tok::kw_center:
+ case tok::kw_precise:
// NOTE: ParseHLSLQualifiers will consume the qualifier token.
ParseHLSLQualifiers(DS.getAttributes());
continue;
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index a4581538fbcec1..11e38f5ec54e8f 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1286,13 +1286,14 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
// OpenCL pipe
case tok::kw_pipe:
- // HLSL interpolation and address space qualifiers
+ // HLSL interpolation, precise, and address space qualifiers
case tok::kw_nointerpolation:
case tok::kw_linear:
case tok::kw_centroid:
case tok::kw_noperspective:
case tok::kw_sample:
case tok::kw_center:
+ case tok::kw_precise:
case tok::kw_groupshared:
case tok::kw_in:
case tok::kw_inout:
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 33b680c4d93d4c..8292e2372d2a44 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -8328,6 +8328,9 @@ ProcessDeclAttribute(Sema &S, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLInterpolationModifier:
S.HLSL().handleInterpolationModifierAttr(D, AL);
break;
+ case ParsedAttr::AT_HLSLPrecise:
+ S.HLSL().handlePreciseAttr(D, AL);
+ break;
case ParsedAttr::AT_HLSLParamModifier:
S.HLSL().handleParamModifierAttr(D, AL);
break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 4fe7ed151e9180..716ab3d7d2a028 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -827,6 +827,14 @@ SemaHLSL::mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
return HLSLParamModifierAttr::Create(getASTContext(), AL);
}
+void SemaHLSL::handlePreciseAttr(Decl *D, const ParsedAttr &AL) {
+ // Only a simplified form of precise is supported: any use of the keyword
+ // puts the whole translation unit in IEEE-strict floating-point mode.
+ getASTContext().setHLSLPreciseUsed();
+ if (!D->hasAttr<HLSLPreciseAttr>())
+ D->addAttr(HLSLPreciseAttr::Create(getASTContext(), AL));
+}
+
void SemaHLSL::handleInterpolationModifierAttr(Decl *D, const ParsedAttr &AL) {
InterpolationModifier Modifier;
switch (static_cast<HLSLInterpolationModifierAttr::Spelling>(
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index e6f6be496e5e58..1784d6098f3b77 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -4503,6 +4503,13 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
FPPragmaOptions.swap(Record);
break;
+ case HLSL_PRECISE_USED:
+ if (Record.size() != 1)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid HLSL precise record");
+ HLSLPreciseUsed |= Record[0] != 0;
+ break;
+
case DECLS_WITH_EFFECTS_TO_VERIFY:
for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/)
DeclsWithEffectsToVerify.push_back(ReadDeclID(F, Record, I));
@@ -5764,6 +5771,9 @@ void ASTReader::InitializeContext() {
assert(ContextObj && "no context to initialize");
ASTContext &Context = *ContextObj;
+ if (HLSLPreciseUsed)
+ Context.setHLSLPreciseUsed();
+
// If there's a listener, notify them that we "read" the translation unit.
if (DeserializationListener)
DeserializationListener->DeclRead(
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 0afba1c84fd627..bd993f72e84be4 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -954,6 +954,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
RECORD(FP_PRAGMA_OPTIONS);
+ RECORD(HLSL_PRECISE_USED);
RECORD(OPENCL_EXTENSIONS);
RECORD(OPENCL_EXTENSION_TYPES);
RECORD(OPENCL_EXTENSION_DECLS);
@@ -5935,6 +5936,11 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
bool isModule = WritingModule != nullptr;
+ if (getLangOpts().HLSL) {
+ RecordData HLSLPreciseUsed = {Context.isHLSLPreciseUsed()};
+ Stream.EmitRecord(HLSL_PRECISE_USED, HLSLPreciseUsed);
+ }
+
// Write the record containing external, unnamed definitions.
if (!EagerlyDeserializedDecls.empty())
Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
diff --git a/clang/test/CodeGenHLSL/precise-pch.hlsl b/clang/test/CodeGenHLSL/precise-pch.hlsl
new file mode 100644
index 00000000000000..b64cb4e5a8b1c2
--- /dev/null
+++ b/clang/test/CodeGenHLSL/precise-pch.hlsl
@@ -0,0 +1,34 @@
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -ffp-contract=on -emit-pch -o %t/header.pch %t/header.hlsl
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -ffp-contract=on -include-pch %t/header.pch -emit-llvm -disable-llvm-passes -o - %t/source.hlsl | FileCheck %s --check-prefixes=CHECK,PRECISE --implicit-check-not=nofpclass
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -ffp-contract=on -include-pch %t/header.pch -emit-pch -o %t/chain.pch %t/chain.hlsl
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -ffp-contract=on -include-pch %t/chain.pch -emit-llvm -disable-llvm-passes -o - %t/source.hlsl | FileCheck %s --check-prefixes=CHECK,PRECISE --implicit-check-not=nofpclass
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library -ffp-contract=on -emit-pch -o %t/spirv.pch %t/header.hlsl
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library -ffp-contract=on -include-pch %t/spirv.pch -emit-llvm -disable-llvm-passes -o - %t/source.hlsl | FileCheck %s --check-prefixes=CHECK,PRECISE --implicit-check-not=nofpclass
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -ffp-contract=on -DNO_PRECISE -emit-pch -o %t/default.pch %t/header.hlsl
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -ffp-contract=on -DNO_PRECISE -include-pch %t/default.pch -emit-llvm -disable-llvm-passes -o - %t/source.hlsl | FileCheck %s --check-prefixes=CHECK,DEFAULT
+
+// CHECK-LABEL: define {{.*}}float @_Z10FromHeaderff(
+// PRECISE: %[[MUL:.*]] = fmul float
+// PRECISE: fadd float %[[MUL]],
+// DEFAULT: call {{.*}}float @llvm.fmuladd.f32(
+// CHECK-LABEL: define {{.*}}float @_Z10FromSourceff(
+// PRECISE: %[[MUL:.*]] = fmul float
+// PRECISE: fadd float %[[MUL]],
+// DEFAULT: call {{.*}}float @llvm.fmuladd.f32(
+
+//--- head...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/232534
More information about the cfe-commits
mailing list