<div>
<p><tt>fpmath</tt> metadata may be attached to any instruction of floating point
- type. It can be used to express the maximum acceptable relative error in the
- result of that instruction, in ULPs, thus potentially allowing the compiler
- to use a more efficient but less accurate method of computing it.
- ULP is defined as follows:</p>
+ type. It can be used to express the maximum acceptable error in the result of
+ that instruction, in ULPs, thus potentially allowing the compiler to use a
+ more efficient but less accurate method of computing it. The number of ULPs
+ may also be the string <tt>"fast"</tt>, which tells the compiler that speed
+ matters more than accuracy, so any fairly accurate method of computation is
+ fine as long as it is quick. ULP is defined as follows:</p>
<blockquote>
</blockquote>
-<p>The metadata node shall consist of a single non-negative floating
- point number representing the maximum relative error. For example,
- 2.5 ULP:</p>
+<p>The metadata node shall consist of a single positive floating point number
+ representing the maximum relative error, or the string <tt>"fast"</tt>.
+ For example:</p>
<div class="doc_code">
<pre>
-!0 = metadata !{ float 2.5 }
+!0 = metadata !{ float 2.5 } ; maximum acceptable inaccuracy is 2.5 ULPs
+!1 = metadata !{ !metadata !"fast" } ; potentially unbounded inaccuracy
</pre>
</div>
<li>The <tt>unwind</tt> instruction is now gone. With the introduction of the
new exception handling system in LLVM 3.0, the <tt>unwind</tt> instruction
became obsolete.</li>
+ <li>Floating point instructions can be annotated with <tt>fpmath</tt> metadata
+ to indicate relaxed precision requirements, such as those corresponding to
+ "fast math".</li>
<li>....</li>
</ul>
#ifndef LLVM_OPERATOR_H
#define LLVM_OPERATOR_H
-#include "llvm/Instruction.h"
#include "llvm/Constants.h"
+#include "llvm/Instruction.h"
+#include "llvm/Type.h"
namespace llvm {
(isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
}
};
-
+
+/// FPMathOperator - Utility class for floating point operations which can have
+/// information about relaxed accuracy requirements attached to them.
+class FPMathOperator : public Operator {
+private:
+ ~FPMathOperator(); // do not implement
+
+public:
+
+ /// \brief Get the maximum error permitted by this operation in ULPs. An
+ /// accuracy of 0.0 means that the operation should be performed with the
+ /// default precision. A huge value is returned if the accuracy is 'fast'.
+ float getFPAccuracy() const;
+
+ /// \brief Return true if the accuracy is 'fast'. This indicates that speed
+ /// is more important than accuracy.
+ bool isFastFPAccuracy() const;
+
+ static inline bool classof(const FPMathOperator *) { return true; }
+ static inline bool classof(const Instruction *I) {
+ return I->getType()->isFPOrFPVectorTy();
+ }
+ static inline bool classof(const Value *V) {
+ return isa<Instruction>(V) && classof(cast<Instruction>(V));
+ }
+};
/// ConcreteOperator - A helper template for defining operators for individual
#include "llvm/Instructions.h"
#include "llvm/BasicBlock.h"
+#include "llvm/LLVMContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
typename Inserter = IRBuilderDefaultInserter<preserveNames> >
class IRBuilder : public IRBuilderBase, public Inserter {
T Folder;
+ MDNode *DefaultFPMathTag;
public:
- IRBuilder(LLVMContext &C, const T &F, const Inserter &I = Inserter())
- : IRBuilderBase(C), Inserter(I), Folder(F) {
+ IRBuilder(LLVMContext &C, const T &F, const Inserter &I = Inserter(),
+ MDNode *FPMathTag = 0)
+ : IRBuilderBase(C), Inserter(I), Folder(F), DefaultFPMathTag(FPMathTag) {
}
- explicit IRBuilder(LLVMContext &C) : IRBuilderBase(C), Folder() {
+ explicit IRBuilder(LLVMContext &C, MDNode *FPMathTag = 0) : IRBuilderBase(C),
+ Folder(), DefaultFPMathTag(FPMathTag) {
}
- explicit IRBuilder(BasicBlock *TheBB, const T &F)
- : IRBuilderBase(TheBB->getContext()), Folder(F) {
+ explicit IRBuilder(BasicBlock *TheBB, const T &F, MDNode *FPMathTag = 0)
+ : IRBuilderBase(TheBB->getContext()), Folder(F),
+ DefaultFPMathTag(FPMathTag) {
SetInsertPoint(TheBB);
}
- explicit IRBuilder(BasicBlock *TheBB)
- : IRBuilderBase(TheBB->getContext()), Folder() {
+ explicit IRBuilder(BasicBlock *TheBB, MDNode *FPMathTag = 0)
+ : IRBuilderBase(TheBB->getContext()), Folder(),
+ DefaultFPMathTag(FPMathTag) {
SetInsertPoint(TheBB);
}
- explicit IRBuilder(Instruction *IP)
- : IRBuilderBase(IP->getContext()), Folder() {
+ explicit IRBuilder(Instruction *IP, MDNode *FPMathTag = 0)
+ : IRBuilderBase(IP->getContext()), Folder(), DefaultFPMathTag(FPMathTag) {
SetInsertPoint(IP);
SetCurrentDebugLocation(IP->getDebugLoc());
}
- explicit IRBuilder(Use &U)
- : IRBuilderBase(U->getContext()), Folder() {
+ explicit IRBuilder(Use &U, MDNode *FPMathTag = 0)
+ : IRBuilderBase(U->getContext()), Folder(), DefaultFPMathTag(FPMathTag) {
SetInsertPoint(U);
SetCurrentDebugLocation(cast<Instruction>(U.getUser())->getDebugLoc());
}
- IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP, const T& F)
- : IRBuilderBase(TheBB->getContext()), Folder(F) {
+ IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP, const T& F,
+ MDNode *FPMathTag = 0)
+ : IRBuilderBase(TheBB->getContext()), Folder(F),
+ DefaultFPMathTag(FPMathTag) {
SetInsertPoint(TheBB, IP);
}
- IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP)
- : IRBuilderBase(TheBB->getContext()), Folder() {
+ IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP, MDNode *FPMathTag = 0)
+ : IRBuilderBase(TheBB->getContext()), Folder(),
+ DefaultFPMathTag(FPMathTag) {
SetInsertPoint(TheBB, IP);
}
/// getFolder - Get the constant folder being used.
const T &getFolder() { return Folder; }
+ /// getDefaultFPMathTag - Get the floating point math metadata being used.
+ MDNode *getDefaultFPMathTag() const { return DefaultFPMathTag; }
+
+ /// SetDefaultFPMathTag - Set the floating point math metadata to be used.
+ void SetDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
+
/// isNamePreserving - Return true if this builder is configured to actually
/// add the requested names to IR created through it.
bool isNamePreserving() const { return preserveNames; }
if (HasNSW) BO->setHasNoSignedWrap();
return BO;
}
+
+ Instruction *AddFPMathTag(Instruction *I, MDNode *FPMathTag) const {
+ if (!FPMathTag)
+ FPMathTag = DefaultFPMathTag;
+ if (FPMathTag)
+ I->setMetadata(LLVMContext::MD_fpmath, FPMathTag);
+ return I;
+ }
public:
Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "",
bool HasNUW = false, bool HasNSW = false) {
Value *CreateNUWAdd(Value *LHS, Value *RHS, const Twine &Name = "") {
return CreateAdd(LHS, RHS, Name, true, false);
}
- Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "") {
+ Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "",
+ MDNode *FPMathTag = 0) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
return Insert(Folder.CreateFAdd(LC, RC), Name);
- return Insert(BinaryOperator::CreateFAdd(LHS, RHS), Name);
+ return Insert(AddFPMathTag(BinaryOperator::CreateFAdd(LHS, RHS),
+ FPMathTag), Name);
}
Value *CreateSub(Value *LHS, Value *RHS, const Twine &Name = "",
bool HasNUW = false, bool HasNSW = false) {
Value *CreateNUWSub(Value *LHS, Value *RHS, const Twine &Name = "") {
return CreateSub(LHS, RHS, Name, true, false);
}
- Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "") {
+ Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "",
+ MDNode *FPMathTag = 0) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
return Insert(Folder.CreateFSub(LC, RC), Name);
- return Insert(BinaryOperator::CreateFSub(LHS, RHS), Name);
+ return Insert(AddFPMathTag(BinaryOperator::CreateFSub(LHS, RHS),
+ FPMathTag), Name);
}
Value *CreateMul(Value *LHS, Value *RHS, const Twine &Name = "",
bool HasNUW = false, bool HasNSW = false) {
Value *CreateNUWMul(Value *LHS, Value *RHS, const Twine &Name = "") {
return CreateMul(LHS, RHS, Name, true, false);
}
- Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "") {
+ Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "",
+ MDNode *FPMathTag = 0) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
return Insert(Folder.CreateFMul(LC, RC), Name);
- return Insert(BinaryOperator::CreateFMul(LHS, RHS), Name);
+ return Insert(AddFPMathTag(BinaryOperator::CreateFMul(LHS, RHS),
+ FPMathTag), Name);
}
Value *CreateUDiv(Value *LHS, Value *RHS, const Twine &Name = "",
bool isExact = false) {
Value *CreateExactSDiv(Value *LHS, Value *RHS, const Twine &Name = "") {
return CreateSDiv(LHS, RHS, Name, true);
}
- Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "") {
+ Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "",
+ MDNode *FPMathTag = 0) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
return Insert(Folder.CreateFDiv(LC, RC), Name);
- return Insert(BinaryOperator::CreateFDiv(LHS, RHS), Name);
+ return Insert(AddFPMathTag(BinaryOperator::CreateFDiv(LHS, RHS),
+ FPMathTag), Name);
}
Value *CreateURem(Value *LHS, Value *RHS, const Twine &Name = "") {
if (Constant *LC = dyn_cast<Constant>(LHS))
return Insert(Folder.CreateSRem(LC, RC), Name);
return Insert(BinaryOperator::CreateSRem(LHS, RHS), Name);
}
- Value *CreateFRem(Value *LHS, Value *RHS, const Twine &Name = "") {
+ Value *CreateFRem(Value *LHS, Value *RHS, const Twine &Name = "",
+ MDNode *FPMathTag = 0) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
return Insert(Folder.CreateFRem(LC, RC), Name);
- return Insert(BinaryOperator::CreateFRem(LHS, RHS), Name);
+ return Insert(AddFPMathTag(BinaryOperator::CreateFRem(LHS, RHS),
+ FPMathTag), Name);
}
Value *CreateShl(Value *LHS, Value *RHS, const Twine &Name = "",
Value *CreateNUWNeg(Value *V, const Twine &Name = "") {
return CreateNeg(V, Name, true, false);
}
- Value *CreateFNeg(Value *V, const Twine &Name = "") {
+ Value *CreateFNeg(Value *V, const Twine &Name = "", MDNode *FPMathTag = 0) {
if (Constant *VC = dyn_cast<Constant>(V))
return Insert(Folder.CreateFNeg(VC), Name);
- return Insert(BinaryOperator::CreateFNeg(V), Name);
+ return Insert(AddFPMathTag(BinaryOperator::CreateFNeg(V), FPMathTag), Name);
}
Value *CreateNot(Value *V, const Twine &Name = "") {
if (Constant *VC = dyn_cast<Constant>(V))
class MDBuilder {
LLVMContext &Context;
+ MDString *getFastString() {
+ return createString("fast");
+ }
public:
MDBuilder(LLVMContext &context) : Context(context) {}
- /// CreateString - Return the given string as metadata.
- MDString *CreateString(StringRef Str) {
+ /// \brief Return the given string as metadata.
+ MDString *createString(StringRef Str) {
return MDString::get(Context, Str);
}
//===------------------------------------------------------------------===//
+ // FPMath metadata.
+ //===------------------------------------------------------------------===//
+
+ /// \brief Return metadata with appropriate settings for 'fast math'.
+ MDNode *createFastFPMath() {
+ return MDNode::get(Context, getFastString());
+ }
+
+ /// \brief Return metadata with the given settings. Special values for the
+ /// Accuracy parameter are 0.0, which means the default (maximal precision)
+ /// setting; and negative values which all mean 'fast'.
+ MDNode *createFPMath(float Accuracy) {
+ if (Accuracy == 0.0)
+ return 0;
+ if (Accuracy < 0.0)
+ return MDNode::get(Context, getFastString());
+ assert(Accuracy > 0.0 && "Invalid fpmath accuracy!");
+ Value *Op = ConstantFP::get(Type::getFloatTy(Context), Accuracy);
+ return MDNode::get(Context, Op);
+ }
+
+
+ //===------------------------------------------------------------------===//
// Range metadata.
//===------------------------------------------------------------------===//
- /// CreateRange - Return metadata describing the range [Lo, Hi).
- MDNode *CreateRange(const APInt &Lo, const APInt &Hi) {
+ /// \brief Return metadata describing the range [Lo, Hi).
+ MDNode *createRange(const APInt &Lo, const APInt &Hi) {
assert(Lo.getBitWidth() == Hi.getBitWidth() && "Mismatched bitwidths!");
// If the range is everything then it is useless.
if (Hi == Lo)
// TBAA metadata.
//===------------------------------------------------------------------===//
- /// CreateAnonymousTBAARoot - Return metadata appropriate for a TBAA root
- /// node. Each returned node is distinct from all other metadata and will
- /// never be identified (uniqued) with anything else.
- MDNode *CreateAnonymousTBAARoot() {
+ /// \brief Return metadata appropriate for a TBAA root node. Each returned
+ /// node is distinct from all other metadata and will never be identified
+ /// (uniqued) with anything else.
+ MDNode *createAnonymousTBAARoot() {
// To ensure uniqueness the root node is self-referential.
MDNode *Dummy = MDNode::getTemporary(Context, ArrayRef<Value*>());
MDNode *Root = MDNode::get(Context, Dummy);
return Root;
}
- /// CreateTBAARoot - Return metadata appropriate for a TBAA root node with
- /// the given name. This may be identified (uniqued) with other roots with
- /// the same name.
- MDNode *CreateTBAARoot(StringRef Name) {
- return MDNode::get(Context, CreateString(Name));
+ /// \brief Return metadata appropriate for a TBAA root node with the given
+ /// name. This may be identified (uniqued) with other roots with the same
+ /// name.
+ MDNode *createTBAARoot(StringRef Name) {
+ return MDNode::get(Context, createString(Name));
}
- /// CreateTBAANode - Return metadata for a non-root TBAA node with the given
- /// name, parent in the TBAA tree, and value for 'pointsToConstantMemory'.
- MDNode *CreateTBAANode(StringRef Name, MDNode *Parent,
+ /// \brief Return metadata for a non-root TBAA node with the given name,
+ /// parent in the TBAA tree, and value for 'pointsToConstantMemory'.
+ MDNode *createTBAANode(StringRef Name, MDNode *Parent,
bool isConstant = false) {
if (isConstant) {
Constant *Flags = ConstantInt::get(Type::getInt64Ty(Context), 1);
- Value *Ops[3] = { CreateString(Name), Parent, Flags };
+ Value *Ops[3] = { createString(Name), Parent, Flags };
return MDNode::get(Context, Ops);
} else {
- Value *Ops[2] = { CreateString(Name), Parent };
+ Value *Ops[2] = { createString(Name), Parent };
return MDNode::get(Context, Ops);
}
}
}
//===----------------------------------------------------------------------===//
+// FPMathOperator Class
+//===----------------------------------------------------------------------===//
+
+/// getFPAccuracy - Get the maximum error permitted by this operation in ULPs.
+/// An accuracy of 0.0 means that the operation should be performed with the
+/// default precision. A huge value is returned if the accuracy is 'fast'.
+float FPMathOperator::getFPAccuracy() const {
+ const MDNode *MD =
+ cast<Instruction>(this)->getMetadata(LLVMContext::MD_fpmath);
+ if (!MD)
+ return 0.0;
+ Value *Op = MD->getOperand(0);
+ if (const ConstantFP *Accuracy = dyn_cast<ConstantFP>(Op))
+ return Accuracy->getValueAPF().convertToFloat();
+ // If it's not a floating point number then it must be 'fast'.
+ assert(isa<MDString>(Op) && cast<MDString>(Op)->getString() == "fast" &&
+ "Expected the 'fast' keyword!");
+ return HUGE_VALF;
+}
+
+/// isFastFPAccuracy - Return true if the accuracy is 'fast'. This says that
+/// speed is more important than accuracy.
+bool FPMathOperator::isFastFPAccuracy() const {
+ const MDNode *MD =
+ cast<Instruction>(this)->getMetadata(LLVMContext::MD_fpmath);
+ if (!MD)
+ return false;
+ Value *Op = MD->getOperand(0);
+ if (isa<ConstantFP>(Op))
+ return false;
+ // If it's not a floating point number then it must be 'fast'.
+ assert(isa<MDString>(Op) && cast<MDString>(Op)->getString() == "fast" &&
+ "Expected the 'fast' keyword!");
+ return true;
+}
+
+
+//===----------------------------------------------------------------------===//
// CastInst Class
//===----------------------------------------------------------------------===//
Assert1(I.getType()->isFPOrFPVectorTy(),
"fpmath requires a floating point result!", &I);
Assert1(MD->getNumOperands() == 1, "fpmath takes one operand!", &I);
- ConstantFP *Op = dyn_cast_or_null<ConstantFP>(MD->getOperand(0));
- Assert1(Op, "fpmath ULPs not a floating point number!", &I);
- APFloat ULPs = Op->getValueAPF();
- Assert1(ULPs.isNormal() || ULPs.isZero(),
- "fpmath ULPs not a normal number!", &I);
- Assert1(!ULPs.isNegative(), "fpmath ULPs is negative!", &I);
+ Value *Op0 = MD->getOperand(0);
+ if (ConstantFP *CFP0 = dyn_cast_or_null<ConstantFP>(Op0)) {
+ APFloat Accuracy = CFP0->getValueAPF();
+ Assert1(Accuracy.isNormal() && !Accuracy.isNegative(),
+ "fpmath accuracy not a positive number!", &I);
+ } else if (MDString *S0 = dyn_cast_or_null<MDString>(Op0)) {
+ Assert1(S0->getString() == "fast", "wrong fpmath accuracy keyword!", &I);
+ } else {
+ Assert1(false, "invalid fpmath accuracy!", &I);
+ }
}
MDNode *MD = I.getMetadata(LLVMContext::MD_range);
; RUN: not llvm-as < %s |& FileCheck %s
-define void @foo(i32 %i, float %f, <2 x float> %g) {
+define void @fpmath1(i32 %i, float %f, <2 x float> %g) {
%s = add i32 %i, %i, !fpmath !0
; CHECK: fpmath requires a floating point result!
%t = fadd float %f, %f, !fpmath !1
%u = fadd float %f, %f, !fpmath !2
; CHECK: fpmath takes one operand!
%v = fadd float %f, %f, !fpmath !3
-; CHECK: fpmath ULPs not a floating point number!
+; CHECK: invalid fpmath accuracy!
%w = fadd float %f, %f, !fpmath !0
; Above line is correct.
%w2 = fadd <2 x float> %g, %g, !fpmath !0
; Above line is correct.
%x = fadd float %f, %f, !fpmath !4
-; CHECK: fpmath ULPs is negative!
+; CHECK: fpmath accuracy not a positive number!
%y = fadd float %f, %f, !fpmath !5
-; CHECK: fpmath ULPs is negative!
+; CHECK: fpmath accuracy not a positive number!
%z = fadd float %f, %f, !fpmath !6
-; CHECK: fpmath ULPs not a normal number!
+; CHECK: fpmath accuracy not a positive number!
+ ret void
+}
+
+define void @fpmath2(float %f, <2 x float> %g) {
+ %w = fadd float %f, %f, !fpmath !7
+; Above line is correct.
+ %w2 = fadd <2 x float> %g, %g, !fpmath !7
+; Above line is correct.
+ %x = fadd float %f, %f, !fpmath !8
+; CHECK: wrong fpmath accuracy keyword!
ret void
}
!2 = metadata !{ float 1.0, float 1.0 }
!3 = metadata !{ i32 1 }
!4 = metadata !{ float -1.0 }
-!5 = metadata !{ float -0.0 }
+!5 = metadata !{ float 0.0 }
!6 = metadata !{ float 0x7FFFFFFF00000000 }
+!7 = metadata !{ metadata !"fast" }
+!8 = metadata !{ metadata !"slow" }
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
+#include "llvm/Operator.h"
+#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/MDBuilder.h"
using namespace llvm;
LLVMContext Context;
};
-TEST_F(MDBuilderTest, CreateString) {
+TEST_F(MDBuilderTest, createString) {
MDBuilder MDHelper(Context);
- MDString *Str0 = MDHelper.CreateString("");
- MDString *Str1 = MDHelper.CreateString("string");
+ MDString *Str0 = MDHelper.createString("");
+ MDString *Str1 = MDHelper.createString("string");
EXPECT_EQ(Str0->getString(), StringRef(""));
EXPECT_EQ(Str1->getString(), StringRef("string"));
}
-
-TEST_F(MDBuilderTest, CreateRangeMetadata) {
+TEST_F(MDBuilderTest, createFastFPMath) {
+ MDBuilder MDHelper(Context);
+ MDNode *MD = MDHelper.createFastFPMath();
+ EXPECT_NE(MD, (MDNode *)0);
+ EXPECT_EQ(MD->getNumOperands(), 1U);
+ Value *Op = MD->getOperand(0);
+ EXPECT_TRUE(isa<MDString>(Op));
+ EXPECT_EQ(cast<MDString>(Op)->getString(), "fast");
+}
+TEST_F(MDBuilderTest, createFPMath) {
+ MDBuilder MDHelper(Context);
+ MDNode *MD0 = MDHelper.createFPMath(0.0);
+ MDNode *MD1 = MDHelper.createFPMath(1.0);
+ MDNode *MDF = MDHelper.createFPMath(-1.0);
+ MDNode *MDF2 = MDHelper.createFastFPMath();
+ EXPECT_EQ(MD0, (MDNode *)0);
+ EXPECT_NE(MD1, (MDNode *)0);
+ EXPECT_EQ(MDF, MDF2);
+ EXPECT_EQ(MD1->getNumOperands(), 1U);
+ Value *Op = MD1->getOperand(0);
+ EXPECT_TRUE(isa<ConstantFP>(Op));
+ EXPECT_TRUE(Op->getType()->isFloatingPointTy());
+ ConstantFP *Val = cast<ConstantFP>(Op);
+ EXPECT_TRUE(Val->isExactlyValue(1.0));
+}
+TEST_F(MDBuilderTest, createRangeMetadata) {
MDBuilder MDHelper(Context);
APInt A(8, 1), B(8, 2);
- MDNode *R0 = MDHelper.CreateRange(A, A);
- MDNode *R1 = MDHelper.CreateRange(A, B);
+ MDNode *R0 = MDHelper.createRange(A, A);
+ MDNode *R1 = MDHelper.createRange(A, B);
EXPECT_EQ(R0, (MDNode *)0);
EXPECT_NE(R1, (MDNode *)0);
EXPECT_EQ(R1->getNumOperands(), 2U);
EXPECT_EQ(C0->getValue(), A);
EXPECT_EQ(C1->getValue(), B);
}
-TEST_F(MDBuilderTest, CreateAnonymousTBAARoot) {
+TEST_F(MDBuilderTest, createAnonymousTBAARoot) {
MDBuilder MDHelper(Context);
- MDNode *R0 = MDHelper.CreateAnonymousTBAARoot();
- MDNode *R1 = MDHelper.CreateAnonymousTBAARoot();
+ MDNode *R0 = MDHelper.createAnonymousTBAARoot();
+ MDNode *R1 = MDHelper.createAnonymousTBAARoot();
EXPECT_NE(R0, R1);
EXPECT_GE(R0->getNumOperands(), 1U);
EXPECT_GE(R1->getNumOperands(), 1U);
EXPECT_TRUE(R0->getNumOperands() == 1 || R0->getOperand(1) == 0);
EXPECT_TRUE(R1->getNumOperands() == 1 || R1->getOperand(1) == 0);
}
-TEST_F(MDBuilderTest, CreateTBAARoot) {
+TEST_F(MDBuilderTest, createTBAARoot) {
MDBuilder MDHelper(Context);
- MDNode *R0 = MDHelper.CreateTBAARoot("Root");
- MDNode *R1 = MDHelper.CreateTBAARoot("Root");
+ MDNode *R0 = MDHelper.createTBAARoot("Root");
+ MDNode *R1 = MDHelper.createTBAARoot("Root");
EXPECT_EQ(R0, R1);
EXPECT_GE(R0->getNumOperands(), 1U);
EXPECT_TRUE(isa<MDString>(R0->getOperand(0)));
EXPECT_EQ(cast<MDString>(R0->getOperand(0))->getString(), "Root");
EXPECT_TRUE(R0->getNumOperands() == 1 || R0->getOperand(1) == 0);
}
-TEST_F(MDBuilderTest, CreateTBAANode) {
+TEST_F(MDBuilderTest, createTBAANode) {
MDBuilder MDHelper(Context);
- MDNode *R = MDHelper.CreateTBAARoot("Root");
- MDNode *N0 = MDHelper.CreateTBAANode("Node", R);
- MDNode *N1 = MDHelper.CreateTBAANode("edoN", R);
- MDNode *N2 = MDHelper.CreateTBAANode("Node", R, true);
- MDNode *N3 = MDHelper.CreateTBAANode("Node", R);
+ MDNode *R = MDHelper.createTBAARoot("Root");
+ MDNode *N0 = MDHelper.createTBAANode("Node", R);
+ MDNode *N1 = MDHelper.createTBAANode("edoN", R);
+ MDNode *N2 = MDHelper.createTBAANode("Node", R, true);
+ MDNode *N3 = MDHelper.createTBAANode("Node", R);
EXPECT_EQ(N0, N3);
EXPECT_NE(N0, N1);
EXPECT_NE(N0, N2);
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/LLVMContext.h"
+#include "llvm/Operator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Support/MDBuilder.h"
+#include "llvm/Support/IRBuilder.h"
#include "llvm/Target/TargetData.h"
#include "gtest/gtest.h"
delete PtrVecB;
}
+TEST(InstructionsTest, FPMathOperator) {
+ LLVMContext &Context = getGlobalContext();
+ IRBuilder<> Builder(Context);
+ MDBuilder MDHelper(Context);
+ Instruction *I = Builder.CreatePHI(Builder.getDoubleTy(), 0);
+ MDNode *MD1 = MDHelper.createFPMath(1.0);
+ MDNode *MDF = MDHelper.createFastFPMath();
+ Value *V1 = Builder.CreateFAdd(I, I, "", MD1);
+ Value *VF = Builder.CreateFAdd(I, I, "", MDF);
+ EXPECT_TRUE(isa<FPMathOperator>(V1));
+ EXPECT_TRUE(isa<FPMathOperator>(VF));
+ FPMathOperator *O1 = cast<FPMathOperator>(V1);
+ FPMathOperator *OF = cast<FPMathOperator>(VF);
+ EXPECT_FALSE(O1->isFastFPAccuracy());
+ EXPECT_TRUE(OF->isFastFPAccuracy());
+ EXPECT_EQ(O1->getFPAccuracy(), 1.0);
+ EXPECT_GT(OF->getFPAccuracy(), 999.0);
+ delete V1;
+ delete VF;
+ delete I;
+}
+
} // end anonymous namespace
} // end namespace llvm