2013-01-07 23:35:46 +08:00
|
|
|
//===- llvm/unittest/IR/IRBuilderTest.cpp - IRBuilder tests ---------------===//
|
2011-05-22 07:14:36 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2011-05-22 07:14:36 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/IRBuilder.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
2015-01-22 02:32:56 +08:00
|
|
|
#include "llvm/IR/DIBuilder.h"
|
2017-06-06 19:06:56 +08:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2019-12-11 23:55:26 +08:00
|
|
|
#include "llvm/IR/IntrinsicsAArch64.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/MDBuilder.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2014-03-04 20:05:47 +08:00
|
|
|
#include "llvm/IR/NoFolder.h"
|
2015-03-31 10:09:55 +08:00
|
|
|
#include "llvm/IR/Verifier.h"
|
2021-11-30 11:43:25 +08:00
|
|
|
#include "gmock/gmock.h"
|
2011-05-22 07:14:36 +08:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
2021-11-30 11:43:25 +08:00
|
|
|
using ::testing::UnorderedElementsAre;
|
2011-05-22 07:14:36 +08:00
|
|
|
|
2011-12-20 10:50:00 +08:00
|
|
|
namespace {
|
2012-06-20 16:39:27 +08:00
|
|
|
|
2011-05-22 07:14:36 +08:00
|
|
|
class IRBuilderTest : public testing::Test {
|
|
|
|
protected:
|
2015-04-11 10:11:45 +08:00
|
|
|
void SetUp() override {
|
2013-11-15 17:34:33 +08:00
|
|
|
M.reset(new Module("MyModule", Ctx));
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
|
2011-05-22 07:14:36 +08:00
|
|
|
/*isVarArg=*/false);
|
2012-07-16 15:44:51 +08:00
|
|
|
F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());
|
2013-11-15 17:34:33 +08:00
|
|
|
BB = BasicBlock::Create(Ctx, "", F);
|
|
|
|
GV = new GlobalVariable(*M, Type::getFloatTy(Ctx), true,
|
2014-06-09 06:29:17 +08:00
|
|
|
GlobalValue::ExternalLinkage, nullptr);
|
2011-05-22 07:14:36 +08:00
|
|
|
}
|
|
|
|
|
2015-04-11 10:11:45 +08:00
|
|
|
void TearDown() override {
|
2014-06-09 06:29:17 +08:00
|
|
|
BB = nullptr;
|
2011-05-22 07:14:36 +08:00
|
|
|
M.reset();
|
|
|
|
}
|
|
|
|
|
2013-11-15 17:34:33 +08:00
|
|
|
LLVMContext Ctx;
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<Module> M;
|
2012-07-16 15:44:51 +08:00
|
|
|
Function *F;
|
2011-05-22 07:14:36 +08:00
|
|
|
BasicBlock *BB;
|
2012-11-29 05:17:34 +08:00
|
|
|
GlobalVariable *GV;
|
2011-05-22 07:14:36 +08:00
|
|
|
};
|
|
|
|
|
2018-02-21 02:21:43 +08:00
|
|
|
TEST_F(IRBuilderTest, Intrinsics) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
Value *V;
|
2018-10-08 18:32:33 +08:00
|
|
|
Instruction *I;
|
2018-02-21 02:21:43 +08:00
|
|
|
CallInst *Call;
|
|
|
|
IntrinsicInst *II;
|
|
|
|
|
2019-02-02 04:44:24 +08:00
|
|
|
V = Builder.CreateLoad(GV->getValueType(), GV);
|
2018-10-08 18:32:33 +08:00
|
|
|
I = cast<Instruction>(Builder.CreateFAdd(V, V));
|
|
|
|
I->setHasNoInfs(true);
|
|
|
|
I->setHasNoNaNs(false);
|
2018-02-21 02:21:43 +08:00
|
|
|
|
|
|
|
Call = Builder.CreateMinNum(V, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::minnum);
|
|
|
|
|
|
|
|
Call = Builder.CreateMaxNum(V, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maxnum);
|
2018-05-30 02:06:50 +08:00
|
|
|
|
[Intrinsic] Add llvm.minimum and llvm.maximum instrinsic functions
Summary:
These new intrinsics have the semantics of the `minimum` and `maximum`
operations specified by the latest draft of IEEE 754-2018. Unlike
llvm.minnum and llvm.maxnum, these new intrinsics propagate NaNs and
always treat -0.0 as less than 0.0. `minimum` and `maximum` lower
directly to the existing `fminnan` and `fmaxnan` ISel DAG nodes. It is
safe to reuse these DAG nodes because before this patch were only
emitted in situations where there were known to be no NaN arguments or
where NaN propagation was correct and there were known to be no zero
arguments. I know of only four backends that lower fminnan and
fmaxnan: WebAssembly, ARM, AArch64, and SystemZ, and each of these
lowers fminnan and fmaxnan to instructions that are compatible with
the IEEE 754-2018 semantics.
Reviewers: aheejin, dschuff, sunfish, javed.absar
Subscribers: kristof.beyls, dexonsmith, kristina, llvm-commits
Differential Revision: https://reviews.llvm.org/D52764
llvm-svn: 344437
2018-10-13 15:21:44 +08:00
|
|
|
Call = Builder.CreateMinimum(V, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::minimum);
|
|
|
|
|
|
|
|
Call = Builder.CreateMaximum(V, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maximum);
|
|
|
|
|
2018-10-08 18:32:33 +08:00
|
|
|
Call = Builder.CreateIntrinsic(Intrinsic::readcyclecounter, {}, {});
|
2018-05-30 02:06:50 +08:00
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::readcyclecounter);
|
2018-10-08 18:32:33 +08:00
|
|
|
|
|
|
|
Call = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fabs);
|
|
|
|
EXPECT_FALSE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
|
|
|
|
|
|
|
Call = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, V, I);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fabs);
|
|
|
|
EXPECT_TRUE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
|
|
|
|
|
|
|
Call = Builder.CreateBinaryIntrinsic(Intrinsic::pow, V, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::pow);
|
|
|
|
EXPECT_FALSE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
|
|
|
|
|
|
|
Call = Builder.CreateBinaryIntrinsic(Intrinsic::pow, V, V, I);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::pow);
|
|
|
|
EXPECT_TRUE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
|
|
|
|
|
|
|
Call = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V});
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma);
|
|
|
|
EXPECT_FALSE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
|
|
|
|
|
|
|
Call = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}, I);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma);
|
|
|
|
EXPECT_TRUE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
|
|
|
|
|
|
|
Call = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}, I);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma);
|
|
|
|
EXPECT_TRUE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
2020-05-26 20:24:05 +08:00
|
|
|
|
|
|
|
Call = Builder.CreateUnaryIntrinsic(Intrinsic::roundeven, V);
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::roundeven);
|
|
|
|
EXPECT_FALSE(II->hasNoInfs());
|
|
|
|
EXPECT_FALSE(II->hasNoNaNs());
|
[FPEnv] Intrinsic for setting rounding mode
To set non-default rounding mode user usually calls function 'fesetround'
from standard C library. This way has some disadvantages.
* It creates unnecessary dependency on libc. On the other hand, setting
rounding mode requires few instructions and could be made by compiler.
Sometimes standard C library even is not available, like in the case of
GPU or AI cores that execute small kernels.
* Compiler could generate more effective code if it knows that a particular
call just sets rounding mode.
This change introduces new IR intrinsic, namely 'llvm.set.rounding', which
sets current rounding mode, similar to 'fesetround'. It however differs
from the latter, because it is a lower level facility:
* 'llvm.set.rounding' does not return any value, whereas 'fesetround'
returns non-zero value in the case of failure. In glibc 'fesetround'
reports failure if its argument is invalid or unsupported or if floating
point operations are unavailable on the hardware. Compiler usually knows
what core it generates code for and it can validate arguments in many
cases.
* Rounding mode is specified in 'fesetround' using constants like
'FE_TONEAREST', which are target dependent. It is inconvenient to work
with such constants at IR level.
C standard provides a target-independent way to specify rounding mode, it
is used in FLT_ROUNDS, however it does not define standard way to set
rounding mode using this encoding.
This change implements only IR intrinsic. Lowering it to machine code is
target-specific and will be implemented latter. Mapping of 'fesetround'
to 'llvm.set.rounding' is also not implemented here.
Differential Revision: https://reviews.llvm.org/D74729
2020-02-03 18:44:42 +08:00
|
|
|
|
|
|
|
Call = Builder.CreateIntrinsic(
|
|
|
|
Intrinsic::set_rounding, {},
|
|
|
|
{Builder.getInt32(static_cast<uint32_t>(RoundingMode::TowardZero))});
|
|
|
|
II = cast<IntrinsicInst>(Call);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::set_rounding);
|
2018-02-21 02:21:43 +08:00
|
|
|
}
|
|
|
|
|
2019-08-27 20:57:09 +08:00
|
|
|
TEST_F(IRBuilderTest, IntrinsicsWithScalableVectors) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
CallInst *Call;
|
|
|
|
FunctionType *FTy;
|
|
|
|
|
|
|
|
// Test scalable flag isn't dropped for intrinsic that is explicitly defined
|
|
|
|
// with scalable vectors, e.g. LLVMType<nxv4i32>.
|
|
|
|
Type *SrcVecTy = VectorType::get(Builder.getHalfTy(), 8, true);
|
|
|
|
Type *DstVecTy = VectorType::get(Builder.getInt32Ty(), 4, true);
|
2020-04-23 17:53:23 +08:00
|
|
|
Type *PredTy = VectorType::get(Builder.getInt1Ty(), 4, true);
|
2019-08-27 20:57:09 +08:00
|
|
|
|
|
|
|
SmallVector<Value*, 3> ArgTys;
|
|
|
|
ArgTys.push_back(UndefValue::get(DstVecTy));
|
|
|
|
ArgTys.push_back(UndefValue::get(PredTy));
|
|
|
|
ArgTys.push_back(UndefValue::get(SrcVecTy));
|
|
|
|
|
|
|
|
Call = Builder.CreateIntrinsic(Intrinsic::aarch64_sve_fcvtzs_i32f16, {},
|
|
|
|
ArgTys, nullptr, "aarch64.sve.fcvtzs.i32f16");
|
|
|
|
FTy = Call->getFunctionType();
|
|
|
|
EXPECT_EQ(FTy->getReturnType(), DstVecTy);
|
|
|
|
for (unsigned i = 0; i != ArgTys.size(); ++i)
|
|
|
|
EXPECT_EQ(FTy->getParamType(i), ArgTys[i]->getType());
|
|
|
|
|
|
|
|
// Test scalable flag isn't dropped for intrinsic defined with
|
|
|
|
// LLVMScalarOrSameVectorWidth.
|
|
|
|
|
|
|
|
Type *VecTy = VectorType::get(Builder.getInt32Ty(), 4, true);
|
|
|
|
Type *PtrToVecTy = VecTy->getPointerTo();
|
|
|
|
PredTy = VectorType::get(Builder.getInt1Ty(), 4, true);
|
|
|
|
|
|
|
|
ArgTys.clear();
|
|
|
|
ArgTys.push_back(UndefValue::get(PtrToVecTy));
|
|
|
|
ArgTys.push_back(UndefValue::get(Builder.getInt32Ty()));
|
|
|
|
ArgTys.push_back(UndefValue::get(PredTy));
|
|
|
|
ArgTys.push_back(UndefValue::get(VecTy));
|
|
|
|
|
|
|
|
Call = Builder.CreateIntrinsic(Intrinsic::masked_load,
|
|
|
|
{VecTy, PtrToVecTy}, ArgTys,
|
|
|
|
nullptr, "masked.load");
|
|
|
|
FTy = Call->getFunctionType();
|
|
|
|
EXPECT_EQ(FTy->getReturnType(), VecTy);
|
|
|
|
for (unsigned i = 0; i != ArgTys.size(); ++i)
|
|
|
|
EXPECT_EQ(FTy->getParamType(i), ArgTys[i]->getType());
|
|
|
|
}
|
|
|
|
|
2021-04-19 21:56:35 +08:00
|
|
|
TEST_F(IRBuilderTest, CreateVScale) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
|
|
|
Constant *Zero = Builder.getInt32(0);
|
|
|
|
Value *VScale = Builder.CreateVScale(Zero);
|
|
|
|
EXPECT_TRUE(isa<ConstantInt>(VScale) && cast<ConstantInt>(VScale)->isZero());
|
|
|
|
}
|
|
|
|
|
[IR][SVE] Add new llvm.experimental.stepvector intrinsic
This patch adds a new llvm.experimental.stepvector intrinsic,
which takes no arguments and returns a linear integer sequence of
values of the form <0, 1, ...>. It is primarily intended for
scalable vectors, although it will work for fixed width vectors
too. It is intended that later patches will make use of this
new intrinsic when vectorising induction variables, currently only
supported for fixed width. I've added a new CreateStepVector
method to the IRBuilder, which will generate a call to this
intrinsic for scalable vectors and fall back on creating a
ConstantVector for fixed width.
For scalable vectors this intrinsic is lowered to a new ISD node
called STEP_VECTOR, which takes a single constant integer argument
as the step. During lowering this argument is set to a value of 1.
The reason for this additional argument at the codegen level is
because in future patches we will introduce various generic DAG
combines such as
mul step_vector(1), 2 -> step_vector(2)
add step_vector(1), step_vector(1) -> step_vector(2)
shl step_vector(1), 1 -> step_vector(2)
etc.
that encourage a canonical format for all targets. This hopefully
means all other targets supporting scalable vectors can benefit
from this too.
I've added cost model tests for both fixed width and scalable
vectors:
llvm/test/Analysis/CostModel/AArch64/neon-stepvector.ll
llvm/test/Analysis/CostModel/AArch64/sve-stepvector.ll
as well as codegen lowering tests for fixed width and scalable
vectors:
llvm/test/CodeGen/AArch64/neon-stepvector.ll
llvm/test/CodeGen/AArch64/sve-stepvector.ll
See this thread for discussion of the intrinsic:
https://lists.llvm.org/pipermail/llvm-dev/2021-January/147943.html
2021-02-08 23:46:24 +08:00
|
|
|
TEST_F(IRBuilderTest, CreateStepVector) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
|
|
|
// Fixed width vectors
|
|
|
|
Type *DstVecTy = VectorType::get(Builder.getInt32Ty(), 4, false);
|
|
|
|
Value *StepVec = Builder.CreateStepVector(DstVecTy);
|
|
|
|
EXPECT_TRUE(isa<Constant>(StepVec));
|
|
|
|
EXPECT_EQ(StepVec->getType(), DstVecTy);
|
|
|
|
|
|
|
|
const auto *VectorValue = cast<Constant>(StepVec);
|
|
|
|
for (unsigned i = 0; i < 4; i++) {
|
|
|
|
EXPECT_TRUE(isa<ConstantInt>(VectorValue->getAggregateElement(i)));
|
|
|
|
ConstantInt *El = cast<ConstantInt>(VectorValue->getAggregateElement(i));
|
|
|
|
EXPECT_EQ(El->getValue(), i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scalable vectors
|
|
|
|
DstVecTy = VectorType::get(Builder.getInt32Ty(), 4, true);
|
|
|
|
StepVec = Builder.CreateStepVector(DstVecTy);
|
|
|
|
EXPECT_TRUE(isa<CallInst>(StepVec));
|
|
|
|
CallInst *Call = cast<CallInst>(StepVec);
|
|
|
|
FunctionType *FTy = Call->getFunctionType();
|
|
|
|
EXPECT_EQ(FTy->getReturnType(), DstVecTy);
|
|
|
|
EXPECT_EQ(Call->getIntrinsicID(), Intrinsic::experimental_stepvector);
|
|
|
|
}
|
|
|
|
|
2021-11-12 22:08:55 +08:00
|
|
|
TEST_F(IRBuilderTest, CreateStepVectorI3) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
|
|
|
// Scalable vectors
|
|
|
|
Type *DstVecTy = VectorType::get(IntegerType::get(Ctx, 3), 2, true);
|
|
|
|
Type *VecI8Ty = VectorType::get(Builder.getInt8Ty(), 2, true);
|
|
|
|
Value *StepVec = Builder.CreateStepVector(DstVecTy);
|
|
|
|
EXPECT_TRUE(isa<TruncInst>(StepVec));
|
|
|
|
TruncInst *Trunc = cast<TruncInst>(StepVec);
|
|
|
|
EXPECT_EQ(Trunc->getDestTy(), DstVecTy);
|
|
|
|
EXPECT_EQ(Trunc->getSrcTy(), VecI8Ty);
|
|
|
|
EXPECT_TRUE(isa<CallInst>(Trunc->getOperand(0)));
|
|
|
|
|
|
|
|
CallInst *Call = cast<CallInst>(Trunc->getOperand(0));
|
|
|
|
FunctionType *FTy = Call->getFunctionType();
|
|
|
|
EXPECT_EQ(FTy->getReturnType(), VecI8Ty);
|
|
|
|
EXPECT_EQ(Call->getIntrinsicID(), Intrinsic::experimental_stepvector);
|
|
|
|
}
|
|
|
|
|
2019-07-09 00:18:18 +08:00
|
|
|
TEST_F(IRBuilderTest, ConstrainedFP) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
Value *V;
|
2019-07-19 02:01:57 +08:00
|
|
|
Value *VDouble;
|
2019-09-07 02:04:34 +08:00
|
|
|
Value *VInt;
|
2019-07-09 00:18:18 +08:00
|
|
|
CallInst *Call;
|
|
|
|
IntrinsicInst *II;
|
2019-07-19 02:01:57 +08:00
|
|
|
GlobalVariable *GVDouble = new GlobalVariable(*M, Type::getDoubleTy(Ctx),
|
|
|
|
true, GlobalValue::ExternalLinkage, nullptr);
|
2019-07-09 00:18:18 +08:00
|
|
|
|
2019-07-09 20:36:36 +08:00
|
|
|
V = Builder.CreateLoad(GV->getValueType(), GV);
|
2019-07-19 02:01:57 +08:00
|
|
|
VDouble = Builder.CreateLoad(GVDouble->getValueType(), GVDouble);
|
2019-07-09 00:18:18 +08:00
|
|
|
|
|
|
|
// See if we get constrained intrinsics instead of non-constrained
|
|
|
|
// instructions.
|
|
|
|
Builder.setIsFPConstrained(true);
|
2019-12-05 04:23:46 +08:00
|
|
|
auto Parent = BB->getParent();
|
|
|
|
Parent->addFnAttr(Attribute::StrictFP);
|
2019-07-09 00:18:18 +08:00
|
|
|
|
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(V));
|
|
|
|
II = cast<IntrinsicInst>(V);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd);
|
|
|
|
|
|
|
|
V = Builder.CreateFSub(V, V);
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(V));
|
|
|
|
II = cast<IntrinsicInst>(V);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub);
|
|
|
|
|
|
|
|
V = Builder.CreateFMul(V, V);
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(V));
|
|
|
|
II = cast<IntrinsicInst>(V);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul);
|
|
|
|
|
|
|
|
V = Builder.CreateFDiv(V, V);
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(V));
|
|
|
|
II = cast<IntrinsicInst>(V);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv);
|
|
|
|
|
|
|
|
V = Builder.CreateFRem(V, V);
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(V));
|
|
|
|
II = cast<IntrinsicInst>(V);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_frem);
|
2019-09-07 02:04:34 +08:00
|
|
|
|
|
|
|
VInt = Builder.CreateFPToUI(VDouble, Builder.getInt32Ty());
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(VInt));
|
|
|
|
II = cast<IntrinsicInst>(VInt);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fptoui);
|
|
|
|
|
|
|
|
VInt = Builder.CreateFPToSI(VDouble, Builder.getInt32Ty());
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(VInt));
|
|
|
|
II = cast<IntrinsicInst>(VInt);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fptosi);
|
2019-07-09 00:18:18 +08:00
|
|
|
|
2019-12-18 01:30:41 +08:00
|
|
|
VDouble = Builder.CreateUIToFP(VInt, Builder.getDoubleTy());
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(VDouble));
|
|
|
|
II = cast<IntrinsicInst>(VDouble);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_uitofp);
|
|
|
|
|
|
|
|
VDouble = Builder.CreateSIToFP(VInt, Builder.getDoubleTy());
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(VDouble));
|
|
|
|
II = cast<IntrinsicInst>(VDouble);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_sitofp);
|
|
|
|
|
2019-07-19 02:01:57 +08:00
|
|
|
V = Builder.CreateFPTrunc(VDouble, Type::getFloatTy(Ctx));
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(V));
|
|
|
|
II = cast<IntrinsicInst>(V);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fptrunc);
|
|
|
|
|
|
|
|
VDouble = Builder.CreateFPExt(V, Type::getDoubleTy(Ctx));
|
|
|
|
ASSERT_TRUE(isa<IntrinsicInst>(VDouble));
|
|
|
|
II = cast<IntrinsicInst>(VDouble);
|
|
|
|
EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fpext);
|
|
|
|
|
2019-10-23 01:07:15 +08:00
|
|
|
// Verify attributes on the call are created automatically.
|
2021-08-14 02:16:52 +08:00
|
|
|
AttributeSet CallAttrs = II->getAttributes().getFnAttrs();
|
2019-10-23 01:07:15 +08:00
|
|
|
EXPECT_EQ(CallAttrs.hasAttribute(Attribute::StrictFP), true);
|
|
|
|
|
2019-12-05 04:23:46 +08:00
|
|
|
// Verify attributes on the containing function are created when requested.
|
|
|
|
Builder.setConstrainedFPFunctionAttr();
|
2019-10-23 01:07:15 +08:00
|
|
|
AttributeList Attrs = BB->getParent()->getAttributes();
|
2021-08-14 02:16:52 +08:00
|
|
|
AttributeSet FnAttrs = Attrs.getFnAttrs();
|
2019-10-23 01:07:15 +08:00
|
|
|
EXPECT_EQ(FnAttrs.hasAttribute(Attribute::StrictFP), true);
|
|
|
|
|
2019-07-09 00:18:18 +08:00
|
|
|
// Verify the codepaths for setting and overriding the default metadata.
|
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
ASSERT_TRUE(isa<ConstrainedFPIntrinsic>(V));
|
|
|
|
auto *CII = cast<ConstrainedFPIntrinsic>(V);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebStrict, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(RoundingMode::Dynamic, CII->getRoundingMode());
|
2019-07-09 00:18:18 +08:00
|
|
|
|
2019-08-29 20:29:11 +08:00
|
|
|
Builder.setDefaultConstrainedExcept(fp::ebIgnore);
|
2020-03-26 15:51:09 +08:00
|
|
|
Builder.setDefaultConstrainedRounding(RoundingMode::TowardPositive);
|
2019-07-09 00:18:18 +08:00
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
CII = cast<ConstrainedFPIntrinsic>(V);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebIgnore, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(CII->getRoundingMode(), RoundingMode::TowardPositive);
|
2019-07-09 00:18:18 +08:00
|
|
|
|
2019-08-29 20:29:11 +08:00
|
|
|
Builder.setDefaultConstrainedExcept(fp::ebIgnore);
|
2020-03-26 15:51:09 +08:00
|
|
|
Builder.setDefaultConstrainedRounding(RoundingMode::NearestTiesToEven);
|
2019-08-13 13:21:18 +08:00
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
CII = cast<ConstrainedFPIntrinsic>(V);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebIgnore, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(RoundingMode::NearestTiesToEven, CII->getRoundingMode());
|
2019-08-13 13:21:18 +08:00
|
|
|
|
2019-08-29 20:29:11 +08:00
|
|
|
Builder.setDefaultConstrainedExcept(fp::ebMayTrap);
|
2020-03-26 15:51:09 +08:00
|
|
|
Builder.setDefaultConstrainedRounding(RoundingMode::TowardNegative);
|
2019-08-13 13:21:18 +08:00
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
CII = cast<ConstrainedFPIntrinsic>(V);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebMayTrap, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(RoundingMode::TowardNegative, CII->getRoundingMode());
|
2019-08-13 13:21:18 +08:00
|
|
|
|
2019-08-29 20:29:11 +08:00
|
|
|
Builder.setDefaultConstrainedExcept(fp::ebStrict);
|
2020-03-26 15:51:09 +08:00
|
|
|
Builder.setDefaultConstrainedRounding(RoundingMode::TowardZero);
|
2019-08-13 13:21:18 +08:00
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
CII = cast<ConstrainedFPIntrinsic>(V);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebStrict, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(RoundingMode::TowardZero, CII->getRoundingMode());
|
2019-08-13 13:21:18 +08:00
|
|
|
|
2019-08-29 20:29:11 +08:00
|
|
|
Builder.setDefaultConstrainedExcept(fp::ebIgnore);
|
2020-03-26 15:51:09 +08:00
|
|
|
Builder.setDefaultConstrainedRounding(RoundingMode::Dynamic);
|
2019-08-13 13:21:18 +08:00
|
|
|
V = Builder.CreateFAdd(V, V);
|
|
|
|
CII = cast<ConstrainedFPIntrinsic>(V);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebIgnore, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(RoundingMode::Dynamic, CII->getRoundingMode());
|
2019-08-13 13:21:18 +08:00
|
|
|
|
2019-07-09 00:18:18 +08:00
|
|
|
// Now override the defaults.
|
|
|
|
Call = Builder.CreateConstrainedFPBinOp(
|
|
|
|
Intrinsic::experimental_constrained_fadd, V, V, nullptr, "", nullptr,
|
2020-03-26 15:51:09 +08:00
|
|
|
RoundingMode::TowardNegative, fp::ebMayTrap);
|
2019-07-09 00:18:18 +08:00
|
|
|
CII = cast<ConstrainedFPIntrinsic>(Call);
|
|
|
|
EXPECT_EQ(CII->getIntrinsicID(), Intrinsic::experimental_constrained_fadd);
|
2019-08-29 20:29:11 +08:00
|
|
|
EXPECT_EQ(fp::ebMayTrap, CII->getExceptionBehavior());
|
2020-03-26 15:51:09 +08:00
|
|
|
EXPECT_EQ(RoundingMode::TowardNegative, CII->getRoundingMode());
|
2019-07-09 00:18:18 +08:00
|
|
|
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
}
|
2020-05-26 20:24:05 +08:00
|
|
|
|
|
|
|
TEST_F(IRBuilderTest, ConstrainedFPIntrinsics) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
Value *V;
|
|
|
|
Value *VDouble;
|
|
|
|
ConstrainedFPIntrinsic *CII;
|
|
|
|
GlobalVariable *GVDouble = new GlobalVariable(
|
|
|
|
*M, Type::getDoubleTy(Ctx), true, GlobalValue::ExternalLinkage, nullptr);
|
|
|
|
VDouble = Builder.CreateLoad(GVDouble->getValueType(), GVDouble);
|
|
|
|
|
|
|
|
Builder.setDefaultConstrainedExcept(fp::ebStrict);
|
|
|
|
Builder.setDefaultConstrainedRounding(RoundingMode::TowardZero);
|
|
|
|
Function *Fn = Intrinsic::getDeclaration(M.get(),
|
|
|
|
Intrinsic::experimental_constrained_roundeven, { Type::getDoubleTy(Ctx) });
|
|
|
|
V = Builder.CreateConstrainedFPCall(Fn, { VDouble });
|
|
|
|
CII = cast<ConstrainedFPIntrinsic>(V);
|
|
|
|
EXPECT_EQ(Intrinsic::experimental_constrained_roundeven, CII->getIntrinsicID());
|
|
|
|
EXPECT_EQ(fp::ebStrict, CII->getExceptionBehavior());
|
|
|
|
}
|
2019-07-09 00:18:18 +08:00
|
|
|
|
2020-07-29 22:33:01 +08:00
|
|
|
TEST_F(IRBuilderTest, ConstrainedFPFunctionCall) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
|
|
|
// Create an empty constrained FP function.
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
|
|
|
|
/*isVarArg=*/false);
|
|
|
|
Function *Callee =
|
|
|
|
Function::Create(FTy, Function::ExternalLinkage, "", M.get());
|
|
|
|
BasicBlock *CalleeBB = BasicBlock::Create(Ctx, "", Callee);
|
|
|
|
IRBuilder<> CalleeBuilder(CalleeBB);
|
|
|
|
CalleeBuilder.setIsFPConstrained(true);
|
|
|
|
CalleeBuilder.setConstrainedFPFunctionAttr();
|
|
|
|
CalleeBuilder.CreateRetVoid();
|
|
|
|
|
|
|
|
// Now call the empty constrained FP function.
|
|
|
|
Builder.setIsFPConstrained(true);
|
|
|
|
Builder.setConstrainedFPFunctionAttr();
|
|
|
|
CallInst *FCall = Builder.CreateCall(Callee, None);
|
|
|
|
|
|
|
|
// Check the attributes to verify the strictfp attribute is on the call.
|
2021-08-14 02:16:52 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
FCall->getAttributes().getFnAttrs().hasAttribute(Attribute::StrictFP));
|
2020-07-29 22:33:01 +08:00
|
|
|
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
}
|
|
|
|
|
2011-05-22 07:14:36 +08:00
|
|
|
TEST_F(IRBuilderTest, Lifetime) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
AllocaInst *Var1 = Builder.CreateAlloca(Builder.getInt8Ty());
|
|
|
|
AllocaInst *Var2 = Builder.CreateAlloca(Builder.getInt32Ty());
|
|
|
|
AllocaInst *Var3 = Builder.CreateAlloca(Builder.getInt8Ty(),
|
|
|
|
Builder.getInt32(123));
|
|
|
|
|
|
|
|
CallInst *Start1 = Builder.CreateLifetimeStart(Var1);
|
|
|
|
CallInst *Start2 = Builder.CreateLifetimeStart(Var2);
|
|
|
|
CallInst *Start3 = Builder.CreateLifetimeStart(Var3, Builder.getInt64(100));
|
|
|
|
|
|
|
|
EXPECT_EQ(Start1->getArgOperand(0), Builder.getInt64(-1));
|
|
|
|
EXPECT_EQ(Start2->getArgOperand(0), Builder.getInt64(-1));
|
|
|
|
EXPECT_EQ(Start3->getArgOperand(0), Builder.getInt64(100));
|
|
|
|
|
|
|
|
EXPECT_EQ(Start1->getArgOperand(1), Var1);
|
|
|
|
EXPECT_NE(Start2->getArgOperand(1), Var2);
|
|
|
|
EXPECT_EQ(Start3->getArgOperand(1), Var3);
|
|
|
|
|
|
|
|
Value *End1 = Builder.CreateLifetimeEnd(Var1);
|
|
|
|
Builder.CreateLifetimeEnd(Var2);
|
|
|
|
Builder.CreateLifetimeEnd(Var3);
|
|
|
|
|
|
|
|
IntrinsicInst *II_Start1 = dyn_cast<IntrinsicInst>(Start1);
|
|
|
|
IntrinsicInst *II_End1 = dyn_cast<IntrinsicInst>(End1);
|
2014-06-09 06:29:17 +08:00
|
|
|
ASSERT_TRUE(II_Start1 != nullptr);
|
2011-05-22 07:14:36 +08:00
|
|
|
EXPECT_EQ(II_Start1->getIntrinsicID(), Intrinsic::lifetime_start);
|
2014-06-09 06:29:17 +08:00
|
|
|
ASSERT_TRUE(II_End1 != nullptr);
|
2011-05-22 07:14:36 +08:00
|
|
|
EXPECT_EQ(II_End1->getIntrinsicID(), Intrinsic::lifetime_end);
|
|
|
|
}
|
2012-06-20 16:39:27 +08:00
|
|
|
|
2012-07-16 15:44:51 +08:00
|
|
|
TEST_F(IRBuilderTest, CreateCondBr) {
|
|
|
|
IRBuilder<> Builder(BB);
|
2013-11-15 17:34:33 +08:00
|
|
|
BasicBlock *TBB = BasicBlock::Create(Ctx, "", F);
|
|
|
|
BasicBlock *FBB = BasicBlock::Create(Ctx, "", F);
|
2012-07-16 15:44:51 +08:00
|
|
|
|
|
|
|
BranchInst *BI = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB);
|
2018-10-15 18:42:50 +08:00
|
|
|
Instruction *TI = BB->getTerminator();
|
2012-07-16 15:44:51 +08:00
|
|
|
EXPECT_EQ(BI, TI);
|
|
|
|
EXPECT_EQ(2u, TI->getNumSuccessors());
|
|
|
|
EXPECT_EQ(TBB, TI->getSuccessor(0));
|
|
|
|
EXPECT_EQ(FBB, TI->getSuccessor(1));
|
2012-07-16 15:45:06 +08:00
|
|
|
|
|
|
|
BI->eraseFromParent();
|
2013-11-15 17:34:33 +08:00
|
|
|
MDNode *Weights = MDBuilder(Ctx).createBranchWeights(42, 13);
|
2012-07-16 15:45:06 +08:00
|
|
|
BI = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB, Weights);
|
|
|
|
TI = BB->getTerminator();
|
|
|
|
EXPECT_EQ(BI, TI);
|
|
|
|
EXPECT_EQ(2u, TI->getNumSuccessors());
|
|
|
|
EXPECT_EQ(TBB, TI->getSuccessor(0));
|
|
|
|
EXPECT_EQ(FBB, TI->getSuccessor(1));
|
|
|
|
EXPECT_EQ(Weights, TI->getMetadata(LLVMContext::MD_prof));
|
2012-07-16 15:44:51 +08:00
|
|
|
}
|
|
|
|
|
2012-12-21 20:03:03 +08:00
|
|
|
TEST_F(IRBuilderTest, LandingPadName) {
|
|
|
|
IRBuilder<> Builder(BB);
|
2015-06-18 04:52:32 +08:00
|
|
|
LandingPadInst *LP = Builder.CreateLandingPad(Builder.getInt32Ty(), 0, "LP");
|
2012-12-21 20:03:03 +08:00
|
|
|
EXPECT_EQ(LP->getName(), "LP");
|
|
|
|
}
|
|
|
|
|
2014-02-26 06:23:04 +08:00
|
|
|
TEST_F(IRBuilderTest, DataLayout) {
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<Module> M(new Module("test", Ctx));
|
2014-02-26 06:23:04 +08:00
|
|
|
M->setDataLayout("e-n32");
|
2015-03-05 02:43:29 +08:00
|
|
|
EXPECT_TRUE(M->getDataLayout().isLegalInteger(32));
|
2014-02-26 06:23:04 +08:00
|
|
|
M->setDataLayout("e");
|
2015-03-05 02:43:29 +08:00
|
|
|
EXPECT_FALSE(M->getDataLayout().isLegalInteger(32));
|
2014-02-26 06:23:04 +08:00
|
|
|
}
|
|
|
|
|
2012-10-31 17:50:01 +08:00
|
|
|
TEST_F(IRBuilderTest, GetIntTy) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
IntegerType *Ty1 = Builder.getInt1Ty();
|
2013-11-15 17:34:33 +08:00
|
|
|
EXPECT_EQ(Ty1, IntegerType::get(Ctx, 1));
|
2012-10-31 17:50:01 +08:00
|
|
|
|
|
|
|
DataLayout* DL = new DataLayout(M.get());
|
2015-03-10 10:37:25 +08:00
|
|
|
IntegerType *IntPtrTy = Builder.getIntPtrTy(*DL);
|
2012-10-31 17:50:01 +08:00
|
|
|
unsigned IntPtrBitSize = DL->getPointerSizeInBits(0);
|
2013-11-15 17:34:33 +08:00
|
|
|
EXPECT_EQ(IntPtrTy, IntegerType::get(Ctx, IntPtrBitSize));
|
2013-01-23 16:31:28 +08:00
|
|
|
delete DL;
|
2012-10-31 17:50:01 +08:00
|
|
|
}
|
|
|
|
|
2019-05-28 21:00:52 +08:00
|
|
|
TEST_F(IRBuilderTest, UnaryOperators) {
|
|
|
|
IRBuilder<NoFolder> Builder(BB);
|
|
|
|
Value *V = Builder.CreateLoad(GV->getValueType(), GV);
|
|
|
|
|
2019-06-10 23:07:29 +08:00
|
|
|
// Test CreateUnOp(X)
|
2019-05-28 21:00:52 +08:00
|
|
|
Value *U = Builder.CreateUnOp(Instruction::FNeg, V);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(U));
|
|
|
|
ASSERT_TRUE(isa<FPMathOperator>(U));
|
|
|
|
ASSERT_TRUE(isa<UnaryOperator>(U));
|
|
|
|
ASSERT_FALSE(isa<BinaryOperator>(U));
|
2019-06-10 23:07:29 +08:00
|
|
|
|
|
|
|
// Test CreateFNegFMF(X)
|
2019-10-19 00:16:36 +08:00
|
|
|
Instruction *I = cast<Instruction>(U);
|
2019-06-10 23:07:29 +08:00
|
|
|
I->setHasNoSignedZeros(true);
|
|
|
|
I->setHasNoNaNs(true);
|
|
|
|
Value *VFMF = Builder.CreateFNegFMF(V, I);
|
|
|
|
Instruction *IFMF = cast<Instruction>(VFMF);
|
|
|
|
EXPECT_TRUE(IFMF->hasNoSignedZeros());
|
|
|
|
EXPECT_TRUE(IFMF->hasNoNaNs());
|
|
|
|
EXPECT_FALSE(IFMF->hasAllowReassoc());
|
2019-05-28 21:00:52 +08:00
|
|
|
}
|
|
|
|
|
2012-11-29 05:19:52 +08:00
|
|
|
TEST_F(IRBuilderTest, FastMathFlags) {
|
|
|
|
IRBuilder<> Builder(BB);
|
2015-07-10 20:52:00 +08:00
|
|
|
Value *F, *FC;
|
2015-12-15 05:59:03 +08:00
|
|
|
Instruction *FDiv, *FAdd, *FCmp, *FCall;
|
2012-11-29 05:19:52 +08:00
|
|
|
|
2019-02-02 04:44:24 +08:00
|
|
|
F = Builder.CreateLoad(GV->getValueType(), GV);
|
2012-11-29 05:19:52 +08:00
|
|
|
F = Builder.CreateFAdd(F, F);
|
|
|
|
|
|
|
|
EXPECT_FALSE(Builder.getFastMathFlags().any());
|
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FAdd = cast<Instruction>(F);
|
|
|
|
EXPECT_FALSE(FAdd->hasNoNaNs());
|
|
|
|
|
|
|
|
FastMathFlags FMF;
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
2012-11-29 05:19:52 +08:00
|
|
|
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
// By default, no flags are set.
|
2012-11-29 05:19:52 +08:00
|
|
|
F = Builder.CreateFAdd(F, F);
|
|
|
|
EXPECT_FALSE(Builder.getFastMathFlags().any());
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FAdd = cast<Instruction>(F);
|
|
|
|
EXPECT_FALSE(FAdd->hasNoNaNs());
|
|
|
|
EXPECT_FALSE(FAdd->hasNoInfs());
|
|
|
|
EXPECT_FALSE(FAdd->hasNoSignedZeros());
|
|
|
|
EXPECT_FALSE(FAdd->hasAllowReciprocal());
|
|
|
|
EXPECT_FALSE(FAdd->hasAllowContract());
|
|
|
|
EXPECT_FALSE(FAdd->hasAllowReassoc());
|
|
|
|
EXPECT_FALSE(FAdd->hasApproxFunc());
|
2012-11-29 05:19:52 +08:00
|
|
|
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
// Set all flags in the instruction.
|
|
|
|
FAdd->setFast(true);
|
|
|
|
EXPECT_TRUE(FAdd->hasNoNaNs());
|
|
|
|
EXPECT_TRUE(FAdd->hasNoInfs());
|
|
|
|
EXPECT_TRUE(FAdd->hasNoSignedZeros());
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowReciprocal());
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowContract());
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowReassoc());
|
|
|
|
EXPECT_TRUE(FAdd->hasApproxFunc());
|
|
|
|
|
|
|
|
// All flags are set in the builder.
|
|
|
|
FMF.setFast();
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
2012-11-29 05:19:52 +08:00
|
|
|
|
|
|
|
F = Builder.CreateFAdd(F, F);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().all());
|
2012-11-29 05:19:52 +08:00
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FAdd = cast<Instruction>(F);
|
|
|
|
EXPECT_TRUE(FAdd->hasNoNaNs());
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
EXPECT_TRUE(FAdd->isFast());
|
2013-12-05 08:32:09 +08:00
|
|
|
|
|
|
|
// Now, try it with CreateBinOp
|
|
|
|
F = Builder.CreateBinOp(Instruction::FAdd, F, F);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FAdd = cast<Instruction>(F);
|
|
|
|
EXPECT_TRUE(FAdd->hasNoNaNs());
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
EXPECT_TRUE(FAdd->isFast());
|
2012-11-29 05:19:52 +08:00
|
|
|
|
|
|
|
F = Builder.CreateFDiv(F, F);
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().all());
|
2012-11-29 05:19:52 +08:00
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FDiv = cast<Instruction>(F);
|
|
|
|
EXPECT_TRUE(FDiv->hasAllowReciprocal());
|
|
|
|
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
// Clear all FMF in the builder.
|
2012-11-29 05:19:52 +08:00
|
|
|
Builder.clearFastMathFlags();
|
|
|
|
|
|
|
|
F = Builder.CreateFDiv(F, F);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FDiv = cast<Instruction>(F);
|
|
|
|
EXPECT_FALSE(FDiv->hasAllowReciprocal());
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
|
|
|
|
// Try individual flags.
|
2012-11-29 05:19:52 +08:00
|
|
|
FMF.clear();
|
2012-12-10 05:12:04 +08:00
|
|
|
FMF.setAllowReciprocal();
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
2012-11-29 05:19:52 +08:00
|
|
|
|
|
|
|
F = Builder.CreateFDiv(F, F);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FDiv = cast<Instruction>(F);
|
|
|
|
EXPECT_TRUE(FDiv->hasAllowReciprocal());
|
|
|
|
|
2012-11-30 05:25:12 +08:00
|
|
|
Builder.clearFastMathFlags();
|
|
|
|
|
2015-07-10 20:52:00 +08:00
|
|
|
FC = Builder.CreateFCmpOEQ(F, F);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(FC));
|
|
|
|
FCmp = cast<Instruction>(FC);
|
|
|
|
EXPECT_FALSE(FCmp->hasAllowReciprocal());
|
|
|
|
|
|
|
|
FMF.clear();
|
|
|
|
FMF.setAllowReciprocal();
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
2015-07-10 20:52:00 +08:00
|
|
|
|
|
|
|
FC = Builder.CreateFCmpOEQ(F, F);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(FC));
|
|
|
|
FCmp = cast<Instruction>(FC);
|
|
|
|
EXPECT_TRUE(FCmp->hasAllowReciprocal());
|
|
|
|
|
2015-12-15 05:59:03 +08:00
|
|
|
Builder.clearFastMathFlags();
|
2017-03-29 04:11:52 +08:00
|
|
|
|
|
|
|
// Test FP-contract
|
|
|
|
FC = Builder.CreateFAdd(F, F);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(FC));
|
|
|
|
FAdd = cast<Instruction>(FC);
|
|
|
|
EXPECT_FALSE(FAdd->hasAllowContract());
|
|
|
|
|
|
|
|
FMF.clear();
|
|
|
|
FMF.setAllowContract(true);
|
|
|
|
Builder.setFastMathFlags(FMF);
|
|
|
|
|
|
|
|
FC = Builder.CreateFAdd(F, F);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().AllowContract);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(FC));
|
|
|
|
FAdd = cast<Instruction>(FC);
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowContract());
|
|
|
|
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
FMF.setApproxFunc();
|
|
|
|
Builder.clearFastMathFlags();
|
|
|
|
Builder.setFastMathFlags(FMF);
|
|
|
|
// Now 'aml' and 'contract' are set.
|
|
|
|
F = Builder.CreateFMul(F, F);
|
|
|
|
FAdd = cast<Instruction>(F);
|
|
|
|
EXPECT_TRUE(FAdd->hasApproxFunc());
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowContract());
|
|
|
|
EXPECT_FALSE(FAdd->hasAllowReassoc());
|
|
|
|
|
|
|
|
FMF.setAllowReassoc();
|
2017-03-29 04:11:52 +08:00
|
|
|
Builder.clearFastMathFlags();
|
[IR] redefine 'UnsafeAlgebra' / 'reassoc' fast-math-flags and add 'trans' fast-math-flag
As discussed on llvm-dev:
http://lists.llvm.org/pipermail/llvm-dev/2016-November/107104.html
and again more recently:
http://lists.llvm.org/pipermail/llvm-dev/2017-October/118118.html
...this is a step in cleaning up our fast-math-flags implementation in IR to better match
the capabilities of both clang's user-visible flags and the backend's flags for SDNode.
As proposed in the above threads, we're replacing the 'UnsafeAlgebra' bit (which had the
'umbrella' meaning that all flags are set) with a new bit that only applies to algebraic
reassociation - 'AllowReassoc'.
We're also adding a bit to allow approximations for library functions called 'ApproxFunc'
(this was initially proposed as 'libm' or similar).
...and we're out of bits. 7 bits ought to be enough for anyone, right? :) FWIW, I did
look at getting this out of SubclassOptionalData via SubclassData (spacious 16-bits),
but that's apparently already used for other purposes. Also, I don't think we can just
add a field to FPMathOperator because Operator is not intended to be instantiated.
We'll defer movement of FMF to another day.
We keep the 'fast' keyword. I thought about removing that, but seeing IR like this:
%f.fast = fadd reassoc nnan ninf nsz arcp contract afn float %op1, %op2
...made me think we want to keep the shortcut synonym.
Finally, this change is binary incompatible with existing IR as seen in the
compatibility tests. This statement:
"Newer releases can ignore features from older releases, but they cannot miscompile
them. For example, if nsw is ever replaced with something else, dropping it would be
a valid way to upgrade the IR."
( http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility )
...provides the flexibility we want to make this change without requiring a new IR
version. Ie, we're not loosening the FP strictness of existing IR. At worst, we will
fail to optimize some previously 'fast' code because it's no longer recognized as
'fast'. This should get fixed as we audit/squash all of the uses of 'isFast()'.
Note: an inter-dependent clang commit to use the new API name should closely follow
commit.
Differential Revision: https://reviews.llvm.org/D39304
llvm-svn: 317488
2017-11-07 00:27:15 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
|
|
|
// Now 'aml' and 'contract' and 'reassoc' are set.
|
|
|
|
F = Builder.CreateFMul(F, F);
|
|
|
|
FAdd = cast<Instruction>(F);
|
|
|
|
EXPECT_TRUE(FAdd->hasApproxFunc());
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowContract());
|
|
|
|
EXPECT_TRUE(FAdd->hasAllowReassoc());
|
2017-03-29 04:11:52 +08:00
|
|
|
|
2015-12-15 05:59:03 +08:00
|
|
|
// Test a call with FMF.
|
|
|
|
auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx),
|
|
|
|
/*isVarArg=*/false);
|
|
|
|
auto Callee =
|
|
|
|
Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get());
|
|
|
|
|
|
|
|
FCall = Builder.CreateCall(Callee, None);
|
|
|
|
EXPECT_FALSE(FCall->hasNoNaNs());
|
|
|
|
|
2019-02-02 04:43:25 +08:00
|
|
|
Function *V =
|
2015-12-31 23:39:34 +08:00
|
|
|
Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get());
|
|
|
|
FCall = Builder.CreateCall(V, None);
|
|
|
|
EXPECT_FALSE(FCall->hasNoNaNs());
|
|
|
|
|
2015-12-15 05:59:03 +08:00
|
|
|
FMF.clear();
|
|
|
|
FMF.setNoNaNs();
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
2015-12-15 05:59:03 +08:00
|
|
|
|
|
|
|
FCall = Builder.CreateCall(Callee, None);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs);
|
|
|
|
EXPECT_TRUE(FCall->hasNoNaNs());
|
|
|
|
|
2015-12-31 23:39:34 +08:00
|
|
|
FCall = Builder.CreateCall(V, None);
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs);
|
|
|
|
EXPECT_TRUE(FCall->hasNoNaNs());
|
|
|
|
|
2015-07-10 20:52:00 +08:00
|
|
|
Builder.clearFastMathFlags();
|
|
|
|
|
2019-04-18 16:57:58 +08:00
|
|
|
// To test a copy, make sure that a '0' and a '1' change state.
|
2012-11-30 05:25:12 +08:00
|
|
|
F = Builder.CreateFDiv(F, F);
|
|
|
|
ASSERT_TRUE(isa<Instruction>(F));
|
|
|
|
FDiv = cast<Instruction>(F);
|
|
|
|
EXPECT_FALSE(FDiv->getFastMathFlags().any());
|
2014-09-03 04:03:00 +08:00
|
|
|
FDiv->setHasAllowReciprocal(true);
|
|
|
|
FAdd->setHasAllowReciprocal(false);
|
2017-03-22 07:50:52 +08:00
|
|
|
FAdd->setHasNoNaNs(true);
|
2012-11-30 05:25:12 +08:00
|
|
|
FDiv->copyFastMathFlags(FAdd);
|
|
|
|
EXPECT_TRUE(FDiv->hasNoNaNs());
|
2014-09-03 04:03:00 +08:00
|
|
|
EXPECT_FALSE(FDiv->hasAllowReciprocal());
|
2012-11-30 05:25:12 +08:00
|
|
|
|
2012-11-29 05:19:52 +08:00
|
|
|
}
|
|
|
|
|
2014-01-05 11:22:33 +08:00
|
|
|
TEST_F(IRBuilderTest, WrapFlags) {
|
2016-03-14 05:05:13 +08:00
|
|
|
IRBuilder<NoFolder> Builder(BB);
|
2014-01-05 11:22:33 +08:00
|
|
|
|
|
|
|
// Test instructions.
|
|
|
|
GlobalVariable *G = new GlobalVariable(*M, Builder.getInt32Ty(), true,
|
2014-06-09 06:29:17 +08:00
|
|
|
GlobalValue::ExternalLinkage, nullptr);
|
2019-02-02 04:44:24 +08:00
|
|
|
Value *V = Builder.CreateLoad(G->getValueType(), G);
|
2014-01-05 11:22:33 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
cast<BinaryOperator>(Builder.CreateNSWAdd(V, V))->hasNoSignedWrap());
|
|
|
|
EXPECT_TRUE(
|
|
|
|
cast<BinaryOperator>(Builder.CreateNSWMul(V, V))->hasNoSignedWrap());
|
|
|
|
EXPECT_TRUE(
|
|
|
|
cast<BinaryOperator>(Builder.CreateNSWSub(V, V))->hasNoSignedWrap());
|
|
|
|
EXPECT_TRUE(cast<BinaryOperator>(
|
|
|
|
Builder.CreateShl(V, V, "", /* NUW */ false, /* NSW */ true))
|
|
|
|
->hasNoSignedWrap());
|
|
|
|
|
|
|
|
EXPECT_TRUE(
|
|
|
|
cast<BinaryOperator>(Builder.CreateNUWAdd(V, V))->hasNoUnsignedWrap());
|
|
|
|
EXPECT_TRUE(
|
|
|
|
cast<BinaryOperator>(Builder.CreateNUWMul(V, V))->hasNoUnsignedWrap());
|
|
|
|
EXPECT_TRUE(
|
|
|
|
cast<BinaryOperator>(Builder.CreateNUWSub(V, V))->hasNoUnsignedWrap());
|
|
|
|
EXPECT_TRUE(cast<BinaryOperator>(
|
|
|
|
Builder.CreateShl(V, V, "", /* NUW */ true, /* NSW */ false))
|
|
|
|
->hasNoUnsignedWrap());
|
|
|
|
|
|
|
|
// Test operators created with constants.
|
|
|
|
Constant *C = Builder.getInt32(42);
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWAdd(C, C))
|
|
|
|
->hasNoSignedWrap());
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWSub(C, C))
|
|
|
|
->hasNoSignedWrap());
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWMul(C, C))
|
|
|
|
->hasNoSignedWrap());
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(
|
|
|
|
Builder.CreateShl(C, C, "", /* NUW */ false, /* NSW */ true))
|
|
|
|
->hasNoSignedWrap());
|
|
|
|
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWAdd(C, C))
|
|
|
|
->hasNoUnsignedWrap());
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWSub(C, C))
|
|
|
|
->hasNoUnsignedWrap());
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWMul(C, C))
|
|
|
|
->hasNoUnsignedWrap());
|
|
|
|
EXPECT_TRUE(cast<OverflowingBinaryOperator>(
|
|
|
|
Builder.CreateShl(C, C, "", /* NUW */ true, /* NSW */ false))
|
|
|
|
->hasNoUnsignedWrap());
|
|
|
|
}
|
|
|
|
|
2013-09-30 23:39:48 +08:00
|
|
|
TEST_F(IRBuilderTest, RAIIHelpersTest) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal());
|
|
|
|
MDBuilder MDB(M->getContext());
|
|
|
|
|
2013-10-06 03:41:41 +08:00
|
|
|
MDNode *FPMathA = MDB.createFPMath(0.01f);
|
|
|
|
MDNode *FPMathB = MDB.createFPMath(0.1f);
|
2013-09-30 23:39:48 +08:00
|
|
|
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setDefaultFPMathTag(FPMathA);
|
2013-09-30 23:39:48 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
IRBuilder<>::FastMathFlagGuard Guard(Builder);
|
|
|
|
FastMathFlags FMF;
|
|
|
|
FMF.setAllowReciprocal();
|
2016-01-13 02:03:37 +08:00
|
|
|
Builder.setFastMathFlags(FMF);
|
|
|
|
Builder.setDefaultFPMathTag(FPMathB);
|
2013-09-30 23:39:48 +08:00
|
|
|
EXPECT_TRUE(Builder.getFastMathFlags().allowReciprocal());
|
|
|
|
EXPECT_EQ(FPMathB, Builder.getDefaultFPMathTag());
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal());
|
|
|
|
EXPECT_EQ(FPMathA, Builder.getDefaultFPMathTag());
|
|
|
|
|
2019-02-02 04:44:24 +08:00
|
|
|
Value *F = Builder.CreateLoad(GV->getValueType(), GV);
|
2013-09-30 23:39:48 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
IRBuilder<>::InsertPointGuard Guard(Builder);
|
|
|
|
Builder.SetInsertPoint(cast<Instruction>(F));
|
2015-10-21 02:30:20 +08:00
|
|
|
EXPECT_EQ(F, &*Builder.GetInsertPoint());
|
2013-09-30 23:39:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(BB->end(), Builder.GetInsertPoint());
|
|
|
|
EXPECT_EQ(BB, Builder.GetInsertBlock());
|
|
|
|
}
|
|
|
|
|
2017-04-27 06:56:44 +08:00
|
|
|
TEST_F(IRBuilderTest, createFunction) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
auto File = DIB.createFile("error.swift", "/");
|
|
|
|
auto CU =
|
|
|
|
DIB.createCompileUnit(dwarf::DW_LANG_Swift, File, "swiftc", true, "", 0);
|
|
|
|
auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
|
2018-11-20 02:29:28 +08:00
|
|
|
auto NoErr = DIB.createFunction(
|
|
|
|
CU, "noerr", "", File, 1, Type, 1, DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
|
2017-04-27 06:56:44 +08:00
|
|
|
EXPECT_TRUE(!NoErr->getThrownTypes());
|
|
|
|
auto Int = DIB.createBasicType("Int", 64, dwarf::DW_ATE_signed);
|
|
|
|
auto Error = DIB.getOrCreateArray({Int});
|
2018-11-20 02:29:28 +08:00
|
|
|
auto Err = DIB.createFunction(
|
|
|
|
CU, "err", "", File, 1, Type, 1, DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized, nullptr,
|
|
|
|
nullptr, Error.get());
|
2017-04-27 06:56:44 +08:00
|
|
|
EXPECT_TRUE(Err->getThrownTypes().get() == Error.get());
|
|
|
|
DIB.finalize();
|
|
|
|
}
|
|
|
|
|
2015-01-22 02:32:56 +08:00
|
|
|
TEST_F(IRBuilderTest, DIBuilder) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
auto File = DIB.createFile("F.CBL", "/");
|
2016-12-15 04:24:54 +08:00
|
|
|
auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74,
|
|
|
|
DIB.createFile("F.CBL", "/"), "llvm-cobol74",
|
|
|
|
true, "", 0);
|
2015-10-15 14:56:10 +08:00
|
|
|
auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
|
2018-11-20 02:29:28 +08:00
|
|
|
auto SP = DIB.createFunction(
|
|
|
|
CU, "foo", "", File, 1, Type, 1, DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
|
2015-11-06 06:03:56 +08:00
|
|
|
F->setSubprogram(SP);
|
2015-01-22 02:32:56 +08:00
|
|
|
AllocaInst *I = Builder.CreateAlloca(Builder.getInt8Ty());
|
2018-11-20 02:29:28 +08:00
|
|
|
auto BarSP = DIB.createFunction(
|
|
|
|
CU, "bar", "", File, 1, Type, 1, DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
|
2015-03-31 00:37:48 +08:00
|
|
|
auto BadScope = DIB.createLexicalBlockFile(BarSP, File, 0);
|
2020-12-16 06:17:04 +08:00
|
|
|
I->setDebugLoc(DILocation::get(Ctx, 2, 0, BadScope));
|
2015-01-22 03:25:35 +08:00
|
|
|
DIB.finalize();
|
2015-03-31 10:09:55 +08:00
|
|
|
EXPECT_TRUE(verifyModule(*M));
|
2015-01-22 02:32:56 +08:00
|
|
|
}
|
|
|
|
|
2018-06-02 07:15:09 +08:00
|
|
|
TEST_F(IRBuilderTest, createArtificialSubprogram) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
auto File = DIB.createFile("main.c", "/");
|
|
|
|
auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "clang",
|
|
|
|
/*isOptimized=*/true, /*Flags=*/"",
|
|
|
|
/*Runtime Version=*/0);
|
|
|
|
auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
|
2018-11-20 02:29:28 +08:00
|
|
|
auto SP = DIB.createFunction(
|
|
|
|
CU, "foo", /*LinkageName=*/"", File,
|
|
|
|
/*LineNo=*/1, Type, /*ScopeLine=*/2, DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
|
2018-06-02 07:15:09 +08:00
|
|
|
EXPECT_TRUE(SP->isDistinct());
|
|
|
|
|
|
|
|
F->setSubprogram(SP);
|
|
|
|
AllocaInst *I = Builder.CreateAlloca(Builder.getInt8Ty());
|
|
|
|
ReturnInst *R = Builder.CreateRetVoid();
|
2020-12-16 06:17:04 +08:00
|
|
|
I->setDebugLoc(DILocation::get(Ctx, 3, 2, SP));
|
|
|
|
R->setDebugLoc(DILocation::get(Ctx, 4, 2, SP));
|
2018-06-02 07:15:09 +08:00
|
|
|
DIB.finalize();
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
|
|
|
|
Function *G = Function::Create(F->getFunctionType(),
|
|
|
|
Function::ExternalLinkage, "", M.get());
|
|
|
|
BasicBlock *GBB = BasicBlock::Create(Ctx, "", G);
|
|
|
|
Builder.SetInsertPoint(GBB);
|
|
|
|
I->removeFromParent();
|
|
|
|
Builder.Insert(I);
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
|
|
|
|
DISubprogram *GSP = DIBuilder::createArtificialSubprogram(F->getSubprogram());
|
|
|
|
EXPECT_EQ(SP->getFile(), GSP->getFile());
|
|
|
|
EXPECT_EQ(SP->getType(), GSP->getType());
|
|
|
|
EXPECT_EQ(SP->getLine(), GSP->getLine());
|
|
|
|
EXPECT_EQ(SP->getScopeLine(), GSP->getScopeLine());
|
|
|
|
EXPECT_TRUE(GSP->isDistinct());
|
|
|
|
|
|
|
|
G->setSubprogram(GSP);
|
|
|
|
EXPECT_TRUE(verifyModule(*M));
|
|
|
|
|
|
|
|
auto *InlinedAtNode =
|
|
|
|
DILocation::getDistinct(Ctx, GSP->getScopeLine(), 0, GSP);
|
|
|
|
DebugLoc DL = I->getDebugLoc();
|
|
|
|
DenseMap<const MDNode *, MDNode *> IANodes;
|
|
|
|
auto IA = DebugLoc::appendInlinedAt(DL, InlinedAtNode, Ctx, IANodes);
|
2020-12-16 06:17:04 +08:00
|
|
|
auto NewDL =
|
|
|
|
DILocation::get(Ctx, DL.getLine(), DL.getCol(), DL.getScope(), IA);
|
2018-06-02 07:15:09 +08:00
|
|
|
I->setDebugLoc(NewDL);
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
|
|
|
|
EXPECT_EQ("foo", SP->getName());
|
|
|
|
EXPECT_EQ("foo", GSP->getName());
|
|
|
|
EXPECT_FALSE(SP->isArtificial());
|
|
|
|
EXPECT_TRUE(GSP->isArtificial());
|
|
|
|
}
|
|
|
|
|
2021-11-30 11:43:25 +08:00
|
|
|
// Check that we can add debug info to an existing DICompileUnit.
|
|
|
|
TEST_F(IRBuilderTest, appendDebugInfo) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
|
|
|
|
auto GetNames = [](DICompileUnit *CU) {
|
|
|
|
SmallVector<StringRef> Names;
|
|
|
|
for (auto *ET : CU->getEnumTypes())
|
|
|
|
Names.push_back(ET->getName());
|
|
|
|
for (auto *RT : CU->getRetainedTypes())
|
|
|
|
Names.push_back(RT->getName());
|
|
|
|
for (auto *GV : CU->getGlobalVariables())
|
|
|
|
Names.push_back(GV->getVariable()->getName());
|
|
|
|
for (auto *IE : CU->getImportedEntities())
|
|
|
|
Names.push_back(IE->getName());
|
|
|
|
for (auto *Node : CU->getMacros())
|
|
|
|
if (auto *MN = dyn_cast_or_null<DIMacro>(Node))
|
|
|
|
Names.push_back(MN->getName());
|
|
|
|
return Names;
|
|
|
|
};
|
|
|
|
|
|
|
|
DICompileUnit *CU;
|
|
|
|
{
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
auto *File = DIB.createFile("main.c", "/");
|
|
|
|
CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "clang",
|
|
|
|
/*isOptimized=*/true, /*Flags=*/"",
|
|
|
|
/*Runtime Version=*/0);
|
|
|
|
auto *ByteTy = DIB.createBasicType("byte0", 8, dwarf::DW_ATE_signed);
|
|
|
|
DIB.createEnumerationType(CU, "ET0", File, /*LineNo=*/0, /*SizeInBits=*/8,
|
|
|
|
/*AlignInBits=*/8, /*Elements=*/{}, ByteTy);
|
|
|
|
DIB.retainType(ByteTy);
|
|
|
|
DIB.createGlobalVariableExpression(CU, "GV0", /*LinkageName=*/"", File,
|
|
|
|
/*LineNo=*/1, ByteTy,
|
|
|
|
/*IsLocalToUnit=*/true);
|
|
|
|
DIB.createImportedDeclaration(CU, nullptr, File, /*LineNo=*/2, "IM0");
|
|
|
|
DIB.createMacro(nullptr, /*LineNo=*/0, dwarf::DW_MACINFO_define, "M0");
|
|
|
|
DIB.finalize();
|
|
|
|
}
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
EXPECT_THAT(GetNames(CU),
|
|
|
|
UnorderedElementsAre("ET0", "byte0", "GV0", "IM0", "M0"));
|
|
|
|
|
|
|
|
{
|
|
|
|
DIBuilder DIB(*M, true, CU);
|
|
|
|
auto *File = CU->getFile();
|
|
|
|
auto *ByteTy = DIB.createBasicType("byte1", 8, dwarf::DW_ATE_signed);
|
|
|
|
DIB.createEnumerationType(CU, "ET1", File, /*LineNo=*/0,
|
|
|
|
/*SizeInBits=*/8, /*AlignInBits=*/8,
|
|
|
|
/*Elements=*/{}, ByteTy);
|
|
|
|
DIB.retainType(ByteTy);
|
|
|
|
DIB.createGlobalVariableExpression(CU, "GV1", /*LinkageName=*/"", File,
|
|
|
|
/*LineNo=*/1, ByteTy,
|
|
|
|
/*IsLocalToUnit=*/true);
|
|
|
|
DIB.createImportedDeclaration(CU, nullptr, File, /*LineNo=*/2, "IM1");
|
|
|
|
DIB.createMacro(nullptr, /*LineNo=*/0, dwarf::DW_MACINFO_define, "M1");
|
|
|
|
DIB.finalize();
|
|
|
|
}
|
|
|
|
EXPECT_FALSE(verifyModule(*M));
|
|
|
|
EXPECT_THAT(GetNames(CU),
|
|
|
|
UnorderedElementsAre("ET0", "byte0", "GV0", "IM0", "M0", "ET1",
|
|
|
|
"byte1", "GV1", "IM1", "M1"));
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:01:22 +08:00
|
|
|
TEST_F(IRBuilderTest, InsertExtractElement) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
2020-06-17 05:55:32 +08:00
|
|
|
auto VecTy = FixedVectorType::get(Builder.getInt64Ty(), 4);
|
2015-04-30 17:01:22 +08:00
|
|
|
auto Elt1 = Builder.getInt64(-1);
|
|
|
|
auto Elt2 = Builder.getInt64(-2);
|
2021-09-27 00:07:49 +08:00
|
|
|
Value *Vec = Builder.CreateInsertElement(VecTy, Elt1, Builder.getInt8(1));
|
2015-04-30 17:01:22 +08:00
|
|
|
Vec = Builder.CreateInsertElement(Vec, Elt2, 2);
|
|
|
|
auto X1 = Builder.CreateExtractElement(Vec, 1);
|
|
|
|
auto X2 = Builder.CreateExtractElement(Vec, Builder.getInt32(2));
|
|
|
|
EXPECT_EQ(Elt1, X1);
|
|
|
|
EXPECT_EQ(Elt2, X2);
|
|
|
|
}
|
|
|
|
|
2015-06-19 15:19:17 +08:00
|
|
|
TEST_F(IRBuilderTest, CreateGlobalStringPtr) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
|
|
|
auto String1a = Builder.CreateGlobalStringPtr("TestString", "String1a");
|
|
|
|
auto String1b = Builder.CreateGlobalStringPtr("TestString", "String1b", 0);
|
|
|
|
auto String2 = Builder.CreateGlobalStringPtr("TestString", "String2", 1);
|
|
|
|
auto String3 = Builder.CreateGlobalString("TestString", "String3", 2);
|
2013-09-30 23:39:48 +08:00
|
|
|
|
2015-06-19 15:19:17 +08:00
|
|
|
EXPECT_TRUE(String1a->getType()->getPointerAddressSpace() == 0);
|
|
|
|
EXPECT_TRUE(String1b->getType()->getPointerAddressSpace() == 0);
|
|
|
|
EXPECT_TRUE(String2->getType()->getPointerAddressSpace() == 1);
|
|
|
|
EXPECT_TRUE(String3->getType()->getPointerAddressSpace() == 2);
|
|
|
|
}
|
2015-07-01 03:07:20 +08:00
|
|
|
|
|
|
|
TEST_F(IRBuilderTest, DebugLoc) {
|
|
|
|
auto CalleeTy = FunctionType::get(Type::getVoidTy(Ctx),
|
|
|
|
/*isVarArg=*/false);
|
|
|
|
auto Callee =
|
|
|
|
Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get());
|
|
|
|
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
auto File = DIB.createFile("tmp.cpp", "/");
|
2016-12-15 04:24:54 +08:00
|
|
|
auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C_plus_plus_11,
|
|
|
|
DIB.createFile("tmp.cpp", "/"), "", true, "",
|
|
|
|
0);
|
2015-10-15 14:56:10 +08:00
|
|
|
auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
|
2015-07-01 03:07:20 +08:00
|
|
|
auto SP =
|
2018-11-20 02:29:28 +08:00
|
|
|
DIB.createFunction(CU, "foo", "foo", File, 1, SPType, 1, DINode::FlagZero,
|
|
|
|
DISubprogram::SPFlagDefinition);
|
2015-07-01 03:07:20 +08:00
|
|
|
DebugLoc DL1 = DILocation::get(Ctx, 2, 0, SP);
|
|
|
|
DebugLoc DL2 = DILocation::get(Ctx, 3, 0, SP);
|
|
|
|
|
|
|
|
auto BB2 = BasicBlock::Create(Ctx, "bb2", F);
|
|
|
|
auto Br = BranchInst::Create(BB2, BB);
|
|
|
|
Br->setDebugLoc(DL1);
|
|
|
|
|
|
|
|
IRBuilder<> Builder(Ctx);
|
|
|
|
Builder.SetInsertPoint(Br);
|
|
|
|
EXPECT_EQ(DL1, Builder.getCurrentDebugLocation());
|
|
|
|
auto Call1 = Builder.CreateCall(Callee, None);
|
|
|
|
EXPECT_EQ(DL1, Call1->getDebugLoc());
|
|
|
|
|
|
|
|
Call1->setDebugLoc(DL2);
|
2015-10-21 02:30:20 +08:00
|
|
|
Builder.SetInsertPoint(Call1->getParent(), Call1->getIterator());
|
2015-07-01 03:07:20 +08:00
|
|
|
EXPECT_EQ(DL2, Builder.getCurrentDebugLocation());
|
|
|
|
auto Call2 = Builder.CreateCall(Callee, None);
|
|
|
|
EXPECT_EQ(DL2, Call2->getDebugLoc());
|
2015-07-01 06:17:29 +08:00
|
|
|
|
|
|
|
DIB.finalize();
|
2015-07-01 03:07:20 +08:00
|
|
|
}
|
2016-03-13 19:11:39 +08:00
|
|
|
|
|
|
|
TEST_F(IRBuilderTest, DIImportedEntity) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
DIBuilder DIB(*M);
|
2017-07-19 08:09:54 +08:00
|
|
|
auto F = DIB.createFile("F.CBL", "/");
|
2016-12-15 04:24:54 +08:00
|
|
|
auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74,
|
2017-07-19 08:09:54 +08:00
|
|
|
F, "llvm-cobol74",
|
2016-12-15 04:24:54 +08:00
|
|
|
true, "", 0);
|
2021-09-07 13:55:44 +08:00
|
|
|
MDTuple *Elements = MDTuple::getDistinct(Ctx, None);
|
|
|
|
|
2017-07-19 08:09:54 +08:00
|
|
|
DIB.createImportedDeclaration(CU, nullptr, F, 1);
|
|
|
|
DIB.createImportedDeclaration(CU, nullptr, F, 1);
|
|
|
|
DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, F, 2);
|
|
|
|
DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, F, 2);
|
2021-09-07 13:55:44 +08:00
|
|
|
DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, F, 2, Elements);
|
|
|
|
DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, F, 2, Elements);
|
2016-03-13 19:11:39 +08:00
|
|
|
DIB.finalize();
|
|
|
|
EXPECT_TRUE(verifyModule(*M));
|
2021-09-07 13:55:44 +08:00
|
|
|
EXPECT_TRUE(CU->getImportedEntities().size() == 3);
|
2016-03-13 19:11:39 +08:00
|
|
|
}
|
2017-01-12 23:49:46 +08:00
|
|
|
|
|
|
|
// 0: #define M0 V0 <-- command line definition
|
|
|
|
// 0: main.c <-- main file
|
|
|
|
// 3: #define M1 V1 <-- M1 definition in main.c
|
|
|
|
// 5: #include "file.h" <-- inclusion of file.h from main.c
|
|
|
|
// 1: #define M2 <-- M2 definition in file.h with no value
|
|
|
|
// 7: #undef M1 V1 <-- M1 un-definition in main.c
|
|
|
|
TEST_F(IRBuilderTest, DIBuilderMacro) {
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
DIBuilder DIB(*M);
|
|
|
|
auto File1 = DIB.createFile("main.c", "/");
|
|
|
|
auto File2 = DIB.createFile("file.h", "/");
|
|
|
|
auto CU = DIB.createCompileUnit(
|
|
|
|
dwarf::DW_LANG_C, DIB.createFile("main.c", "/"), "llvm-c", true, "", 0);
|
|
|
|
auto MDef0 =
|
|
|
|
DIB.createMacro(nullptr, 0, dwarf::DW_MACINFO_define, "M0", "V0");
|
|
|
|
auto TMF1 = DIB.createTempMacroFile(nullptr, 0, File1);
|
|
|
|
auto MDef1 = DIB.createMacro(TMF1, 3, dwarf::DW_MACINFO_define, "M1", "V1");
|
|
|
|
auto TMF2 = DIB.createTempMacroFile(TMF1, 5, File2);
|
|
|
|
auto MDef2 = DIB.createMacro(TMF2, 1, dwarf::DW_MACINFO_define, "M2");
|
|
|
|
auto MUndef1 = DIB.createMacro(TMF1, 7, dwarf::DW_MACINFO_undef, "M1");
|
|
|
|
|
|
|
|
EXPECT_EQ(dwarf::DW_MACINFO_define, MDef1->getMacinfoType());
|
2017-01-13 01:44:32 +08:00
|
|
|
EXPECT_EQ(3u, MDef1->getLine());
|
2017-01-12 23:49:46 +08:00
|
|
|
EXPECT_EQ("M1", MDef1->getName());
|
|
|
|
EXPECT_EQ("V1", MDef1->getValue());
|
|
|
|
|
|
|
|
EXPECT_EQ(dwarf::DW_MACINFO_undef, MUndef1->getMacinfoType());
|
2017-01-13 01:44:32 +08:00
|
|
|
EXPECT_EQ(7u, MUndef1->getLine());
|
2017-01-12 23:49:46 +08:00
|
|
|
EXPECT_EQ("M1", MUndef1->getName());
|
|
|
|
EXPECT_EQ("", MUndef1->getValue());
|
|
|
|
|
|
|
|
EXPECT_EQ(dwarf::DW_MACINFO_start_file, TMF2->getMacinfoType());
|
2017-01-13 01:44:32 +08:00
|
|
|
EXPECT_EQ(5u, TMF2->getLine());
|
2017-01-12 23:49:46 +08:00
|
|
|
EXPECT_EQ(File2, TMF2->getFile());
|
|
|
|
|
|
|
|
DIB.finalize();
|
|
|
|
|
|
|
|
SmallVector<Metadata *, 4> Elements;
|
|
|
|
Elements.push_back(MDef2);
|
|
|
|
auto MF2 = DIMacroFile::get(Ctx, dwarf::DW_MACINFO_start_file, 5, File2,
|
|
|
|
DIB.getOrCreateMacroArray(Elements));
|
|
|
|
|
|
|
|
Elements.clear();
|
|
|
|
Elements.push_back(MDef1);
|
|
|
|
Elements.push_back(MF2);
|
|
|
|
Elements.push_back(MUndef1);
|
|
|
|
auto MF1 = DIMacroFile::get(Ctx, dwarf::DW_MACINFO_start_file, 0, File1,
|
|
|
|
DIB.getOrCreateMacroArray(Elements));
|
|
|
|
|
|
|
|
Elements.clear();
|
|
|
|
Elements.push_back(MDef0);
|
|
|
|
Elements.push_back(MF1);
|
|
|
|
auto MN0 = MDTuple::get(Ctx, Elements);
|
|
|
|
EXPECT_EQ(MN0, CU->getRawMacros());
|
|
|
|
|
|
|
|
Elements.clear();
|
|
|
|
Elements.push_back(MDef1);
|
|
|
|
Elements.push_back(MF2);
|
|
|
|
Elements.push_back(MUndef1);
|
|
|
|
auto MN1 = MDTuple::get(Ctx, Elements);
|
|
|
|
EXPECT_EQ(MN1, MF1->getRawElements());
|
|
|
|
|
|
|
|
Elements.clear();
|
|
|
|
Elements.push_back(MDef2);
|
|
|
|
auto MN2 = MDTuple::get(Ctx, Elements);
|
|
|
|
EXPECT_EQ(MN2, MF2->getRawElements());
|
|
|
|
EXPECT_TRUE(verifyModule(*M));
|
|
|
|
}
|
2020-02-18 12:10:30 +08:00
|
|
|
|
|
|
|
TEST_F(IRBuilderTest, NoFolderNames) {
|
|
|
|
IRBuilder<NoFolder> Builder(BB);
|
|
|
|
auto *Add =
|
|
|
|
Builder.CreateAdd(Builder.getInt32(1), Builder.getInt32(2), "add");
|
|
|
|
EXPECT_EQ(Add->getName(), "add");
|
|
|
|
}
|
2012-06-20 16:39:27 +08:00
|
|
|
}
|