Pass some basic tests
All checks were successful
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 1m2s
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 1m8s
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 1m7s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 6m0s
CI / ci (Release, ubuntu-latest) (push) Successful in 1m3s
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 1m8s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 1m7s
CI / ci (Debug, ubuntu-latest) (push) Successful in 6m0s
All checks were successful
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 1m2s
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 1m8s
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 1m7s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 6m0s
CI / ci (Release, ubuntu-latest) (push) Successful in 1m3s
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 1m8s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 1m7s
CI / ci (Debug, ubuntu-latest) (push) Successful in 6m0s
This commit is contained in:
parent
04ca049e6c
commit
0a506b2e01
@ -48,6 +48,6 @@ target_link_libraries(llvm_bindings PUBLIC
|
||||
|
||||
target_link_libraries(bb PUBLIC llvm_bindings)
|
||||
|
||||
add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -funsigned-char -fwrapv -fno-strict-aliasing)
|
||||
add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -fno-signed-char -fwrapv -fno-strict-aliasing)
|
||||
add_compile_definitions(CMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}")
|
||||
add_compile_definitions(BB_CI=${BB_CI})
|
||||
|
5225
src/compiler.bbb
5225
src/compiler.bbb
File diff suppressed because it is too large
Load Diff
@ -440,6 +440,8 @@ global_variable String names[] =
|
||||
string_literal("bool_pair"),
|
||||
string_literal("min_max"),
|
||||
string_literal("field_parent_pointer"),
|
||||
string_literal("leading_trailing_zeroes"),
|
||||
string_literal("pointer_sub"),
|
||||
};
|
||||
|
||||
void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
|
||||
@ -612,7 +614,7 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
|
||||
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
|
||||
if (!success)
|
||||
{
|
||||
print(string_literal("Self-hosted tests failed to compile: "));
|
||||
print(string_literal("Self-hosted tests failed: "));
|
||||
print(build_mode_to_string(compiler_build_mode));
|
||||
print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n"));
|
||||
bb_fail();
|
||||
|
@ -872,7 +872,6 @@ enum class UnaryId
|
||||
plus,
|
||||
ampersand,
|
||||
exclamation,
|
||||
tilde,
|
||||
enum_name,
|
||||
extend,
|
||||
truncate,
|
||||
@ -884,6 +883,8 @@ enum class UnaryId
|
||||
dereference,
|
||||
pointer_from_int,
|
||||
enum_from_int,
|
||||
leading_zeroes,
|
||||
trailing_zeroes,
|
||||
};
|
||||
|
||||
struct ValueUnary
|
||||
@ -1105,7 +1106,9 @@ struct Value
|
||||
case ValueId::zero:
|
||||
return true;
|
||||
case ValueId::unary:
|
||||
return unary.value->is_constant();
|
||||
case ValueId::binary:
|
||||
return binary.left->is_constant() && binary.right->is_constant();
|
||||
case ValueId::field_access:
|
||||
case ValueId::array_expression:
|
||||
case ValueId::call:
|
||||
@ -1197,6 +1200,8 @@ struct LLVMIntrinsicId
|
||||
|
||||
enum class IntrinsicIndex
|
||||
{
|
||||
clz,
|
||||
ctz,
|
||||
smax,
|
||||
smin,
|
||||
trap,
|
||||
@ -1209,6 +1214,8 @@ enum class IntrinsicIndex
|
||||
};
|
||||
|
||||
global_variable String intrinsic_names[] = {
|
||||
string_literal("llvm.ctlz"),
|
||||
string_literal("llvm.cttz"),
|
||||
string_literal("llvm.smax"),
|
||||
string_literal("llvm.smin"),
|
||||
string_literal("llvm.trap"),
|
||||
@ -1389,6 +1396,11 @@ fn Type* sint32(Module* module)
|
||||
return integer_type(module, { .bit_count = 32, .is_signed = true });
|
||||
}
|
||||
|
||||
fn Type* sint64(Module* module)
|
||||
{
|
||||
return integer_type(module, { .bit_count = 64, .is_signed = true });
|
||||
}
|
||||
|
||||
struct Options
|
||||
{
|
||||
String content;
|
||||
|
1014
src/emitter.cpp
1014
src/emitter.cpp
File diff suppressed because it is too large
Load Diff
209
src/llvm.cpp
209
src/llvm.cpp
@ -26,83 +26,12 @@
|
||||
|
||||
#include "lld/Common/CommonLinkerContext.h"
|
||||
|
||||
fn llvm::StringRef string_ref(String string)
|
||||
{
|
||||
return llvm::StringRef((char*)string.pointer, string.length);
|
||||
}
|
||||
|
||||
EXPORT LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name)
|
||||
{
|
||||
auto module = new llvm::Module(string_ref(name), *llvm::unwrap(context));
|
||||
return wrap(module);
|
||||
}
|
||||
|
||||
EXPORT 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)
|
||||
{
|
||||
llvm::GlobalValue::LinkageTypes linkage;
|
||||
switch (linkage_type)
|
||||
{
|
||||
case LLVMExternalLinkage: linkage = llvm::GlobalValue::ExternalLinkage; break;
|
||||
case LLVMInternalLinkage: linkage = llvm::GlobalValue::InternalLinkage; break;
|
||||
default: trap();
|
||||
}
|
||||
|
||||
llvm::GlobalValue::ThreadLocalMode tlm;
|
||||
switch (thread_local_mode)
|
||||
{
|
||||
case LLVMNotThreadLocal: tlm = llvm::GlobalValue::NotThreadLocal; break;
|
||||
default: trap();
|
||||
}
|
||||
auto* global = new llvm::GlobalVariable(*llvm::unwrap(module), llvm::unwrap(type), is_constant, linkage, llvm::unwrap<llvm::Constant>(initial_value), string_ref(name), before ? llvm::unwrap<llvm::GlobalVariable>(before) : 0, tlm, address_space, externally_initialized);
|
||||
return wrap(global);
|
||||
}
|
||||
|
||||
EXPORT void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type)
|
||||
{
|
||||
auto sp = llvm::unwrap<llvm::DISubprogram>(subprogram);
|
||||
sp->replaceType(llvm::unwrap<llvm::DISubroutineType>(subroutine_type));
|
||||
}
|
||||
|
||||
EXPORT LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name)
|
||||
{
|
||||
llvm::GlobalValue::LinkageTypes llvm_linkage_type;
|
||||
switch (linkage_type)
|
||||
{
|
||||
case LLVMExternalLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalLinkage; break;
|
||||
case LLVMAvailableExternallyLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage; break;
|
||||
case LLVMLinkOnceAnyLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage; break;
|
||||
case LLVMLinkOnceODRLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage; break;
|
||||
case LLVMWeakAnyLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakAnyLinkage; break;
|
||||
case LLVMWeakODRLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakODRLinkage; break;
|
||||
case LLVMAppendingLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AppendingLinkage; break;
|
||||
case LLVMInternalLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::InternalLinkage; break;
|
||||
case LLVMPrivateLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::PrivateLinkage; break;
|
||||
case LLVMExternalWeakLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalWeakLinkage; break;
|
||||
case LLVMCommonLinkage:
|
||||
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::CommonLinkage; break;
|
||||
default:
|
||||
trap();
|
||||
}
|
||||
auto* function = llvm::Function::Create(llvm::unwrap<llvm::FunctionType>(function_type), llvm_linkage_type, address_space, string_ref(name), llvm::unwrap(module));
|
||||
return wrap(function);
|
||||
}
|
||||
|
||||
EXPORT LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function)
|
||||
{
|
||||
auto* basic_block = llvm::BasicBlock::Create(*llvm::unwrap(context), string_ref(name), parent_function ? llvm::unwrap<llvm::Function>(parent_function) : 0);
|
||||
return wrap(basic_block);
|
||||
}
|
||||
|
||||
// If there are multiple uses of the return-value slot, just check
|
||||
// for something immediately preceding the IP. Sometimes this can
|
||||
// happen with how we generate implicit-returns; it can also happen
|
||||
@ -169,142 +98,6 @@ EXPORT LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LL
|
||||
return wrap(store);
|
||||
}
|
||||
|
||||
EXPORT bool llvm_value_use_empty(LLVMValueRef value)
|
||||
{
|
||||
return llvm::unwrap(value)->use_empty();
|
||||
}
|
||||
|
||||
EXPORT bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block)
|
||||
{
|
||||
return llvm::unwrap(basic_block)->empty();
|
||||
}
|
||||
|
||||
EXPORT LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef b, LLVMTypeRef type, unsigned address_space, u32 alignment, String name)
|
||||
{
|
||||
auto& builder = *llvm::unwrap(b);
|
||||
auto llvm_alignment = llvm::Align(alignment);
|
||||
return wrap(builder.Insert(new llvm::AllocaInst(llvm::unwrap(type), address_space, 0, llvm_alignment), string_ref(name)));
|
||||
}
|
||||
|
||||
fn String stream_to_string(llvm::raw_string_ostream& stream)
|
||||
{
|
||||
// No need to call stream.flush(); because it's string-based
|
||||
stream.flush();
|
||||
|
||||
auto string = stream.str();
|
||||
auto length = string.length();
|
||||
|
||||
u8* result = 0;
|
||||
if (length)
|
||||
{
|
||||
result = new u8[length + 1];
|
||||
memcpy(result, string.c_str(), length);
|
||||
result[length] = 0;
|
||||
}
|
||||
|
||||
return String{ result, length };
|
||||
}
|
||||
|
||||
EXPORT String llvm_function_to_string(llvm::Function& function)
|
||||
{
|
||||
std::string buffer;
|
||||
llvm::raw_string_ostream os(buffer);
|
||||
function.print(os);
|
||||
os.flush();
|
||||
auto result = stream_to_string(os);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_function_verify(LLVMValueRef function_value, String* error_message)
|
||||
{
|
||||
std::string message_buffer;
|
||||
llvm::raw_string_ostream message_stream(message_buffer);
|
||||
|
||||
auto& function = *llvm::unwrap<llvm::Function>(function_value);
|
||||
bool result = verifyFunction(function, &message_stream);
|
||||
*error_message = stream_to_string(message_stream);
|
||||
|
||||
// We invert the condition because LLVM conventions are just stupid
|
||||
return !result;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_module_verify(LLVMModuleRef m, String* error_message)
|
||||
{
|
||||
std::string message_buffer;
|
||||
llvm::raw_string_ostream message_stream(message_buffer);
|
||||
|
||||
const auto& module = *llvm::unwrap(m);
|
||||
bool result = llvm::verifyModule(module, &message_stream);
|
||||
*error_message = stream_to_string(message_stream);
|
||||
|
||||
// We invert the condition because LLVM conventions are just stupid
|
||||
return !result;
|
||||
}
|
||||
|
||||
EXPORT String llvm_module_to_string(LLVMModuleRef module)
|
||||
{
|
||||
std::string buffer;
|
||||
llvm::raw_string_ostream stream(buffer);
|
||||
llvm::unwrap(module)->print(stream, 0);
|
||||
|
||||
return stream_to_string(stream);
|
||||
}
|
||||
|
||||
EXPORT String llvm_default_target_triple()
|
||||
{
|
||||
auto triple = llvm::sys::getDefaultTargetTriple();
|
||||
auto length = triple.length();
|
||||
|
||||
u8* pointer = 0;
|
||||
if (length)
|
||||
{
|
||||
pointer = new u8[length + 1];
|
||||
memcpy(pointer, triple.c_str(), length);
|
||||
pointer[length] = 0;
|
||||
}
|
||||
|
||||
return { pointer, length };
|
||||
}
|
||||
|
||||
EXPORT String llvm_host_cpu_name()
|
||||
{
|
||||
auto cpu = llvm::sys::getHostCPUName();
|
||||
auto result = String { (u8*)cpu.data(), cpu.size() };
|
||||
assert(result.pointer[result.length] == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT String llvm_host_cpu_features()
|
||||
{
|
||||
llvm::SubtargetFeatures Features;
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
auto host_cpu_features = llvm::sys::getHostCPUFeatures();
|
||||
#else
|
||||
StringMap<bool> host_cpu_features;
|
||||
if (!sys::getHostCPUFeatures(host_cpu_features)) {
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
for (const auto &[Feature, IsEnabled] : host_cpu_features)
|
||||
{
|
||||
Features.AddFeature(Feature, IsEnabled);
|
||||
}
|
||||
|
||||
auto feature_string = Features.getString();
|
||||
auto length = feature_string.length();
|
||||
|
||||
u8* result = 0;
|
||||
if (length)
|
||||
{
|
||||
result = new u8[length + 1];
|
||||
memcpy(result, feature_string.c_str(), length + 1);
|
||||
result[length] = 0;
|
||||
}
|
||||
|
||||
return { result, length };
|
||||
}
|
||||
|
||||
EXPORT void llvm_module_run_optimization_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, BBLLVMOptimizationPipelineOptions options)
|
||||
{
|
||||
auto module = llvm::unwrap(m);
|
||||
@ -423,7 +216,7 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli
|
||||
{
|
||||
std::error_code error_code;
|
||||
|
||||
stream = std::make_unique<llvm::raw_fd_ostream>(string_ref(options->output_file_path), error_code, llvm::sys::fs::OF_None);
|
||||
stream = std::make_unique<llvm::raw_fd_ostream>(llvm::StringRef((char*)options->output_file_path.pointer, options->output_file_path.length), error_code, llvm::sys::fs::OF_None);
|
||||
|
||||
if (error_code)
|
||||
{
|
||||
|
21
src/llvm.hpp
21
src/llvm.hpp
@ -117,33 +117,12 @@ enum class DwarfType
|
||||
HP_VAX_complex_float_d = 0x90, // D floating complex.
|
||||
};
|
||||
|
||||
|
||||
fn bool llvm_initialized = false;
|
||||
|
||||
extern "C" String llvm_default_target_triple();
|
||||
extern "C" String llvm_host_cpu_name();
|
||||
extern "C" String llvm_host_cpu_features();
|
||||
|
||||
extern "C" LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name);
|
||||
|
||||
extern "C" LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name);
|
||||
|
||||
extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function);
|
||||
|
||||
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);
|
||||
|
||||
extern "C" LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef builder, LLVMTypeRef type, unsigned address_space, u32 alignment, String name);
|
||||
extern "C" bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block);
|
||||
|
||||
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" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type);
|
||||
|
||||
extern "C" String llvm_module_to_string(LLVMModuleRef module);
|
||||
|
||||
extern "C" void llvm_module_run_optimization_pipeline(LLVMModuleRef module, LLVMTargetMachineRef target_machine, BBLLVMOptimizationPipelineOptions options);
|
||||
extern "C" BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, const BBLLVMCodeGenerationPipelineOptions* options);
|
||||
|
||||
|
164
src/parser.cpp
164
src/parser.cpp
@ -14,12 +14,14 @@ enum class ValueIntrinsic
|
||||
integer_max,
|
||||
int_from_enum,
|
||||
int_from_pointer,
|
||||
leading_zeroes,
|
||||
max,
|
||||
min,
|
||||
pointer_cast,
|
||||
pointer_from_int,
|
||||
select,
|
||||
string_to_enum,
|
||||
trailing_zeroes,
|
||||
trap,
|
||||
truncate,
|
||||
va_start,
|
||||
@ -399,6 +401,77 @@ fn String parse_identifier(Module* module)
|
||||
return module->content(start, end);
|
||||
}
|
||||
|
||||
fn u8 escape_character(u8 ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'n': return '\n';
|
||||
case 't': return '\t';
|
||||
case 'r': return '\r';
|
||||
case '\'': return '\'';
|
||||
case '\\': return '\\';
|
||||
default: report_error();
|
||||
}
|
||||
}
|
||||
|
||||
fn String parse_string_literal(Module* module)
|
||||
{
|
||||
expect_character(module, '"');
|
||||
|
||||
auto start = module->offset;
|
||||
u64 escape_character_count = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
auto ch = module->content[module->offset];
|
||||
if (ch == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
escape_character_count += ch == '\\';
|
||||
module->offset += 1;
|
||||
}
|
||||
|
||||
auto end = module->offset;
|
||||
auto length = end - start - escape_character_count;
|
||||
auto pointer = (u8*)arena_allocate_bytes(module->arena, length + 1, 1);
|
||||
auto string_literal = String{ .pointer = pointer, .length = length };
|
||||
|
||||
for (u64 source_i = start, i = 0; source_i < end; source_i += 1, i += 1)
|
||||
{
|
||||
auto ch = module->content[source_i];
|
||||
if (ch == '\\')
|
||||
{
|
||||
source_i += 1;
|
||||
ch = module->content[source_i];
|
||||
string_literal[i] = escape_character(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
string_literal[i] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
expect_character(module, '"');
|
||||
|
||||
return string_literal;
|
||||
}
|
||||
|
||||
fn String parse_name(Module* module)
|
||||
{
|
||||
String result;
|
||||
if (module->content[module->offset] == '"')
|
||||
{
|
||||
result = parse_string_literal(module);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = parse_identifier(module);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn u64 accumulate_hexadecimal(u64 accumulator, u8 ch)
|
||||
{
|
||||
u64 value;
|
||||
@ -670,7 +743,7 @@ fn FunctionHeaderParsing parse_function_header(Module* module, Scope* scope, boo
|
||||
|
||||
if (mandate_argument_names)
|
||||
{
|
||||
argument_name = parse_identifier(module);
|
||||
argument_name = arena_duplicate_string(module->arena, parse_identifier(module));
|
||||
|
||||
skip_space(module);
|
||||
|
||||
@ -1048,61 +1121,6 @@ fn u64 parse_binary(Module* module)
|
||||
return value;
|
||||
}
|
||||
|
||||
fn u8 escape_character(u8 ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'n': return '\n';
|
||||
case 't': return '\t';
|
||||
case 'r': return '\r';
|
||||
case '\'': return '\'';
|
||||
default: report_error();
|
||||
}
|
||||
}
|
||||
|
||||
fn String parse_string_literal(Module* module)
|
||||
{
|
||||
expect_character(module, '"');
|
||||
|
||||
auto start = module->offset;
|
||||
u64 escape_character_count = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
auto ch = module->content[module->offset];
|
||||
if (ch == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
escape_character_count += ch == '\\';
|
||||
module->offset += 1;
|
||||
}
|
||||
|
||||
auto end = module->offset;
|
||||
auto length = end - start - escape_character_count;
|
||||
auto pointer = (u8*)arena_allocate_bytes(module->arena, length + 1, 1);
|
||||
auto string_literal = String{ .pointer = pointer, .length = length };
|
||||
|
||||
for (u64 source_i = start, i = 0; source_i < end; source_i += 1, i += 1)
|
||||
{
|
||||
auto ch = module->content[source_i];
|
||||
if (ch == '\\')
|
||||
{
|
||||
source_i += 1;
|
||||
ch = module->content[source_i];
|
||||
string_literal[i] = escape_character(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
string_literal[i] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
expect_character(module, '"');
|
||||
|
||||
return string_literal;
|
||||
}
|
||||
|
||||
fn Token tokenize(Module* module)
|
||||
{
|
||||
skip_space(module);
|
||||
@ -1168,12 +1186,14 @@ fn Token tokenize(Module* module)
|
||||
string_literal("integer_max"),
|
||||
string_literal("int_from_enum"),
|
||||
string_literal("int_from_pointer"),
|
||||
string_literal("leading_zeroes"),
|
||||
string_literal("max"),
|
||||
string_literal("min"),
|
||||
string_literal("pointer_cast"),
|
||||
string_literal("pointer_from_int"),
|
||||
string_literal("select"),
|
||||
string_literal("string_to_enum"),
|
||||
string_literal("trailing_zeroes"),
|
||||
string_literal("trap"),
|
||||
string_literal("truncate"),
|
||||
string_literal("va_start"),
|
||||
@ -1682,9 +1702,11 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
||||
case ValueIntrinsic::extend:
|
||||
case ValueIntrinsic::int_from_enum:
|
||||
case ValueIntrinsic::int_from_pointer:
|
||||
case ValueIntrinsic::leading_zeroes:
|
||||
case ValueIntrinsic::truncate:
|
||||
case ValueIntrinsic::pointer_cast:
|
||||
case ValueIntrinsic::pointer_from_int:
|
||||
case ValueIntrinsic::trailing_zeroes:
|
||||
case ValueIntrinsic::va_end:
|
||||
{
|
||||
UnaryId id;
|
||||
@ -1695,9 +1717,11 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
||||
case ValueIntrinsic::extend: id = UnaryId::extend; break;
|
||||
case ValueIntrinsic::int_from_enum: id = UnaryId::int_from_enum; break;
|
||||
case ValueIntrinsic::int_from_pointer: id = UnaryId::int_from_pointer; break;
|
||||
case ValueIntrinsic::leading_zeroes: id = UnaryId::leading_zeroes; break;
|
||||
case ValueIntrinsic::truncate: id = UnaryId::truncate; break;
|
||||
case ValueIntrinsic::pointer_cast: id = UnaryId::pointer_cast; break;
|
||||
case ValueIntrinsic::pointer_from_int: id = UnaryId::pointer_from_int; break;
|
||||
case ValueIntrinsic::trailing_zeroes: id = UnaryId::trailing_zeroes; break;
|
||||
case ValueIntrinsic::va_end: id = UnaryId::va_end; break;
|
||||
default: unreachable();
|
||||
}
|
||||
@ -1973,7 +1997,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
||||
} break;
|
||||
case TokenId::dot:
|
||||
{
|
||||
auto identifier = parse_identifier(module);
|
||||
auto identifier = parse_name(module);
|
||||
result = new_value(module);
|
||||
|
||||
*result = {
|
||||
@ -2573,7 +2597,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
||||
module->offset += 1;
|
||||
skip_space(module);
|
||||
|
||||
auto local_name = parse_identifier(module);
|
||||
auto local_name = arena_duplicate_string(module->arena, parse_identifier(module));
|
||||
skip_space(module);
|
||||
|
||||
Type* local_type = 0;
|
||||
@ -2761,7 +2785,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
|
||||
|
||||
if (is_identifier_start(module->content[module->offset]))
|
||||
{
|
||||
auto local_name = parse_identifier(module);
|
||||
auto local_name = arena_duplicate_string(module->arena, parse_identifier(module));
|
||||
auto local = new_local(module, scope);
|
||||
*local = {
|
||||
.variable = {
|
||||
@ -3128,20 +3152,6 @@ fn Block* parse_block(Module* module, Scope* parent_scope)
|
||||
return block;
|
||||
}
|
||||
|
||||
fn String parse_name(Module* module)
|
||||
{
|
||||
String result;
|
||||
if (module->content[module->offset] == '"')
|
||||
{
|
||||
result = parse_string_literal(module);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = parse_identifier(module);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void parse(Module* module)
|
||||
{
|
||||
auto scope = &module->scope;
|
||||
@ -3217,7 +3227,7 @@ void parse(Module* module)
|
||||
skip_space(module);
|
||||
}
|
||||
|
||||
auto global_name = parse_identifier(module);
|
||||
auto global_name = arena_duplicate_string(module->arena, parse_identifier(module));
|
||||
|
||||
Global* global_forward_declaration = 0;
|
||||
Global* last_global = module->first_global;
|
||||
@ -3444,8 +3454,6 @@ void parse(Module* module)
|
||||
u64 int_value_buffer[64];
|
||||
|
||||
bool is_resolved = true;
|
||||
bool implicit_value = false;
|
||||
unused(implicit_value);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -3674,7 +3682,7 @@ void parse(Module* module)
|
||||
break;
|
||||
}
|
||||
|
||||
auto argument_name = parse_identifier(module);
|
||||
auto argument_name = arena_duplicate_string(module->arena, parse_identifier(module));
|
||||
|
||||
skip_space(module);
|
||||
|
||||
@ -3757,7 +3765,7 @@ void parse(Module* module)
|
||||
auto argument_line = get_line(module);
|
||||
auto argument_column = get_column(module);
|
||||
|
||||
auto argument_name = parse_identifier(module);
|
||||
auto argument_name = arena_duplicate_string(module->arena, parse_identifier(module));
|
||||
|
||||
skip_space(module);
|
||||
expect_character(module, ':');
|
||||
|
10
tests/leading_trailing_zeroes.bbb
Normal file
10
tests/leading_trailing_zeroes.bbb
Normal file
@ -0,0 +1,10 @@
|
||||
[export] main = fn [cc(c)] () s32
|
||||
{
|
||||
>a: u32 = 0b111;
|
||||
if (#leading_zeroes(a) != 29) #trap();
|
||||
if (#trailing_zeroes(a) != 0) #trap();
|
||||
>b: u8 = 0b11010;
|
||||
if (#leading_zeroes(b) != 3) #trap();
|
||||
if (#trailing_zeroes(b) != 1) #trap();
|
||||
return 0;
|
||||
}
|
9
tests/pointer_sub.bbb
Normal file
9
tests/pointer_sub.bbb
Normal file
@ -0,0 +1,9 @@
|
||||
[export] main = fn [cc(c)] () s32
|
||||
{
|
||||
>a: [_]s32 = [ 3, 1 ];
|
||||
>p0 = &a[0];
|
||||
>p1 = p0 + 1;
|
||||
>sub: u32 = #truncate(p1 - p0);
|
||||
if (sub != 1) #trap();
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user