]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
1 | // Licensed to the Apache Software Foundation (ASF) under one |
2 | // or more contributor license agreements. See the NOTICE file | |
3 | // distributed with this work for additional information | |
4 | // regarding copyright ownership. The ASF licenses this file | |
5 | // to you under the Apache License, Version 2.0 (the | |
6 | // "License"); you may not use this file except in compliance | |
7 | // with the License. You may obtain a copy of the License at | |
8 | // | |
9 | // http://www.apache.org/licenses/LICENSE-2.0 | |
10 | // | |
11 | // Unless required by applicable law or agreed to in writing, | |
12 | // software distributed under the License is distributed on an | |
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | // KIND, either express or implied. See the License for the | |
15 | // specific language governing permissions and limitations | |
16 | // under the License. | |
17 | ||
18 | #pragma once | |
19 | ||
20 | #include <memory> | |
21 | #include <string> | |
22 | #include <vector> | |
23 | ||
24 | #include "gandiva/function_ir_builder.h" | |
25 | ||
26 | namespace gandiva { | |
27 | ||
28 | /// @brief Decimal IR functions | |
29 | class DecimalIR : public FunctionIRBuilder { | |
30 | public: | |
31 | explicit DecimalIR(Engine* engine) | |
32 | : FunctionIRBuilder(engine), enable_ir_traces_(false) {} | |
33 | ||
34 | /// Build decimal IR functions and add them to the engine. | |
35 | static Status AddFunctions(Engine* engine); | |
36 | ||
37 | void EnableTraces() { enable_ir_traces_ = true; } | |
38 | ||
39 | llvm::Value* CallDecimalFunction(const std::string& function_name, | |
40 | llvm::Type* return_type, | |
41 | const std::vector<llvm::Value*>& args); | |
42 | ||
43 | private: | |
44 | /// The intrinsic fn for divide with small divisors is about 10x slower, so not | |
45 | /// using these. | |
46 | static const bool kUseOverflowIntrinsics = false; | |
47 | ||
48 | // Holder for an i128 value, along with its with scale and precision. | |
49 | class ValueFull { | |
50 | public: | |
51 | ValueFull(llvm::Value* value, llvm::Value* precision, llvm::Value* scale) | |
52 | : value_(value), precision_(precision), scale_(scale) {} | |
53 | ||
54 | llvm::Value* value() const { return value_; } | |
55 | llvm::Value* precision() const { return precision_; } | |
56 | llvm::Value* scale() const { return scale_; } | |
57 | ||
58 | private: | |
59 | llvm::Value* value_; | |
60 | llvm::Value* precision_; | |
61 | llvm::Value* scale_; | |
62 | }; | |
63 | ||
64 | // Holder for an i128 value, and a boolean indicating overflow. | |
65 | class ValueWithOverflow { | |
66 | public: | |
67 | ValueWithOverflow(llvm::Value* value, llvm::Value* overflow) | |
68 | : value_(value), overflow_(overflow) {} | |
69 | ||
70 | // Make from IR struct | |
71 | static ValueWithOverflow MakeFromStruct(DecimalIR* decimal_ir, llvm::Value* dstruct); | |
72 | ||
73 | // Build a corresponding IR struct | |
74 | llvm::Value* AsStruct(DecimalIR* decimal_ir) const; | |
75 | ||
76 | llvm::Value* value() const { return value_; } | |
77 | llvm::Value* overflow() const { return overflow_; } | |
78 | ||
79 | private: | |
80 | llvm::Value* value_; | |
81 | llvm::Value* overflow_; | |
82 | }; | |
83 | ||
84 | // Holder for an i128 value that is split into two i64s | |
85 | class ValueSplit { | |
86 | public: | |
87 | ValueSplit(llvm::Value* high, llvm::Value* low) : high_(high), low_(low) {} | |
88 | ||
89 | // Make from i128 value | |
90 | static ValueSplit MakeFromInt128(DecimalIR* decimal_ir, llvm::Value* in); | |
91 | ||
92 | // Make from IR struct | |
93 | static ValueSplit MakeFromStruct(DecimalIR* decimal_ir, llvm::Value* dstruct); | |
94 | ||
95 | // Combine the two parts into an i128 | |
96 | llvm::Value* AsInt128(DecimalIR* decimal_ir) const; | |
97 | ||
98 | llvm::Value* high() const { return high_; } | |
99 | llvm::Value* low() const { return low_; } | |
100 | ||
101 | private: | |
102 | llvm::Value* high_; | |
103 | llvm::Value* low_; | |
104 | }; | |
105 | ||
106 | // Add global variables to the module. | |
107 | static void AddGlobals(Engine* engine); | |
108 | ||
109 | // Initialize intrinsic functions that are used by decimal operations. | |
110 | void InitializeIntrinsics(); | |
111 | ||
112 | // Create IR builder for decimal add function. | |
113 | static Status MakeAdd(Engine* engine, std::shared_ptr<FunctionIRBuilder>* out); | |
114 | ||
115 | // Get the multiplier for specified scale (i.e 10^scale) | |
116 | llvm::Value* GetScaleMultiplier(llvm::Value* scale); | |
117 | ||
118 | // Get the higher of the two scales | |
119 | llvm::Value* GetHigherScale(llvm::Value* x_scale, llvm::Value* y_scale); | |
120 | ||
121 | // Increase scale of 'in_value' by 'increase_scale_by'. | |
122 | // - If 'increase_scale_by' is <= 0, does nothing. | |
123 | llvm::Value* IncreaseScale(llvm::Value* in_value, llvm::Value* increase_scale_by); | |
124 | ||
125 | // Similar to IncreaseScale. but, also check if there is overflow. | |
126 | ValueWithOverflow IncreaseScaleWithOverflowCheck(llvm::Value* in_value, | |
127 | llvm::Value* increase_scale_by); | |
128 | ||
129 | // Reduce scale of 'in_value' by 'reduce_scale_by'. | |
130 | // - If 'reduce_scale_by' is <= 0, does nothing. | |
131 | llvm::Value* ReduceScale(llvm::Value* in_value, llvm::Value* reduce_scale_by); | |
132 | ||
133 | // Fast path of add: guaranteed no overflow | |
134 | llvm::Value* AddFastPath(const ValueFull& x, const ValueFull& y); | |
135 | ||
136 | // Similar to AddFastPath, but check if there's an overflow. | |
137 | ValueWithOverflow AddWithOverflowCheck(const ValueFull& x, const ValueFull& y, | |
138 | const ValueFull& out); | |
139 | ||
140 | // Do addition of large integers (both positive and negative). | |
141 | llvm::Value* AddLarge(const ValueFull& x, const ValueFull& y, const ValueFull& out); | |
142 | ||
143 | // Get the combined overflow (logical or). | |
144 | llvm::Value* GetCombinedOverflow(std::vector<ValueWithOverflow> values); | |
145 | ||
146 | // Build the function for adding decimals. | |
147 | Status BuildAdd(); | |
148 | ||
149 | // Build the function for decimal subtraction. | |
150 | Status BuildSubtract(); | |
151 | ||
152 | // Build the function for decimal multiplication. | |
153 | Status BuildMultiply(); | |
154 | ||
155 | // Build the function for decimal division/mod. | |
156 | Status BuildDivideOrMod(const std::string& function_name, | |
157 | const std::string& internal_name); | |
158 | ||
159 | Status BuildCompare(const std::string& function_name, | |
160 | llvm::ICmpInst::Predicate cmp_instruction); | |
161 | ||
162 | Status BuildDecimalFunction(const std::string& function_name, llvm::Type* return_type, | |
163 | std::vector<NamedArg> in_types); | |
164 | ||
165 | // Add a trace in IR code. | |
166 | void AddTrace(const std::string& fmt, std::vector<llvm::Value*> args); | |
167 | ||
168 | // Add a trace msg along with a 32-bit integer. | |
169 | void AddTrace32(const std::string& msg, llvm::Value* value); | |
170 | ||
171 | // Add a trace msg along with a 128-bit integer. | |
172 | void AddTrace128(const std::string& msg, llvm::Value* value); | |
173 | ||
174 | // name of the global variable having the array of scale multipliers. | |
175 | static const char* kScaleMultipliersName; | |
176 | ||
177 | // Intrinsic functions | |
178 | llvm::Function* sadd_with_overflow_fn_; | |
179 | llvm::Function* smul_with_overflow_fn_; | |
180 | ||
181 | // struct { i128: value, i1: overflow} | |
182 | llvm::Type* i128_with_overflow_struct_type_; | |
183 | ||
184 | // if set to true, ir traces are enabled. Useful for debugging. | |
185 | bool enable_ir_traces_; | |
186 | }; | |
187 | ||
188 | } // namespace gandiva |