Skip to content

Commit 0e19500

Browse files
committed
Address review comments
- introduced bundle operands for 32-bit vslues, - simplified demormal mode search, - updated documentation.
1 parent 22742e2 commit 0e19500

File tree

4 files changed

+146
-72
lines changed

4 files changed

+146
-72
lines changed

llvm/docs/LangRef.rst

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3114,10 +3114,25 @@ be one of the values:
31143114

31153115
::
31163116

3117-
``"ieee"`` - preserve denormals,
3118-
``"zero"`` - flush to +0.0 or -0.0 depending on value sign,
3119-
``"pzero"`` - flush to +0.0,
3120-
``"dyn"`` - concrete mode is read from some register.
3117+
"ieee" - preserve denormals,
3118+
"zero" - flush to +0.0 or -0.0 depending on value sign,
3119+
"pzero" - flush to +0.0,
3120+
"dyn" - concrete mode is read from some register.
3121+
3122+
Such bundle operand specifies denormal behavior for all floating-point types.
3123+
It is possible to override denormal behavior for specific type, if the target
3124+
supports that. Now only type "f32" allows such overriding, if a bundle operand
3125+
has prefix "denorm.f32.in=" or "denormal.f32.out=", its specifies denormal mode
3126+
for ``float`` values in the affected instruction. For example:
3127+
3128+
.. code-block:: llvm
3129+
3130+
; denormal arguments are flushed to zero preserving sign.
3131+
call float @llvm.trunc.f32(float %x) [ "fp.control"(metadata !"denorm.in=ieee", metadata !"denorm.f32.in=zero") ]
3132+
3133+
; denormal arguments are flushed to +0.0.
3134+
call float @llvm.trunc.f32(float %x) [ "fp.control"(metadata !"denorm.in=pzero") ]
3135+
31213136

31223137
An operand bundle tagged with "fp.except" may be associated with operations
31233138
that can read or write floating-point exception flags. It contains a single

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,12 +1104,15 @@ void addFPRoundingBundle(LLVMContext &Ctx,
11041104
void addFPExceptionBundle(LLVMContext &Ctx,
11051105
SmallVectorImpl<OperandBundleDef> &Bundles,
11061106
fp::ExceptionBehavior Except);
1107-
void addFPInputDenormBundle(LLVMContext &Ctx,
1108-
SmallVectorImpl<OperandBundleDef> &Bundles,
1109-
DenormalMode::DenormalModeKind Mode);
1110-
void addFPOutputDenormBundle(LLVMContext &Ctx,
1111-
SmallVectorImpl<OperandBundleDef> &Bundles,
1112-
DenormalMode::DenormalModeKind Mode);
1107+
std::optional<DenormalMode::DenormalModeKind>
1108+
getDenormModeBundle(const OperandBundleUse &Control, bool Unput,
1109+
const fltSemantics *FPSem);
1110+
void addInputDenormBundle(LLVMContext &Ctx,
1111+
SmallVectorImpl<OperandBundleDef> &Bundles,
1112+
DenormalMode::DenormalModeKind Mode);
1113+
void addOutputDenormBundle(LLVMContext &Ctx,
1114+
SmallVectorImpl<OperandBundleDef> &Bundles,
1115+
DenormalMode::DenormalModeKind Mode);
11131116

11141117
//===----------------------------------------------------------------------===//
11151118
// CallBase Class
@@ -2184,13 +2187,20 @@ class CallBase : public Instruction {
21842187
fp::ExceptionBehavior getExceptionBehavior() const;
21852188

21862189
/// Return input denormal mode specified by operand bundles.
2187-
DenormalMode::DenormalModeKind getInputDenormMode() const;
2190+
std::optional<DenormalMode::DenormalModeKind>
2191+
getInputDenormMode(const fltSemantics *FPSem = nullptr) const;
21882192

21892193
/// Return output denormal mode specified by operand bundles.
2190-
DenormalMode::DenormalModeKind getOutputDenormMode() const;
2194+
std::optional<DenormalMode::DenormalModeKind>
2195+
getOutputDenormMode(const fltSemantics *FPSem = nullptr) const;
21912196

2192-
/// Return input and output denormal modes specified by operand bundles.
2193-
DenormalMode getDenormMode() const;
2197+
/// Return input denormal mode specified by operand bundles.
2198+
std::optional<DenormalMode::DenormalModeKind>
2199+
getInputDenormModeFromBundle(const fltSemantics *FPSem = nullptr) const;
2200+
2201+
/// Return output denormal mode specified by operand bundles.
2202+
std::optional<DenormalMode::DenormalModeKind>
2203+
getOutputDenormModeFromBundle(const fltSemantics *FPSem = nullptr) const;
21942204

21952205
/// Used to keep track of an operand bundle. See the main comment on
21962206
/// OperandBundleUser above.

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,8 +3025,7 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
30253025
}
30263026
if (mayFoldConstrained(const_cast<ConstrainedFPIntrinsic *>(ConstrIntr),
30273027
St)) {
3028-
auto DenormOut = Call->getOutputDenormMode();
3029-
DenormalMode::DenormalModeKind Mode = DenormOut;
3028+
DenormalMode::DenormalModeKind Mode = *Call->getOutputDenormMode();
30303029
return flushDenormalConstant(Op2->getType(), Res, Mode);
30313030
}
30323031
return nullptr;

llvm/lib/IR/Instructions.cpp

Lines changed: 106 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -682,69 +682,96 @@ fp::ExceptionBehavior CallBase::getExceptionBehavior() const {
682682
return fp::ebIgnore;
683683
}
684684

685-
DenormalMode::DenormalModeKind CallBase::getInputDenormMode() const {
686-
if (auto InDenormBundle = getOperandBundle(LLVMContext::OB_fp_control)) {
687-
auto DenormOperand =
688-
getBundleOperandByPrefix(*InDenormBundle, "denorm.in=");
689-
if (DenormOperand) {
690-
if (auto Mode = parseDenormalKindFromOperandBundle(*DenormOperand))
691-
return *Mode;
692-
} else {
693-
return DenormalMode::IEEE;
694-
}
685+
/// Returns the input denormal behavior specified by operand bundles.
686+
///
687+
/// Searches for the bundle operand that specifies denormal behavior for the
688+
/// given type, or for any type if the argument is \a nullptr.
689+
///
690+
/// \param FPSem - pointer to the FP semantics of a call argument type. If
691+
/// \a nullptr, searches for a common denormal mode
692+
/// specification, specified by the operand with prefix
693+
/// "denorm.in=".
694+
std::optional<DenormalMode::DenormalModeKind>
695+
CallBase::getInputDenormModeFromBundle(const fltSemantics *FPSem) const {
696+
if (auto ControlBundle = getOperandBundle(LLVMContext::OB_fp_control)) {
697+
if (FPSem)
698+
if (auto Result = getDenormModeBundle(*ControlBundle, true, FPSem))
699+
return Result;
700+
if (auto Result = getDenormModeBundle(*ControlBundle, true, nullptr))
701+
return Result;
702+
}
703+
return std::nullopt;
704+
}
705+
706+
/// Returns the output denormal behavior specified by operand bundles.
707+
///
708+
/// Searches for the bundle operand that specifies denormal behavior for the
709+
/// given type, or for any type if the argument is \a nullptr.
710+
///
711+
/// \param FPSem - pointer to the FP semantics of the call result type. If
712+
/// \a nullptr, searches for a common denormal mode
713+
/// specification, specified by the operand with prefix
714+
/// "denorm.out=".
715+
std::optional<DenormalMode::DenormalModeKind>
716+
CallBase::getOutputDenormModeFromBundle(const fltSemantics *FPSem) const {
717+
if (auto ControlBundle = getOperandBundle(LLVMContext::OB_fp_control)) {
718+
if (FPSem)
719+
if (auto Result = getDenormModeBundle(*ControlBundle, false, FPSem))
720+
return Result;
721+
if (auto Result = getDenormModeBundle(*ControlBundle, false, nullptr))
722+
return Result;
695723
}
724+
return std::nullopt;
725+
}
726+
727+
/// Returns the input denormal behavior to be used for the call evaluation.
728+
///
729+
/// Searches operand bundles first for matching denormal behavior
730+
/// specifications. If not found in bundles, falls back to checking function
731+
/// attributes.
732+
///
733+
/// \param FPSem - pointer to the FP semantics of the call argument type. If
734+
/// \a nullptr, searches for a common denormal mode
735+
/// specification, using the operand with prefix "denorm.in=".
736+
std::optional<DenormalMode::DenormalModeKind>
737+
CallBase::getInputDenormMode(const fltSemantics *FPSem) const {
738+
if (auto Result = getInputDenormModeFromBundle(FPSem))
739+
return Result;
696740

697741
if (!getParent())
698-
return DenormalMode::IEEE;
742+
return std::nullopt;
699743
const Function *F = getFunction();
700744
if (!F)
701-
return DenormalMode::IEEE;
702-
703-
Type *Ty = nullptr;
704-
for (auto &A : args())
705-
if (auto *T = A.get()->getType(); T->isFPOrFPVectorTy()) {
706-
Ty = T;
707-
break;
708-
}
709-
assert(Ty && "Some input argument must be of floating-point type");
745+
return std::nullopt;
710746

711-
Ty = Ty->getScalarType();
712-
return F->getDenormalMode(Ty->getFltSemantics()).Input;
747+
if (FPSem)
748+
return F->getDenormalMode(*FPSem).Input;
749+
return F->getDenormalModeRaw().Input;
713750
}
714751

715-
DenormalMode::DenormalModeKind CallBase::getOutputDenormMode() const {
716-
if (auto InDenormBundle = getOperandBundle(LLVMContext::OB_fp_control)) {
717-
auto DenormOperand =
718-
getBundleOperandByPrefix(*InDenormBundle, "denorm.out=");
719-
if (DenormOperand) {
720-
if (auto Mode = parseDenormalKindFromOperandBundle(*DenormOperand))
721-
return *Mode;
722-
} else {
723-
return DenormalMode::IEEE;
724-
}
725-
}
752+
/// Returns the output denormal behavior to be used for the call evaluation.
753+
///
754+
/// Searches operand bundles first for matching denormal behavior
755+
/// specifications. If not found in bundles, falls back to checking function
756+
/// attributes.
757+
///
758+
/// \param FPSem - pointer to the FP semantics of the call result type. If
759+
/// \a nullptr, searches for a common denormal mode
760+
/// specification, using the operand with prefix "denorm.out=".
761+
std::optional<DenormalMode::DenormalModeKind>
762+
CallBase::getOutputDenormMode(const fltSemantics *FPSem) const {
763+
if (auto Result = getOutputDenormModeFromBundle(FPSem))
764+
return Result;
726765

727766
if (!getParent())
728-
return DenormalMode::IEEE;
767+
return std::nullopt;
729768
const Function *F = getFunction();
730769
if (!F)
731-
return DenormalMode::IEEE;
732-
733-
Type *Ty = getType();
734-
assert(Ty->isFPOrFPVectorTy() && "Unexpected output type");
735-
736-
Ty = Ty->getScalarType();
737-
return F->getDenormalMode(Ty->getFltSemantics()).Output;
738-
}
770+
return std::nullopt;
739771

740-
DenormalMode CallBase::getDenormMode() const {
741-
auto InputMode = getInputDenormMode();
742-
auto OutputMode = getOutputDenormMode();
743-
if (!InputMode)
744-
InputMode = DenormalMode::IEEE;
745-
if (!OutputMode)
746-
OutputMode = DenormalMode::IEEE;
747-
return DenormalMode(OutputMode, InputMode);
772+
if (FPSem)
773+
return F->getDenormalMode(*FPSem).Output;
774+
return F->getDenormalModeRaw().Output;
748775
}
749776

750777
MemoryEffects CallBase::getFloatingPointMemoryEffects() const {
@@ -946,9 +973,32 @@ void llvm::addFPExceptionBundle(LLVMContext &Ctx,
946973
Bundles.emplace_back("fp.except", EB);
947974
}
948975

949-
void llvm::addFPInputDenormBundle(LLVMContext &Ctx,
950-
SmallVectorImpl<OperandBundleDef> &Bundles,
951-
DenormalMode::DenormalModeKind Mode) {
976+
static StringRef getBundledDenormPrefix(const fltSemantics *FPSem, bool Input) {
977+
// Only f32 is supported now.
978+
unsigned TypeIndex = FPSem == &APFloat::IEEEsingle();
979+
if (FPSem && !TypeIndex)
980+
return StringRef();
981+
static const StringRef Prefix[2][2] = {{"denorm.out=", "denorm.in="},
982+
{"denorm.f32.out=", "denorm.f32.in="}};
983+
return Prefix[TypeIndex][Input];
984+
}
985+
986+
std::optional<DenormalMode::DenormalModeKind>
987+
llvm::getDenormModeBundle(const OperandBundleUse &Control, bool Unput,
988+
const fltSemantics *FPSem) {
989+
assert(Control.getTagID() == LLVMContext::OB_fp_control);
990+
StringRef Prefix = getBundledDenormPrefix(FPSem, true);
991+
if (Prefix.empty())
992+
return std::nullopt;
993+
auto DenormOperand = getBundleOperandByPrefix(Control, Prefix);
994+
if (DenormOperand)
995+
return parseDenormalKindFromOperandBundle(*DenormOperand);
996+
return std::nullopt;
997+
}
998+
999+
void llvm::addInputDenormBundle(LLVMContext &Ctx,
1000+
SmallVectorImpl<OperandBundleDef> &Bundles,
1001+
DenormalMode::DenormalModeKind Mode) {
9521002
std::optional<StringRef> DenormValue = printDenormalForOperandBundle(Mode);
9531003
if (!DenormValue)
9541004
return;
@@ -958,9 +1008,9 @@ void llvm::addFPInputDenormBundle(LLVMContext &Ctx,
9581008
addOperandToBundleTag(Ctx, Bundles, "fp.control", Prefix.size(), DenormItem);
9591009
}
9601010

961-
void llvm::addFPOutputDenormBundle(LLVMContext &Ctx,
962-
SmallVectorImpl<OperandBundleDef> &Bundles,
963-
DenormalMode::DenormalModeKind Mode) {
1011+
void llvm::addOutputDenormBundle(LLVMContext &Ctx,
1012+
SmallVectorImpl<OperandBundleDef> &Bundles,
1013+
DenormalMode::DenormalModeKind Mode) {
9641014
std::optional<StringRef> DenormValue = printDenormalForOperandBundle(Mode);
9651015
if (!DenormValue)
9661016
return;

0 commit comments

Comments
 (0)