Index: llvm/include/llvm-c/Core.h =================================================================== --- llvm/include/llvm-c/Core.h +++ llvm/include/llvm-c/Core.h @@ -274,6 +274,8 @@ LLVMConstantIntValueKind, LLVMConstantFPValueKind, LLVMConstantPointerNullValueKind, + LLVMConstantTokenFPRoundValueKind, + LLVMConstantTokenFPExceptValueKind, LLVMConstantTokenNoneValueKind, LLVMMetadataAsValueValueKind, Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -363,7 +363,9 @@ CST_CODE_INLINEASM = 23, // INLINEASM: [sideeffect|alignstack| // asmdialect,asmstr,conststr] CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x operands] - CST_CODE_CE_UNOP = 25, // CE_UNOP: [opcode, opval] + CST_CODE_CE_UNOP = 25, // CE_UNOP: [opcode, opval] + CST_CODE_FPROUND = 26, // CE_FPROUND: [opcode, opval] + CST_CODE_FPEXCEPT = 27, // CE_FPEXCEPT: [opcode, opval] }; /// CastOpcodes - These are values used in the bitcode files to encode which Index: llvm/include/llvm/IR/Constants.h =================================================================== --- llvm/include/llvm/IR/Constants.h +++ llvm/include/llvm/IR/Constants.h @@ -30,6 +30,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/OperandTraits.h" +#include "llvm/IR/FPEnv.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" @@ -834,6 +835,64 @@ } }; +//===----------------------------------------------------------------------===// +/// A constant token that represents floating point rounding mode +/// +class ConstantTokenFPRound final : public ConstantData { + friend class Constant; + + explicit ConstantTokenFPRound(LLVMContext &Context, fp::RoundingMode RM) + : ConstantData(Type::getTokenTy(Context), ConstantTokenFPRoundVal), + RM(RM) {} + + void destroyConstantImpl(); + + fp::RoundingMode RM; + +public: + ConstantTokenFPRound(const ConstantTokenFPRound &) = delete; + + fp::RoundingMode getRoundingMode() const { return RM; } + + /// Return the ConstantTokenFPRound for the given rounding mode. + static ConstantTokenFPRound *get(LLVMContext &Context, fp::RoundingMode RM); + + /// Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return V->getValueID() == ConstantTokenFPRoundVal; + } +}; + +//===----------------------------------------------------------------------===// +/// A constant token that represents floating point exception semantics +/// +class ConstantTokenFPExcept final : public ConstantData { + friend class Constant; + + explicit ConstantTokenFPExcept(LLVMContext &Context, + fp::ExceptionBehavior EB) + : ConstantData(Type::getTokenTy(Context), ConstantTokenFPExceptVal), + EB(EB) {} + + void destroyConstantImpl(); + + fp::ExceptionBehavior EB; + +public: + ConstantTokenFPExcept(const ConstantTokenFPExcept &) = delete; + + fp::ExceptionBehavior getExceptionBehavior() const { return EB; } + + /// Return the ConstantTokenFPExcept for the given exception behavior. + static ConstantTokenFPExcept *get(LLVMContext &Context, + fp::ExceptionBehavior EB); + + /// Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return V->getValueID() == ConstantTokenFPExceptVal; + } +}; + /// The address of a basic block. /// class BlockAddress final : public Constant { Index: llvm/include/llvm/IR/FPEnv.h =================================================================== --- /dev/null +++ llvm/include/llvm/IR/FPEnv.h @@ -0,0 +1,72 @@ +//===- FPEnv.h ---- FP Environment ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// @file +/// This file contains the declarations of entities that describe floating +/// point environment and related functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_FPENV_H +#define LLVM_IR_FPENV_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace llvm { + +namespace fp { + +/// Rounding mode used for floating point operations. +/// +/// Each of these values correspond to some metadata argument value of a +/// constrained floating point intrinsic. See the LLVM Language Reference Manual +/// for details. +enum RoundingMode : uint8_t { + rmDynamic, ///< This corresponds to "fpround.dynamic". + rmToNearest, ///< This corresponds to "fpround.tonearest". + rmDownward, ///< This corresponds to "fpround.downward". + rmUpward, ///< This corresponds to "fpround.upward". + rmTowardZero, ///< This corresponds to "fpround.tozero". + numRoundingModes +}; + +/// Exception behavior used for floating point operations. +/// +/// Each of these values correspond to some metadata argument value of a +/// constrained floating point intrinsic. See the LLVM Language Reference Manual +/// for details. +enum ExceptionBehavior : uint8_t { + ebIgnore, ///< This corresponds to "fpexcept.ignore". + ebMayTrap, ///< This corresponds to "fpexcept.maytrap". + ebStrict, ///< This corresponds to "fpexcept.strict". + numExceptionBehaviors +}; + +} + +/// Returns a valid RoundingMode enumerator when given a string +/// that is valid as input in constrained intrinsic rounding mode +/// metadata. +Optional StrToRoundingMode(StringRef); + +/// For any RoundingMode enumerator, returns a string valid as input in +/// constrained intrinsic rounding mode metadata. +Optional RoundingModeToStr(fp::RoundingMode); + +/// Returns a valid ExceptionBehavior enumerator when given a string +/// valid as input in constrained intrinsic exception behavior metadata. +Optional StrToExceptionBehavior(StringRef); + +/// For any ExceptionBehavior enumerator, returns a string valid as +/// input in constrained intrinsic exception behavior metadata. +Optional ExceptionBehaviorToStr(fp::ExceptionBehavior); + +} +#endif \ No newline at end of file Index: llvm/include/llvm/IR/Value.def =================================================================== --- llvm/include/llvm/IR/Value.def +++ llvm/include/llvm/IR/Value.def @@ -79,6 +79,8 @@ HANDLE_CONSTANT(ConstantInt) HANDLE_CONSTANT(ConstantFP) HANDLE_CONSTANT(ConstantPointerNull) +HANDLE_CONSTANT(ConstantTokenFPRound) +HANDLE_CONSTANT(ConstantTokenFPExcept) HANDLE_CONSTANT(ConstantTokenNone) HANDLE_CONSTANT_MARKER(ConstantFirstVal, Function) Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -802,6 +802,18 @@ KEYWORD(bit); KEYWORD(varFlags); + // Floating point rounding mode keywords + KEYWORD(rmDynamic); + KEYWORD(rmToNearest); + KEYWORD(rmDownward); + KEYWORD(rmUpward); + KEYWORD(rmTowardZero); + + // Floating point exception behavior keywords + KEYWORD(ebIgnore); + KEYWORD(ebMayTrap); + KEYWORD(ebStrict); + #undef KEYWORD // Keywords for types. Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -3108,6 +3108,40 @@ case lltok::kw_zeroinitializer: ID.Kind = ValID::t_Zero; break; case lltok::kw_none: ID.Kind = ValID::t_None; break; + case lltok::kw_rmDynamic: + ID.ConstantVal = ConstantTokenFPRound::get(Context, fp::rmDynamic); + ID.Kind = ValID::t_Constant; + break; + case lltok::kw_rmToNearest: + ID.ConstantVal = ConstantTokenFPRound::get(Context, fp::rmToNearest); + ID.Kind = ValID::t_Constant; + break; + case lltok::kw_rmDownward: + ID.ConstantVal = ConstantTokenFPRound::get(Context, fp::rmDownward); + ID.Kind = ValID::t_Constant; + break; + case lltok::kw_rmUpward: + ID.ConstantVal = ConstantTokenFPRound::get(Context, fp::rmUpward); + ID.Kind = ValID::t_Constant; + break; + case lltok::kw_rmTowardZero: + ID.ConstantVal = ConstantTokenFPRound::get(Context, fp::rmTowardZero); + ID.Kind = ValID::t_Constant; + break; + + case lltok::kw_ebIgnore: + ID.ConstantVal = ConstantTokenFPExcept::get(Context, fp::ebIgnore); + ID.Kind = ValID::t_Constant; + break; + case lltok::kw_ebMayTrap: + ID.ConstantVal = ConstantTokenFPExcept::get(Context, fp::ebMayTrap); + ID.Kind = ValID::t_Constant; + break; + case lltok::kw_ebStrict: + ID.ConstantVal = ConstantTokenFPExcept::get(Context, fp::ebStrict); + ID.Kind = ValID::t_Constant; + break; + case lltok::lbrace: { // ValID ::= '{' ConstVector '}' Lex.Lex(); Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -434,6 +434,18 @@ kw_bit, kw_varFlags, + // FP rounding modes + kw_rmDynamic, + kw_rmToNearest, + kw_rmDownward, + kw_rmUpward, + kw_rmTowardZero, + + // FP exception behaviors + kw_ebIgnore, + kw_ebMayTrap, + kw_ebStrict, + // Unsigned Valued tokens (UIntVal). LabelID, // 42: GlobalID, // @42 Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2378,6 +2378,18 @@ return error("Invalid type for a constant null value"); V = Constant::getNullValue(CurTy); break; + case bitc::CST_CODE_FPROUND: // FPROUND: [intval] + if (!CurTy->isTokenTy() || Record.empty()) + return error("Invalid record"); + V = ConstantTokenFPRound::get(Context, + static_cast(Record[0])); + break; + case bitc::CST_CODE_FPEXCEPT: // FPEXCEPT: [intval] + if (!CurTy->isTokenTy() || Record.empty()) + return error("Invalid record"); + V = ConstantTokenFPExcept::get( + Context, static_cast(Record[0])); + break; case bitc::CST_CODE_INTEGER: // INTEGER: [intval] if (!CurTy->isIntegerTy() || Record.empty()) return error("Invalid record"); Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2343,6 +2343,12 @@ Code = bitc::CST_CODE_NULL; } else if (isa(C)) { Code = bitc::CST_CODE_UNDEF; + } else if (const auto *Tok = dyn_cast(C)) { + Code = bitc::CST_CODE_FPROUND; + Record.push_back(static_cast(Tok->getRoundingMode())); + } else if (const auto *Tok = dyn_cast(C)) { + Code = bitc::CST_CODE_FPEXCEPT; + Record.push_back(static_cast(Tok->getExceptionBehavior())); } else if (const ConstantInt *IV = dyn_cast(C)) { if (IV->getBitWidth() <= 64) { uint64_t V = IV->getSExtValue(); Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -1499,6 +1499,26 @@ return; } + if (auto *Tok = dyn_cast(CV)) { + switch (Tok->getRoundingMode()) { + default: llvm_unreachable("Invalid FP rounding mode token"); + case fp::rmDynamic: Out << "rmDynamic"; return; + case fp::rmToNearest: Out << "rmToNearest"; return; + case fp::rmDownward: Out << "rmDownward"; return; + case fp::rmUpward: Out << "rmUpward"; return; + case fp::rmTowardZero: Out << "rmTowardZero"; return; + } + } + + if (auto *Tok = dyn_cast(CV)) { + switch (Tok->getExceptionBehavior()) { + default: llvm_unreachable("Invalid FP exception behavior token"); + case fp::ebIgnore: Out << "ebIgnore"; return; + case fp::ebMayTrap: Out << "ebMayTrap"; return; + case fp::ebStrict: Out << "ebStrict"; return; + } + } + if (isa(CV)) { Out << "undef"; return; Index: llvm/lib/IR/Constants.cpp =================================================================== --- llvm/lib/IR/Constants.cpp +++ llvm/lib/IR/Constants.cpp @@ -1192,6 +1192,38 @@ llvm_unreachable("You can't ConstantTokenNone->destroyConstantImpl()!"); } +ConstantTokenFPRound *ConstantTokenFPRound::get(LLVMContext &Context, + fp::RoundingMode RM) { + LLVMContextImpl *pImpl = Context.pImpl; + int Idx = static_cast(RM); + assert(Idx >= 0 && Idx < fp::numRoundingModes && + "Unexpected FP rounding mode constant request"); + if (!pImpl->FPRoundTokens[Idx]) + pImpl->FPRoundTokens[Idx].reset(new ConstantTokenFPRound(Context, RM)); + return pImpl->FPRoundTokens[Idx].get(); +} + +/// Remove the constant from the constant table. +void ConstantTokenFPRound::destroyConstantImpl() { + llvm_unreachable("You can't ConstantTokenFPRound->destroyConstantImpl()!"); +} + +ConstantTokenFPExcept *ConstantTokenFPExcept::get(LLVMContext &Context, + fp::ExceptionBehavior EB) { + LLVMContextImpl *pImpl = Context.pImpl; + int Idx = static_cast(EB); + assert(Idx >= 0 && Idx < fp::numExceptionBehaviors && + "Unexpected FP rounding mode constant request"); + if (!pImpl->FPExceptTokens[Idx]) + pImpl->FPExceptTokens[Idx].reset(new ConstantTokenFPExcept(Context, EB)); + return pImpl->FPExceptTokens[Idx].get(); +} + +/// Remove the constant from the constant table. +void ConstantTokenFPExcept::destroyConstantImpl() { + llvm_unreachable("You can't ConstantTokenFPExcept->destroyConstantImpl()!"); +} + // Utility function for determining if a ConstantExpr is a CastOp or not. This // can't be inline because we don't want to #include Instruction.h into // Constant.h Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -34,6 +34,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/FPEnv.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/RemarkStreamer.h" @@ -1314,6 +1315,10 @@ ConstantInt *TheTrueVal = nullptr; ConstantInt *TheFalseVal = nullptr; + std::unique_ptr FPRoundTokens[fp::numRoundingModes]; + std::unique_ptr + FPExceptTokens[fp::numExceptionBehaviors]; + std::unique_ptr TheNoneToken; // Basic type instances. Index: llvm/test/Assembler/fpconstraint-tokens.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/fpconstraint-tokens.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s +; Basic smoke test for FP constraint tokens. + +; CHECK: declare void @llvm.fp.constraint.test() +declare void @llvm.fp.constraint.test() + +define void @f() { +; CHECK: call void @llvm.fp.constraint.test() [ "fpround"(token rmDynamic), "fpexcept"(token ebStrict) ] +; CHECK: call void @llvm.fp.constraint.test() [ "fpround"(token rmToNearest), "fpexcept"(token ebIgnore) ] +; CHECK: call void @llvm.fp.constraint.test() [ "fpround"(token rmDownward), "fpexcept"(token ebIgnore) ] +; CHECK: call void @llvm.fp.constraint.test() [ "fpround"(token rmUpward), "fpexcept"(token ebMayTrap) ] +; CHECK: call void @llvm.fp.constraint.test() [ "fpround"(token rmTowardZero), "fpexcept"(token ebMayTrap) ] + call void @llvm.fp.constraint.test() [ "fpround"(token rmDynamic), "fpexcept"(token ebStrict) ] + call void @llvm.fp.constraint.test() [ "fpround"(token rmToNearest), "fpexcept"(token ebIgnore) ] + call void @llvm.fp.constraint.test() [ "fpround"(token rmDownward), "fpexcept"(token ebIgnore) ] + call void @llvm.fp.constraint.test() [ "fpround"(token rmUpward), "fpexcept"(token ebMayTrap) ] + call void @llvm.fp.constraint.test() [ "fpround"(token rmTowardZero), "fpexcept"(token ebMayTrap) ] + ret void +}