]> git.proxmox.com Git - ceph.git/blame - ceph/src/arrow/cpp/src/gandiva/decimal_ir.h
import quincy 17.2.0
[ceph.git] / ceph / src / arrow / cpp / src / gandiva / decimal_ir.h
CommitLineData
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
26namespace gandiva {
27
28/// @brief Decimal IR functions
29class 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