// Iterate over the tuples in the sorter in batches/vectors of the given size void Sorter::VectorizedIterate( CodeGen &codegen, llvm::Value *sorter_ptr, uint32_t vector_size, Sorter::VectorizedIterateCallback &callback) const { llvm::Value *start_pos = GetStartPosition(codegen, sorter_ptr); llvm::Value *num_tuples = GetNumberOfStoredTuples(codegen, sorter_ptr); // Determine the number of bytes to skip per vector llvm::Value *vec_sz = codegen.Const32(vector_size); llvm::Value *tuple_size = GetTupleSize(codegen); llvm::Value *skip = codegen->CreateMul(vec_sz, tuple_size); lang::VectorizedLoop loop{ codegen, num_tuples, vector_size, {{"pos", start_pos}}}; { llvm::Value *curr_pos = loop.GetLoopVar(0); auto curr_range = loop.GetCurrentRange(); // Provide an accessor into the sorted space SorterAccess sorter_access{*this, start_pos}; // Issue the callback callback.ProcessEntries(codegen, curr_range.start, curr_range.end, sorter_access); // Bump the pointer by the size of a tuple llvm::Value *next_pos = codegen->CreateInBoundsGEP(curr_pos, skip); loop.LoopEnd(codegen, {next_pos}); } }
codegen::Value Sorter::SorterAccess::LoadRowValue( CodeGen &codegen, Sorter::SorterAccess::Row &row, uint32_t column_index) const { if (row.row_pos_ == nullptr) { auto *addr = codegen->CreateInBoundsGEP(codegen.CharPtrType(), start_pos_, row.row_idx_); row.row_pos_ = codegen->CreateLoad(addr); } const auto &storage_format = sorter_.GetStorageFormat(); UpdateableStorage::NullBitmap null_bitmap(codegen, storage_format, row.row_pos_); return storage_format.GetValue(codegen, row.row_pos_, column_index, null_bitmap); }
codegen::Value Sorter::SorterAccess::LoadRowValue( CodeGen &codegen, Sorter::SorterAccess::Row &row, uint32_t column_index) const { if (row.row_pos_ == nullptr) { auto *tuple_size = sorter_.GetTupleSize(codegen); auto *skip = codegen->CreateMul(row.row_idx_, tuple_size); row.row_pos_ = codegen->CreateInBoundsGEP(codegen.ByteType(), start_pos_, skip); } const auto &storage_format = sorter_.GetStorageFormat(); UpdateableStorage::NullBitmap null_bitmap{codegen, storage_format, row.row_pos_}; if (!null_bitmap.IsNullable(column_index)) { return storage_format.GetValueSkipNull(codegen, row.row_pos_, column_index); } else { return storage_format.GetValue(codegen, row.row_pos_, column_index, null_bitmap); } }
// Load a given column for the row with the given TID codegen::Value TileGroup::LoadColumn( CodeGen &codegen, llvm::Value *tid, const TileGroup::ColumnLayout &layout) const { // We're calculating: col[tid] = col_start + (tid * col_stride) llvm::Value *col_address = codegen->CreateInBoundsGEP(codegen.ByteType(), layout.col_start_ptr, codegen->CreateMul(tid, layout.col_stride)); // The value, length and is_null check llvm::Value *val = nullptr, *length = nullptr, *is_null = nullptr; // Column metadata bool is_nullable = schema_.AllowNull(layout.col_id); const auto &column = schema_.GetColumn(layout.col_id); const auto &sql_type = type::SqlType::LookupType(column.GetType()); // Check if it's a string or numeric value if (sql_type.IsVariableLength()) { auto *varlen_type = VarlenProxy::GetType(codegen); auto *varlen_ptr_ptr = codegen->CreateBitCast( col_address, varlen_type->getPointerTo()->getPointerTo()); if (is_nullable) { codegen::Varlen::GetPtrAndLength( codegen, codegen->CreateLoad(varlen_ptr_ptr), val, length, is_null); } else { codegen::Varlen::SafeGetPtrAndLength( codegen, codegen->CreateLoad(varlen_ptr_ptr), val, length); } PL_ASSERT(val != nullptr && length != nullptr); } else { // Get the LLVM type of the column llvm::Type *col_type = nullptr, *col_len_type = nullptr; sql_type.GetTypeForMaterialization(codegen, col_type, col_len_type); PL_ASSERT(col_type != nullptr && col_len_type == nullptr); // val = *(col_type*)col_address; val = codegen->CreateLoad( col_type, codegen->CreateBitCast(col_address, col_type->getPointerTo())); if (is_nullable) { // To check for NULL, we need to perform a comparison between the value we // just read from the table with the NULL value for the column's type. We // need to be careful that the runtime type of both values is not NULL to // bypass the type system's NULL checking logic. if (sql_type.TypeId() == peloton::type::TypeId::BOOLEAN) { is_null = type::Boolean::Instance().CheckNull(codegen, col_address); } else { auto val_tmp = codegen::Value{sql_type, val}; auto null_val = codegen::Value{sql_type, sql_type.GetNullValue(codegen).GetValue()}; auto val_is_null = val_tmp.CompareEq(codegen, null_val); PL_ASSERT(!val_is_null.IsNullable()); is_null = val_is_null.GetValue(); } } } // Names val->setName(column.GetName()); if (length != nullptr) length->setName(column.GetName() + ".len"); if (is_null != nullptr) is_null->setName(column.GetName() + ".null"); // Return the value auto type = type::Type{column.GetType(), is_nullable}; return codegen::Value{type, val, length, is_null}; }