GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/codegen/ConstantFolding.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 16 16 100.0%
Functions: 21 319 6.6%
Branches: 17 32 53.1%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file codegen/ConstantFolding.h
5 ///
6 /// @authors Nick Avramoussis
7 ///
8 /// @brief Constant folding for C++ bindings.
9 ///
10
11 #ifndef OPENVDB_AX_CODEGEN_CONSTANT_FOLDING_HAS_BEEN_INCLUDED
12 #define OPENVDB_AX_CODEGEN_CONSTANT_FOLDING_HAS_BEEN_INCLUDED
13
14 #include "Types.h"
15
16 #include <openvdb/version.h>
17
18 #include <llvm/IR/Constants.h>
19
20 #include <type_traits>
21 #include <vector>
22
23 namespace openvdb {
24 OPENVDB_USE_VERSION_NAMESPACE
25 namespace OPENVDB_VERSION_NAME {
26
27 namespace ax {
28 namespace codegen {
29
30 /// @brief Constant folding support structure
31 ///
32 template <typename SignatureT,
33 size_t I = FunctionTraits<SignatureT>::N_ARGS>
34 struct ConstantFolder
35 {
36 using ArgT = typename FunctionTraits<SignatureT>::template Arg<I-1>;
37 using ArgumentValueType = typename ArgT::Type;
38
39 // @brief Attempts evaluate a given function with a provided set of constant llvm
40 // values. If successful, the function is invoked and the result is stored
41 // and returned in an llvm::Value.
42 // @details Currently only scalar constant folding is supported due to the way
43 // vectors and matrices are alloced. Functions which return void are also
44 // not supported for constant folding.
45 // @param args The vector of llvm constants that comprise the function arguments.
46 // Note that the size of this vector is expected to match the size of
47 // the required function arguments and the templated parameter I
48 // @param function The function to invoke if all arguments have a valid mapping.
49 // @param C The llvm Context
50 // @param ts The list of evaluated C types from the provided llvm constants. This
51 // is expected to be empty (not provided) on the first call to fold and
52 // is used on subsequent recursive calls.
53 template <typename ...Tys>
54 static llvm::Value*
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 797 times.
1594 fold(const std::vector<llvm::Constant*>& args,
56 const SignatureT& function,
57 llvm::LLVMContext& C,
58 Tys&&... ts)
59 {
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 797 times.
1594 assert(I-1 < args.size());
61
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 665 times.
1594 llvm::Constant* constant = args[I-1];
62 const llvm::Type* type = constant->getType();
63
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 665 times.
1594 if (type->isIntegerTy()) {
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
264 assert(llvm::isa<llvm::ConstantInt>(constant));
65 llvm::ConstantInt* cint =
66 264 llvm::cast<llvm::ConstantInt>(constant);
67 const uint64_t val = cint->getLimitedValue();
68 return call<uint64_t, ArgumentValueType>(args, function, C, val, ts...);
69 }
70
4/4
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 229 times.
✓ Branch 2 taken 360 times.
✓ Branch 3 taken 76 times.
1330 else if (type->isFloatTy() || type->isDoubleTy()) {
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
1178 assert(llvm::isa<llvm::ConstantFP>(constant));
72 llvm::ConstantFP* cfp =
73 1178 llvm::cast<llvm::ConstantFP>(constant);
74 const llvm::APFloat& apf = cfp->getValueAPF();
75
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 360 times.
1178 if (type->isFloatTy()) {
76 458 const float val = apf.convertToFloat();
77 return call<float, ArgumentValueType>(args, function, C, val, ts...);
78 }
79
1/2
✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
720 if (type->isDoubleTy()) {
80 720 const double val = apf.convertToDouble();
81 return call<double, ArgumentValueType>(args, function, C, val, ts...);
82 }
83 }
84 else if (type->isArrayTy()) {
85 // @todo currently all arrays are alloced anyway which
86 // needs to be handled or changed
87 return nullptr;
88 }
89 // fallback
90 return nullptr;
91 }
92 private:
93 // @brief Specialization for supported implicit casting matching AX's supported
94 // scalar casting. Continues to traverse the constant argument list.
95 template <typename In, typename Out, typename ...Tys>
96 static typename std::enable_if<std::is_convertible<In, Out>::value, llvm::Value*>::type
97 call(const std::vector<llvm::Constant*>& args,
98 const SignatureT& function,
99 llvm::LLVMContext& C,
100 const In& arg,
101 Tys&&... ts)
102 {
103 using Next = ConstantFolder<SignatureT, I-1>;
104 280 return Next::fold(args, function, C, Out(arg), ts...);
105 }
106
107 // @brief Specialization for unsupported implicit casting. Bails out with a
108 // nullptr return.
109 template <typename In, typename Out, typename ...Tys>
110 static typename std::enable_if<!std::is_convertible<In, Out>::value, llvm::Value*>::type
111 call(const std::vector<llvm::Constant*>&,
112 const SignatureT&,
113 llvm::LLVMContext&,
114 const In&, Tys&&...)
115 {
116 return nullptr;
117 }
118 };
119
120 template <typename SignatureT>
121 struct ConstantFolder<SignatureT, 0>
122 {
123 // @brief The final call to fold when all arguments have been evaluated (or no
124 // arguments exist).
125 template <typename ...Tys>
126 static llvm::Value*
127 fold(const std::vector<llvm::Constant*>& args,
128 const SignatureT& function,
129 llvm::LLVMContext& C,
130 Tys&&... ts)
131 {
132 using ReturnT = typename FunctionTraits<SignatureT>::ReturnType;
133 return call<ReturnT>(args, function, C, ts...);
134 }
135
136 private:
137
138 // @brief Specialization for the invoking of the provided function if the return
139 // type is not void or a pointer
140 template <typename ReturnT, typename ...Tys>
141 static typename std::enable_if<!std::is_pointer<ReturnT>::value &&
142 !std::is_same<ReturnT, void>::value, llvm::Value*>::type
143 call(const std::vector<llvm::Constant*>&,
144 const SignatureT& function,
145 llvm::LLVMContext& C,
146 Tys&&... ts)
147 {
148
1/6
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
442 const ReturnT result = function(ts...);
149
1/6
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
442 return LLVMType<ReturnT>::get(C, result);
150 }
151
152 // @brief Specialization if the return type is void or a pointer. No folding is
153 // supported.
154 template <typename ReturnT, typename ...Tys>
155 static typename std::enable_if<std::is_pointer<ReturnT>::value ||
156 std::is_same<ReturnT, void>::value, llvm::Value*>::type
157 call(const std::vector<llvm::Constant*>&,
158 const SignatureT&,
159 llvm::LLVMContext&,
160 Tys&&...)
161 {
162 return nullptr;
163 }
164 };
165
166 } // namespace codegen
167 } // namespace ax
168 } // namespace OPENVDB_VERSION_NAME
169 } // namespace openvdb
170
171 #endif // OPENVDB_AX_CODEGEN_CONSTANT_FOLDING_HAS_BEEN_INCLUDED
172
173