+ std::string(get_enumerant_name(decoration.value)));
}
auto member_type = member.type->get_or_make_type();
- if(::LLVMGetTypeKind(member_type) == ::LLVMStructTypeKind
- && ::LLVMIsOpaqueStruct(member_type))
+ if(::LLVMGetTypeKind(member_type.type) == ::LLVMStructTypeKind
+ && ::LLVMIsOpaqueStruct(member_type.type))
{
if(dynamic_cast<const Struct_type_descriptor *>(member.type.get()))
throw Parser_error(instruction_start_index,
instruction_start_index,
"struct can't have opaque struct members");
}
- std::size_t alignment = ::LLVMPreferredAlignmentOfType(target_data, member_type);
- assert(is_power_of_2(alignment));
- std::size_t size = ::LLVMABISizeOfType(target_data, member_type);
- if(alignment > total_alignment)
- total_alignment = alignment;
- member_descriptors.push_back(Member_descriptor(alignment, size, member_type));
+ assert(is_power_of_2(member_type.alignment));
+ std::size_t size = ::LLVMABISizeOfType(target_data, member_type.type);
+ if(member_type.alignment > total_alignment)
+ total_alignment = member_type.alignment;
+ member_descriptors.push_back(
+ Member_descriptor(member_type.alignment, size, member_type.type));
}
assert(member_descriptors.size() == members.size());
assert(is_power_of_2(total_alignment));
{
member_types.push_back(::LLVMInt8TypeInContext(context)); // so it isn't empty
}
- constexpr bool is_packed = false;
- ::LLVMStructSetBody(type, member_types.data(), member_types.size(), is_packed);
+ constexpr bool is_packed = true;
+ ::LLVMStructSetBody(type.type, member_types.data(), member_types.size(), is_packed);
+ type.alignment = total_alignment;
is_complete = true;
}
util::Enum_set<Capability> enabled_capabilities;
::LLVMContextRef context;
::LLVMTargetMachineRef target_machine;
+ ::LLVMTargetDataRef target_data;
[[gnu::unused]] const std::uint64_t shader_id;
std::string name_prefix_string;
llvm_wrapper::Module module;
if(auto *type = dynamic_cast<Simple_type_descriptor *>(constant->type.get()))
{
auto llvm_type = type->get_or_make_type();
- if(::LLVMGetTypeKind(llvm_type) != ::LLVMIntegerTypeKind)
+ if(::LLVMGetTypeKind(llvm_type.type) != ::LLVMIntegerTypeKind)
throw Parser_error(instruction_start_index,
instruction_start_index,
"id is not a constant integer");
if(auto *type = dynamic_cast<Simple_type_descriptor *>(constant->type.get()))
{
auto llvm_type = type->get_or_make_type();
- if(::LLVMGetTypeKind(llvm_type) != ::LLVMIntegerTypeKind)
+ if(::LLVMGetTypeKind(llvm_type.type) != ::LLVMIntegerTypeKind)
throw Parser_error(instruction_start_index,
instruction_start_index,
"id is not a constant integer");
}
module = llvm_wrapper::Module::create_with_target_machine(
get_prefixed_name("module").c_str(), context, target_machine);
+ target_data = ::LLVMGetModuleDataLayout(module.get());
builder = llvm_wrapper::Builder::create(context);
- auto target_data = ::LLVMGetModuleDataLayout(module.get());
constexpr std::size_t no_instruction_index = 0;
io_struct =
std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
assert(implicit_function_arguments.size() == 1);
static_assert(io_struct_argument_index == 0, "");
implicit_function_arguments[io_struct_argument_index] =
- std::make_shared<Pointer_type_descriptor>(
- std::vector<Decoration_with_parameters>{}, io_struct, no_instruction_index);
+ std::make_shared<Pointer_type_descriptor>(std::vector<Decoration_with_parameters>{},
+ io_struct,
+ no_instruction_index,
+ target_data);
inputs_struct =
std::make_shared<Struct_type_descriptor>(std::vector<Decoration_with_parameters>{},
context,
case Stage::calculate_types:
{
auto &state = get_id_state(instruction.result);
- state.type = std::make_shared<Simple_type_descriptor>(state.decorations,
- ::LLVMVoidTypeInContext(context));
+ state.type = std::make_shared<Simple_type_descriptor>(
+ state.decorations, LLVM_type_and_alignment(::LLVMVoidTypeInContext(context), 1));
break;
}
case Stage::generate_code:
case 16:
case 32:
case 64:
+ {
+ auto type = ::LLVMIntTypeInContext(context, instruction.width);
state.type = std::make_shared<Simple_type_descriptor>(
- state.decorations, ::LLVMIntTypeInContext(context, instruction.width));
+ state.decorations,
+ LLVM_type_and_alignment(type, ::LLVMPreferredAlignmentOfType(target_data, type)));
break;
+ }
default:
throw Parser_error(
instruction_start_index, instruction_start_index, "invalid int width");
case Stage::calculate_types:
{
auto &state = get_id_state(instruction.result);
+ ::LLVMTypeRef type = nullptr;
switch(instruction.width)
{
case 16:
- state.type = std::make_shared<Simple_type_descriptor>(state.decorations,
- ::LLVMHalfTypeInContext(context));
+ type = ::LLVMHalfTypeInContext(context);
break;
case 32:
- state.type = std::make_shared<Simple_type_descriptor>(
- state.decorations, ::LLVMFloatTypeInContext(context));
+ type = ::LLVMFloatTypeInContext(context);
break;
case 64:
- state.type = std::make_shared<Simple_type_descriptor>(
- state.decorations, ::LLVMDoubleTypeInContext(context));
+ type = ::LLVMDoubleTypeInContext(context);
break;
default:
throw Parser_error(
instruction_start_index, instruction_start_index, "invalid float width");
}
+ state.type = std::make_shared<Simple_type_descriptor>(
+ state.decorations,
+ LLVM_type_and_alignment(type, ::LLVMPreferredAlignmentOfType(target_data, type)));
break;
}
case Stage::generate_code:
state.type = std::make_shared<Vector_type_descriptor>(
state.decorations,
get_type<Simple_type_descriptor>(instruction.component_type, instruction_start_index),
- instruction.component_count);
+ instruction.component_count,
+ target_data);
break;
}
case Stage::generate_code:
state.type = std::make_shared<Matrix_type_descriptor>(
state.decorations,
get_type<Vector_type_descriptor>(instruction.column_type, instruction_start_index),
- instruction.column_count);
+ instruction.column_count,
+ target_data);
break;
}
case Stage::generate_code:
state.type = std::make_shared<Pointer_type_descriptor>(
state.decorations,
get_type(instruction.type, instruction_start_index),
- instruction_start_index);
+ instruction_start_index,
+ target_data);
}
else if(auto *pointer_type = dynamic_cast<Pointer_type_descriptor *>(state.type.get()))
{
state.decorations,
get_type(instruction.return_type, instruction_start_index),
std::move(args),
- instruction_start_index);
+ instruction_start_index,
+ target_data);
break;
}
case Stage::generate_code:
if(auto *simple_type = dynamic_cast<Simple_type_descriptor *>(type.get()))
{
auto llvm_type = simple_type->get_or_make_type();
- switch(::LLVMGetTypeKind(llvm_type))
+ switch(::LLVMGetTypeKind(llvm_type.type))
{
case LLVMFloatTypeKind:
{
::LLVMConstBitCast(
::LLVMConstInt(
::LLVMInt32TypeInContext(context), instruction.value[0], false),
- llvm_type));
+ llvm_type.type));
break;
}
case LLVMIntegerTypeKind:
{
- switch(::LLVMGetIntTypeWidth(llvm_type))
+ switch(::LLVMGetIntTypeWidth(llvm_type.type))
{
case 16:
{
instruction_start_index,
"OpConstant immediate value is wrong size for type int16");
state.constant = std::make_shared<Simple_constant_descriptor>(
- type, ::LLVMConstInt(llvm_type, instruction.value[0], false));
+ type, ::LLVMConstInt(llvm_type.type, instruction.value[0], false));
break;
}
case 32:
instruction_start_index,
"OpConstant immediate value is wrong size for type int32");
state.constant = std::make_shared<Simple_constant_descriptor>(
- type, ::LLVMConstInt(llvm_type, instruction.value[0], false));
+ type, ::LLVMConstInt(llvm_type.type, instruction.value[0], false));
break;
}
case 64:
"OpConstant immediate value is wrong size for type int64");
state.constant = std::make_shared<Simple_constant_descriptor>(
type,
- ::LLVMConstInt(llvm_type,
+ ::LLVMConstInt(llvm_type.type,
(static_cast<std::uint64_t>(instruction.value[1]) << 32)
| instruction.value[0],
false));
instruction_start_index,
instruction_start_index,
"unimplemented simple type for OpConstant: "
- + std::string(llvm_wrapper::print_type_to_string(llvm_type)));
+ + std::string(llvm_wrapper::print_type_to_string(llvm_type.type)));
}
break;
}
(static_cast<std::uint64_t>(instruction.value[1]) << 32)
| instruction.value[0],
false),
- llvm_type));
+ llvm_type.type));
break;
}
case LLVMHalfTypeKind:
::LLVMConstBitCast(
::LLVMConstInt(
::LLVMInt16TypeInContext(context), instruction.value[0], false),
- llvm_type));
+ llvm_type.type));
break;
}
default:
instruction_start_index,
instruction_start_index,
"unimplemented simple type for OpConstant: "
- + std::string(llvm_wrapper::print_type_to_string(llvm_type)));
+ + std::string(llvm_wrapper::print_type_to_string(llvm_type.type)));
}
}
}
function_name = std::string(state.op_entry_points[0].entry_point.name);
function_name = get_or_make_prefixed_name(std::move(function_name));
auto function = ::LLVMAddFunction(
- module.get(), function_name.c_str(), function_type->get_or_make_type());
+ module.get(), function_name.c_str(), function_type->get_or_make_type().type);
llvm_wrapper::Module::set_function_target_machine(function, target_machine);
state.function = Function_state(function_type, function, std::move(function_name));
break;
auto type =
get_type<Pointer_type_descriptor>(instruction.result_type, instruction_start_index);
state.value = Value(::LLVMBuildAlloca(builder.get(),
- type->get_base_type()->get_or_make_type(),
+ type->get_base_type()->get_or_make_type().type,
get_name(instruction.result).c_str()),
type);
+ ::LLVMSetAlignment(state.value->value, type->get_base_type()->get_or_make_type().alignment);
return;
}
case Storage_class::generic:
get_id_state(instruction.pointer).value.value().value,
get_name(instruction.result).c_str()),
get_type(instruction.result_type, instruction_start_index));
+ ::LLVMSetAlignment(state.value->value, state.value->type->get_or_make_type().alignment);
break;
}
}
throw Parser_error(instruction_start_index,
instruction_start_index,
"OpStore nontemporal not implemented");
- ::LLVMBuildStore(builder.get(),
- get_id_state(instruction.object).value.value().value,
- get_id_state(instruction.pointer).value.value().value);
+ auto &object_value = get_id_state(instruction.object).value.value();
+ auto &pointer_value = get_id_state(instruction.pointer).value.value();
+ ::LLVMSetAlignment(::LLVMBuildStore(builder.get(),
+ object_value.value,
+ pointer_value.value), object_value.type->get_or_make_type().alignment);
break;
}
}
throw Parser_error(instruction_start_index,
instruction_start_index,
"too few inputs to construct a vector");
- result_value = ::LLVMGetUndef(type.get_or_make_type());
+ result_value = ::LLVMGetUndef(type.get_or_make_type().type);
std::uint32_t insert_index = 0;
auto insert_element = [&](::LLVMValueRef element)
{
state.value =
Value(::LLVMBuildFPToUI(builder.get(),
get_id_state(instruction.float_value).value.value().value,
- result_type->get_or_make_type(),
+ result_type->get_or_make_type().type,
get_name(instruction.result).c_str()),
result_type);
break;
state.value =
Value(::LLVMBuildSIToFP(builder.get(),
get_id_state(instruction.signed_value).value.value().value,
- result_type->get_or_make_type(),
+ result_type->get_or_make_type().type,
get_name(instruction.result).c_str()),
result_type);
break;
+ std::string(get_enumerant_name(instruction.get_operation())));
auto result_type = get_type(instruction.result_type, instruction_start_index);
auto result_type_int_width = ::LLVMGetIntTypeWidth(
- llvm_wrapper::get_scalar_or_vector_element_type(result_type->get_or_make_type()));
+ llvm_wrapper::get_scalar_or_vector_element_type(result_type->get_or_make_type().type));
auto &arg = get_id_state(instruction.unsigned_value).value.value();
auto arg_int_width = ::LLVMGetIntTypeWidth(
- llvm_wrapper::get_scalar_or_vector_element_type(arg.type->get_or_make_type()));
+ llvm_wrapper::get_scalar_or_vector_element_type(arg.type->get_or_make_type().type));
auto opcode = ::LLVMTrunc;
if(result_type_int_width > arg_int_width)
opcode = ::LLVMZExt;
state.value = Value(::LLVMBuildCast(builder.get(),
opcode,
arg.value,
- result_type->get_or_make_type(),
+ result_type->get_or_make_type().type,
get_name(instruction.result).c_str()),
result_type);
break;
}
state.value = Value(::LLVMBuildBitCast(builder.get(),
arg.value,
- result_type->get_or_make_type(),
+ result_type->get_or_make_type().type,
get_name(instruction.result).c_str()),
result_type);
break;
get_or_make_label(instruction.default_),
instruction.target.size());
for(auto &target : instruction.target)
- ::LLVMAddCase(switch_instruction,
- ::LLVMConstInt(selector.type->get_or_make_type(), target.part_1, false),
- get_or_make_label(target.part_2));
+ ::LLVMAddCase(
+ switch_instruction,
+ ::LLVMConstInt(selector.type->get_or_make_type().type, target.part_1, false),
+ get_or_make_label(target.part_2));
break;
}
}
#include <cassert>
#include <type_traits>
#include <utility>
+#include <cstddef>
#include "llvm_wrapper/llvm_wrapper.h"
namespace vulkan_cpu
{
namespace spirv_to_llvm
{
+struct LLVM_type_and_alignment
+{
+ ::LLVMTypeRef type;
+ std::size_t alignment;
+ constexpr LLVM_type_and_alignment() noexcept : type(nullptr), alignment(0)
+ {
+ }
+ constexpr LLVM_type_and_alignment(::LLVMTypeRef type, std::size_t alignment) noexcept
+ : type(type),
+ alignment(alignment)
+ {
+ }
+};
+
class Simple_type_descriptor;
class Vector_type_descriptor;
class Matrix_type_descriptor;
{
}
virtual ~Type_descriptor() = default;
- virtual ::LLVMTypeRef get_or_make_type() = 0;
+ virtual LLVM_type_and_alignment get_or_make_type() = 0;
virtual void visit(Type_visitor &type_visitor) = 0;
void visit(Type_visitor &&type_visitor)
{
class Simple_type_descriptor final : public Type_descriptor
{
private:
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
public:
explicit Simple_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
- ::LLVMTypeRef type) noexcept
+ LLVM_type_and_alignment type) noexcept
: Type_descriptor(std::move(decorations)),
type(type)
{
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
return type;
}
class Vector_type_descriptor final : public Type_descriptor
{
private:
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
std::shared_ptr<Simple_type_descriptor> element_type;
std::size_t element_count;
public:
explicit Vector_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
std::shared_ptr<Simple_type_descriptor> element_type,
- std::size_t element_count) noexcept
+ std::size_t element_count,
+ ::LLVMTargetDataRef target_data) noexcept
: Type_descriptor(std::move(decorations)),
- type(::LLVMVectorType(element_type->get_or_make_type(), element_count)),
+ type(make_vector_type(element_type, element_count, target_data)),
element_type(std::move(element_type)),
element_count(element_count)
{
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ static LLVM_type_and_alignment make_vector_type(
+ const std::shared_ptr<Simple_type_descriptor> &element_type,
+ std::size_t element_count,
+ ::LLVMTargetDataRef target_data)
+ {
+ auto llvm_element_type = element_type->get_or_make_type();
+ auto type = ::LLVMVectorType(llvm_element_type.type, element_count);
+ std::size_t alignment = ::LLVMPreferredAlignmentOfType(target_data, type);
+ constexpr std::size_t max_abi_alignment = alignof(std::max_align_t);
+ if(alignment > max_abi_alignment)
+ alignment = max_abi_alignment;
+ return {type, alignment};
+ }
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
return type;
}
class Matrix_type_descriptor final : public Type_descriptor
{
private:
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
std::shared_ptr<Vector_type_descriptor> column_type;
std::size_t column_count;
public:
explicit Matrix_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
std::shared_ptr<Vector_type_descriptor> column_type,
- std::size_t column_count) noexcept
+ std::size_t column_count,
+ ::LLVMTargetDataRef target_data) noexcept
: Type_descriptor(std::move(decorations)),
- type(::LLVMVectorType(column_type->get_element_type()->get_or_make_type(),
- column_type->get_element_count() * column_count)),
+ type(Vector_type_descriptor::make_vector_type(column_type->get_element_type(),
+ column_type->get_element_count()
+ * column_count,
+ target_data)),
column_type(std::move(column_type)),
column_count(column_count)
{
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
return type;
}
class Array_type_descriptor final : public Type_descriptor
{
private:
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
std::shared_ptr<Type_descriptor> element_type;
std::size_t element_count;
std::size_t instruction_start_index;
std::size_t element_count,
std::size_t instruction_start_index) noexcept
: Type_descriptor(std::move(decorations)),
- type(::LLVMVectorType(element_type->get_or_make_type(), element_count)),
+ type(),
element_type(std::move(element_type)),
element_count(element_count),
instruction_start_index(instruction_start_index)
{
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
- if(!type)
+ if(!type.type)
{
Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
- type = ::LLVMArrayType(element_type->get_or_make_type(), element_count);
+ auto llvm_element_type = element_type->get_or_make_type();
+ type = LLVM_type_and_alignment(::LLVMArrayType(llvm_element_type.type, element_count),
+ llvm_element_type.alignment);
}
return type;
}
private:
std::shared_ptr<Type_descriptor> base;
std::size_t instruction_start_index;
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
Recursion_checker_state recursion_checker_state;
public:
Pointer_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
std::shared_ptr<Type_descriptor> base,
- std::size_t instruction_start_index) noexcept
+ std::size_t instruction_start_index,
+ ::LLVMTargetDataRef target_data) noexcept
: Type_descriptor(std::move(decorations)),
base(std::move(base)),
instruction_start_index(instruction_start_index),
- type(nullptr)
+ type(nullptr, llvm_wrapper::Target_data::get_pointer_alignment(target_data))
{
}
const std::shared_ptr<Type_descriptor> &get_base_type() const noexcept
base = std::move(new_base);
}
explicit Pointer_type_descriptor(std::vector<spirv::Decoration_with_parameters> decorations,
- std::size_t instruction_start_index) noexcept
+ std::size_t instruction_start_index,
+ ::LLVMTargetDataRef target_data) noexcept
: Type_descriptor(std::move(decorations)),
base(nullptr),
instruction_start_index(instruction_start_index),
- type(nullptr)
+ type(nullptr, llvm_wrapper::Target_data::get_pointer_alignment(target_data))
{
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
- if(!type)
+ if(!type.type)
{
Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
if(!base)
"attempting to create type from pointer forward declaration");
auto base_type = base->get_or_make_type();
constexpr unsigned default_address_space = 0;
- type = ::LLVMPointerType(base_type, default_address_space);
+ type.type = ::LLVMPointerType(base_type.type, default_address_space);
}
return type;
}
private:
std::shared_ptr<Type_descriptor> return_type;
std::vector<std::shared_ptr<Type_descriptor>> args;
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
Recursion_checker_state recursion_checker_state;
std::size_t instruction_start_index;
bool is_var_arg;
std::shared_ptr<Type_descriptor> return_type,
std::vector<std::shared_ptr<Type_descriptor>> args,
std::size_t instruction_start_index,
+ ::LLVMTargetDataRef target_data,
bool is_var_arg = false) noexcept
: Type_descriptor(std::move(decorations)),
return_type(std::move(return_type)),
args(std::move(args)),
- type(nullptr),
+ type(nullptr, llvm_wrapper::Target_data::get_pointer_alignment(target_data)),
instruction_start_index(instruction_start_index),
is_var_arg(is_var_arg)
{
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
- if(!type)
+ if(!type.type)
{
Recursion_checker recursion_checker(recursion_checker_state, instruction_start_index);
std::vector<::LLVMTypeRef> llvm_args;
llvm_args.reserve(args.size());
auto llvm_return_type = return_type->get_or_make_type();
for(auto &arg : args)
- llvm_args.push_back(arg->get_or_make_type());
- type = ::LLVMFunctionType(
- llvm_return_type, llvm_args.data(), llvm_args.size(), is_var_arg);
+ llvm_args.push_back(arg->get_or_make_type().type);
+ type.type = ::LLVMFunctionType(
+ llvm_return_type.type, llvm_args.data(), llvm_args.size(), is_var_arg);
}
return type;
}
private:
std::vector<Member> members;
util::Enum_map<spirv::Built_in, std::size_t> builtin_members;
- ::LLVMTypeRef type;
+ LLVM_type_and_alignment type;
bool is_complete;
Recursion_checker_state recursion_checker_state;
std::size_t instruction_start_index;
: Type_descriptor(std::move(decorations)),
members(std::move(members)),
builtin_members{},
- type(::LLVMStructCreateNamed(context, name)),
+ type(::LLVMStructCreateNamed(context, name), 0),
is_complete(false),
instruction_start_index(instruction_start_index),
context(context),
for(std::size_t member_index = 0; member_index < members.size(); member_index++)
on_add_member(member_index);
}
- virtual ::LLVMTypeRef get_or_make_type() override
+ virtual LLVM_type_and_alignment get_or_make_type() override
{
if(!is_complete)
{