blob: a2df356242fa1479acb6ece9278f8df3fd1f5b86 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "codegen/codegen-anyval.h"
#include "common/names.h"
using namespace impala;
using namespace impala_udf;
using namespace llvm;
const char* CodegenAnyVal::LLVM_BOOLEANVAL_NAME = "struct.impala_udf::BooleanVal";
const char* CodegenAnyVal::LLVM_TINYINTVAL_NAME = "struct.impala_udf::TinyIntVal";
const char* CodegenAnyVal::LLVM_SMALLINTVAL_NAME = "struct.impala_udf::SmallIntVal";
const char* CodegenAnyVal::LLVM_INTVAL_NAME = "struct.impala_udf::IntVal";
const char* CodegenAnyVal::LLVM_BIGINTVAL_NAME = "struct.impala_udf::BigIntVal";
const char* CodegenAnyVal::LLVM_FLOATVAL_NAME = "struct.impala_udf::FloatVal";
const char* CodegenAnyVal::LLVM_DOUBLEVAL_NAME = "struct.impala_udf::DoubleVal";
const char* CodegenAnyVal::LLVM_STRINGVAL_NAME = "struct.impala_udf::StringVal";
const char* CodegenAnyVal::LLVM_TIMESTAMPVAL_NAME = "struct.impala_udf::TimestampVal";
const char* CodegenAnyVal::LLVM_DECIMALVAL_NAME = "struct.impala_udf::DecimalVal";
Type* CodegenAnyVal::GetLoweredType(LlvmCodeGen* cg, const ColumnType& type) {
switch(type.type) {
case TYPE_BOOLEAN: // i16
return cg->smallint_type();
case TYPE_TINYINT: // i16
return cg->smallint_type();
case TYPE_SMALLINT: // i32
return cg->int_type();
case TYPE_INT: // i64
return cg->bigint_type();
case TYPE_BIGINT: // { i8, i64 }
return StructType::get(cg->tinyint_type(), cg->bigint_type(), NULL);
case TYPE_FLOAT: // i64
return cg->bigint_type();
case TYPE_DOUBLE: // { i8, double }
return StructType::get(cg->tinyint_type(), cg->double_type(), NULL);
case TYPE_STRING: // { i64, i8* }
case TYPE_VARCHAR: // { i64, i8* }
return StructType::get(cg->bigint_type(), cg->ptr_type(), NULL);
case TYPE_CHAR:
DCHECK(false) << "NYI:" << type.DebugString();
return NULL;
case TYPE_TIMESTAMP: // { i64, i64 }
return StructType::get(cg->bigint_type(), cg->bigint_type(), NULL);
case TYPE_DECIMAL: // %"struct.impala_udf::DecimalVal" (isn't lowered)
// = { {i8}, [15 x i8], {i128} }
return cg->GetType(LLVM_DECIMALVAL_NAME);
default:
DCHECK(false) << "Unsupported type: " << type;
return NULL;
}
}
Type* CodegenAnyVal::GetLoweredPtrType(LlvmCodeGen* cg, const ColumnType& type) {
return GetLoweredType(cg, type)->getPointerTo();
}
Type* CodegenAnyVal::GetUnloweredType(LlvmCodeGen* cg, const ColumnType& type) {
Type* result;
switch(type.type) {
case TYPE_BOOLEAN:
result = cg->GetType(LLVM_BOOLEANVAL_NAME);
break;
case TYPE_TINYINT:
result = cg->GetType(LLVM_TINYINTVAL_NAME);
break;
case TYPE_SMALLINT:
result = cg->GetType(LLVM_SMALLINTVAL_NAME);
break;
case TYPE_INT:
result = cg->GetType(LLVM_INTVAL_NAME);
break;
case TYPE_BIGINT:
result = cg->GetType(LLVM_BIGINTVAL_NAME);
break;
case TYPE_FLOAT:
result = cg->GetType(LLVM_FLOATVAL_NAME);
break;
case TYPE_DOUBLE:
result = cg->GetType(LLVM_DOUBLEVAL_NAME);
break;
case TYPE_STRING:
case TYPE_VARCHAR:
result = cg->GetType(LLVM_STRINGVAL_NAME);
break;
case TYPE_CHAR:
DCHECK(false) << "NYI:" << type.DebugString();
return NULL;
case TYPE_TIMESTAMP:
result = cg->GetType(LLVM_TIMESTAMPVAL_NAME);
break;
case TYPE_DECIMAL:
result = cg->GetType(LLVM_DECIMALVAL_NAME);
break;
default:
DCHECK(false) << "Unsupported type: " << type;
return NULL;
}
DCHECK(result != NULL) << type.DebugString();
return result;
}
Type* CodegenAnyVal::GetUnloweredPtrType(LlvmCodeGen* cg, const ColumnType& type) {
return GetUnloweredType(cg, type)->getPointerTo();
}
Value* CodegenAnyVal::CreateCall(
LlvmCodeGen* cg, LlvmCodeGen::LlvmBuilder* builder, Function* fn,
ArrayRef<Value*> args, const char* name, Value* result_ptr) {
if (fn->getReturnType()->isVoidTy()) {
// Void return type indicates that this function returns a DecimalVal via the first
// argument (which should be a DecimalVal*).
Function::arg_iterator ret_arg = fn->arg_begin();
DCHECK(ret_arg->getType()->isPointerTy());
Type* ret_type = ret_arg->getType()->getPointerElementType();
DCHECK_EQ(ret_type, cg->GetType(LLVM_DECIMALVAL_NAME));
// We need to pass a DecimalVal pointer to 'fn' that will be populated with the result
// value. Use 'result_ptr' if specified, otherwise alloca one.
Value* ret_ptr = (result_ptr == NULL) ?
cg->CreateEntryBlockAlloca(*builder, ret_type, name) : result_ptr;
vector<Value*> new_args = args.vec();
new_args.insert(new_args.begin(), ret_ptr);
builder->CreateCall(fn, new_args);
// If 'result_ptr' was specified, we're done. Otherwise load and return the result.
if (result_ptr != NULL) return NULL;
return builder->CreateLoad(ret_ptr, name);
} else {
// Function returns *Val normally (note that it could still be returning a DecimalVal,
// since we generate non-complaint functions)
Value* ret = builder->CreateCall(fn, args, name);
if (result_ptr == NULL) return ret;
builder->CreateStore(ret, result_ptr);
return NULL;
}
}
CodegenAnyVal CodegenAnyVal::CreateCallWrapped(
LlvmCodeGen* cg, LlvmCodeGen::LlvmBuilder* builder, const ColumnType& type,
Function* fn, ArrayRef<Value*> args, const char* name) {
Value* v = CreateCall(cg, builder, fn, args, name);
return CodegenAnyVal(cg, builder, type, v, name);
}
CodegenAnyVal::CodegenAnyVal(LlvmCodeGen* codegen, LlvmCodeGen::LlvmBuilder* builder,
const ColumnType& type, Value* value, const char* name)
: type_(type),
value_(value),
name_(name),
codegen_(codegen),
builder_(builder) {
Type* value_type = GetLoweredType(codegen, type);
if (value_ == NULL) {
// No Value* was specified, so allocate one on the stack and load it.
Value* ptr = codegen_->CreateEntryBlockAlloca(*builder, value_type);
value_ = builder_->CreateLoad(ptr, name_);
}
DCHECK_EQ(value_->getType(), value_type);
}
Value* CodegenAnyVal::GetIsNull(const char* name) {
switch (type_.type) {
case TYPE_BIGINT:
case TYPE_DOUBLE: {
// Lowered type is of form { i8, * }. Get the i8 value.
Value* is_null_i8 = builder_->CreateExtractValue(value_, 0);
DCHECK(is_null_i8->getType() == codegen_->tinyint_type());
return builder_->CreateTrunc(is_null_i8, codegen_->boolean_type(), name);
}
case TYPE_DECIMAL: {
// Lowered type is of the form { {i8}, ... }
uint32_t idxs[] = {0, 0};
Value* is_null_i8 = builder_->CreateExtractValue(value_, idxs);
DCHECK(is_null_i8->getType() == codegen_->tinyint_type());
return builder_->CreateTrunc(is_null_i8, codegen_->boolean_type(), name);
}
case TYPE_STRING:
case TYPE_VARCHAR:
case TYPE_TIMESTAMP: {
// Lowered type is of form { i64, *}. Get the first byte of the i64 value.
Value* v = builder_->CreateExtractValue(value_, 0);
DCHECK(v->getType() == codegen_->bigint_type());
return builder_->CreateTrunc(v, codegen_->boolean_type(), name);
}
case TYPE_CHAR:
DCHECK(false) << "NYI:" << type_.DebugString();
return NULL;
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT:
case TYPE_FLOAT:
// Lowered type is an integer. Get the first byte.
return builder_->CreateTrunc(value_, codegen_->boolean_type(), name);
default:
DCHECK(false);
return NULL;
}
}
void CodegenAnyVal::SetIsNull(Value* is_null) {
switch(type_.type) {
case TYPE_BIGINT:
case TYPE_DOUBLE: {
// Lowered type is of form { i8, * }. Set the i8 value to 'is_null'.
Value* is_null_ext =
builder_->CreateZExt(is_null, codegen_->tinyint_type(), "is_null_ext");
value_ = builder_->CreateInsertValue(value_, is_null_ext, 0, name_);
break;
}
case TYPE_DECIMAL: {
// Lowered type is of form { {i8}, [15 x i8], {i128} }. Set the i8 value to
// 'is_null'.
Value* is_null_ext =
builder_->CreateZExt(is_null, codegen_->tinyint_type(), "is_null_ext");
// Index into the {i8} struct as well as the outer struct.
uint32_t idxs[] = {0, 0};
value_ = builder_->CreateInsertValue(value_, is_null_ext, idxs, name_);
break;
}
case TYPE_STRING:
case TYPE_VARCHAR:
case TYPE_TIMESTAMP: {
// Lowered type is of the form { i64, * }. Set the first byte of the i64 value to
// 'is_null'
Value* v = builder_->CreateExtractValue(value_, 0);
v = builder_->CreateAnd(v, -0x100LL, "masked");
Value* is_null_ext = builder_->CreateZExt(is_null, v->getType(), "is_null_ext");
v = builder_->CreateOr(v, is_null_ext);
value_ = builder_->CreateInsertValue(value_, v, 0, name_);
break;
}
case TYPE_CHAR:
DCHECK(false) << "NYI:" << type_.DebugString();
break;
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT:
case TYPE_FLOAT: {
// Lowered type is an integer. Set the first byte to 'is_null'.
value_ = builder_->CreateAnd(value_, -0x100LL, "masked");
Value* is_null_ext = builder_->CreateZExt(is_null, value_->getType(), "is_null_ext");
value_ = builder_->CreateOr(value_, is_null_ext, name_);
break;
}
default:
DCHECK(false) << "NYI: " << type_.DebugString();
}
}
Value* CodegenAnyVal::GetVal(const char* name) {
DCHECK(type_.type != TYPE_STRING)
<< "Use GetPtr and GetLen for StringVal";
DCHECK(type_.type != TYPE_VARCHAR)
<< "Use GetPtr and GetLen for Varchar";
DCHECK(type_.type != TYPE_CHAR)
<< "Use GetPtr and GetLen for Char";
DCHECK(type_.type != TYPE_TIMESTAMP)
<< "Use GetDate and GetTimeOfDay for TimestampVals";
switch(type_.type) {
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT: {
// Lowered type is an integer. Get the high bytes.
int num_bits = type_.GetByteSize() * 8;
Value* val = GetHighBits(num_bits, value_, name);
if (type_.type == TYPE_BOOLEAN) {
// Return booleans as i1 (vs. i8)
val = builder_->CreateTrunc(val, builder_->getInt1Ty(), name);
}
return val;
}
case TYPE_FLOAT: {
// Same as above, but we must cast the value to a float.
Value* val = GetHighBits(32, value_);
return builder_->CreateBitCast(val, codegen_->float_type());
}
case TYPE_BIGINT:
case TYPE_DOUBLE:
// Lowered type is of form { i8, * }. Get the second value.
return builder_->CreateExtractValue(value_, 1, name);
case TYPE_DECIMAL: {
// Lowered type is of form { {i8}, [15 x i8], {i128} }. Get the i128 value and
// truncate it to the correct size. (The {i128} corresponds to the union of the
// different width int types.)
uint32_t idxs[] = {2, 0};
Value* val = builder_->CreateExtractValue(value_, idxs, name);
return builder_->CreateTrunc(val, codegen_->GetType(type_), name);
break;
}
default:
DCHECK(false) << "Unsupported type: " << type_;
return NULL;
}
}
void CodegenAnyVal::SetVal(Value* val) {
DCHECK(type_.type != TYPE_STRING) << "Use SetPtr and SetLen for StringVals";
DCHECK(type_.type != TYPE_VARCHAR) << "Use SetPtr and SetLen for StringVals";
DCHECK(type_.type != TYPE_CHAR) << "Use SetPtr and SetLen for StringVals";
DCHECK(type_.type != TYPE_TIMESTAMP)
<< "Use SetDate and SetTimeOfDay for TimestampVals";
switch(type_.type) {
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT: {
// Lowered type is an integer. Set the high bytes to 'val'.
int num_bits = type_.GetByteSize() * 8;
value_ = SetHighBits(num_bits, val, value_, name_);
break;
}
case TYPE_FLOAT:
// Same as above, but we must cast 'val' to an integer type.
val = builder_->CreateBitCast(val, codegen_->int_type());
value_ = SetHighBits(32, val, value_, name_);
break;
case TYPE_BIGINT:
case TYPE_DOUBLE:
// Lowered type is of form { i8, * }. Set the second value to 'val'.
value_ = builder_->CreateInsertValue(value_, val, 1, name_);
break;
case TYPE_DECIMAL: {
// Lowered type is of the form { {i8}, [15 x i8], {i128} }. Set the i128 value to
// 'val'. (The {i128} corresponds to the union of the different width int types.)
DCHECK_EQ(val->getType()->getIntegerBitWidth(), type_.GetByteSize() * 8);
val = builder_->CreateSExt(val, Type::getIntNTy(codegen_->context(), 128));
uint32_t idxs[] = {2, 0};
value_ = builder_->CreateInsertValue(value_, val, idxs, name_);
break;
}
default:
DCHECK(false) << "Unsupported type: " << type_;
}
}
void CodegenAnyVal::SetVal(bool val) {
DCHECK_EQ(type_.type, TYPE_BOOLEAN);
SetVal(builder_->getInt1(val));
}
void CodegenAnyVal::SetVal(int8_t val) {
DCHECK_EQ(type_.type, TYPE_TINYINT);
SetVal(builder_->getInt8(val));
}
void CodegenAnyVal::SetVal(int16_t val) {
DCHECK_EQ(type_.type, TYPE_SMALLINT);
SetVal(builder_->getInt16(val));
}
void CodegenAnyVal::SetVal(int32_t val) {
DCHECK(type_.type == TYPE_INT || type_.type == TYPE_DECIMAL);
SetVal(builder_->getInt32(val));
}
void CodegenAnyVal::SetVal(int64_t val) {
DCHECK(type_.type == TYPE_BIGINT || type_.type == TYPE_DECIMAL);
SetVal(builder_->getInt64(val));
}
void CodegenAnyVal::SetVal(int128_t val) {
DCHECK_EQ(type_.type, TYPE_DECIMAL);
// TODO: is there a better way to do this?
// Set high bits
Value* ir_val = ConstantInt::get(codegen_->i128_type(), HighBits(val));
ir_val = builder_->CreateShl(ir_val, 64, "tmp");
// Set low bits
ir_val = builder_->CreateOr(ir_val, LowBits(val), "tmp");
SetVal(ir_val);
}
void CodegenAnyVal::SetVal(float val) {
DCHECK_EQ(type_.type, TYPE_FLOAT);
SetVal(ConstantFP::get(builder_->getFloatTy(), val));
}
void CodegenAnyVal::SetVal(double val) {
DCHECK_EQ(type_.type, TYPE_DOUBLE);
SetVal(ConstantFP::get(builder_->getDoubleTy(), val));
}
Value* CodegenAnyVal::GetPtr() {
// Set the second pointer value to 'ptr'.
DCHECK(type_.IsStringType());
return builder_->CreateExtractValue(value_, 1, name_);
}
Value* CodegenAnyVal::GetLen() {
// Get the high bytes of the first value.
DCHECK(type_.IsStringType());
Value* v = builder_->CreateExtractValue(value_, 0);
return GetHighBits(32, v);
}
void CodegenAnyVal::SetPtr(Value* ptr) {
// Set the second pointer value to 'ptr'.
DCHECK(type_.IsStringType());
value_ = builder_->CreateInsertValue(value_, ptr, 1, name_);
}
void CodegenAnyVal::SetLen(Value* len) {
// Set the high bytes of the first value to 'len'.
DCHECK(type_.IsStringType());
Value* v = builder_->CreateExtractValue(value_, 0);
v = SetHighBits(32, len, v);
value_ = builder_->CreateInsertValue(value_, v, 0, name_);
}
Value* CodegenAnyVal::GetTimeOfDay() {
// Get the second i64 value.
DCHECK_EQ(type_.type, TYPE_TIMESTAMP);
return builder_->CreateExtractValue(value_, 1);
}
Value* CodegenAnyVal::GetDate() {
// Get the high bytes of the first value.
DCHECK_EQ(type_.type, TYPE_TIMESTAMP);
Value* v = builder_->CreateExtractValue(value_, 0);
return GetHighBits(32, v);
}
void CodegenAnyVal::SetTimeOfDay(Value* time_of_day) {
// Set the second i64 value to 'time_of_day'.
DCHECK_EQ(type_.type, TYPE_TIMESTAMP);
value_ = builder_->CreateInsertValue(value_, time_of_day, 1, name_);
}
void CodegenAnyVal::SetDate(Value* date) {
// Set the high bytes of the first value to 'date'.
DCHECK_EQ(type_.type, TYPE_TIMESTAMP);
Value* v = builder_->CreateExtractValue(value_, 0);
v = SetHighBits(32, date, v);
value_ = builder_->CreateInsertValue(value_, v, 0, name_);
}
Value* CodegenAnyVal::GetUnloweredPtr() {
Value* value_ptr = codegen_->CreateEntryBlockAlloca(*builder_, value_->getType());
builder_->CreateStore(value_, value_ptr);
return builder_->CreateBitCast(value_ptr, GetUnloweredPtrType(codegen_, type_));
}
void CodegenAnyVal::SetFromRawPtr(Value* raw_ptr) {
Value* val_ptr =
builder_->CreateBitCast(raw_ptr, codegen_->GetPtrType(type_), "val_ptr");
Value* val = builder_->CreateLoad(val_ptr);
SetFromRawValue(val);
}
void CodegenAnyVal::SetFromRawValue(Value* raw_val) {
DCHECK_EQ(raw_val->getType(), codegen_->GetType(type_))
<< endl << LlvmCodeGen::Print(raw_val)
<< endl << type_ << " => " << LlvmCodeGen::Print(codegen_->GetType(type_));
switch (type_.type) {
case TYPE_STRING:
case TYPE_VARCHAR: {
// Convert StringValue to StringVal
SetPtr(builder_->CreateExtractValue(raw_val, 0, "ptr"));
SetLen(builder_->CreateExtractValue(raw_val, 1, "len"));
break;
}
case TYPE_CHAR:
DCHECK(false) << "NYI:" << type_.DebugString();
break;
case TYPE_TIMESTAMP: {
// Convert TimestampValue to TimestampVal
// TimestampValue has type
// { boost::posix_time::time_duration, boost::gregorian::date }
// = { {{{i64}}}, {{i32}} }
// Extract time_of_day i64 from boost::posix_time::time_duration.
uint32_t time_of_day_idxs[] = {0, 0, 0, 0};
Value* time_of_day =
builder_->CreateExtractValue(raw_val, time_of_day_idxs, "time_of_day");
DCHECK(time_of_day->getType()->isIntegerTy(64));
SetTimeOfDay(time_of_day);
// Extract i32 from boost::gregorian::date
uint32_t date_idxs[] = {1, 0, 0};
Value* date = builder_->CreateExtractValue(raw_val, date_idxs, "date");
DCHECK(date->getType()->isIntegerTy(32));
SetDate(date);
break;
}
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT:
case TYPE_BIGINT:
case TYPE_FLOAT:
case TYPE_DOUBLE:
case TYPE_DECIMAL:
// raw_val is a native type
SetVal(raw_val);
break;
default:
DCHECK(false) << "NYI: " << type_.DebugString();
break;
}
}
Value* CodegenAnyVal::ToNativeValue(MemPool* pool) {
Type* raw_type = codegen_->GetType(type_);
Value* raw_val = Constant::getNullValue(raw_type);
switch (type_.type) {
case TYPE_STRING:
case TYPE_VARCHAR: {
// Convert StringVal to StringValue
Value* len = GetLen();
raw_val = builder_->CreateInsertValue(raw_val, len, 1);
if (pool == NULL) {
// Set raw_val.ptr from this->ptr
raw_val = builder_->CreateInsertValue(raw_val, GetPtr(), 0);
} else {
// Allocate raw_val.ptr from 'pool' and copy this->ptr
Value* new_ptr = codegen_->CodegenAllocate(builder_, pool, len, "new_ptr");
codegen_->CodegenMemcpy(builder_, new_ptr, GetPtr(), len);
raw_val = builder_->CreateInsertValue(raw_val, new_ptr, 0);
}
break;
}
case TYPE_TIMESTAMP: {
// Convert TimestampVal to TimestampValue
// TimestampValue has type
// { boost::posix_time::time_duration, boost::gregorian::date }
// = { {{{i64}}}, {{i32}} }
uint32_t time_of_day_idxs[] = {0, 0, 0, 0};
raw_val = builder_->CreateInsertValue(raw_val, GetTimeOfDay(), time_of_day_idxs);
uint32_t date_idxs[] = {1, 0, 0};
raw_val = builder_->CreateInsertValue(raw_val, GetDate(), date_idxs);
break;
}
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT:
case TYPE_BIGINT:
case TYPE_FLOAT:
case TYPE_DOUBLE:
case TYPE_DECIMAL:
// raw_val is a native type
raw_val = GetVal();
break;
default:
DCHECK(false) << "NYI: " << type_.DebugString();
break;
}
return raw_val;
}
Value* CodegenAnyVal::ToNativePtr(Value* native_ptr, MemPool* pool) {
Value* v = ToNativeValue(pool);
if (native_ptr == NULL) {
native_ptr = codegen_->CreateEntryBlockAlloca(*builder_, v->getType());
}
builder_->CreateStore(v, native_ptr);
return native_ptr;
}
// Example output for materializing an int slot:
//
// ; [insert point starts here]
// %is_null = trunc i64 %src to i1
// br i1 %is_null, label %null, label %non_null ;
//
// non_null: ; preds = %entry
// %slot = getelementptr inbounds { i8, i32, %"struct.impala::StringValue" }* %tuple,
// i32 0, i32 1
// %2 = ashr i64 %src, 32
// %3 = trunc i64 %2 to i32
// store i32 %3, i32* %slot
// br label %end_write
//
// null: ; preds = %entry
// call void @SetNull6({ i8, i32, %"struct.impala::StringValue" }* %tuple)
// br label %end_write
//
// end_write: ; preds = %null, %non_null
// ; [insert point ends here]
void CodegenAnyVal::WriteToSlot(const SlotDescriptor& slot_desc, Value* tuple,
MemPool* pool, BasicBlock* insert_before) {
DCHECK(tuple->getType()->isPointerTy());
DCHECK(tuple->getType()->getPointerElementType()->isStructTy());
LLVMContext& context = codegen_->context();
Function* fn = builder_->GetInsertBlock()->getParent();
// Create new block that will come after conditional blocks if necessary
if (insert_before == NULL) insert_before = BasicBlock::Create(context, "end_write", fn);
// Create new basic blocks and br instruction
BasicBlock* non_null_block = BasicBlock::Create(context, "non_null", fn, insert_before);
BasicBlock* null_block = BasicBlock::Create(context, "null", fn, insert_before);
builder_->CreateCondBr(GetIsNull(), null_block, non_null_block);
// Non-null block: write slot
builder_->SetInsertPoint(non_null_block);
Value* slot = builder_->CreateStructGEP(NULL, tuple, slot_desc.llvm_field_idx(),
"slot");
ToNativePtr(slot, pool);
builder_->CreateBr(insert_before);
// Null block: set null bit
builder_->SetInsertPoint(null_block);
Function* set_null_fn = slot_desc.GetUpdateNullFn(codegen_, true);
DCHECK(set_null_fn != NULL);
builder_->CreateCall(set_null_fn, tuple);
builder_->CreateBr(insert_before);
// Leave builder_ after conditional blocks
builder_->SetInsertPoint(insert_before);
}
Value* CodegenAnyVal::Eq(CodegenAnyVal* other) {
DCHECK_EQ(type_, other->type_);
switch (type_.type) {
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT:
case TYPE_BIGINT:
case TYPE_DECIMAL:
return builder_->CreateICmpEQ(GetVal(), other->GetVal(), "eq");
case TYPE_FLOAT:
case TYPE_DOUBLE:
return builder_->CreateFCmpUEQ(GetVal(), other->GetVal(), "eq");
case TYPE_STRING:
case TYPE_VARCHAR: {
Function* eq_fn =
codegen_->GetFunction(IRFunction::CODEGEN_ANYVAL_STRING_VAL_EQ, false);
return builder_->CreateCall(
eq_fn, ArrayRef<Value*>({GetUnloweredPtr(), other->GetUnloweredPtr()}), "eq");
}
case TYPE_TIMESTAMP: {
Function* eq_fn =
codegen_->GetFunction(IRFunction::CODEGEN_ANYVAL_TIMESTAMP_VAL_EQ, false);
return builder_->CreateCall(
eq_fn, ArrayRef<Value*>({GetUnloweredPtr(), other->GetUnloweredPtr()}), "eq");
}
default:
DCHECK(false) << "NYI: " << type_.DebugString();
return NULL;
}
}
Value* CodegenAnyVal::EqToNativePtr(Value* native_ptr) {
Value* val = NULL;
if (!type_.IsStringType()) {
val = builder_->CreateLoad(native_ptr);
}
switch (type_.type) {
case TYPE_NULL:
return codegen_->false_value();
case TYPE_BOOLEAN:
case TYPE_TINYINT:
case TYPE_SMALLINT:
case TYPE_INT:
case TYPE_BIGINT:
case TYPE_DECIMAL:
return builder_->CreateICmpEQ(GetVal(), val, "cmp_raw");
case TYPE_FLOAT:
case TYPE_DOUBLE:
return builder_->CreateFCmpUEQ(GetVal(), val, "cmp_raw");
case TYPE_STRING:
case TYPE_VARCHAR: {
Function* eq_fn =
codegen_->GetFunction(IRFunction::CODEGEN_ANYVAL_STRING_VALUE_EQ, false);
return builder_->CreateCall(eq_fn,
ArrayRef<Value*>({GetUnloweredPtr(), native_ptr}), "cmp_raw");
}
case TYPE_TIMESTAMP: {
Function* eq_fn =
codegen_->GetFunction(IRFunction::CODEGEN_ANYVAL_TIMESTAMP_VALUE_EQ, false);
return builder_->CreateCall(eq_fn,
ArrayRef<Value*>({GetUnloweredPtr(), native_ptr}), "cmp_raw");
}
default:
DCHECK(false) << "NYI: " << type_.DebugString();
return NULL;
}
}
Value* CodegenAnyVal::Compare(CodegenAnyVal* other, const char* name) {
DCHECK_EQ(type_, other->type_);
Value* v1 = ToNativePtr();
Value* void_v1 = builder_->CreateBitCast(v1, codegen_->ptr_type());
Value* v2 = other->ToNativePtr();
Value* void_v2 = builder_->CreateBitCast(v2, codegen_->ptr_type());
Value* type_ptr = codegen_->GetPtrTo(builder_, type_.ToIR(codegen_), "type");
Function* compare_fn = codegen_->GetFunction(IRFunction::RAW_VALUE_COMPARE, false);
Value* args[] = { void_v1, void_v2, type_ptr };
return builder_->CreateCall(compare_fn, args, name);
}
Value* CodegenAnyVal::GetHighBits(int num_bits, Value* v, const char* name) {
DCHECK_EQ(v->getType()->getIntegerBitWidth(), num_bits * 2);
Value* shifted = builder_->CreateAShr(v, num_bits);
return builder_->CreateTrunc(
shifted, IntegerType::get(codegen_->context(), num_bits));
}
// Example output: (num_bits = 8)
// %1 = zext i1 %src to i16
// %2 = shl i16 %1, 8
// %3 = and i16 %dst1 255 ; clear the top half of dst
// %dst2 = or i16 %3, %2 ; set the top of half of dst to src
Value* CodegenAnyVal::SetHighBits(int num_bits, Value* src, Value* dst,
const char* name) {
DCHECK_LE(src->getType()->getIntegerBitWidth(), num_bits);
DCHECK_EQ(dst->getType()->getIntegerBitWidth(), num_bits * 2);
Value* extended_src =
builder_->CreateZExt(src, IntegerType::get(codegen_->context(), num_bits * 2));
Value* shifted_src = builder_->CreateShl(extended_src, num_bits);
Value* masked_dst = builder_->CreateAnd(dst, (1LL << num_bits) - 1);
return builder_->CreateOr(masked_dst, shifted_src, name);
}
Value* CodegenAnyVal::GetNullVal(LlvmCodeGen* codegen, const ColumnType& type) {
Type* val_type = GetLoweredType(codegen, type);
return GetNullVal(codegen, val_type);
}
Value* CodegenAnyVal::GetNullVal(LlvmCodeGen* codegen, Type* val_type) {
if (val_type->isStructTy()) {
StructType* struct_type = cast<StructType>(val_type);
if (struct_type->getNumElements() == 3) {
DCHECK_EQ(val_type, codegen->GetType(LLVM_DECIMALVAL_NAME));
// Return the struct { {1}, 0, 0 } (the 'is_null' byte, i.e. the first value's first
// byte, is set to 1, the other bytes don't matter)
StructType* anyval_struct_type = cast<StructType>(struct_type->getElementType(0));
Type* is_null_type = anyval_struct_type->getElementType(0);
Value* null_anyval =
ConstantStruct::get(anyval_struct_type, ConstantInt::get(is_null_type, 1));
Type* type2 = struct_type->getElementType(1);
Type* type3 = struct_type->getElementType(2);
return ConstantStruct::get(struct_type, null_anyval, Constant::getNullValue(type2),
Constant::getNullValue(type3), NULL);
}
// Return the struct { 1, 0 } (the 'is_null' byte, i.e. the first value's first byte,
// is set to 1, the other bytes don't matter)
DCHECK_EQ(struct_type->getNumElements(), 2);
Type* type1 = struct_type->getElementType(0);
DCHECK(type1->isIntegerTy()) << LlvmCodeGen::Print(type1);
Type* type2 = struct_type->getElementType(1);
return ConstantStruct::get(
struct_type, ConstantInt::get(type1, 1), Constant::getNullValue(type2), NULL);
}
// Return the int 1 ('is_null' byte is 1, other bytes don't matter)
DCHECK(val_type->isIntegerTy());
return ConstantInt::get(val_type, 1);
}
CodegenAnyVal CodegenAnyVal::GetNonNullVal(LlvmCodeGen* codegen,
LlvmCodeGen::LlvmBuilder* builder, const ColumnType& type, const char* name) {
Type* val_type = GetLoweredType(codegen, type);
// All zeros => 'is_null' = false
Value* value = Constant::getNullValue(val_type);
return CodegenAnyVal(codegen, builder, type, value, name);
}