wip
This commit is contained in:
parent
c07849aa79
commit
cbf757f565
@ -21,6 +21,7 @@ add_executable(bb
|
|||||||
src/llvm.cpp
|
src/llvm.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
target_include_directories(bb PUBLIC src)
|
target_include_directories(bb PUBLIC src)
|
||||||
target_compile_definitions(bb PUBLIC
|
target_compile_definitions(bb PUBLIC
|
||||||
$<$<CONFIG:Debug>:BB_DEBUG=1>
|
$<$<CONFIG:Debug>:BB_DEBUG=1>
|
||||||
@ -45,5 +46,9 @@ target_link_libraries(bb PUBLIC
|
|||||||
# ${LLD_WASM}
|
# ${LLD_WASM}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_compile_options(bb PRIVATE -Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -funsigned-char -fwrapv -fno-strict-aliasing)
|
||||||
|
if (NOT APPLE)
|
||||||
|
target_compile_options(bb PRIVATE -Wno-missing-designated-field-initializers)
|
||||||
|
endif()
|
||||||
#target_compile_options(bb PRIVATE -fsanitize=address)
|
#target_compile_options(bb PRIVATE -fsanitize=address)
|
||||||
#target_link_options(bb PRIVATE -fsanitize=address)
|
#target_link_options(bb PRIVATE -fsanitize=address)
|
||||||
|
35
generate.sh
35
generate.sh
@ -1,7 +1,34 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -eu
|
set -eu
|
||||||
rm -rf build
|
CMAKE_BUILD_TYPE=Debug
|
||||||
mkdir build
|
LLVM_CMAKE_BUILD_TYPE=Release
|
||||||
cd build
|
BUILD_DIR=build
|
||||||
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=MOLD -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-Release -DCMAKE_COLOR_DIAGNOSTICS=ON
|
|
||||||
|
BIRTH_NATIVE_OS_STRING=$OSTYPE
|
||||||
|
|
||||||
|
case "$BIRTH_NATIVE_OS_STRING" in
|
||||||
|
darwin*) BIRTH_OS="macos";;
|
||||||
|
linux*) BIRTH_OS="linux";;
|
||||||
|
msys*) BIRTH_OS="windows";;
|
||||||
|
*) exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
BIRTH_NATIVE_ARCH_STRING="$(uname -m)"
|
||||||
|
|
||||||
|
case "$BIRTH_NATIVE_ARCH_STRING" in
|
||||||
|
x86_64) BIRTH_ARCH="x86_64";;
|
||||||
|
arm64) BIRTH_ARCH="aarch64";;
|
||||||
|
*) exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$BIRTH_OS" in
|
||||||
|
linux) LINKER_TYPE=MOLD;;
|
||||||
|
*) LINKER_TYPE=DEFAULT;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
rm -rf $BUILD_DIR
|
||||||
|
mkdir $BUILD_DIR
|
||||||
|
cd $BUILD_DIR
|
||||||
|
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=$LINKER_TYPE -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=$HOME/dev/llvm/install/llvm_20.1.3_$BIRTH_ARCH-$BIRTH_OS-$LLVM_CMAKE_BUILD_TYPE -DCMAKE_COLOR_DIAGNOSTICS=ON
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -60,7 +60,7 @@ fn void compile(Arena* arena, Options options)
|
|||||||
type_it += 1;
|
type_it += 1;
|
||||||
auto noreturn_type = type_it;
|
auto noreturn_type = type_it;
|
||||||
type_it += 1;
|
type_it += 1;
|
||||||
assert(type_it - base_type_allocation.pointer == base_allocation_type_count);
|
assert((u64)(type_it - base_type_allocation.pointer) == base_allocation_type_count);
|
||||||
|
|
||||||
previous->next = void_type;
|
previous->next = void_type;
|
||||||
*void_type = {
|
*void_type = {
|
||||||
@ -260,6 +260,7 @@ global_variable String names[] = {
|
|||||||
string_literal("c_string_to_slice"),
|
string_literal("c_string_to_slice"),
|
||||||
string_literal("c_struct_with_array"),
|
string_literal("c_struct_with_array"),
|
||||||
string_literal("c_function_pointer"),
|
string_literal("c_function_pointer"),
|
||||||
|
string_literal("basic_bool_call"),
|
||||||
string_literal("c_abi"),
|
string_literal("c_abi"),
|
||||||
string_literal("string_to_enum"),
|
string_literal("string_to_enum"),
|
||||||
string_literal("abi_enum_bool"),
|
string_literal("abi_enum_bool"),
|
||||||
@ -291,6 +292,7 @@ global_variable String names[] = {
|
|||||||
|
|
||||||
void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
|
void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
|
||||||
{
|
{
|
||||||
|
unused(environment);
|
||||||
Arena* arena = arena_initialize_default(8 * mb);
|
Arena* arena = arena_initialize_default(8 * mb);
|
||||||
|
|
||||||
if (arguments.length < 2)
|
if (arguments.length < 2)
|
||||||
@ -407,7 +409,7 @@ void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
|
|||||||
.relative_file_path = relative_file_path,
|
.relative_file_path = relative_file_path,
|
||||||
.build_mode = build_mode,
|
.build_mode = build_mode,
|
||||||
.has_debug_info = has_debug_info,
|
.has_debug_info = has_debug_info,
|
||||||
.silent = false,
|
.silent = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: introduce test
|
// TODO: introduce test
|
||||||
|
477
src/compiler.h
477
src/compiler.h
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
|
#include <llvm-c/Types.h>
|
||||||
#define report_error() trap_raw()
|
#define report_error() trap()
|
||||||
|
|
||||||
enum class Command
|
enum class Command
|
||||||
{
|
{
|
||||||
@ -38,6 +38,23 @@ fn String build_mode_to_string(BuildMode build_mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bool build_mode_is_optimized(BuildMode build_mode)
|
||||||
|
{
|
||||||
|
switch (build_mode)
|
||||||
|
{
|
||||||
|
case BuildMode::debug_none:
|
||||||
|
case BuildMode::debug:
|
||||||
|
return false;
|
||||||
|
case BuildMode::soft_optimize:
|
||||||
|
case BuildMode::optimize_for_speed:
|
||||||
|
case BuildMode::optimize_for_size:
|
||||||
|
case BuildMode::aggressively_optimize_for_speed:
|
||||||
|
case BuildMode::aggressively_optimize_for_size:
|
||||||
|
return true;
|
||||||
|
case BuildMode::count: unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class ValueKind
|
enum class ValueKind
|
||||||
{
|
{
|
||||||
right,
|
right,
|
||||||
@ -65,6 +82,165 @@ struct Argument;
|
|||||||
struct Scope;
|
struct Scope;
|
||||||
struct MacroDeclaration;
|
struct MacroDeclaration;
|
||||||
|
|
||||||
|
struct DirectAttributes
|
||||||
|
{
|
||||||
|
u32 offset;
|
||||||
|
u32 alignment;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndirectAttributes
|
||||||
|
{
|
||||||
|
u32 alignment;
|
||||||
|
u32 address_space;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AbiKind : u8
|
||||||
|
{
|
||||||
|
ignore,
|
||||||
|
direct,
|
||||||
|
extend,
|
||||||
|
indirect,
|
||||||
|
indirect_aliased,
|
||||||
|
expand,
|
||||||
|
coerce_and_expand,
|
||||||
|
in_alloca,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbiFlags
|
||||||
|
{
|
||||||
|
AbiKind kind;
|
||||||
|
bool padding_in_reg;
|
||||||
|
bool in_alloca_sret;
|
||||||
|
bool in_alloca_indirect;
|
||||||
|
bool indirect_by_value;
|
||||||
|
bool indirect_realign;
|
||||||
|
bool sret_after_this;
|
||||||
|
bool in_reg;
|
||||||
|
bool can_be_flattened;
|
||||||
|
bool sign_extension;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbiInformation
|
||||||
|
{
|
||||||
|
Type* semantic_type;
|
||||||
|
Type* coerce_to_type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
Type* unpadded_coerce_and_expand_type;
|
||||||
|
} padding;
|
||||||
|
u16 padding_argument_index;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
DirectAttributes direct;
|
||||||
|
IndirectAttributes indirect;
|
||||||
|
u32 alloca_field_index;
|
||||||
|
} attributes;
|
||||||
|
AbiFlags flags;
|
||||||
|
u16 abi_start;
|
||||||
|
u16 abi_count;
|
||||||
|
|
||||||
|
inline void set_sret_after_this(bool sret_after_this)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::indirect);
|
||||||
|
flags.sret_after_this = sret_after_this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_indirect_realign(bool realign)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::indirect);
|
||||||
|
flags.indirect_realign = realign;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_indirect_by_value(bool by_value)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::indirect);
|
||||||
|
flags.indirect_by_value = by_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_indirect_align(u32 alignment)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::indirect || flags.kind == AbiKind::indirect_aliased);
|
||||||
|
attributes.indirect.alignment = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool can_have_coerce_to_type()
|
||||||
|
{
|
||||||
|
switch (flags.kind)
|
||||||
|
{
|
||||||
|
case AbiKind::direct:
|
||||||
|
case AbiKind::extend:
|
||||||
|
case AbiKind::coerce_and_expand:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_coerce_to_type(Type* coerce_to_type)
|
||||||
|
{
|
||||||
|
assert(can_have_coerce_to_type());
|
||||||
|
this->coerce_to_type = coerce_to_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Type* get_coerce_to_type()
|
||||||
|
{
|
||||||
|
assert(can_have_coerce_to_type());
|
||||||
|
return coerce_to_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_padding_type(Type* padding_type)
|
||||||
|
{
|
||||||
|
assert(can_have_padding_type());
|
||||||
|
padding = {
|
||||||
|
.type = padding_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool can_have_padding_type()
|
||||||
|
{
|
||||||
|
switch (flags.kind)
|
||||||
|
{
|
||||||
|
case AbiKind::direct:
|
||||||
|
case AbiKind::extend:
|
||||||
|
case AbiKind::indirect:
|
||||||
|
case AbiKind::indirect_aliased:
|
||||||
|
case AbiKind::expand:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Type* get_padding_type()
|
||||||
|
{
|
||||||
|
return can_have_padding_type() ? padding.type : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_direct_offset(u32 offset)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend);
|
||||||
|
attributes.direct.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_direct_alignment(u32 alignment)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend);
|
||||||
|
attributes.direct.alignment = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_can_be_flattened(bool can_be_flattened)
|
||||||
|
{
|
||||||
|
assert(flags.kind == AbiKind::direct);
|
||||||
|
flags.can_be_flattened = can_be_flattened;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool get_can_be_flattened()
|
||||||
|
{
|
||||||
|
return flags.can_be_flattened;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Target
|
struct Target
|
||||||
{
|
{
|
||||||
CPUArchitecture cpu;
|
CPUArchitecture cpu;
|
||||||
@ -87,6 +263,24 @@ enum class CallingConvention
|
|||||||
count,
|
count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ResolvedCallingConvention
|
||||||
|
{
|
||||||
|
system_v,
|
||||||
|
win64,
|
||||||
|
count,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn ResolvedCallingConvention resolve_calling_convention(CallingConvention cc)
|
||||||
|
{
|
||||||
|
switch (cc)
|
||||||
|
{
|
||||||
|
case CallingConvention::c:
|
||||||
|
// TODO:
|
||||||
|
return ResolvedCallingConvention::system_v;
|
||||||
|
case CallingConvention::count: unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class InlineBehavior
|
enum class InlineBehavior
|
||||||
{
|
{
|
||||||
normal,
|
normal,
|
||||||
@ -116,6 +310,8 @@ enum class TypeId
|
|||||||
alias,
|
alias,
|
||||||
union_type,
|
union_type,
|
||||||
unresolved,
|
unresolved,
|
||||||
|
vector,
|
||||||
|
floating_point,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeInteger
|
struct TypeInteger
|
||||||
@ -124,12 +320,29 @@ struct TypeInteger
|
|||||||
bool is_signed;
|
bool is_signed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AbiRegisterCountSystemV
|
||||||
|
{
|
||||||
|
u32 gpr;
|
||||||
|
u32 sse;
|
||||||
|
};
|
||||||
|
|
||||||
|
union AbiRegisterCount
|
||||||
|
{
|
||||||
|
AbiRegisterCountSystemV system_v;
|
||||||
|
};
|
||||||
|
|
||||||
struct TypeFunction
|
struct TypeFunction
|
||||||
{
|
{
|
||||||
Type* semantic_return_type;
|
Type* semantic_return_type;
|
||||||
Slice<Type*> semantic_argument_types;
|
Slice<Type*> semantic_argument_types;
|
||||||
CallingConvention calling_convention;
|
CallingConvention calling_convention;
|
||||||
bool is_variable_arguments;
|
bool is_variable_arguments;
|
||||||
|
// ABI
|
||||||
|
Slice<Type*> abi_argument_types;
|
||||||
|
Type* abi_return_type;
|
||||||
|
AbiRegisterCount available_registers;
|
||||||
|
Slice<AbiInformation> argument_abis;
|
||||||
|
AbiInformation return_abi;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypePointer
|
struct TypePointer
|
||||||
@ -140,8 +353,9 @@ struct TypePointer
|
|||||||
|
|
||||||
struct TypeArray
|
struct TypeArray
|
||||||
{
|
{
|
||||||
u64 element_count;
|
|
||||||
Type* element_type;
|
Type* element_type;
|
||||||
|
u64 element_count;
|
||||||
|
Type* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnresolvedEnumField
|
struct UnresolvedEnumField
|
||||||
@ -169,6 +383,9 @@ struct TypeEnum
|
|||||||
{
|
{
|
||||||
Slice<EnumField> fields;
|
Slice<EnumField> fields;
|
||||||
Type* backing_type;
|
Type* backing_type;
|
||||||
|
LLVMValueRef string_to_enum_function;
|
||||||
|
LLVMTypeRef string_to_enum_struct_type;
|
||||||
|
Global* name_array;
|
||||||
u32 line;
|
u32 line;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -221,6 +438,13 @@ struct TypeUnion
|
|||||||
u32 biggest_field;
|
u32 biggest_field;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LLVMType
|
||||||
|
{
|
||||||
|
LLVMTypeRef abi;
|
||||||
|
LLVMTypeRef memory;
|
||||||
|
LLVMMetadataRef debug;
|
||||||
|
};
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -238,6 +462,7 @@ struct Type
|
|||||||
TypeId id;
|
TypeId id;
|
||||||
String name;
|
String name;
|
||||||
Type* next;
|
Type* next;
|
||||||
|
LLVMType llvm;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn u32 align_bit_count(u32 bit_count)
|
fn u32 align_bit_count(u32 bit_count)
|
||||||
@ -263,6 +488,10 @@ fn u64 get_byte_size(Type* type)
|
|||||||
assert(byte_count == 1 || byte_count == 2 || byte_count == 4 || byte_count == 8 || byte_count == 16);
|
assert(byte_count == 1 || byte_count == 2 || byte_count == 4 || byte_count == 8 || byte_count == 16);
|
||||||
return byte_count;
|
return byte_count;
|
||||||
} break;
|
} break;
|
||||||
|
case TypeId::pointer:
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
} break;
|
||||||
case TypeId::array:
|
case TypeId::array:
|
||||||
{
|
{
|
||||||
auto element_type = type->array.element_type;
|
auto element_type = type->array.element_type;
|
||||||
@ -281,7 +510,12 @@ fn u64 get_byte_size(Type* type)
|
|||||||
auto result = get_byte_size(type->enumerator.backing_type);
|
auto result = get_byte_size(type->enumerator.backing_type);
|
||||||
return result;
|
return result;
|
||||||
} break;
|
} break;
|
||||||
default: trap_raw();
|
case TypeId::bits:
|
||||||
|
{
|
||||||
|
auto result = get_byte_size(type->bits.backing_type);
|
||||||
|
return result;
|
||||||
|
} break;
|
||||||
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +545,16 @@ fn u32 get_byte_alignment(Type* type)
|
|||||||
auto result = get_byte_alignment(type->enumerator.backing_type);
|
auto result = get_byte_alignment(type->enumerator.backing_type);
|
||||||
return result;
|
return result;
|
||||||
} break;
|
} break;
|
||||||
default: trap_raw();
|
case TypeId::pointer:
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
} break;
|
||||||
|
case TypeId::bits:
|
||||||
|
{
|
||||||
|
auto result = get_byte_alignment(type->bits.backing_type);
|
||||||
|
return result;
|
||||||
|
} break;
|
||||||
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +563,8 @@ fn u64 get_bit_size(Type* type)
|
|||||||
switch (type->id)
|
switch (type->id)
|
||||||
{
|
{
|
||||||
case TypeId::integer: return type->integer.bit_count;
|
case TypeId::integer: return type->integer.bit_count;
|
||||||
default: trap_raw();
|
case TypeId::enumerator: return get_bit_size(type->enumerator.backing_type);
|
||||||
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +584,7 @@ struct Scope
|
|||||||
u32 line;
|
u32 line;
|
||||||
u32 column;
|
u32 column;
|
||||||
ScopeKind kind;
|
ScopeKind kind;
|
||||||
|
LLVMMetadataRef llvm;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StatementId
|
enum class StatementId
|
||||||
@ -461,7 +706,6 @@ enum class ValueId
|
|||||||
variable_reference,
|
variable_reference,
|
||||||
macro_reference,
|
macro_reference,
|
||||||
macro_instantiation,
|
macro_instantiation,
|
||||||
dereference,
|
|
||||||
call,
|
call,
|
||||||
global,
|
global,
|
||||||
array_initialization,
|
array_initialization,
|
||||||
@ -479,6 +723,8 @@ enum class ValueId
|
|||||||
zero,
|
zero,
|
||||||
select,
|
select,
|
||||||
string_to_enum,
|
string_to_enum,
|
||||||
|
local,
|
||||||
|
argument,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ValueConstantInteger
|
struct ValueConstantInteger
|
||||||
@ -487,12 +733,19 @@ struct ValueConstantInteger
|
|||||||
bool is_signed;
|
bool is_signed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FunctionLLVM
|
||||||
|
{
|
||||||
|
LLVMBasicBlockRef return_block;
|
||||||
|
LLVMValueRef return_alloca;
|
||||||
|
};
|
||||||
|
|
||||||
struct ValueFunction
|
struct ValueFunction
|
||||||
{
|
{
|
||||||
Slice<Argument> arguments;
|
Slice<Argument> arguments;
|
||||||
Scope scope;
|
Scope scope;
|
||||||
Block* block;
|
Block* block;
|
||||||
FunctionAttributes attributes;
|
FunctionAttributes attributes;
|
||||||
|
FunctionLLVM llvm;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UnaryId
|
enum class UnaryId
|
||||||
@ -510,6 +763,7 @@ enum class UnaryId
|
|||||||
int_from_pointer,
|
int_from_pointer,
|
||||||
va_end,
|
va_end,
|
||||||
bitwise_not,
|
bitwise_not,
|
||||||
|
dereference,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ValueUnary
|
struct ValueUnary
|
||||||
@ -565,6 +819,7 @@ struct ValueCall
|
|||||||
{
|
{
|
||||||
Value* callable;
|
Value* callable;
|
||||||
Slice<Value*> arguments;
|
Slice<Value*> arguments;
|
||||||
|
Type* function_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ValueArrayInitialization
|
struct ValueArrayInitialization
|
||||||
@ -666,6 +921,8 @@ struct MacroInstantiation
|
|||||||
u32 column;
|
u32 column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn bool variable_is_constant(Value* value);
|
||||||
|
|
||||||
struct Value
|
struct Value
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -676,7 +933,6 @@ struct Value
|
|||||||
ValueBinary binary;
|
ValueBinary binary;
|
||||||
Variable* variable_reference;
|
Variable* variable_reference;
|
||||||
ValueUnaryType unary_type;
|
ValueUnaryType unary_type;
|
||||||
Value* dereference;
|
|
||||||
ValueCall call;
|
ValueCall call;
|
||||||
ValueArrayInitialization array_initialization;
|
ValueArrayInitialization array_initialization;
|
||||||
ValueArrayExpression array_expression;
|
ValueArrayExpression array_expression;
|
||||||
@ -694,6 +950,7 @@ struct Value
|
|||||||
Type* type;
|
Type* type;
|
||||||
ValueId id;
|
ValueId id;
|
||||||
ValueKind kind;
|
ValueKind kind;
|
||||||
|
LLVMValueRef llvm;
|
||||||
|
|
||||||
bool is_constant()
|
bool is_constant()
|
||||||
{
|
{
|
||||||
@ -701,7 +958,27 @@ struct Value
|
|||||||
{
|
{
|
||||||
case ValueId::constant_integer:
|
case ValueId::constant_integer:
|
||||||
return true;
|
return true;
|
||||||
default: trap_raw();
|
case ValueId::unary:
|
||||||
|
case ValueId::binary:
|
||||||
|
case ValueId::field_access:
|
||||||
|
case ValueId::array_expression:
|
||||||
|
case ValueId::call:
|
||||||
|
return false;
|
||||||
|
case ValueId::variable_reference:
|
||||||
|
{
|
||||||
|
return variable_is_constant(this);
|
||||||
|
} break;
|
||||||
|
case ValueId::array_initialization:
|
||||||
|
{
|
||||||
|
assert(type); // This asserts that the value type has been analyzed and `is_constant` was properly set
|
||||||
|
return array_initialization.is_constant;
|
||||||
|
} break;
|
||||||
|
case ValueId::aggregate_initialization:
|
||||||
|
{
|
||||||
|
assert(type); // This asserts that the value type has been analyzed and `is_constant` was properly set
|
||||||
|
return aggregate_initialization.is_constant;
|
||||||
|
} break;
|
||||||
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -717,6 +994,28 @@ struct Variable
|
|||||||
u32 column;
|
u32 column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn bool variable_is_constant(Value* value)
|
||||||
|
{
|
||||||
|
assert(value->id == ValueId::variable_reference);
|
||||||
|
auto* variable = value->variable_reference;
|
||||||
|
|
||||||
|
switch (value->kind)
|
||||||
|
{
|
||||||
|
case ValueKind::left:
|
||||||
|
{
|
||||||
|
switch (variable->scope->kind)
|
||||||
|
{
|
||||||
|
case ScopeKind::global:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case ValueKind::right:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class Linkage
|
enum class Linkage
|
||||||
{
|
{
|
||||||
internal,
|
internal,
|
||||||
@ -742,6 +1041,47 @@ struct Argument
|
|||||||
u32 index;
|
u32 index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LLVMIntrinsicId
|
||||||
|
{
|
||||||
|
u32 n;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class IntrinsicIndex
|
||||||
|
{
|
||||||
|
trap,
|
||||||
|
va_start,
|
||||||
|
va_end,
|
||||||
|
va_copy,
|
||||||
|
count,
|
||||||
|
};
|
||||||
|
|
||||||
|
global_variable String intrinsic_names[] = {
|
||||||
|
string_literal("llvm.trap"),
|
||||||
|
string_literal("llvm.va_start"),
|
||||||
|
string_literal("llvm.va_end"),
|
||||||
|
string_literal("llvm.va_copy"),
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(array_length(intrinsic_names) == (u64)IntrinsicIndex::count);
|
||||||
|
|
||||||
|
struct ModuleLLVM
|
||||||
|
{
|
||||||
|
LLVMContextRef context;
|
||||||
|
LLVMModuleRef module;
|
||||||
|
LLVMBuilderRef builder;
|
||||||
|
LLVMDIBuilderRef di_builder;
|
||||||
|
LLVMMetadataRef file;
|
||||||
|
LLVMMetadataRef compile_unit;
|
||||||
|
LLVMTypeRef pointer_type;
|
||||||
|
LLVMTypeRef void_type;
|
||||||
|
LLVMIntrinsicId intrinsic_table[(u64)IntrinsicIndex::count];
|
||||||
|
LLVMValueRef memcmp;
|
||||||
|
LLVMMetadataRef inlined_at;
|
||||||
|
LLVMBasicBlockRef continue_block;
|
||||||
|
LLVMBasicBlockRef exit_block;
|
||||||
|
u32 debug_tag;
|
||||||
|
};
|
||||||
|
|
||||||
struct Module
|
struct Module
|
||||||
{
|
{
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
@ -768,6 +1108,7 @@ struct Module
|
|||||||
MacroDeclaration* current_macro_declaration;
|
MacroDeclaration* current_macro_declaration;
|
||||||
MacroInstantiation* current_macro_instantiation;
|
MacroInstantiation* current_macro_instantiation;
|
||||||
|
|
||||||
|
ModuleLLVM llvm;
|
||||||
Scope scope;
|
Scope scope;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
@ -788,6 +1129,10 @@ fn Type* integer_type(Module* module, TypeInteger integer)
|
|||||||
{
|
{
|
||||||
assert(integer.bit_count);
|
assert(integer.bit_count);
|
||||||
assert(integer.bit_count <= 64 || integer.bit_count == 128);
|
assert(integer.bit_count <= 64 || integer.bit_count == 128);
|
||||||
|
if (integer.is_signed)
|
||||||
|
{
|
||||||
|
assert(integer.bit_count > 1);
|
||||||
|
}
|
||||||
auto index = integer.bit_count == 128 ? (i128_offset + integer.is_signed) : (integer.bit_count - 1 + (64 * integer.is_signed));
|
auto index = integer.bit_count == 128 ? (i128_offset + integer.is_signed) : (integer.bit_count - 1 + (64 * integer.is_signed));
|
||||||
auto* result_type = module->first_type + index;
|
auto* result_type = module->first_type + index;
|
||||||
assert(result_type->id == TypeId::integer);
|
assert(result_type->id == TypeId::integer);
|
||||||
@ -806,6 +1151,31 @@ fn Type* noreturn_type(Module* module)
|
|||||||
return void_type(module) + 1;
|
return void_type(module) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn Type* uint1(Module* module)
|
||||||
|
{
|
||||||
|
return integer_type(module, { .bit_count = 1, .is_signed = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Type* uint8(Module* module)
|
||||||
|
{
|
||||||
|
return integer_type(module, { .bit_count = 8, .is_signed = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Type* uint32(Module* module)
|
||||||
|
{
|
||||||
|
return integer_type(module, { .bit_count = 32, .is_signed = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Type* uint64(Module* module)
|
||||||
|
{
|
||||||
|
return integer_type(module, { .bit_count = 64, .is_signed = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Type* sint32(Module* module)
|
||||||
|
{
|
||||||
|
return integer_type(module, { .bit_count = 32, .is_signed = true });
|
||||||
|
}
|
||||||
|
|
||||||
struct Options
|
struct Options
|
||||||
{
|
{
|
||||||
String content;
|
String content;
|
||||||
@ -899,6 +1269,7 @@ fn Type* get_pointer_type(Module* module, Type* element_type)
|
|||||||
string_literal("&"),
|
string_literal("&"),
|
||||||
element_type->name,
|
element_type->name,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto result = type_allocate_init(module, {
|
auto result = type_allocate_init(module, {
|
||||||
.pointer = {
|
.pointer = {
|
||||||
.element_type = element_type,
|
.element_type = element_type,
|
||||||
@ -907,6 +1278,17 @@ fn Type* get_pointer_type(Module* module, Type* element_type)
|
|||||||
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
.name = arena_join_string(module->arena, array_to_slice(name_parts)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (last_pointer_type)
|
||||||
|
{
|
||||||
|
assert(module->first_pointer_type);
|
||||||
|
last_pointer_type->pointer.next = result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(!module->first_pointer_type);
|
||||||
|
module->first_pointer_type = result;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,7 +1341,7 @@ fn Type* get_slice_type(Module* module, Type* element_type)
|
|||||||
};
|
};
|
||||||
fields[1] = {
|
fields[1] = {
|
||||||
.name = string_literal("length"),
|
.name = string_literal("length"),
|
||||||
.type = integer_type(module, { .bit_count = 64, .is_signed = false }),
|
.type = uint64(module),
|
||||||
.offset = 8,
|
.offset = 8,
|
||||||
.line = 0,
|
.line = 0,
|
||||||
};
|
};
|
||||||
@ -982,7 +1364,7 @@ fn Type* get_slice_type(Module* module, Type* element_type)
|
|||||||
|
|
||||||
if (last_slice_type)
|
if (last_slice_type)
|
||||||
{
|
{
|
||||||
last_slice_type->next = result;
|
last_slice_type->structure.next = result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -992,5 +1374,78 @@ fn Type* get_slice_type(Module* module, Type* element_type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn String array_name(Module* module, Type* element_type, u64 element_count)
|
||||||
|
{
|
||||||
|
u8 buffer[512];
|
||||||
|
auto buffer_slice = String{ .pointer = buffer, .length = array_length(buffer) };
|
||||||
|
|
||||||
|
u64 i = 0;
|
||||||
|
|
||||||
|
buffer[i] = '[';
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
i += format_integer_decimal(buffer_slice(i), element_count);
|
||||||
|
|
||||||
|
buffer[i] = ']';
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
auto element_name = element_type->name;
|
||||||
|
memcpy(buffer + i, element_name.pointer, element_name.length);
|
||||||
|
i += element_name.length;
|
||||||
|
|
||||||
|
auto name = arena_duplicate_string(module->arena, buffer_slice(0, i));
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Type* get_array_type(Module* module, Type* element_type, u64 element_count)
|
||||||
|
{
|
||||||
|
assert(element_type);
|
||||||
|
assert(element_count);
|
||||||
|
|
||||||
|
Type* array_type = module->first_array_type;
|
||||||
|
|
||||||
|
if (array_type)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
assert(array_type->id == TypeId::array);
|
||||||
|
auto* candidate_element_type = array_type->array.element_type;
|
||||||
|
if (candidate_element_type == element_type)
|
||||||
|
{
|
||||||
|
return array_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array_type->array.next)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_type = array_type->array.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* last_array_type = array_type;
|
||||||
|
|
||||||
|
auto result = type_allocate_init(module, {
|
||||||
|
.array = {
|
||||||
|
.element_type = element_type,
|
||||||
|
.element_count = element_count,
|
||||||
|
},
|
||||||
|
.id = TypeId::array,
|
||||||
|
.name = array_name(module, element_type, element_count),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (last_array_type)
|
||||||
|
{
|
||||||
|
last_array_type->array.next = result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
module->first_array_type = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void parse(Module* module);
|
void parse(Module* module);
|
||||||
void emit(Module* module);
|
void emit(Module* module);
|
||||||
|
6302
src/emitter.cpp
6302
src/emitter.cpp
File diff suppressed because it is too large
Load Diff
63
src/lib.h
63
src/lib.h
@ -8,6 +8,7 @@
|
|||||||
#define breakpoint() __builtin_debugtrap()
|
#define breakpoint() __builtin_debugtrap()
|
||||||
#define string_literal_length(s) (sizeof(s) - 1)
|
#define string_literal_length(s) (sizeof(s) - 1)
|
||||||
#define string_literal(s) ((String){ .pointer = (u8*)(s), .length = string_literal_length(s), })
|
#define string_literal(s) ((String){ .pointer = (u8*)(s), .length = string_literal_length(s), })
|
||||||
|
#define split_string_literal(s) (char*)(s), string_literal_length(s)
|
||||||
#define offsetof(S, f) __builtin_offsetof(S, f)
|
#define offsetof(S, f) __builtin_offsetof(S, f)
|
||||||
|
|
||||||
#define array_length(arr) sizeof(arr) / sizeof((arr)[0])
|
#define array_length(arr) sizeof(arr) / sizeof((arr)[0])
|
||||||
@ -16,9 +17,9 @@
|
|||||||
#define backing_type(E) __underlying_type(E)
|
#define backing_type(E) __underlying_type(E)
|
||||||
|
|
||||||
#define unreachable_raw() __builtin_unreachable()
|
#define unreachable_raw() __builtin_unreachable()
|
||||||
#define trap_raw() __builtin_trap()
|
#define trap() __builtin_trap()
|
||||||
#if BB_DEBUG
|
#if BB_DEBUG
|
||||||
#define unreachable() trap_raw()
|
#define unreachable() trap()
|
||||||
#else
|
#else
|
||||||
#define unreachable() unreachable_raw()
|
#define unreachable() unreachable_raw()
|
||||||
#endif
|
#endif
|
||||||
@ -300,14 +301,32 @@ fn void* os_reserve(void* base, u64 size, ProtectionFlags protection, MapFlags m
|
|||||||
.read = protection.read,
|
.read = protection.read,
|
||||||
.write = protection.write,
|
.write = protection.write,
|
||||||
.execute = protection.execute,
|
.execute = protection.execute,
|
||||||
|
.sem = 0,
|
||||||
|
._ = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto map_flags = MAP
|
auto map_flags = MAP
|
||||||
{
|
{
|
||||||
.type = map.priv ? MAP::Type::priv : MAP::Type::shared,
|
.type = map.priv ? MAP::Type::priv : MAP::Type::shared,
|
||||||
|
.fixed = 0,
|
||||||
.anonymous = map.anonymous,
|
.anonymous = map.anonymous,
|
||||||
|
.bit32 = 0,
|
||||||
|
._0 = 0,
|
||||||
|
.grows_down = 0,
|
||||||
|
._1 = 0,
|
||||||
|
.deny_write = 0,
|
||||||
|
.executable = 0,
|
||||||
|
.locked = 0,
|
||||||
.no_reserve = map.no_reserve,
|
.no_reserve = map.no_reserve,
|
||||||
.populate = map.populate,
|
.populate = map.populate,
|
||||||
|
.non_block = 0,
|
||||||
|
.stack = 0,
|
||||||
|
.huge_tlb = 0,
|
||||||
|
.sync = 0,
|
||||||
|
.fixed_no_replace = 0,
|
||||||
|
._2 = 0,
|
||||||
|
.uninitialized = 0,
|
||||||
|
._3 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* address = mmap(base, size, protection_flags, map_flags, -1, 0);
|
auto* address = mmap(base, size, protection_flags, map_flags, -1, 0);
|
||||||
@ -323,6 +342,8 @@ fn void os_commit(void* address, u64 size, ProtectionFlags protection)
|
|||||||
.read = protection.read,
|
.read = protection.read,
|
||||||
.write = protection.write,
|
.write = protection.write,
|
||||||
.execute = protection.execute,
|
.execute = protection.execute,
|
||||||
|
.sem = 0,
|
||||||
|
._ = 0,
|
||||||
};
|
};
|
||||||
auto result = mprotect(address, size, protection_flags);
|
auto result = mprotect(address, size, protection_flags);
|
||||||
assert(!result);
|
assert(!result);
|
||||||
@ -616,7 +637,7 @@ fn String file_read(Arena* arena, String file_path)
|
|||||||
{
|
{
|
||||||
if (os_is_debugger_present())
|
if (os_is_debugger_present())
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -639,3 +660,39 @@ fn u64 next_power_of_two(u64 n)
|
|||||||
n += 1;
|
n += 1;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn u8 format_integer_decimal(String buffer, u64 v)
|
||||||
|
{
|
||||||
|
u8 byte_count = 0;
|
||||||
|
auto value = v;
|
||||||
|
|
||||||
|
if (value != 0)
|
||||||
|
{
|
||||||
|
u8 reverse_buffer[64];
|
||||||
|
u8 reverse_index = 0;
|
||||||
|
|
||||||
|
while (value != 0)
|
||||||
|
{
|
||||||
|
auto digit_value = (u8)(value % 10);
|
||||||
|
auto ascii_character = digit_value + '0';
|
||||||
|
value /= 10;
|
||||||
|
reverse_buffer[reverse_index] = ascii_character;
|
||||||
|
reverse_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (reverse_index != 0)
|
||||||
|
{
|
||||||
|
reverse_index -= 1;
|
||||||
|
buffer[byte_count] = reverse_buffer[reverse_index];
|
||||||
|
byte_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer[0] = '0';
|
||||||
|
byte_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
912
src/llvm.cpp
912
src/llvm.cpp
File diff suppressed because it is too large
Load Diff
340
src/llvm.h
340
src/llvm.h
@ -1,46 +1,318 @@
|
|||||||
#include <lib.h>
|
#pragma once
|
||||||
|
|
||||||
namespace llvm
|
#include <lib.h>
|
||||||
|
#include <llvm-c/Core.h>
|
||||||
|
#include <llvm-c/Analysis.h>
|
||||||
|
#include <llvm-c/Target.h>
|
||||||
|
#include <llvm-c/Analysis.h>
|
||||||
|
#include <llvm-c/DebugInfo.h>
|
||||||
|
|
||||||
|
enum class BBLLVMUWTableKind : u64
|
||||||
{
|
{
|
||||||
class Type;
|
None = 0, ///< No unwind table requested
|
||||||
class Value;
|
Sync = 1, ///< "Synchronous" unwind tables
|
||||||
}
|
Async = 2, ///< "Asynchronous" unwind tables (instr precise)
|
||||||
|
Default = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BBLLVMFramePointerKind : u64
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
reserved = 1,
|
||||||
|
non_leaf = 2,
|
||||||
|
all = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ZeroCallUsedRegsKind : u64
|
||||||
|
{
|
||||||
|
all = 0,
|
||||||
|
skip = 1 << 0,
|
||||||
|
only_used = 1 << 1,
|
||||||
|
only_gpr = 1 << 2,
|
||||||
|
only_arg = 1 << 3,
|
||||||
|
used_gpr_arg = only_used | only_gpr | only_arg,
|
||||||
|
used_gpr = only_used | only_gpr,
|
||||||
|
used_arg = only_used | only_arg,
|
||||||
|
used = only_used,
|
||||||
|
all_gpr_arg = only_gpr | only_arg,
|
||||||
|
all_gpr = only_gpr,
|
||||||
|
all_arg = only_arg,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BBLLVMFunctionAttributesFlags0
|
||||||
|
{
|
||||||
|
u64 noreturn:1;
|
||||||
|
u64 cmse_ns_call:1;
|
||||||
|
u64 nounwind:1;
|
||||||
|
u64 returns_twice:1;
|
||||||
|
u64 cold:1;
|
||||||
|
u64 hot:1;
|
||||||
|
u64 no_duplicate:1;
|
||||||
|
u64 convergent:1;
|
||||||
|
u64 no_merge:1;
|
||||||
|
u64 will_return:1;
|
||||||
|
u64 no_caller_saved_registers:1;
|
||||||
|
u64 no_cf_check:1;
|
||||||
|
u64 no_callback:1;
|
||||||
|
u64 alloc_size:1;
|
||||||
|
u64 uniform_work_group_size:1;
|
||||||
|
u64 aarch64_pstate_sm_body:1;
|
||||||
|
u64 aarch64_pstate_sm_enabled:1;
|
||||||
|
u64 aarch64_pstate_sm_compatible:1;
|
||||||
|
u64 aarch64_preserves_za:1;
|
||||||
|
u64 aarch64_in_za:1;
|
||||||
|
u64 aarch64_out_za:1;
|
||||||
|
u64 aarch64_inout_za:1;
|
||||||
|
u64 aarch64_preserves_zt0:1;
|
||||||
|
u64 aarch64_in_zt0:1;
|
||||||
|
u64 aarch64_out_zt0:1;
|
||||||
|
u64 aarch64_inout_zt0:1;
|
||||||
|
u64 optimize_for_size:1;
|
||||||
|
u64 min_size:1;
|
||||||
|
u64 no_red_zone:1;
|
||||||
|
u64 indirect_tls_seg_refs:1;
|
||||||
|
u64 no_implicit_floats:1;
|
||||||
|
u64 sample_profile_suffix_elision_policy:1;
|
||||||
|
u64 memory_none:1;
|
||||||
|
u64 memory_readonly:1;
|
||||||
|
u64 memory_inaccessible_or_arg_memory_only:1;
|
||||||
|
u64 memory_arg_memory_only:1;
|
||||||
|
u64 strict_fp:1;
|
||||||
|
u64 no_inline:1;
|
||||||
|
u64 always_inline:1;
|
||||||
|
u64 guard_no_cf:1;
|
||||||
|
|
||||||
|
// TODO: branch protection function attributes
|
||||||
|
// TODO: cpu features
|
||||||
|
|
||||||
|
// Call-site begin
|
||||||
|
u64 call_no_builtins:1;
|
||||||
|
|
||||||
|
BBLLVMFramePointerKind definition_frame_pointer_kind:2;
|
||||||
|
u64 definition_less_precise_fpmad:1;
|
||||||
|
u64 definition_null_pointer_is_valid:1;
|
||||||
|
u64 definition_no_trapping_fp_math:1;
|
||||||
|
u64 definition_no_infs_fp_math:1;
|
||||||
|
u64 definition_no_nans_fp_math:1;
|
||||||
|
u64 definition_approx_func_fp_math:1;
|
||||||
|
u64 definition_unsafe_fp_math:1;
|
||||||
|
u64 definition_use_soft_float:1;
|
||||||
|
u64 definition_no_signed_zeroes_fp_math:1;
|
||||||
|
u64 definition_stack_realignment:1;
|
||||||
|
u64 definition_backchain:1;
|
||||||
|
u64 definition_split_stack:1;
|
||||||
|
u64 definition_speculative_load_hardening:1;
|
||||||
|
ZeroCallUsedRegsKind definition_zero_call_used_registers:4;
|
||||||
|
// TODO: denormal builtins
|
||||||
|
u64 definition_non_lazy_bind:1;
|
||||||
|
u64 definition_cmse_nonsecure_entry:1;
|
||||||
|
BBLLVMUWTableKind definition_unwind_table_kind:2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(BBLLVMFunctionAttributesFlags0) == sizeof(u64));
|
||||||
|
|
||||||
|
struct BBLLVMFunctionAttributesFlags1
|
||||||
|
{
|
||||||
|
u64 definition_disable_tail_calls:1;
|
||||||
|
u64 definition_stack_protect_strong:1;
|
||||||
|
u64 definition_stack_protect:1;
|
||||||
|
u64 definition_stack_protect_req:1;
|
||||||
|
u64 definition_aarch64_new_za:1;
|
||||||
|
u64 definition_aarch64_new_zt0:1;
|
||||||
|
u64 definition_optimize_none:1;
|
||||||
|
u64 definition_naked:1;
|
||||||
|
u64 definition_inline_hint:1;
|
||||||
|
u64 _:55;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(BBLLVMFunctionAttributesFlags1) == sizeof(u64));
|
||||||
|
|
||||||
|
struct BBLLVMFunctionAttributes
|
||||||
|
{
|
||||||
|
String prefer_vector_width;
|
||||||
|
String stack_protector_buffer_size;
|
||||||
|
String definition_probe_stack;
|
||||||
|
String definition_stack_probe_size;
|
||||||
|
|
||||||
|
BBLLVMFunctionAttributesFlags0 flags0;
|
||||||
|
BBLLVMFunctionAttributesFlags1 flags1;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(BBLLVMFunctionAttributes) == 10 * sizeof(u64));
|
||||||
|
|
||||||
|
struct BBLLVMArgumentAttributes
|
||||||
|
{
|
||||||
|
LLVMTypeRef semantic_type;
|
||||||
|
LLVMTypeRef abi_type;
|
||||||
|
u64 dereferenceable_bytes;
|
||||||
|
u32 alignment;
|
||||||
|
u32 no_alias:1;
|
||||||
|
u32 non_null:1;
|
||||||
|
u32 no_undef:1;
|
||||||
|
u32 sign_extend:1;
|
||||||
|
u32 zero_extend:1;
|
||||||
|
u32 in_reg:1;
|
||||||
|
u32 no_fp_class:10;
|
||||||
|
u32 struct_return:1;
|
||||||
|
u32 writable:1;
|
||||||
|
u32 dead_on_unwind:1;
|
||||||
|
u32 in_alloca:1;
|
||||||
|
u32 dereferenceable:1;
|
||||||
|
u32 dereferenceable_or_null:1;
|
||||||
|
u32 nest:1;
|
||||||
|
u32 by_value:1;
|
||||||
|
u32 by_reference:1;
|
||||||
|
u32 no_capture:1;
|
||||||
|
u32 _:6;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(BBLLVMArgumentAttributes) == 2 * sizeof(LLVMTypeRef) + 2 * sizeof(u64));
|
||||||
|
|
||||||
|
struct BBLLVMAttributeListOptions
|
||||||
|
{
|
||||||
|
BBLLVMFunctionAttributes function;
|
||||||
|
BBLLVMArgumentAttributes return_;
|
||||||
|
BBLLVMArgumentAttributes* argument_pointer;
|
||||||
|
u64 argument_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(BBLLVMAttributeListOptions) == sizeof(BBLLVMFunctionAttributes) + sizeof(BBLLVMArgumentAttributes) + sizeof(void*) + sizeof(u64));
|
||||||
|
|
||||||
|
typedef void* BBLLVMAttributeList;
|
||||||
|
|
||||||
|
enum class DwarfEmissionKind
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
full,
|
||||||
|
line_tables_only,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DwarfType
|
||||||
|
{
|
||||||
|
void_type = 0x0,
|
||||||
|
address = 0x1,
|
||||||
|
boolean = 0x2,
|
||||||
|
complex_float = 0x3,
|
||||||
|
float_type = 0x4,
|
||||||
|
signed_type = 0x5,
|
||||||
|
signed_char = 0x6,
|
||||||
|
unsigned_type = 0x7,
|
||||||
|
unsigned_char = 0x8,
|
||||||
|
|
||||||
|
// DWARF 3.
|
||||||
|
imaginary_float = 0x9,
|
||||||
|
packed_decimal = 0xa,
|
||||||
|
numeric_string = 0xb,
|
||||||
|
edited = 0xc,
|
||||||
|
signed_fixed = 0xd,
|
||||||
|
unsigned_fixed = 0xe,
|
||||||
|
decimal_float = 0xf,
|
||||||
|
|
||||||
|
// DWARF 4.
|
||||||
|
UTF = 0x10,
|
||||||
|
|
||||||
|
// DWARF 5.
|
||||||
|
UCS = 0x11,
|
||||||
|
ASCII = 0x12,
|
||||||
|
|
||||||
|
// HP extensions.
|
||||||
|
HP_float80 = 0x80, // Floating-point (80 bit).
|
||||||
|
HP_complex_float80 = 0x81, // Complex floating-point (80 bit).
|
||||||
|
HP_float128 = 0x82, // Floating-point (128 bit).
|
||||||
|
HP_complex_float128 = 0x83, // Complex fp (128 bit).
|
||||||
|
HP_floathpintel = 0x84, // Floating-point (82 bit IA64).
|
||||||
|
HP_imaginary_float80 = 0x85,
|
||||||
|
HP_imaginary_float128 = 0x86,
|
||||||
|
HP_VAX_float = 0x88, // F or G floating.
|
||||||
|
HP_VAX_float_d = 0x89, // D floating.
|
||||||
|
HP_packed_decimal = 0x8a, // Cobol.
|
||||||
|
HP_zoned_decimal = 0x8b, // Cobol.
|
||||||
|
HP_edited = 0x8c, // Cobol.
|
||||||
|
HP_signed_fixed = 0x8d, // Cobol.
|
||||||
|
HP_unsigned_fixed = 0x8e, // Cobol.
|
||||||
|
HP_VAX_complex_float = 0x8f, // F or G floating complex.
|
||||||
|
HP_VAX_complex_float_d = 0x90, // D floating complex.
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DIFlagsVisibility : u32
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
private_ = 1,
|
||||||
|
protected_ = 2,
|
||||||
|
public_ = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DIFlagsInheritance : u32
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
single_ = 1,
|
||||||
|
multiple_ = 2,
|
||||||
|
virtual_ = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DIFlags
|
||||||
|
{
|
||||||
|
DIFlagsVisibility visibility:2;
|
||||||
|
u32 forward_declaration:1;
|
||||||
|
u32 apple_block:1;
|
||||||
|
u32 block_by_ref_struct:1;
|
||||||
|
u32 virtual_:1;
|
||||||
|
u32 artificial:1;
|
||||||
|
u32 explicit_:1;
|
||||||
|
u32 prototyped:1;
|
||||||
|
u32 objective_c_class_complete:1;
|
||||||
|
u32 object_pointer:1;
|
||||||
|
u32 vector:1;
|
||||||
|
u32 static_member:1;
|
||||||
|
u32 lvalue_reference:1;
|
||||||
|
u32 rvalue_reference:1;
|
||||||
|
u32 reserved:1;
|
||||||
|
DIFlagsInheritance inheritance:2;
|
||||||
|
u32 introduced_virtual:1;
|
||||||
|
u32 bit_field:1;
|
||||||
|
u32 no_return:1;
|
||||||
|
u32 type_pass_by_value:1;
|
||||||
|
u32 type_pass_by_reference:1;
|
||||||
|
u32 enum_class:1;
|
||||||
|
u32 thunk:1;
|
||||||
|
u32 non_trivial:1;
|
||||||
|
u32 big_endian:1;
|
||||||
|
u32 little_endian:1;
|
||||||
|
u32 all_calls_described:1;
|
||||||
|
u32 _:3;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(DIFlags) == sizeof(u32));
|
||||||
|
|
||||||
|
|
||||||
fn bool llvm_initialized = false;
|
fn bool llvm_initialized = false;
|
||||||
|
|
||||||
extern "C" void LLVMInitializeX86TargetInfo();
|
|
||||||
extern "C" void LLVMInitializeX86Target();
|
|
||||||
extern "C" void LLVMInitializeX86TargetMC();
|
|
||||||
extern "C" void LLVMInitializeX86AsmPrinter();
|
|
||||||
extern "C" void LLVMInitializeX86AsmParser();
|
|
||||||
extern "C" void LLVMInitializeX86Disassembler();
|
|
||||||
|
|
||||||
extern "C" String llvm_default_target_triple();
|
extern "C" String llvm_default_target_triple();
|
||||||
extern "C" String llvm_host_cpu_name();
|
extern "C" String llvm_host_cpu_name();
|
||||||
extern "C" String llvm_host_cpu_features();
|
extern "C" String llvm_host_cpu_features();
|
||||||
|
|
||||||
struct LLVMGlobal
|
extern "C" LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name);
|
||||||
{
|
|
||||||
String host_triple;
|
|
||||||
String host_cpu_model;
|
|
||||||
String host_cpu_features;
|
|
||||||
};
|
|
||||||
|
|
||||||
global_variable LLVMGlobal llvm_global;
|
extern "C" LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name);
|
||||||
|
extern "C" void llvm_function_set_attributes(LLVMValueRef function, BBLLVMAttributeList attribute_list);
|
||||||
|
|
||||||
fn void initialize_all()
|
extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function);
|
||||||
{
|
|
||||||
assert(!llvm_initialized);
|
extern "C" LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMValueRef before, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized);
|
||||||
LLVMInitializeX86TargetInfo();
|
|
||||||
LLVMInitializeX86Target();
|
extern "C" LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef builder, LLVMTypeRef type, unsigned address_space, u32 alignment, String name);
|
||||||
LLVMInitializeX86TargetMC();
|
extern "C" bool llvm_value_has_one_use(LLVMValueRef value);
|
||||||
LLVMInitializeX86AsmPrinter();
|
extern "C" LLVMValueRef llvm_basic_block_user_begin(LLVMBasicBlockRef basic_block);
|
||||||
LLVMInitializeX86AsmParser();
|
extern "C" void llvm_basic_block_delete(LLVMBasicBlockRef basic_block);
|
||||||
LLVMInitializeX86Disassembler();
|
extern "C" bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block);
|
||||||
|
extern "C" void llvm_function_set_attributes(LLVMValueRef f, BBLLVMAttributeList attribute_list_handle);
|
||||||
|
extern "C" void llvm_call_base_set_attributes(LLVMValueRef call_value, BBLLVMAttributeList attribute_list_handle);
|
||||||
|
|
||||||
|
extern "C" BBLLVMAttributeList llvm_attribute_list_build(LLVMContextRef context, BBLLVMAttributeListOptions* attributes, bool call_site);
|
||||||
|
extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LLVMValueRef ra, LLVMTypeRef et);
|
||||||
|
extern "C" bool llvm_value_use_empty(LLVMValueRef value);
|
||||||
|
extern "C" bool llvm_function_verify(LLVMValueRef function_value, String* error_message);
|
||||||
|
extern "C" bool llvm_module_verify(LLVMModuleRef m, String* error_message);
|
||||||
|
|
||||||
|
extern "C" String llvm_module_to_string(LLVMModuleRef module);
|
||||||
|
|
||||||
llvm_global = {
|
|
||||||
.host_triple = llvm_default_target_triple(),
|
|
||||||
.host_cpu_model = llvm_host_cpu_name(),
|
|
||||||
.host_cpu_features = llvm_host_cpu_features(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
156
src/parser.cpp
156
src/parser.cpp
@ -309,22 +309,22 @@ fn bool is_hexadecimal_alpha_upper(u8 ch)
|
|||||||
|
|
||||||
fn bool is_hexadecimal_alpha(u8 ch)
|
fn bool is_hexadecimal_alpha(u8 ch)
|
||||||
{
|
{
|
||||||
return is_hexadecimal_alpha_lower(ch) | is_hexadecimal_alpha_upper(ch);
|
return is_hexadecimal_alpha_lower(ch) || is_hexadecimal_alpha_upper(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool is_hexadecimal(u8 ch)
|
fn bool is_hexadecimal(u8 ch)
|
||||||
{
|
{
|
||||||
return is_decimal(ch) | is_hexadecimal_alpha(ch);
|
return is_decimal(ch) || is_hexadecimal_alpha(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool is_identifier_start(u8 ch)
|
fn bool is_identifier_start(u8 ch)
|
||||||
{
|
{
|
||||||
return (is_lower(ch) | is_upper(ch)) | (ch == '_');
|
return (is_lower(ch) || is_upper(ch)) || (ch == '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool is_identifier(u8 ch)
|
fn bool is_identifier(u8 ch)
|
||||||
{
|
{
|
||||||
return is_identifier_start(ch) | is_decimal(ch);
|
return is_identifier_start(ch) || is_decimal(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn u32 get_line(Module* module)
|
fn u32 get_line(Module* module)
|
||||||
@ -530,64 +530,6 @@ fn u64 parse_integer_decimal_assume_valid(String string)
|
|||||||
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
|
fn Value* parse_value(Module* module, Scope* scope, ValueBuilder builder);
|
||||||
|
|
||||||
|
|
||||||
fn u8 format_integer_decimal(String buffer, u64 v)
|
|
||||||
{
|
|
||||||
u8 byte_count = 0;
|
|
||||||
auto value = v;
|
|
||||||
|
|
||||||
if (value != 0)
|
|
||||||
{
|
|
||||||
u8 reverse_buffer[64];
|
|
||||||
u8 reverse_index = 0;
|
|
||||||
|
|
||||||
while (value != 0)
|
|
||||||
{
|
|
||||||
auto digit_value = (u8)(value % 10);
|
|
||||||
auto ascii_character = digit_value + '0';
|
|
||||||
value /= 10;
|
|
||||||
reverse_buffer[reverse_index] = ascii_character;
|
|
||||||
reverse_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (reverse_index != 0)
|
|
||||||
{
|
|
||||||
reverse_index -= 1;
|
|
||||||
buffer[byte_count] = reverse_buffer[reverse_index];
|
|
||||||
byte_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[0] = '0';
|
|
||||||
byte_count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return byte_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn String array_name(Module* module, Type* element_type, u64 element_count)
|
|
||||||
{
|
|
||||||
u8 buffer[512];
|
|
||||||
auto buffer_slice = String{ .pointer = buffer, .length = array_length(buffer) };
|
|
||||||
|
|
||||||
u64 i = 0;
|
|
||||||
|
|
||||||
buffer[i] = left_bracket;
|
|
||||||
i += 1;
|
|
||||||
|
|
||||||
i += format_integer_decimal(buffer_slice(i), element_count);
|
|
||||||
|
|
||||||
buffer[i] = right_bracket;
|
|
||||||
i += 1;
|
|
||||||
|
|
||||||
auto element_name = element_type->name;
|
|
||||||
memcpy(buffer + i, element_name.pointer, element_name.length);
|
|
||||||
i += element_name.length;
|
|
||||||
|
|
||||||
auto name = arena_duplicate_string(module->arena, buffer_slice(0, i));
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn Type* parse_type(Module* module, Scope* scope)
|
fn Type* parse_type(Module* module, Scope* scope)
|
||||||
{
|
{
|
||||||
auto start_character = module->content[module->offset];
|
auto start_character = module->content[module->offset];
|
||||||
@ -729,8 +671,8 @@ fn Type* parse_type(Module* module, Scope* scope)
|
|||||||
assert(!length_value);
|
assert(!length_value);
|
||||||
auto result = type_allocate_init(module, {
|
auto result = type_allocate_init(module, {
|
||||||
.array = {
|
.array = {
|
||||||
.element_count = 0,
|
|
||||||
.element_type = element_type,
|
.element_type = element_type,
|
||||||
|
.element_count = 0,
|
||||||
},
|
},
|
||||||
.id = TypeId::array,
|
.id = TypeId::array,
|
||||||
.name = string_literal(""),
|
.name = string_literal(""),
|
||||||
@ -747,15 +689,8 @@ fn Type* parse_type(Module* module, Scope* scope)
|
|||||||
|
|
||||||
assert(element_count != 0);
|
assert(element_count != 0);
|
||||||
|
|
||||||
auto result = type_allocate_init(module, {
|
auto array_type = get_array_type(module, element_type, element_count);
|
||||||
.array = {
|
return array_type;
|
||||||
.element_count = element_count,
|
|
||||||
.element_type = element_type,
|
|
||||||
},
|
|
||||||
.id = TypeId::array,
|
|
||||||
.name = array_name(module, element_type, element_count),
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,7 +821,7 @@ fn u8 escape_character(u8 ch)
|
|||||||
{
|
{
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
default: trap_raw();
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -984,7 +919,7 @@ fn Token tokenize(Module* module)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case '<':
|
case '<':
|
||||||
@ -1100,12 +1035,11 @@ fn Token tokenize(Module* module)
|
|||||||
auto ch = module->content[module->offset];
|
auto ch = module->content[module->offset];
|
||||||
if (ch == '"')
|
if (ch == '"')
|
||||||
{
|
{
|
||||||
module->offset += 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ch == '\\')
|
else if (ch == '\\')
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1114,6 +1048,7 @@ fn Token tokenize(Module* module)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto end = module->offset;
|
auto end = module->offset;
|
||||||
|
module->offset += 1;
|
||||||
auto string_literal = module->content(start, end);
|
auto string_literal = module->content(start, end);
|
||||||
|
|
||||||
token = {
|
token = {
|
||||||
@ -1369,7 +1304,7 @@ fn Value* reference_identifier(Module* module, Scope* current_scope, String iden
|
|||||||
{
|
{
|
||||||
assert(scope->parent);
|
assert(scope->parent);
|
||||||
auto function = scope_to_function(scope);
|
auto function = scope_to_function(scope);
|
||||||
for (auto argument: function->arguments)
|
for (auto& argument: function->arguments)
|
||||||
{
|
{
|
||||||
if (identifier.equal(argument.variable.name))
|
if (identifier.equal(argument.variable.name))
|
||||||
{
|
{
|
||||||
@ -1416,7 +1351,7 @@ fn Value* reference_identifier(Module* module, Scope* current_scope, String iden
|
|||||||
{
|
{
|
||||||
if (identifier.equal(constant_argument.name))
|
if (identifier.equal(constant_argument.name))
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1431,7 +1366,7 @@ fn Value* reference_identifier(Module* module, Scope* current_scope, String iden
|
|||||||
} break;
|
} break;
|
||||||
case ScopeKind::macro_instantiation:
|
case ScopeKind::macro_instantiation:
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1520,7 +1455,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
{
|
{
|
||||||
case ValueIntrinsic::align_of:
|
case ValueIntrinsic::align_of:
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
} break;
|
} break;
|
||||||
case ValueIntrinsic::enum_name:
|
case ValueIntrinsic::enum_name:
|
||||||
case ValueIntrinsic::extend:
|
case ValueIntrinsic::extend:
|
||||||
@ -1679,7 +1614,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
} break;
|
} break;
|
||||||
case ValueIntrinsic::va_copy:
|
case ValueIntrinsic::va_copy:
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
} break;
|
} break;
|
||||||
case ValueIntrinsic::count: unreachable();
|
case ValueIntrinsic::count: unreachable();
|
||||||
}
|
}
|
||||||
@ -1895,7 +1830,7 @@ fn Precedence get_token_precedence(TokenId id)
|
|||||||
case TokenId::dot:
|
case TokenId::dot:
|
||||||
precedence = Precedence::postfix;
|
precedence = Precedence::postfix;
|
||||||
break;
|
break;
|
||||||
default: trap_raw();
|
default: trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
return precedence;
|
return precedence;
|
||||||
@ -2018,8 +1953,11 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
{
|
{
|
||||||
result = new_value(module);
|
result = new_value(module);
|
||||||
*result = {
|
*result = {
|
||||||
.dereference = left,
|
.unary = {
|
||||||
.id = ValueId::dereference,
|
.value = left,
|
||||||
|
.id = UnaryId::dereference,
|
||||||
|
},
|
||||||
|
.id = ValueId::unary,
|
||||||
.kind = ValueKind::right,
|
.kind = ValueKind::right,
|
||||||
};
|
};
|
||||||
} break;
|
} break;
|
||||||
@ -2116,7 +2054,7 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
{
|
{
|
||||||
case ConstantArgumentId::value:
|
case ConstantArgumentId::value:
|
||||||
{
|
{
|
||||||
trap_raw(); // TODO
|
trap(); // TODO
|
||||||
} break;
|
} break;
|
||||||
case ConstantArgumentId::type:
|
case ConstantArgumentId::type:
|
||||||
{
|
{
|
||||||
@ -2208,6 +2146,7 @@ fn Value* parse_right(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
.start = start_value,
|
.start = start_value,
|
||||||
.end = end_value,
|
.end = end_value,
|
||||||
},
|
},
|
||||||
|
.id = ValueId::slice_expression,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2394,7 +2333,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
|||||||
{
|
{
|
||||||
case StatementStartKeyword::underscore_st:
|
case StatementStartKeyword::underscore_st:
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
} break;
|
} break;
|
||||||
case StatementStartKeyword::return_st:
|
case StatementStartKeyword::return_st:
|
||||||
{
|
{
|
||||||
@ -2462,7 +2401,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
|||||||
.right_values = {},
|
.right_values = {},
|
||||||
.predicate = 0,
|
.predicate = 0,
|
||||||
.scope = {
|
.scope = {
|
||||||
.parent = scope,
|
.parent = parent_scope,
|
||||||
.line = statement_line,
|
.line = statement_line,
|
||||||
.column = statement_column,
|
.column = statement_column,
|
||||||
.kind = ScopeKind::for_each,
|
.kind = ScopeKind::for_each,
|
||||||
@ -2511,7 +2450,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
@ -2741,7 +2680,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
|||||||
case TokenId::assign_ampersand: id = StatementAssignmentId::assign_and; break;
|
case TokenId::assign_ampersand: id = StatementAssignmentId::assign_and; break;
|
||||||
case TokenId::assign_bar: id = StatementAssignmentId::assign_or; break;
|
case TokenId::assign_bar: id = StatementAssignmentId::assign_or; break;
|
||||||
case TokenId::assign_caret: id = StatementAssignmentId::assign_xor; break;
|
case TokenId::assign_caret: id = StatementAssignmentId::assign_xor; break;
|
||||||
default: trap_raw();
|
default: trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
@ -2759,7 +2698,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -2804,6 +2743,10 @@ fn Block* parse_block(Module* module, Scope* parent_scope)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* statement = parse_statement(module, scope);
|
auto* statement = parse_statement(module, scope);
|
||||||
|
if (!block->first_statement)
|
||||||
|
{
|
||||||
|
block->first_statement = statement;
|
||||||
|
}
|
||||||
|
|
||||||
if (current_statement)
|
if (current_statement)
|
||||||
{
|
{
|
||||||
@ -2951,8 +2894,6 @@ void parse(Module* module)
|
|||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
|
|
||||||
bool is_global_keyword = false;
|
|
||||||
|
|
||||||
enum class GlobalKeyword
|
enum class GlobalKeyword
|
||||||
{
|
{
|
||||||
bits,
|
bits,
|
||||||
@ -3099,16 +3040,13 @@ void parse(Module* module)
|
|||||||
skip_space(module);
|
skip_space(module);
|
||||||
expect_character(module, left_brace);
|
expect_character(module, left_brace);
|
||||||
|
|
||||||
u64 highest_value = 0;
|
|
||||||
u64 lowest_value = ~(u64)0;
|
|
||||||
|
|
||||||
u64 field_count = 0;
|
u64 field_count = 0;
|
||||||
String name_buffer[64];
|
String name_buffer[64];
|
||||||
Value* value_buffer[64];
|
|
||||||
u64 int_value_buffer[64];
|
u64 int_value_buffer[64];
|
||||||
|
|
||||||
bool is_resolved = true;
|
bool is_resolved = true;
|
||||||
bool implicit_value = false;
|
bool implicit_value = false;
|
||||||
|
unused(implicit_value);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -3122,11 +3060,11 @@ void parse(Module* module)
|
|||||||
field_count += 1;
|
field_count += 1;
|
||||||
|
|
||||||
auto field_name = parse_identifier(module);
|
auto field_name = parse_identifier(module);
|
||||||
|
name_buffer[field_index] = field_name;
|
||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
|
|
||||||
u64 field_integer_value = field_index;
|
u64 field_integer_value = field_index;
|
||||||
Value* field_value = 0;
|
|
||||||
|
|
||||||
if (consume_character_if_match(module, '='))
|
if (consume_character_if_match(module, '='))
|
||||||
{
|
{
|
||||||
@ -3142,17 +3080,17 @@ void parse(Module* module)
|
|||||||
{
|
{
|
||||||
field_integer_value = field_value->constant_integer.value;
|
field_integer_value = field_value->constant_integer.value;
|
||||||
} break;
|
} break;
|
||||||
default: trap_raw();
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3163,6 +3101,8 @@ void parse(Module* module)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int_value_buffer[i] = field_integer_value;
|
||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
consume_character_if_match(module, ',');
|
consume_character_if_match(module, ',');
|
||||||
}
|
}
|
||||||
@ -3171,7 +3111,7 @@ void parse(Module* module)
|
|||||||
{
|
{
|
||||||
auto fields = arena_allocate<EnumField>(module->arena, field_count);
|
auto fields = arena_allocate<EnumField>(module->arena, field_count);
|
||||||
u64 highest_value = 0;
|
u64 highest_value = 0;
|
||||||
auto lowest_value = ~(u64)0;
|
// auto lowest_value = ~(u64)0;
|
||||||
|
|
||||||
for (u64 i = 0; i < field_count; i += 1)
|
for (u64 i = 0; i < field_count; i += 1)
|
||||||
{
|
{
|
||||||
@ -3204,7 +3144,7 @@ void parse(Module* module)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case GlobalKeyword::function:
|
case GlobalKeyword::function:
|
||||||
@ -3412,7 +3352,7 @@ void parse(Module* module)
|
|||||||
.line = line,
|
.line = line,
|
||||||
.column = 0,
|
.column = 0,
|
||||||
},
|
},
|
||||||
.index = i,
|
.index = i + 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3436,6 +3376,8 @@ void parse(Module* module)
|
|||||||
{
|
{
|
||||||
Type* type_argument_buffer[64];
|
Type* type_argument_buffer[64];
|
||||||
u64 type_argument_count = 0;
|
u64 type_argument_count = 0;
|
||||||
|
unused(type_argument_buffer);
|
||||||
|
unused(type_argument_count);
|
||||||
|
|
||||||
ConstantArgument constant_argument_buffer[64];
|
ConstantArgument constant_argument_buffer[64];
|
||||||
u64 constant_argument_count = 0;
|
u64 constant_argument_count = 0;
|
||||||
@ -3463,7 +3405,7 @@ void parse(Module* module)
|
|||||||
|
|
||||||
if (has_value)
|
if (has_value)
|
||||||
{
|
{
|
||||||
trap_raw(); // TODO
|
trap(); // TODO
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3520,7 +3462,7 @@ void parse(Module* module)
|
|||||||
if (module->last_macro_declaration)
|
if (module->last_macro_declaration)
|
||||||
{
|
{
|
||||||
assert(module->first_macro_declaration);
|
assert(module->first_macro_declaration);
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3568,7 +3510,7 @@ void parse(Module* module)
|
|||||||
.line = argument_line,
|
.line = argument_line,
|
||||||
.column = argument_column,
|
.column = argument_column,
|
||||||
},
|
},
|
||||||
.index = argument_index,
|
.index = argument_index + 1,
|
||||||
};
|
};
|
||||||
argument_count += 1;
|
argument_count += 1;
|
||||||
|
|
||||||
@ -3601,7 +3543,7 @@ void parse(Module* module)
|
|||||||
Type* struct_type;
|
Type* struct_type;
|
||||||
if (forward_declaration)
|
if (forward_declaration)
|
||||||
{
|
{
|
||||||
trap_raw();
|
trap();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
16
tests/basic_bool_call.bbb
Normal file
16
tests/basic_bool_call.bbb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
require = fn (ok: u1) void
|
||||||
|
{
|
||||||
|
if (!ok) #trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
bb_bool = fn (x: u8) void
|
||||||
|
{
|
||||||
|
require(#truncate(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
bb_bool(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user