Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions cpp/src/gandiva/decimal_ir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,10 @@ DecimalIR::ValueWithOverflow DecimalIR::AddWithOverflowCheck(const ValueFull& x,
// This is pretty complex, so use CPP fns.
llvm::Value* DecimalIR::AddLarge(const ValueFull& x, const ValueFull& y,
const ValueFull& out) {
auto block = ir_builder()->GetInsertBlock();
auto out_high_ptr = new llvm::AllocaInst(types()->i64_type(), 0, "out_hi", block);
auto out_low_ptr = new llvm::AllocaInst(types()->i64_type(), 0, "out_low", block);
auto& entry = ir_builder()->GetInsertBlock()->getParent()->getEntryBlock();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be merged with the other change ? It looks like the code is duplicated. Maybe via a helper function ?

llvm::IRBuilder<> entry_builder(&entry, entry.begin());
auto out_high_ptr = entry_builder.CreateAlloca(types()->i64_type(), nullptr, "out_hi");
auto out_low_ptr = entry_builder.CreateAlloca(types()->i64_type(), nullptr, "out_low");
auto x_split = ValueSplit::MakeFromInt128(this, x.value());
auto y_split = ValueSplit::MakeFromInt128(this, y.value());

Expand Down Expand Up @@ -454,9 +455,12 @@ llvm::Value* DecimalIR::CallDecimalFunction(const std::string& function_name,
llvm::Value* result = nullptr;
if (return_type == i128) {
// for i128 ret, replace with two int64* args, and join them.
auto block = ir_builder()->GetInsertBlock();
auto out_high_ptr = new llvm::AllocaInst(i64, 0, "out_hi", block);
auto out_low_ptr = new llvm::AllocaInst(i64, 0, "out_low", block);
// Decimal calls can be emitted inside the record loop or a CASE branch.
// Allocate return slots once per invocation, rather than once per row.
auto& entry = ir_builder()->GetInsertBlock()->getParent()->getEntryBlock();
llvm::IRBuilder<> entry_builder(&entry, entry.begin());
auto out_high_ptr = entry_builder.CreateAlloca(i64, nullptr, "out_hi");
auto out_low_ptr = entry_builder.CreateAlloca(i64, nullptr, "out_low");
dis_assembled_args.push_back(out_high_ptr);
dis_assembled_args.push_back(out_low_ptr);

Expand Down
36 changes: 36 additions & 0 deletions cpp/src/gandiva/tests/decimal_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,42 @@ std::vector<Decimal128> TestDecimal::MakeDecimalVector(std::vector<std::string>
return ret;
}

TEST_F(TestDecimal, CastLargeBatch) {
// Allocating decimal return slots in the record loop can exhaust the stack
// when optimization is disabled. A single int32-to-decimal cast is sufficient.
constexpr int kNumRecords = 1 << 19;
auto input_field = arrow::field("large_batch_decimal", arrow::int32());
auto schema = arrow::schema({input_field});
auto decimal_type = arrow::decimal128(10, 0);
auto decimal = TreeExprBuilder::MakeFunction(
"castDECIMAL", {TreeExprBuilder::MakeField(input_field)}, decimal_type);
auto expression =
TreeExprBuilder::MakeExpression(decimal, arrow::field("result", decimal_type));

std::vector<int32_t> values(kNumRecords);
std::vector<bool> validity(kNumRecords);
std::vector<Decimal128> expected_values(kNumRecords);
for (int i = 0; i < kNumRecords; ++i) {
values[i] = i % 17 - 8;
validity[i] = i % 11 != 0;
expected_values[i] = Decimal128(values[i]);
}
auto batch = arrow::RecordBatch::Make(schema, kNumRecords,
{MakeArrowArrayInt32(values, validity)});
auto expected = MakeArrowArrayDecimal(decimal_type, expected_values, validity);

for (bool optimize : {false, true}) {
SCOPED_TRACE(optimize);
auto config = std::make_shared<Configuration>(optimize);
std::shared_ptr<Projector> projector;
ASSERT_OK(Projector::Make(schema, {expression}, config, &projector));
arrow::ArrayVector output;
ASSERT_OK(projector->Evaluate(*batch, pool_, &output));
ASSERT_EQ(output.size(), 1);
EXPECT_ARROW_ARRAY_EQUALS(expected, output[0]);
}
}

TEST_F(TestDecimal, TestSimple) {
// schema for input fields
constexpr int32_t precision = 36;
Expand Down
Loading