Pass first test with LLVM. Ditch C transpiler

This commit is contained in:
David Gonzalez Martin 2024-01-26 18:54:03 +01:00
parent 81b1aefca4
commit 395bdd4cc4
49 changed files with 9605 additions and 8970 deletions

View File

@ -13,13 +13,8 @@ concurrency:
cancel-in-progress: true
jobs:
build:
strategy:
matrix:
os: [
ubuntu-latest,
]
runs-on: ${{ matrix.os }}
build_and_test:
runs-on: [ self-hosted, Linux, x64 ]
timeout-minutes: 15
steps:
- name: Checkout
@ -29,4 +24,4 @@ jobs:
with:
version: master
- name: Test
run: ./ci.sh
run: ./ci.sh ../todo_foo_debug_path ../../../../../dev/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

834
bootstrap/backend/llvm.cpp Normal file
View File

@ -0,0 +1,834 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/FileSystem.h"
#include "lld/Common/CommonLinkerContext.h"
using namespace llvm;
extern "C" LLVMContext* NativityLLVMCreateContext()
{
auto* context = new LLVMContext();
return context;
}
extern "C" Module* NativityLLVMCreateModule(const char* name_ptr, size_t name_len, LLVMContext& context)
{
auto name = StringRef(name_ptr, name_len);
auto* module = new Module(name, context);
return module;
}
extern "C" IRBuilder<>* NativityLLVMCreateBuilder(LLVMContext& Context)
{
auto* builder = new IRBuilder<>(Context);
return builder;
}
extern "C" DIBuilder* NativityLLVMModuleCreateDebugInfoBuilder(Module& module)
{
DIBuilder* builder = new DIBuilder(module);
return builder;
}
extern "C" DIFile* NativityLLVMDebugInfoBuilderCreateFile(DIBuilder& builder, const char* filename_ptr, size_t filename_len, const char* directory_ptr, size_t directory_len)
{
auto filename = StringRef(filename_ptr, filename_len);
auto directory = StringRef(directory_ptr, directory_len);
auto* file = builder.createFile(filename, directory);
return file;
}
extern "C" DICompileUnit* NativityLLVMDebugInfoBuilderCreateCompileUnit(DIBuilder& builder, unsigned language, DIFile* file, const char* producer_ptr, size_t producer_len, bool is_optimized, const char* flags_ptr, size_t flags_len, unsigned runtime_version, const char* split_name_ptr, size_t split_name_len, DICompileUnit::DebugEmissionKind debug_emission_kind, uint64_t DWOId, bool split_debug_inlining, bool debug_info_for_profiling, DICompileUnit::DebugNameTableKind debug_name_table_kind, bool ranges_base_address, const char* sysroot_ptr, size_t sysroot_len, const char* sdk_ptr, size_t sdk_len)
{
auto producer = StringRef(producer_ptr, producer_len);
auto flags = StringRef(flags_ptr, flags_len);
auto split_name = StringRef(split_name_ptr, split_name_len);
auto sysroot = StringRef(sysroot_ptr, sysroot_len);
auto sdk = StringRef(sdk_ptr, sdk_len);
auto* compile_unit = builder.createCompileUnit(language, file, producer, is_optimized, flags, runtime_version, split_name, debug_emission_kind, DWOId, split_debug_inlining, debug_info_for_profiling, debug_name_table_kind, ranges_base_address, sysroot, sdk);
return compile_unit;
}
extern "C" DISubprogram* NativityLLVMDebugInfoBuilderCreateFunction(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, const char* linkage_name_ptr, size_t linkage_name_len, DIFile* file, unsigned line_number, DISubroutineType* type, unsigned scope_line, DINode::DIFlags flags, DISubprogram::DISPFlags subprogram_flags, DISubprogram* declaration)
{
auto name = StringRef(name_ptr, name_len);
auto linkage_name = StringRef(linkage_name_ptr, linkage_name_len);
DITemplateParameterArray template_parameters = nullptr;
DITypeArray thrown_types = nullptr;
DINodeArray annotations = nullptr;
StringRef target_function_name = "";
auto* function = builder.createFunction(scope, name, linkage_name, file, line_number, type, scope_line, flags, subprogram_flags, template_parameters, declaration, thrown_types, annotations, target_function_name);
return function;
}
extern "C" DISubroutineType* NativityLLVMDebugInfoBuilderCreateSubroutineType(DIBuilder& builder, DIType** parameter_types_ptr, size_t parameter_type_count, DINode::DIFlags flags, dwarf::CallingConvention calling_convention)
{
auto metadata_list = ArrayRef<Metadata*>(reinterpret_cast<Metadata**>( parameter_types_ptr), parameter_type_count);
auto parameter_types = builder.getOrCreateTypeArray(metadata_list);
auto* subroutine_type = builder.createSubroutineType(parameter_types, flags, calling_convention);
return subroutine_type;
}
extern "C" DILexicalBlock* NativityLLVMDebugInfoBuilderCreateLexicalBlock(DIBuilder& builder, DIScope* parent_scope, DIFile* parent_file, unsigned line, unsigned column)
{
assert(isa<DILocalScope>(parent_scope));
auto* block = builder.createLexicalBlock(parent_scope, parent_file, line, column);
return block;
}
extern "C" void NativityLLVMBuilderSetCurrentDebugLocation(IRBuilder<>& builder, LLVMContext& context, unsigned line, unsigned column, DIScope* scope, Function* function)
{
auto debug_location = DILocation::get(context, line, column, scope);
builder.SetCurrentDebugLocation(debug_location);
}
extern "C" DILocalVariable* NativityLLVMDebugInfoBuilderCreateParameterVariable(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, unsigned argument_index, DIFile* file, unsigned line_number, DIType* type, bool always_preserve, DINode::DIFlags flags)
{
assert(isa<DILocalScope>(scope));
auto name = StringRef(name_ptr, name_len);
auto* parameter_variable = builder.createParameterVariable(scope, name, argument_index, file, line_number, type, always_preserve, flags);
return parameter_variable;
}
extern "C" DILocalVariable* NativityLLVMDebugInfoBuilderCreateAutoVariable(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line_number, DIType* type, bool always_preserve, DINode::DIFlags flags, uint32_t alignment) // 0 means 1 << 0 (alignment of 1)
{
auto name = StringRef(name_ptr, name_len);
auto* auto_variable = builder.createAutoVariable(scope, name, file, line_number, type, always_preserve, flags, alignment);
return auto_variable;
}
extern "C" Instruction* NativityLLVMDebugInfoBuilderInsertDeclare(DIBuilder& builder, Value* pointer, DILocalVariable* local_variable, LLVMContext& context, unsigned line, unsigned column, DIScope* scope, BasicBlock* basic_block)
{
auto debug_location = DILocation::get(context, line, column, scope);
auto* expression = builder.createExpression();
auto* instruction = builder.insertDeclare(pointer, local_variable, expression, debug_location, basic_block);
return instruction;
}
extern "C" DIType* NativityLLVMDebugInfoBuilderCreateBasicType(DIBuilder& builder, const char* name_ptr, size_t name_len, uint64_t bit_count, unsigned dwarf_encoding, DINode::DIFlags flags)
{
auto name = StringRef(name_ptr, name_len);
auto* type = builder.createBasicType(name, bit_count, dwarf_encoding, flags);
return type;
}
extern "C" DIDerivedType* NativityLLVMDebugInfoBuilderCreatePointerType(DIBuilder& builder, DIType* element_type, uint64_t pointer_bit_count, uint32_t alignment, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
std::optional<unsigned> DWARFAddressSpace = std::nullopt;
DINodeArray annotations = nullptr;
auto* pointer_type = builder.createPointerType(element_type, pointer_bit_count, alignment, DWARFAddressSpace, name, annotations);
return pointer_type;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateStructType(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line_number, uint64_t bit_count, uint32_t alignment, DINode::DIFlags flags, DIType* derived_from, DIType** element_type_ptr, size_t element_type_count)
{
auto name = StringRef(name_ptr, name_len);
auto type_array = ArrayRef<Metadata*>(reinterpret_cast<Metadata**>(element_type_ptr), element_type_count);
auto* struct_type = builder.createStructType(scope, name, file, line_number, bit_count, alignment, flags, derived_from, builder.getOrCreateArray(type_array));
return struct_type;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateArrayType(DIBuilder& builder, uint64_t bit_size, uint32_t alignment, DIType* type, size_t element_count)
{
Metadata* subranges[1] = {
builder.getOrCreateSubrange(0, element_count),
};
DINodeArray subscripts = builder.getOrCreateArray(ArrayRef<Metadata*>(subranges, sizeof(subranges) / sizeof(subranges[0])));
auto* array_type = builder.createArrayType(bit_size, alignment, type, subscripts);
return array_type;
}
extern "C" DIEnumerator* NativityLLVMDebugInfoBuilderCreateEnumerator(DIBuilder& builder, const char* name_ptr, size_t name_len, uint64_t value, bool is_unsigned)
{
// DIEnumerator *DIBuilder::createEnumerator(StringRef Name, uint64_t Val,
auto name = StringRef(name_ptr, name_len);
auto* enumerator = builder.createEnumerator(name, value, is_unsigned);
return enumerator;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateEnumerationType(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line, uint64_t bit_size, uint32_t alignment, DIEnumerator** enumerator_ptr, size_t enumerator_count, DIType* underlying_type)
{
auto name = StringRef(name_ptr, name_len);
DINodeArray enumerators = builder.getOrCreateArray(ArrayRef<Metadata*>(reinterpret_cast<Metadata**>(enumerator_ptr), enumerator_count));
auto* enumeration_type = builder.createEnumerationType(scope, name, file, line, bit_size, alignment, enumerators, underlying_type);
return enumeration_type;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType(DIBuilder& builder, unsigned tag, const char* name_ptr, size_t name_len, DIScope* scope, DIFile* file, unsigned line)
{
auto name = StringRef(name_ptr, name_len);
auto* composite_type = builder.createReplaceableCompositeType(tag, name, scope, file, line);
return composite_type;
}
extern "C" DISubprogram* NativityLLVMDebugInfoScopeToSubprogram(DIScope* scope)
{
auto* subprogram = dyn_cast<DISubprogram>(scope);
return subprogram;
}
extern "C" void NativityLLVMDebugInfoBuilderFinalizeSubprogram(DIBuilder& builder, DISubprogram* subprogram, const Function* function)
{
assert(subprogram->describes(function));
builder.finalizeSubprogram(subprogram);
}
extern "C" void NativityLLVMDebugInfoBuilderFinalize(DIBuilder& builder)
{
builder.finalize();
}
extern "C" DIFile* NativityLLVMDebugInfoSubprogramGetFile(DISubprogram& subprogram)
{
auto* file = subprogram.getFile();
return file;
}
extern "C" DIType* NativityLLVMDebugInfoSubprogramGetArgumentType(DISubprogram& subprogram, size_t argument_index)
{
auto* argument_type = subprogram.getType()->getTypeArray()[argument_index];
return argument_type;
}
extern "C" unsigned NativityLLVMArgumentGetIndex(Argument& argument)
{
unsigned argument_index = argument.getArgNo();
return argument_index;
}
extern "C" FunctionType* NativityLLVMGetFunctionType(Type* return_type, Type** type_ptr, size_t type_count, bool var_args)
{
auto types = ArrayRef<Type*>(type_ptr, type_count);
auto* function_type = FunctionType::get(return_type, types, var_args);
return function_type;
}
extern "C" IntegerType* NativityLLVMGetIntegerType(LLVMContext& context, unsigned bit_count)
{
auto integer_type = IntegerType::get(context, bit_count);
return integer_type;
}
extern "C" PointerType* NativityLLVMGetPointerType(LLVMContext& context, unsigned address_space)
{
auto pointer_type = PointerType::get(context, address_space);
return pointer_type;
}
extern "C" ArrayType* NativityLLVMGetArrayType(Type* element_type, uint64_t element_count)
{
auto* array_type = ArrayType::get(element_type, element_count);
return array_type;
}
extern "C" StructType* NativityLLVMCreateStructType(LLVMContext& context, Type** type_ptr, size_t type_count, const char* name_ptr, size_t name_len, bool is_packed)
{
auto types = ArrayRef<Type*>(type_ptr, type_count);
auto name = StringRef(name_ptr, name_len);
auto* struct_type = StructType::create(context, types, name, is_packed);
return struct_type;
}
extern "C" Function* NativityLLVMModuleGetFunction(Module& module, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* function = module.getFunction(name);
return function;
}
extern "C" void NativityLLVMFunctionAddAttributeKey(Function& function, Attribute::AttrKind attribute)
{
function.addFnAttr(attribute);
}
extern "C" Function* NativityLLVModuleCreateFunction(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* function = Function::Create(function_type, linkage_type, address_space, name, module);
return function;
}
extern "C" BasicBlock* NativityLLVMCreateBasicBlock(LLVMContext& context, const char* name_ptr, size_t name_len, Function* parent, BasicBlock* insert_before)
{
auto name = StringRef(name_ptr, name_len);
auto* basic_block = BasicBlock::Create(context, name, parent, insert_before);
return basic_block;
}
extern "C" PHINode* NativityLLVMCreatePhiNode(Type* type, unsigned reserved_value_count, const char* name_ptr, size_t name_len, BasicBlock* basic_block)
{
auto name = StringRef(name_ptr, name_len);
auto* phi_node = PHINode::Create(type, reserved_value_count, name, basic_block);
return phi_node;
}
extern "C" void NativityLLVMBasicBlockRemoveFromParent(BasicBlock* basic_block)
{
basic_block->eraseFromParent();
}
extern "C" void NativityLLVMBuilderSetInsertPoint(IRBuilder<>& builder, BasicBlock* basic_block)
{
builder.SetInsertPoint(basic_block);
}
extern "C" void NativityLLVMValueSetName(Value* value, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
value->setName(name);
}
extern "C" Type* NativityLLVMValueGetType(Value* value)
{
auto* type = value->getType();
return type;
}
extern "C" void NativityLLVMFunctionGetArguments(Function& function, Argument** argument_ptr, size_t* argument_count)
{
auto actual_argument_count = function.arg_size();
assert(actual_argument_count <= *argument_count);
*argument_count = actual_argument_count;
size_t arg_i = 0;
for (auto& Arg : function.args()) {
argument_ptr[arg_i] = &Arg;
arg_i += 1;
}
}
extern "C" void NativityLLVMFunctionSetSubprogram(Function& function, DISubprogram* subprogram)
{
function.setSubprogram(subprogram);
}
extern "C" DISubprogram* NativityLLVMFunctionGetSubprogram(Function& function)
{
auto* subprogram = function.getSubprogram();
return subprogram;
}
extern "C" Constant* NativityLLVMConstantStruct(StructType* struct_type, Constant** constant_ptr, size_t constant_count)
{
auto constants = ArrayRef<Constant*>(constant_ptr, constant_count);
auto* constant_struct = ConstantStruct::get(struct_type, constants);
return constant_struct;
}
extern "C" StoreInst* NativityLLVMBuilderCreateStore(IRBuilder<>& builder, Value* value, Value* pointer, bool is_volatile)
{
auto* store = builder.CreateStore(value, pointer, is_volatile);
return store;
}
extern "C" AllocaInst* NativityLLVMBuilderCreateAlloca(IRBuilder<>& builder, Type* type, unsigned address_space, Value* array_size, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* alloca = builder.CreateAlloca(type, address_space, array_size, name);
return alloca;
}
extern "C" Type* NativityLLVMGetVoidType(LLVMContext& context)
{
auto* void_type = Type::getVoidTy(context);
return void_type;
}
extern "C" Value* NativityLLVMBuilderCreateICmp(IRBuilder<>& builder, CmpInst::Predicate comparation, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* icmp = builder.CreateICmp(comparation, left, right, name);
return icmp;
}
extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* value, bool is_volatile, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* load = builder.CreateLoad(type, value, is_volatile, name);
return load;
}
extern "C" ReturnInst* NativityLLVMBuilderCreateRet(IRBuilder<>& builder, Value* value)
{
auto* ret = builder.CreateRet(value);
return ret;
}
extern "C" InlineAsm* NativityLLVMGetInlineAssembly(FunctionType* function_type, const char* assembly_ptr, size_t assembly_len, const char* constraints_ptr, size_t constrains_len, bool has_side_effects, bool is_align_stack, InlineAsm::AsmDialect dialect, bool can_throw)
{
auto assembly = StringRef(assembly_ptr, assembly_len);
auto constraints = StringRef(constraints_ptr, constrains_len);
auto* inline_asm = InlineAsm::get(function_type, assembly, constraints, has_side_effects, is_align_stack, dialect, can_throw);
return inline_asm;
}
extern "C" Value* NativityLLVMBuilderCreateCast(IRBuilder<>& builder, Instruction::CastOps cast_type, Value* value, Type* type, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* cast = builder.CreateCast(cast_type, value, type, name);
return cast;
}
extern "C" CallInst* NativityLLVMBuilderCreateCall(IRBuilder<>& builder, FunctionType* function_type, Value* callee, Value** argument_ptr, size_t argument_count, const char* name_ptr, size_t name_len, MDNode* fp_math_tag)
{
if (auto* foo = static_cast<FunctionType*>(callee->getType())) {
int k = 0;
}
auto arguments = ArrayRef<Value*>(argument_ptr, argument_count);
auto name = StringRef(name_ptr, name_len);
auto* call = builder.CreateCall(function_type, callee, arguments, name, fp_math_tag);
return call;
}
extern "C" UnreachableInst* NativityLLVMBuilderCreateUnreachable(IRBuilder<>& builder)
{
auto* unreachable = builder.CreateUnreachable();
return unreachable;
}
extern "C" GlobalVariable* NativityLLVMModuleAddGlobalVariable(Module& module, Type* type, bool is_constant, GlobalValue::LinkageTypes linkage_type, Constant* initializer, const char* name_ptr, size_t name_len, GlobalVariable* insert_before, GlobalValue::ThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized)
{
auto name = StringRef(name_ptr, name_len);
auto* global_variable = new GlobalVariable(module, type, is_constant, linkage_type, initializer, name, insert_before, thread_local_mode, address_space, externally_initialized);
return global_variable;
}
extern "C" Value* NativityLLVMBuilderCreateAdd(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* add = builder.CreateAdd(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return add;
}
extern "C" Value* NativityLLVMBuilderCreateSub(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* add = builder.CreateSub(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return add;
}
extern "C" Value* NativityLLVMBuilderCreateMultiply(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* multiply = builder.CreateMul(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return multiply;
}
extern "C" Value* NativityLLVMBuilderCreateUDiv(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateUDiv(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateSDiv(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateSDiv(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateURem(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateURem(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateSRem(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateSRem(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateXor(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateXor(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateAnd(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateAnd(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateOr(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateOr(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateShiftLeft(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* shl = builder.CreateShl(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return shl;
}
extern "C" Value* NativityLLVMBuilderCreateLogicalShiftRight(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateLShr(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateArithmeticShiftRight(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateAShr(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateGEP(IRBuilder<>& builder, Type* type, Value* pointer, Value** index_ptr, size_t index_count, const char* name_ptr, size_t name_len, bool in_bounds)
{
auto index_list = ArrayRef<Value*>(index_ptr, index_count);
auto name = StringRef(name_ptr, name_len);
auto* GEP = builder.CreateGEP(type, pointer, index_list, name, in_bounds);
return GEP;
}
extern "C" BranchInst* NativityLLVMBuilderCreateBranch(IRBuilder<>& builder, BasicBlock* basic_block)
{
auto* conditional_branch = builder.CreateBr(basic_block);
return conditional_branch;
}
extern "C" BranchInst* NativityLLVMBuilderCreateConditionalBranch(IRBuilder<>& builder, Value* condition, BasicBlock* true_block, BasicBlock* false_block, MDNode* branch_weights, MDNode* unpredictable)
{
auto* conditional_branch = builder.CreateCondBr(condition, true_block, false_block, branch_weights, unpredictable);
return conditional_branch;
}
extern "C" Intrinsic::ID NativityLLVMLookupIntrinsic(const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
Intrinsic::ID id = Function::lookupIntrinsicID(name);
return id;
}
extern "C" FunctionType* NativityLLVMContextGetIntrinsicType(LLVMContext& context, Intrinsic::ID intrinsic_id, Type** parameter_type_ptr, size_t parameter_type_count)
{
assert(intrinsic_id < Intrinsic::num_intrinsics);
auto parameter_types = ArrayRef<Type*>(parameter_type_ptr, parameter_type_count);
auto* function_type = Intrinsic::getType(context, intrinsic_id, parameter_types);
return function_type;
}
extern "C" Function* NativityLLVMModuleGetIntrinsicDeclaration(Module* module, Intrinsic::ID intrinsic_id, Type** parameter_types_ptr, size_t parameter_type_count)
{
auto parameter_types = ArrayRef<Type*>(parameter_types_ptr, parameter_type_count);
assert(intrinsic_id < Intrinsic::num_intrinsics);
Function* function = Intrinsic::getDeclaration(module, intrinsic_id, parameter_types);
return function;
}
extern "C" Value* NativityLLVMBuilderCreateExtractValue(IRBuilder<>& builder, Value* aggregate, unsigned* indices_ptr, size_t indices_len, const char* name_ptr, size_t name_len)
{
auto indices = ArrayRef<unsigned>(indices_ptr, indices_len);
auto name = StringRef(name_ptr, name_len);
auto* value = builder.CreateExtractValue(aggregate, indices, name);
return value;
}
extern "C" Value* NativityLLVMBuilderCreateInsertValue(IRBuilder<>& builder, Value* aggregate, Value* value, unsigned* indices_ptr, size_t indices_len, const char* name_ptr, size_t name_len)
{
auto indices = ArrayRef<unsigned>(indices_ptr, indices_len);
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateInsertValue(aggregate, value, indices, name);
return result;
}
extern "C" ConstantInt* NativityLLVMContextGetConstantInt(LLVMContext& context, unsigned bit_count, uint64_t value, bool is_signed)
{
auto int_type = APInt(bit_count, value, is_signed);
auto constant_int = ConstantInt::get(context, int_type);
return constant_int;
}
extern "C" Constant* NativityLLVMContextGetConstString(LLVMContext& context, const char* string_ptr, size_t string_len, bool null_terminate)
{
auto string = StringRef(string_ptr, string_len);
auto* constant = ConstantDataArray::getString(context, string, null_terminate);
return constant;
}
extern "C" Constant* NativityLLVMContextGetConstArray(ArrayType* array_type, Constant** value_ptr, size_t value_count)
{
auto values = ArrayRef<Constant*>(value_ptr, value_count);
auto* constant_array = ConstantArray::get(array_type, values);
return constant_array;
}
extern "C" Constant* NativityLLVMContextCreateGlobalStringPointer(IRBuilder<>& builder, const char* string_ptr, size_t string_len, const char* name_ptr, size_t name_len, unsigned address_space, Module* module)
{
auto string = StringRef(string_ptr, string_len);
auto name = StringRef(name_ptr, name_len);
Constant* constant = builder.CreateGlobalStringPtr(string, name, address_space, module);
return constant;
}
extern "C" bool NativityLLVMVerifyFunction(Function& function, const char** message_ptr, size_t* message_len)
{
std::string message_buffer;
raw_string_ostream message_stream(message_buffer);
bool result = verifyFunction(function, &message_stream);
message_stream.flush();
auto size = message_stream.str().size();
*message_ptr = strndup(message_stream.str().c_str(), size);
*message_len = size;
// We invert the condition because LLVM conventions are just stupid
return !result;
}
extern "C" bool NativityLLVMVerifyModule(const Module& module, const char** message_ptr, size_t* message_len)
{
std::string message_buffer;
raw_string_ostream message_stream(message_buffer);
bool result = verifyModule(module, &message_stream);
message_stream.flush();
auto size = message_stream.str().size();
*message_ptr = strndup(message_stream.str().c_str(), size);
*message_len = size;
// We invert the condition because LLVM conventions are just stupid
return !result;
}
extern "C" Type* NativityLLVMFunctionGetReturnType(const Function& function)
{
auto* return_type = function.getReturnType();
return return_type;
}
extern "C" const char* NativityLLVMFunctionToString(const Function& function, size_t* len)
{
std::string buf;
raw_string_ostream os(buf);
function.print(os);
os.flush();
*len = buf.size();
auto* result = strdup(buf.c_str());
return result;
}
extern "C" Type* NativityLLVMAllocatGetAllocatedType(AllocaInst& alloca)
{
auto* type = alloca.getAllocatedType();
return type;
}
extern "C" AllocaInst* NativityLLVMValueToAlloca(Value* value)
{
assert(value);
auto* alloca = dyn_cast<AllocaInst>(value);
return alloca;
}
extern "C" Constant* NativityLLVMValueToConstant(Value* value)
{
assert(value);
auto* constant = dyn_cast<Constant>(value);
return constant;
}
extern "C" Function* NativityLLVMValueToFunction(Value* value)
{
assert(value);
auto* function = dyn_cast<Function>(value);
return function;
}
extern "C" bool NativityLLVMTypeIsPointer(Type* type)
{
bool is_pointer = type->isPointerTy();
return is_pointer;
}
extern "C" bool NativityLLVMTypeIsInteger(Type* type)
{
bool is_integer = type->isIntegerTy();
return is_integer;
}
extern "C" StructType* NativityLLVMTypeToStruct(Type* type)
{
auto* struct_type = dyn_cast<StructType>(type);
return struct_type;
}
extern "C" FunctionType* NativityLLVMTypeToFunction(Type* type)
{
auto* function_type = dyn_cast<FunctionType>(type);
return function_type;
}
extern "C" ArrayType* NativityLLVMTypeToArray(Type* type)
{
auto* array_type = dyn_cast<ArrayType>(type);
return array_type;
}
extern "C" Type* NativityLLVMArrayTypeGetElementType(ArrayType* array_type)
{
auto* element_type = array_type->getElementType();
return element_type;
}
extern "C" const char* NativityLLVMModuleToString(const Module& module, size_t* len)
{
std::string buf;
raw_string_ostream os(buf);
module.print(os, nullptr);
os.flush();
*len = buf.size();
auto* result = strdup(buf.c_str());
return result;
}
extern "C" BasicBlock* NativityLLVMBuilderGetInsertBlock(IRBuilder<>& builder)
{
return builder.GetInsertBlock();
}
extern "C" bool NativityLLVMBuilderIsCurrentBlockTerminated(IRBuilder<>& builder)
{
return builder.GetInsertBlock()->getTerminator() != nullptr;
}
extern "C" UndefValue* NativityLLVMGetUndefined(Type* type)
{
auto* undefined_value = UndefValue::get(type);
return undefined_value;
}
extern "C" void NativityLLVMFunctionSetCallingConvention(Function& function, CallingConv::ID calling_convention)
{
function.setCallingConv(calling_convention);
}
extern "C" CallingConv::ID NativityLLVMFunctionGetCallingConvention(Function& function)
{
auto calling_convention = function.getCallingConv();
return calling_convention;
}
extern "C" void NativityLLVMCallSetCallingConvention(CallBase& call_instruction, CallingConv::ID calling_convention)
{
call_instruction.setCallingConv(calling_convention);
}
extern "C" Constant* NativityLLVMGetStruct(StructType* struct_type, Constant** constants_ptr, size_t constant_count)
{
auto constants = ArrayRef(constants_ptr, constant_count);
auto* named_struct = ConstantStruct::get(struct_type, constants);
return named_struct;
}
namespace lld {
namespace coff {
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
namespace elf {
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
namespace wasm {
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
}
extern "C" bool NativityLLVMGenerateMachineCode(Module& module, const char* object_file_path_ptr, size_t object_file_path_len, const char* file_path_ptr, size_t file_path_len)
{
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs(); InitializeAllAsmParsers();
InitializeAllAsmPrinters();
auto target_triple = "x86_64-linux-none";
auto cpu = "generic";
auto features = "";
TargetOptions target_options;
std::string error;
auto* target = TargetRegistry::lookupTarget(target_triple, error);
assert(target);
auto target_machine = target->createTargetMachine(target_triple, cpu, features, target_options, Reloc::Static);
assert(target_machine);
module.setDataLayout(target_machine->createDataLayout());
module.setTargetTriple(target_triple);
#if 0
SmallVector<char> bytes;
raw_svector_ostream message_stream(bytes);
auto stream = buffer_ostream(message_stream);
#else
std::error_code EC;
auto object_file_path = StringRef(object_file_path_ptr, object_file_path_len);
raw_fd_ostream stream(object_file_path, EC, sys::fs::OF_None);
if (EC) {
return false;
}
#endif
legacy::PassManager pass;
bool result = target_machine->addPassesToEmitFile(pass, stream, nullptr, llvm::CGFT_ObjectFile, false);
if (result) {
// We invert the condition because LLVM conventions are just stupid
return false;
}
pass.run(module);
stream.flush();
std::vector<const char*> args;
args.push_back("ld.lld");
args.push_back(object_file_path_ptr);
args.push_back("-o");
args.push_back(file_path_ptr);
lld::elf::link(args, llvm::outs(), llvm::errs(), true, false);
return true;
}
extern "C" bool NativityLLVMCompareTypes(Type* a, Type* b)
{
if (auto* int_a = dyn_cast<IntegerType>(a)) {
auto* int_b = dyn_cast<IntegerType>(b);
assert(int_b);
auto a_bit_count = int_a->getBitWidth();
auto b_bit_count = int_b->getBitWidth();
assert(a_bit_count == b_bit_count);
}
return a == b;
}

3489
bootstrap/backend/llvm.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
const llvm = @import("llvm.zig");
const LLVM = llvm.LLVM;
pub extern fn NativityLLVMCreateContext() ?*LLVM.Context;
pub extern fn NativityLLVMCreateModule(module_name_ptr: [*:0]const u8, module_name_len: usize, context: *LLVM.Context) ?*LLVM.Module;
pub extern fn NativityLLVMCreateBuilder(context: *LLVM.Context) ?*LLVM.Builder;
pub extern fn NativityLLVMGetFunctionType(return_type: *LLVM.Type, argument_type_ptr: [*]const *LLVM.Type, argument_type_len: usize, is_var_args: bool) ?*LLVM.Type.Function;
pub extern fn NativityLLVMGetIntegerType(context: *LLVM.Context, bit_count: u32) ?*LLVM.Type.Integer;
pub extern fn NativityLLVMGetPointerType(context: *LLVM.Context, address_space: u32) ?*LLVM.Type.Pointer;
pub extern fn NativityLLVMGetArrayType(element_type: *LLVM.Type, element_count: u64) ?*LLVM.Type.Array;
pub extern fn NativityLLVMCreateStructType(context: *LLVM.Context, type_ptr: [*]const *LLVM.Type, type_count: usize, name_ptr: [*]const u8, name_len: usize, is_packed: bool) ?*LLVM.Type.Struct;
pub extern fn NativityLLVMConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_count: usize) ?*LLVM.Value.Constant;
pub extern fn NativityLLVMModuleGetFunction(module: *LLVM.Module, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Function;
pub extern fn NativityLLVModuleCreateFunction(module: *LLVM.Module, function_type: *LLVM.Type.Function, linkage: LLVM.Linkage, address_space: c_uint, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Function;
pub extern fn NativityLLVMModuleCreateDebugInfoBuilder(module: *LLVM.Module) ?*LLVM.DebugInfo.Builder;
pub extern fn NativityLLVMDebugInfoBuilderCreateFile(builder: *LLVM.DebugInfo.Builder, filename_ptr: [*]const u8, filename_len: usize, directory_ptr: [*]const u8, directory_len: usize) ?*LLVM.DebugInfo.File;
pub extern fn NativityLLVMDebugInfoBuilderCreateCompileUnit(builder: *LLVM.DebugInfo.Builder, language: LLVM.DebugInfo.Language, file: *LLVM.DebugInfo.File, producer_ptr: [*]const u8, producer_len: usize, is_optimized: bool, flags_ptr: [*]const u8, flags_len: usize, runtime_version: c_uint, split_name_ptr: [*]const u8, split_name_len: usize, debug_info_emission_kind: LLVM.DebugInfo.CompileUnit.EmissionKind, DWOId: u64, split_debug_inlining: bool, debug_info_for_profiling: bool, debug_info_name_table_kind: LLVM.DebugInfo.CompileUnit.NameTableKind, ranges_base_address: bool, sysroot_ptr: [*]const u8, sysroot_len: usize, sdk_ptr: [*]const u8, sdk_len: usize) ?*LLVM.DebugInfo.CompileUnit;
pub extern fn NativityLLVMDebugInfoBuilderCreateFunction(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, linkage_name_ptr: [*]const u8, linkage_name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.SubroutineType, scope_line: c_uint, flags: LLVM.DebugInfo.Node.Flags, subprogram_flags: LLVM.DebugInfo.Subprogram.Flags, declaration: ?*LLVM.DebugInfo.Subprogram) ?*LLVM.DebugInfo.Subprogram;
pub extern fn NativityLLVMDebugInfoBuilderCreateSubroutineType(builder: *LLVM.DebugInfo.Builder, parameter_types_ptr: [*]const *LLVM.DebugInfo.Type, parameter_type_count: usize, flags: LLVM.DebugInfo.Node.Flags, calling_convention: LLVM.DebugInfo.CallingConvention) ?*LLVM.DebugInfo.SubroutineType;
pub extern fn NativityLLVMDebugInfoBuilderCreateLexicalBlock(builder: *LLVM.DebugInfo.Builder, parent_scope: *LLVM.DebugInfo.Scope, parent_file: *LLVM.DebugInfo.File, line: c_uint, column: c_uint) ?*LLVM.DebugInfo.LexicalBlock;
pub extern fn NativityLLVMDebugInfoBuilderCreateParameterVariable(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, argument_index: c_uint, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, always_preserve: bool, flags: LLVM.DebugInfo.Node.Flags) ?*LLVM.DebugInfo.LocalVariable;
pub extern fn NativityLLVMDebugInfoBuilderCreateAutoVariable(builder: *LLVM.DebugInfo.Builder, scope: *LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: *LLVM.DebugInfo.File, line_number: c_uint, type: *LLVM.DebugInfo.Type, always_preserve: bool, flags: LLVM.DebugInfo.Node.Flags, alignment: u32) ?*LLVM.DebugInfo.LocalVariable; // 0 means 1 << 0 (alignment of 1)
pub extern fn NativityLLVMDebugInfoBuilderInsertDeclare(builder: *LLVM.DebugInfo.Builder, pointer: *LLVM.Value, local_variable: *LLVM.DebugInfo.LocalVariable, context: *LLVM.Context, line: c_uint, column: c_uint, scope: *LLVM.DebugInfo.Scope, basic_block: *LLVM.Value.BasicBlock) ?*LLVM.Value.Instruction;
pub extern fn NativityLLVMDebugInfoBuilderCreateBasicType(builder: *LLVM.DebugInfo.Builder, name_ptr: [*]const u8, name_len: usize, bit_count: u64, dwarf_encoding: LLVM.DebugInfo.AttributeType, flags: LLVM.DebugInfo.Node.Flags) ?*LLVM.DebugInfo.Type;
pub extern fn NativityLLVMDebugInfoBuilderCreatePointerType(builder: *LLVM.DebugInfo.Builder, element_type: *LLVM.DebugInfo.Type, pointer_bit_count: u64, alignment: u32, name_ptr: [*]const u8, name_len: usize) ?*LLVM.DebugInfo.Type.Derived;
pub extern fn NativityLLVMDebugInfoBuilderCreateStructType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: ?*LLVM.DebugInfo.File, line_number: c_uint, bit_count: u64, alignment: u32, flags: LLVM.DebugInfo.Node.Flags, derived_from: ?*LLVM.DebugInfo.Type, element_type_ptr: [*]const *LLVM.DebugInfo.Type, element_type_count: usize) ?*LLVM.DebugInfo.Type.Composite;
pub extern fn NativityLLVMDebugInfoBuilderCreateArrayType(builder: *LLVM.DebugInfo.Builder, bit_size: u64, alignment: u32, type: *LLVM.DebugInfo.Type, element_count: usize) ?*LLVM.DebugInfo.Type.Composite;
pub extern fn NativityLLVMDebugInfoBuilderCreateEnumerationType(builder: *LLVM.DebugInfo.Builder, scope: ?*LLVM.DebugInfo.Scope, name_ptr: [*]const u8, name_len: usize, file: *LLVM.DebugInfo.File, line: c_uint, bit_size: u64, alignment: u32, enumerator_ptr: [*]const *LLVM.DebugInfo.Type.Enumerator, enumerator_count: usize, underlying_type: *LLVM.DebugInfo.Type) ?*LLVM.DebugInfo.Type.Composite;
pub extern fn NativityLLVMDebugInfoBuilderCreateEnumerator(builder: *LLVM.DebugInfo.Builder, name_ptr: [*]const u8, name_len: usize, value: u64, is_unsigned: bool) ?*LLVM.DebugInfo.Type.Enumerator;
pub extern fn NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType(builder: *LLVM.DebugInfo.Builder, tag: c_uint, name_ptr: [*]const u8, name_len: usize, scope: ?*LLVM.DebugInfo.Scope, file: ?*LLVM.DebugInfo.File, line: c_uint) ?*LLVM.DebugInfo.Type.Composite;
pub extern fn NativityLLVMDebugInfoBuilderFinalizeSubprogram(builder: *LLVM.DebugInfo.Builder, subprogram: *LLVM.DebugInfo.Subprogram, function: *LLVM.Value.Function) void;
pub extern fn NativityLLVMDebugInfoBuilderFinalize(builder: *LLVM.DebugInfo.Builder) void;
pub extern fn NativityLLVMDebugInfoSubprogramGetFile(subprogram: *LLVM.DebugInfo.Subprogram) ?*LLVM.DebugInfo.File;
pub extern fn NativityLLVMDebugInfoSubprogramGetArgumentType(subprogram: *LLVM.DebugInfo.Subprogram, argument_index: usize) ?*LLVM.DebugInfo.Type;
pub extern fn NativityLLVMDebugInfoScopeToSubprogram(scope: *LLVM.DebugInfo.Scope) ?*LLVM.DebugInfo.Subprogram;
pub extern fn NativityLLVMCreateBasicBlock(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, parent_function: ?*LLVM.Value.Function, insert_before: ?*LLVM.Value.BasicBlock) ?*LLVM.Value.BasicBlock;
pub extern fn NativityLLVMBasicBlockRemoveFromParent(basic_block: *LLVM.Value.BasicBlock) void;
pub extern fn NativityLLVMBuilderSetInsertPoint(builder: *LLVM.Builder, basic_block: *LLVM.Value.BasicBlock) void;
pub extern fn NativityLLVMBuilderGetInsertBlock(builder: *LLVM.Builder) ?*LLVM.Value.BasicBlock;
pub extern fn NativityLLVMBuilderSetCurrentDebugLocation(builder: *LLVM.Builder, context: *LLVM.Context, line: c_uint, column: c_uint, scope: *LLVM.DebugInfo.Scope, function: *LLVM.Value.Function) void;
pub extern fn NativityLLVMValueSetName(value: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) void;
pub extern fn NativityLLVMValueGetType(value: *LLVM.Value) *LLVM.Type;
pub extern fn NativityLLVMArgumentGetIndex(argument: *LLVM.Value.Argument) c_uint;
pub extern fn NativityLLVMFunctionGetArguments(function: *LLVM.Value.Function, argument_ptr: [*]*LLVM.Value.Argument, argument_len: *usize) void;
pub extern fn NativityLLVMFunctionGetReturnType(function: *LLVM.Value.Function) ?*LLVM.Type;
pub extern fn NativityLLVMBuilderCreateAlloca(builder: *LLVM.Builder, type: *LLVM.Type, address_space: c_uint, array_size: ?*LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Instruction.Alloca;
pub extern fn NativityLLVMBuilderCreateStore(builder: *LLVM.Builder, value: *LLVM.Value, pointer: *LLVM.Value, is_volatile: bool) ?*LLVM.Value.Instruction.Store;
pub extern fn NativityLLVMContextGetConstantInt(context: *LLVM.Context, bit_count: c_uint, value: u64, is_signed: bool) ?*LLVM.Value.Constant.Int;
pub extern fn NativityLLVMContextGetConstString(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, null_terminate: bool) ?*LLVM.Value.Constant;
pub extern fn NativityLLVMContextGetConstArray(array_type: *LLVM.Type.Array, value_ptr: [*]const *LLVM.Value.Constant, value_count: usize) ?*LLVM.Value.Constant;
pub extern fn NativityLLVMBuilderCreateICmp(builder: *LLVM.Builder, integer_comparison: LLVM.Value.Instruction.ICmp.Kind, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value.Instruction.Load;
pub extern fn NativityLLVMBuilderCreateRet(builder: *LLVM.Builder, value: ?*LLVM.Value) ?*LLVM.Value.Instruction.Ret;
pub extern fn NativityLLVMBuilderCreateCast(builder: *LLVM.Builder, cast_type: LLVM.Value.Instruction.Cast.Type, value: *LLVM.Value, type: *LLVM.Type, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMFunctionAddAttributeKey(builder: *LLVM.Value.Function, attribute_key: LLVM.Attribute) void;
pub extern fn NativityLLVMGetVoidType(context: *LLVM.Context) ?*LLVM.Type;
pub extern fn NativityLLVMGetInlineAssembly(function_type: *LLVM.Type.Function, assembly_ptr: [*]const u8, assembly_len: usize, constraints_ptr: [*]const u8, constrains_len: usize, has_side_effects: bool, is_align_stack: bool, dialect: LLVM.Value.InlineAssembly.Dialect, can_throw: bool) ?*LLVM.Value.InlineAssembly;
pub extern fn NativityLLVMBuilderCreateCall(builder: *LLVM.Builder, function_type: *LLVM.Type.Function, callee: *LLVM.Value, argument_ptr: [*]const *LLVM.Value, argument_count: usize, name_ptr: [*]const u8, name_len: usize, fp_math_tag: ?*LLVM.Metadata.Node) ?*LLVM.Value.Instruction.Call;
pub extern fn NativityLLVMBuilderCreateUnreachable(builder: *LLVM.Builder) ?*LLVM.Value.Instruction.Unreachable;
pub extern fn NativityLLVMModuleAddGlobalVariable(module: *LLVM.Module, type: *LLVM.Type, is_constant: bool, linkage: LLVM.Linkage, initializer: ?*LLVM.Value.Constant, name_ptr: [*]const u8, name_len: usize, insert_before: ?*LLVM.Value.Constant.GlobalVariable, thread_local_mode: LLVM.ThreadLocalMode, address_space: c_uint, externally_initialized: bool) ?*LLVM.Value.Constant.GlobalVariable;
pub extern fn NativityLLVMBuilderCreateAdd(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateSub(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateMultiply(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateShiftLeft(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, no_unsigned_wrapping: bool, no_signed_wrapping: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateUDiv(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateSDiv(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateURem(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateSRem(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateLogicalShiftRight(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateArithmeticShiftRight(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize, is_exact: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateXor(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateAnd(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateOr(builder: *LLVM.Builder, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateGEP(builder: *LLVM.Builder, type: *LLVM.Type, pointer: *LLVM.Value, index_ptr: [*]const *LLVM.Value, index_count: usize, name_ptr: [*]const u8, name_len: usize, in_bounds: bool) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateBranch(builder: *LLVM.Builder, basic_block: *LLVM.Value.BasicBlock) ?*LLVM.Value.Instruction.Branch;
pub extern fn NativityLLVMBuilderCreateConditionalBranch(builder: *LLVM.Builder, condition: *LLVM.Value, true_block: *LLVM.Value.BasicBlock, false_block: *LLVM.Value.BasicBlock, branch_weights: ?*LLVM.Metadata.Node, unpredictable: ?*LLVM.Metadata.Node) ?*LLVM.Value.Instruction.Branch;
pub extern fn NativityLLVMVerifyFunction(function: *LLVM.Value.Function, message_ptr: *[*]const u8, message_len: *usize) bool;
pub extern fn NativityLLVMVerifyModule(module: *LLVM.Module, message_ptr: *[*]const u8, message_len: *usize) bool;
pub extern fn NativityLLVMModuleToString(module: *LLVM.Module, message_len: *usize) [*]const u8;
pub extern fn NativityLLVMFunctionToString(function: *LLVM.Value.Function, message_len: *usize) [*]const u8;
pub extern fn NativityLLVMGenerateMachineCode(module: *LLVM.Module, object_file_path_ptr: [*]const u8, object_file_path_len: usize, file_path_ptr: [*]const u8, file_path_len: usize) bool;
pub extern fn NativityLLVMBuilderIsCurrentBlockTerminated(builder: *LLVM.Builder) bool;
pub extern fn NativityLLVMGetUndefined(type: *LLVM.Type) ?*LLVM.Value.Constant.Undefined;
pub extern fn NativityLLVMFunctionSetCallingConvention(function: *LLVM.Value.Function, calling_convention: LLVM.Value.Function.CallingConvention) void;
pub extern fn NativityLLVMFunctionGetCallingConvention(function: *LLVM.Value.Function) LLVM.Value.Function.CallingConvention;
pub extern fn NativityLLVMFunctionSetSubprogram(function: *LLVM.Value.Function, subprogram: *LLVM.DebugInfo.Subprogram) void;
pub extern fn NativityLLVMFunctionGetSubprogram(function: *LLVM.Value.Function) ?*LLVM.DebugInfo.Subprogram;
pub extern fn NativityLLVMCallSetCallingConvention(instruction: *LLVM.Value.Instruction.Call, calling_convention: LLVM.Value.Function.CallingConvention) void;
pub extern fn NativityLLVMGetStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) ?*LLVM.Value.Constant;
pub extern fn NativityLLVMValueToConstant(value: *LLVM.Value) ?*LLVM.Value.Constant;
pub extern fn NativityLLVMValueToFunction(value: *LLVM.Value) ?*LLVM.Value.Function;
pub extern fn NativityLLVMTypeIsPointer(type: *LLVM.Type) bool;
pub extern fn NativityLLVMTypeIsInteger(type: *LLVM.Type) bool;
pub extern fn NativityLLVMTypeToStruct(type: *LLVM.Type) ?*LLVM.Type.Struct;
pub extern fn NativityLLVMTypeToFunction(type: *LLVM.Type) ?*LLVM.Type.Function;
pub extern fn NativityLLVMTypeToArray(type: *LLVM.Type) ?*LLVM.Type.Array;
pub extern fn NativityLLVMArrayTypeGetElementType(array_type: *LLVM.Type.Array) ?*LLVM.Type;
pub extern fn NativityLLVMLookupIntrinsic(name_ptr: [*]const u8, name_len: usize) LLVM.Value.IntrinsicID;
pub extern fn NativityLLVMModuleGetIntrinsicDeclaration(module: *LLVM.Module, intrinsic_id: LLVM.Value.IntrinsicID, parameter_types_ptr: [*]const *LLVM.Type, parameter_type_count: usize) ?*LLVM.Value.Function;
pub extern fn NativityLLVMContextGetIntrinsicType(context: *LLVM.Context, intrinsic_id: LLVM.Value.IntrinsicID, parameter_type_ptr: [*]const *LLVM.Type, parameter_type_count: usize) ?*LLVM.Type.Function;
pub extern fn NativityLLVMBuilderCreateExtractValue(builder: *LLVM.Builder, aggregate: *LLVM.Value, indices_ptr: [*]const c_uint, indices_len: usize, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMBuilderCreateInsertValue(builder: *LLVM.Builder, aggregate: *LLVM.Value, value: *LLVM.Value, indices_ptr: [*]const c_uint, indices_len: usize, name_ptr: [*]const u8, name_len: usize) ?*LLVM.Value;
pub extern fn NativityLLVMContextCreateGlobalStringPointer(builder: *LLVM.Builder, string_ptr: [*]const u8, string_len: usize, name_ptr: [*]const u8, name_len: usize, address_space: c_uint, module: *LLVM.Module) ?*LLVM.Value.Constant;
pub extern fn NativityLLVMCompareTypes(a: *LLVM.Type, b: *LLVM.Type) bool;
pub extern fn NativityLLVMCreatePhiNode(type: *LLVM.Type, reserved_value_count: c_uint, name_ptr: [*]const u8, name_len: usize, basic_block: ?*LLVM.Value.BasicBlock) ?*LLVM.Value.Instruction.PhiNode;
pub extern fn NativityLLVMAllocatGetAllocatedType(alloca: *LLVM.Value.Instruction.Alloca) *LLVM.Type;
pub extern fn NativityLLVMValueToAlloca(value: *LLVM.Value) ?*LLVM.Value.Instruction.Alloca;

View File

@ -6,204 +6,163 @@ pub const AutoArrayHashMap = std.AutoArrayHashMapUnmanaged;
pub const ArrayList = std.ArrayListUnmanaged;
pub const ArrayListAligned = std.ArrayListAlignedUnmanaged;
pub const AutoHashMap = std.AutoHashMapUnmanaged;
pub const BoundedArray = std.BoundedArray;
pub const HashMap = std.HashMapUnmanaged;
pub const SegmentedList = std.SegmentedList;
pub const StringHashMap = std.StringHashMapUnmanaged;
pub const StringArrayHashMap = std.StringArrayHashMapUnmanaged;
pub fn BlockList(comptime T: type) type {
pub fn BlockList(comptime T: type, comptime E: type) type {
const item_count = 64;
const Block = struct {
items: [item_count]T = undefined,
bitset: Bitset = Bitset.initEmpty(),
const Bitset = std.StaticBitSet(item_count);
fn allocateIndex(block: *@This()) !u6 {
if (block.bitset.mask != std.math.maxInt(@TypeOf(block.bitset.mask))) {
const index = @ctz(~block.bitset.mask);
block.bitset.set(index);
return @intCast(index);
} else {
return error.OutOfMemory;
}
}
};
return struct {
// TODO: make this not reallocate the whole block. Instead, use a pointer to the block as the ArrayList item
blocks: ArrayList(*Block) = .{},
len: usize = 0,
first_block: u32 = 0,
const Block = BoundedArray(T, item_count);
const List = @This();
pub const Index = packed struct(u32) {
element: u6,
block: u24,
_reserved: bool = false,
invalid: bool = false,
pub const Index = getIndexForType(T, E);
pub const ElementIndex = Index.Index;
pub const invalid = Index{
.invalid = true,
.element = 0,
.block = 0,
};
// pub const append = switch (list_type) {
// .index => appendIndexed,
// .pointer => appendPointer,
// };
// pub const addOne = switch (list_type) {
// .index => addOneIndexed,
// .pointer => addOnePointer,
// };
pub fn eq(index: Index, other: Index) bool {
return @as(u32, @bitCast(index)) == @as(u32, @bitCast(other));
}
pub fn uniqueInteger(index: Index) u32 {
assert(!index.invalid);
return @as(u30, @truncate(@as(u32, @bitCast(index))));
}
pub fn fromInteger(usize_index: usize) Index {
const index: u32 = @intCast(usize_index);
const block: u24 = @intCast(index / item_count);
const i: u6 = @intCast(index % item_count);
return .{
.element = i,
.block = block,
};
}
};
pub const Iterator = struct {
index: Index,
list: *List,
pub const Pair = struct {
index: Index,
};
pub fn nextIndex(i: *Iterator) ?Index {
// TODO: optimize with ctz and masking out already iterated indices in the bitmask
for (i.index.block..i.list.blocks.items.len) |block_index| {
for (@as(u8, i.index.element)..item_count) |element_index| {
if (i.list.blocks.items[block_index].bitset.isSet(element_index)) {
const index = Index{
.element = @intCast(element_index),
.block = @intCast(block_index),
};
i.index = index;
i.index.element +%= 1;
i.index.block = @as(u24, @intCast(block_index)) + @intFromBool(i.index.element < element_index);
return index;
}
}
}
return null;
}
pub fn nextPointer(i: *Iterator) ?*T {
if (i.nextIndex()) |index| {
const result = i.list.get(index);
return result;
} else {
return null;
}
}
};
pub fn iterator(list: *List) Iterator {
return .{
.index = Index{
.element = 0,
.block = 0,
},
.list = list,
};
pub fn wrapSplit(block: usize, element: usize) ElementIndex {
return @enumFromInt(block * item_count + element);
}
pub fn get(list: *List, index: Index) *T {
assert(!index.invalid);
return &list.blocks.items[index.block].items[index.element];
pub fn get(list: *List, index: ElementIndex) *T {
assert(index != .null);
const i: u32 = @intFromEnum(index);
const block_index = i / item_count;
const element_index = i % item_count;
const block = list.blocks.items[block_index];
const block_slice = block.buffer[0..block.len];
const element = &block_slice[element_index];
return element;
}
pub fn append(list: *List, allocator: Allocator, element: T) !Index {
pub fn append(list: *List, allocator: Allocator, element: T) !ElementIndex {
const result = try list.addOne(allocator);
list.get(result).* = element;
return result;
}
pub fn addOne(list: *List, allocator: Allocator) !Index {
try list.ensureCapacity(allocator, list.len + 1);
const max_allocation = list.blocks.items.len * item_count;
const result = switch (list.len < max_allocation) {
true => blk: {
const block = list.blocks.items[list.first_block];
if (block.allocateIndex()) |element_index| {
break :blk Index{
.element = element_index,
.block = @intCast(list.first_block),
};
} else |_| {
@panic("TODO");
}
},
false => blk: {
const block_index = list.blocks.items.len;
const new_block = try allocator.create(Block);
new_block.* = .{};
list.blocks.appendAssumeCapacity(new_block);
const element_index = new_block.allocateIndex() catch unreachable;
list.first_block += @intFromBool(block_index != 0);
break :blk Index{
.element = element_index,
.block = @intCast(block_index),
};
},
};
list.len += 1;
return result;
pub fn addOne(list: *List, allocator: Allocator) !ElementIndex {
const block_index = try list.getFreeBlock(allocator);
const block = list.blocks.items[block_index];
const index = block.len;
_ = try block.addOne();
return @enumFromInt(block_index * item_count + index);
}
pub fn ensureCapacity(list: *List, allocator: Allocator, new_capacity: usize) !void {
const max_allocation = list.blocks.items.len * item_count;
if (max_allocation < new_capacity) {
const block_count = new_capacity / item_count + @intFromBool(new_capacity % item_count != 0);
try list.blocks.ensureTotalCapacity(allocator, block_count);
fn getFreeBlock(list: *List, allocator: Allocator) !usize {
for (list.blocks.items, 0..) |block, i| {
block.ensureUnusedCapacity(1) catch continue;
return i;
} else {
const new_block = try allocator.create(Block);
new_block.* = .{};
const block_index = list.blocks.items.len;
try list.blocks.append(allocator, new_block);
return block_index;
}
}
pub fn indexOf(list: *List, elem: *const T) Index {
pub fn indexOf(list: *List, elem: *const T) ElementIndex {
const address = @intFromPtr(elem);
for (list.blocks.items, 0..) |*block, block_index| {
const base = @intFromPtr(&block.items[0]);
for (list.blocks.items, 0..) |block, block_index| {
const base = @intFromPtr(&block.buffer[0]);
const top = base + @sizeOf(T) * item_count;
if (address >= base and address < top) {
return .{
.block = @intCast(block_index),
.element = @intCast(@divExact(address - base, @sizeOf(T))),
};
const result: u32 = @intCast(block_index * item_count + @divExact(address - base, @sizeOf(T)));
return Index.wrap(result);
}
}
@panic("not found");
}
};
}
test "Bitset index allocation" {
const expect = std.testing.expect;
var block = Block{};
for (0..item_count) |expected_index| {
const new_index = try block.allocateIndex();
try expect(new_index == expected_index);
}
pub fn getIndexForType(comptime T: type, comptime E: type) type {
assert(@typeInfo(E) == .Enum);
_ = T;
const IndexType = u32;
const MAX = std.math.maxInt(IndexType);
_ = block.allocateIndex() catch return;
const EnumField = std.builtin.Type.EnumField;
comptime var fields: []const EnumField = &.{};
// comptime var enum_value: comptime_int = 0;
fields = fields ++ @typeInfo(E).Enum.fields;
return error.TestUnexpectedResult;
// for (names) |name| {
// fields = fields ++ [1]EnumField{.{
// .name = name,
// .value = enum_value,
// }};
// enum_value += 1;
// }
fields = fields ++ [1]EnumField{.{
.name = "null",
.value = MAX,
}};
const Result = @Type(.{
.Enum = .{
.tag_type = IndexType,
.fields = fields,
.decls = &.{},
.is_exhaustive = false,
},
});
return struct {
pub const Index = Result;
pub fn unwrap(this: Index) IndexType {
assert(this != .null);
return @intFromEnum(this);
}
pub fn wrap(value: IndexType) Index {
assert(value < MAX);
return @enumFromInt(value);
}
pub fn addInt(this: Index, value: IndexType) Index{
const this_int = @intFromEnum(this);
return @enumFromInt(this_int + value);
}
pub fn subInt(this: Index, value: IndexType) IndexType{
const this_int = @intFromEnum(this);
return this_int - value;
}
pub fn add(a: Index, b: Index) Index{
return @enumFromInt(@intFromEnum(a) + @intFromEnum(b));
}
pub fn sub(a: Index, b: Index) IndexType{
return @intFromEnum(a) - @intFromEnum(b);
}
};
}
pub const ListType = enum{
index,
pointer,
};
pub fn enumFromString(comptime E: type, string: []const u8) ?E {
return inline for (@typeInfo(E).Enum.fields) |enum_field| {
if (std.mem.eql(u8, string, enum_field.name)) {

View File

@ -0,0 +1,435 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const log = std.log;
const equal = std.mem.eql;
const data_structures = @import("../data_structures.zig");
const ArrayList = data_structures.ArrayList;
const enumFromString = data_structures.enumFromString;
const Compilation = @import("../Compilation.zig");
const File = Compilation.File;
const logln = Compilation.logln;
const Token = Compilation.Token;
const fs = @import("../fs.zig");
// Needed information
// Token: u8
// line: u32
// column: u16
// offset: u32
// len: u24
pub const Result = struct {
offset: Token.Index,
count: u32,
line_offset: u32,
line_count: u32,
// ids: ArrayList(Token.Id) = .{},
// token_lines: ArrayList(u32) = .{},
// file_line_offsets: ArrayList(u32) = .{},
// token_offsets: ArrayList(u32) = .{},
// token_lengths: ArrayList(u32) = .{},
time: u64 = 0,
};
pub const Logger = enum {
start,
end,
new_token,
number_literals,
pub var bitset = std.EnumSet(Logger).initMany(&.{
.new_token,
.start,
.end,
.number_literals,
});
};
pub fn analyze(allocator: Allocator, text: []const u8, token_buffer: *Token.Buffer) !Result {
assert(text.len <= std.math.maxInt(u32));
const len: u32 = @intCast(text.len);
var lexer = Result{
.offset = token_buffer.getOffset(),
.line_offset = token_buffer.getLineOffset(),
.count = 0,
.line_count = 0,
};
const time_start = std.time.Instant.now() catch unreachable;
try token_buffer.line_offsets.append(allocator, 0);
for (text, 0..) |byte, index| {
if (byte == '\n') {
try token_buffer.line_offsets.append(allocator, @intCast(index + 1));
}
}
var index: u32 = 0;
var line_index: u32 = lexer.line_offset;
try token_buffer.tokens.ensureUnusedCapacity(allocator, text.len / 4);
logln(.lexer, .end, "START LEXER - TOKEN OFFSET: {} - LINE OFFSET: {}", .{Token.unwrap(lexer.offset), lexer.line_offset});
while (index < len) {
const start_index = index;
const start_character = text[index];
const token_id: Token.Id = switch (start_character) {
'a'...'z', 'A'...'Z', '_' => blk: {
while (true) {
const ch = text[index];
if ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_' or (ch >= '0' and ch <= '9')) {
index += 1;
continue;
}
break;
}
// const identifier = text[start_index..][0 .. index - start_index];
// logln("Identifier: {s}", .{identifier});
if (start_character == 'u' or start_character == 's' and text[start_index + 1] >= '0' and text[start_index + 1] <= '9') {
var index_integer = start_index + 1;
while (text[index_integer] >= '0' and text[index_integer] <= '9') {
index_integer += 1;
}
if (index_integer == index) {
const id: Token.Id = switch (start_character) {
'u' => .keyword_unsigned_integer,
's' => .keyword_signed_integer,
else => unreachable,
};
break :blk id;
}
}
const string = text[start_index..][0 .. index - start_index];
break :blk if (enumFromString(Compilation.FixedKeyword, string)) |fixed_keyword| switch (fixed_keyword) {
inline else => |comptime_fixed_keyword| @field(Token.Id, "fixed_keyword_" ++ @tagName(comptime_fixed_keyword)),
} else if (equal(u8, string, "_")) .discard else .identifier;
},
'0'...'9' => blk: {
// Detect other non-decimal literals
if (text[index] == '0' and index + 1 < text.len) {
if (text[index + 1] == 'x') {
index += 2;
} else if (text[index + 1] == 'b') {
index += 2;
} else if (text[index + 1] == 'o') {
index += 2;
}
}
while (text[index] >= '0' and text[index] <= '9' or text[index] >= 'a' and text[index] <= 'f' or text[index] >= 'A' and text[index] <= 'F') {
index += 1;
}
break :blk .number_literal;
},
'\'' => blk: {
index += 1;
index += @intFromBool(text[index] == '\'');
index += 1;
const is_end_char_literal = text[index] == '\'';
index += @intFromBool(is_end_char_literal);
if (!is_end_char_literal) unreachable;
break :blk .character_literal;
},
'"' => blk: {
index += 1;
while (true) {
if (text[index] == '"' and text[index - 1] != '"') {
break;
}
index += 1;
}
index += 1;
break :blk .string_literal;
},
'#' => blk: {
index += 1;
// const start_intrinsic = index;
while (true) {
const ch = text[index];
if ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_') {
index += 1;
} else break;
}
// const end_intrinsic = index;
// const intrinsic_identifier = text[start_intrinsic..][0 .. end_intrinsic - start_intrinsic];
// _ = intrinsic_identifier;
break :blk .intrinsic;
},
'\n' => {
index += 1;
line_index += 1;
continue;
},
' ', '\r', '\t' => {
index += 1;
continue;
},
'(' => blk: {
index += 1;
break :blk .operator_left_parenthesis;
},
')' => blk: {
index += 1;
break :blk .operator_right_parenthesis;
},
'{' => blk: {
index += 1;
break :blk .operator_left_brace;
},
'}' => blk: {
index += 1;
break :blk .operator_right_brace;
},
'[' => blk: {
index += 1;
break :blk .operator_left_bracket;
},
']' => blk: {
index += 1;
break :blk .operator_right_bracket;
},
'<' => blk: {
index += 1;
switch (text[index]) {
'<' => {
index += 1;
break :blk switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_shift_left_assign;
},
else => .operator_shift_left,
};
},
'=' => {
index += 1;
break :blk .operator_compare_less_equal;
},
else =>break :blk .operator_compare_less,
}
},
'>' => blk: {
index += 1;
switch (text[index]) {
'>' => {
index += 1;
break :blk switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_shift_right_assign;
},
else => .operator_shift_right,
};
},
'=' => {
index += 1;
break :blk .operator_compare_greater_equal;
},
else =>break :blk .operator_compare_greater,
}
},
';' => blk: {
index += 1;
break :blk .operator_semicolon;
},
'@' => blk: {
index += 1;
break :blk .operator_at;
},
',' => blk: {
index += 1;
break :blk .operator_comma;
},
'.' => blk: {
index += 1;
break :blk .operator_dot;
},
':' => blk: {
index += 1;
break :blk .operator_colon;
},
'!' => blk: {
index += 1;
switch (text[index]) {
'=' => {
index += 1;
break :blk .operator_compare_not_equal;
},
else => break :blk .operator_bang,
}
},
'=' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_compare_equal;
},
'>' => b: {
index += 1;
break :b .operator_switch_case;
},
else => .operator_assign,
};
break :blk token_id;
},
'+' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_add_assign;
},
else => .operator_add,
};
break :blk token_id;
},
'-' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_sub_assign;
},
else => .operator_minus,
};
break :blk token_id;
},
'*' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_mul_assign;
},
else => .operator_asterisk,
};
break :blk token_id;
},
'/' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_div_assign;
},
else => .operator_div,
};
break :blk token_id;
},
'%' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_mod_assign;
},
else => .operator_mod,
};
break :blk token_id;
},
'|' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_or_assign;
},
else => .operator_bar,
};
break :blk token_id;
},
'&' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_and_assign;
},
else => .operator_ampersand,
};
break :blk token_id;
},
'^' => blk: {
index += 1;
const token_id: Token.Id = switch (text[index]) {
'=' => b: {
index += 1;
break :b .operator_xor_assign;
},
else => .operator_xor,
};
break :blk token_id;
},
'?' => blk: {
index += 1;
break :blk .operator_optional;
},
'$' => blk: {
index += 1;
break :blk .operator_dollar;
},
else => |ch| {
std.debug.panic("NI: '{c}'", .{ch});
},
};
const end_index = index;
const token_length = end_index - start_index;
token_buffer.tokens.appendAssumeCapacity(.{
.id = token_id,
.offset = start_index,
.length = token_length,
.line = line_index,
});
const line_offset = token_buffer.line_offsets.items[line_index];
const column = start_index - line_offset;
logln(.lexer, .new_token, "T at line {}, column {}, byte offset {}, with length {} -line offset: {}- ({s})", .{line_index, column, start_index, token_length, line_offset, @tagName(token_id)});
}
logln(.lexer, .end, "END LEXER - TOKEN OFFSET: {} - LINE OFFSET: {}", .{Token.unwrap(lexer.offset), lexer.line_offset});
lexer.count = Token.sub(token_buffer.getOffset(), lexer.offset);
lexer.line_count = token_buffer.getLineOffset() - lexer.line_offset;
const time_end = std.time.Instant.now() catch unreachable;
lexer.time = time_end.since(time_start);
return lexer;
}

View File

@ -1,265 +0,0 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const log = std.log;
const equal = std.mem.eql;
const data_structures = @import("../data_structures.zig");
const ArrayList = data_structures.ArrayList;
const enumFromString = data_structures.enumFromString;
const Compilation = @import("../Compilation.zig");
const File = Compilation.File;
const logln = Compilation.logln;
const fs = @import("../fs.zig");
// TODO: switch to packed struct when speed is important
pub const Token = struct {
start: u32,
len: u24,
id: Id,
pub const Id = enum(u8) {
eof = 0x00,
keyword_unsigned_integer = 0x01,
keyword_signed_integer = 0x02,
identifier = 0x03,
number_literal = 0x04,
string_literal = 0x05,
discard = 0x06,
bang = '!', // 0x21
hash = '#', // 0x23
dollar_sign = '$', // 0x24
modulus = '%', // 0x25
ampersand = '&', // 0x26
left_parenthesis = '(', // 0x28
right_parenthesis = ')', // 0x29
asterisk = '*', // 0x2a
plus = '+', // 0x2b
comma = ',', // 0x2c
minus = '-', // 0x2d
period = '.', // 0x2e
slash = '/', // 0x2f
colon = ':', // 0x3a
semicolon = ';', // 0x3b
less = '<', // 0x3c
equal = '=', // 0x3d
greater = '>', // 0x3e
question_mark = '?', // 0x3f
at = '@', // 0x40
left_bracket = '[', // 0x5b
backlash = '\\', // 0x5c
right_bracket = ']', // 0x5d
caret = '^', // 0x5e
underscore = '_', // 0x5f
grave = '`', // 0x60
left_brace = '{', // 0x7b
vertical_bar = '|', // 0x7c
right_brace = '}', // 0x7d
tilde = '~', // 0x7e
fixed_keyword_function = 0x7f,
fixed_keyword_const = 0x80,
fixed_keyword_var = 0x81,
fixed_keyword_void = 0x82,
fixed_keyword_noreturn = 0x83,
fixed_keyword_comptime = 0x84,
fixed_keyword_while = 0x85,
fixed_keyword_bool = 0x86,
fixed_keyword_true = 0x87,
fixed_keyword_false = 0x88,
fixed_keyword_fn = 0x89,
fixed_keyword_unreachable = 0x8a,
fixed_keyword_return = 0x8b,
fixed_keyword_ssize = 0x8c,
fixed_keyword_usize = 0x8d,
fixed_keyword_switch = 0x8e,
fixed_keyword_if = 0x8f,
fixed_keyword_else = 0x90,
fixed_keyword_struct = 0x91,
fixed_keyword_enum = 0x92,
fixed_keyword_union = 0x93,
fixed_keyword_extern = 0x94,
fixed_keyword_null = 0x95,
fixed_keyword_align = 0x96,
fixed_keyword_export = 0x97,
fixed_keyword_cc = 0x98,
fixed_keyword_for = 0x99,
fixed_keyword_undefined = 0x9a,
fixed_keyword_break = 0x9b,
};
pub const Index = u32;
};
pub const FixedKeyword = enum {
@"comptime",
@"const",
@"var",
void,
noreturn,
function,
@"while",
bool,
true,
false,
@"fn",
@"unreachable",
@"return",
ssize,
usize,
@"switch",
@"if",
@"else",
@"struct",
@"enum",
@"union",
@"extern",
null,
@"align",
@"export",
cc,
@"for",
undefined,
@"break",
};
pub const Result = struct {
tokens: ArrayList(Token),
time: u64,
};
pub const Logger = enum {
main,
new_token,
number_literals,
pub var bitset = std.EnumSet(Logger).initMany(&.{
// .new_token,
.number_literals,
});
};
pub fn analyze(allocator: Allocator, text: []const u8, file_index: File.Index) !Result {
_ = file_index;
const time_start = std.time.Instant.now() catch unreachable;
var tokens = try ArrayList(Token).initCapacity(allocator, text.len / 8);
var index: usize = 0;
while (index < text.len) {
const start_index = index;
const start_character = text[index];
const token_id: Token.Id = switch (start_character) {
'a'...'z', 'A'...'Z', '_' => blk: {
while (true) {
const ch = text[index];
if ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_' or (ch >= '0' and ch <= '9')) {
index += 1;
continue;
}
break;
}
// const identifier = text[start_index..][0 .. index - start_index];
// logln("Identifier: {s}", .{identifier});
if (start_character == 'u' or start_character == 's') {
var index_integer = start_index + 1;
while (text[index_integer] >= '0' and text[index_integer] <= '9') {
index_integer += 1;
}
if (index_integer == index) {
const id: Token.Id = switch (start_character) {
'u' => .keyword_unsigned_integer,
's' => .keyword_signed_integer,
else => unreachable,
};
break :blk id;
}
}
const string = text[start_index..][0 .. index - start_index];
break :blk if (enumFromString(FixedKeyword, string)) |fixed_keyword| switch (fixed_keyword) {
inline else => |comptime_fixed_keyword| @field(Token.Id, "fixed_keyword_" ++ @tagName(comptime_fixed_keyword)),
} else if (equal(u8, string, "_")) .discard else .identifier;
},
'0'...'9' => blk: {
// Detect other non-decimal literals
if (text[index] == '0' and index + 1 < text.len) {
logln(.lexer, .number_literals, "Number starts with 0. Checking for non-decimal literals...", .{});
if (text[index + 1] == 'x') {
logln(.lexer, .number_literals, "Hex", .{});
index += 2;
} else if (text[index + 1] == 'b') {
logln(.lexer, .number_literals, "Bin", .{});
index += 2;
} else if (text[index + 1] == 'o') {
logln(.lexer, .number_literals, "Decimal", .{});
index += 2;
}
}
while (text[index] >= '0' and text[index] <= '9' or text[index] >= 'a' and text[index] <= 'f' or text[index] >= 'A' and text[index] <= 'F') {
index += 1;
}
break :blk .number_literal;
},
'\'' => {
unreachable;
},
'"' => blk: {
index += 1;
while (true) {
if (text[index] == '"' and text[index - 1] != '"') {
break;
}
index += 1;
}
index += 1;
break :blk .string_literal;
},
' ', '\n', '\r', '\t' => {
index += 1;
continue;
},
'(', ')', '{', '}', '[', ']', '=', ';', '#', '@', ',', '.', ':', '>', '<', '!', '+', '-', '*', '\\', '/', '&', '|', '^', '?', '$' => |operator| blk: {
index += 1;
break :blk @enumFromInt(operator);
},
else => |ch| {
std.debug.panic("NI: '{c}'", .{ch});
},
};
const end_index = index;
const token = Token{
.start = @intCast(start_index),
.len = @intCast(end_index - start_index),
.id = token_id,
};
logln(.lexer, .new_token, "New token {s} added: {s}", .{ @tagName(token.id), text[token.start..][0..token.len] });
try tokens.append(allocator, token);
}
for (tokens.items, 0..) |token, i| {
logln(.lexer, .main, "#{} {s}\n", .{ i, @tagName(token.id) });
}
const time_end = std.time.Instant.now() catch unreachable;
const time = time_end.since(time_start);
return .{
.tokens = tokens,
.time = time,
};
}

File diff suppressed because it is too large Load Diff

View File

@ -5,10 +5,8 @@ const Compilation = @import("Compilation.zig");
pub const panic = Compilation.panic;
pub fn main() !void {
const GPA = std.heap.GeneralPurposeAllocator(.{});
var gpa = GPA{};
try Compilation.init(gpa.allocator());
var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
try Compilation.init(arena_allocator.allocator());
}
test {

231
build.zig
View File

@ -3,19 +3,238 @@ var all: bool = false;
pub fn build(b: *std.Build) !void {
all = b.option(bool, "all", "All") orelse false;
const target = b.standardTargetOptions(.{});
const optimization = b.standardOptimizeOption(.{});
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true;
const llvm_debug = b.option(bool, "llvm_debug", "Use LLVM in the debug version") orelse false;
const llvm_debug_path = b.option([]const u8, "llvm_debug_path", "LLVM debug path") orelse "../dev/llvm-17-static-debug";
const llvm_release_path = b.option([]const u8, "llvm_release_path", "LLVM release path") orelse "../dev/llvm-17-static-release";
const target_query = try std.zig.CrossTarget.parse(.{
.arch_os_abi = "native-linux-musl",
});
const target = b.resolveTargetQuery(target_query);
const exe = b.addExecutable(.{
.name = "nat",
.root_source_file = .{ .path = "bootstrap/main.zig" },
.target = target,
.optimize = optimization,
.use_llvm = use_llvm,
.use_lld = false,
.use_llvm = true,
.use_lld = true,
});
exe.unwind_tables = false;
exe.omit_frame_pointer = false;
exe.formatted_panics = false;
exe.root_module.unwind_tables = false;
exe.root_module.omit_frame_pointer = false;
const llvm_dir = if (llvm_debug) llvm_debug_path else llvm_release_path;
const llvm_include_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_dir, "/include" });
const llvm_lib_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_dir, "/lib" });
exe.linkLibC();
exe.linkLibCpp();
exe.addIncludePath(std.Build.LazyPath.relative(llvm_include_dir));
exe.addCSourceFile(.{
.file = std.Build.LazyPath.relative("bootstrap/backend/llvm.cpp"),
.flags = &.{"-g"},
});
const llvm_libraries = [_][]const u8{
"libLLVMAArch64AsmParser.a",
"libLLVMAArch64CodeGen.a",
"libLLVMAArch64Desc.a",
"libLLVMAArch64Disassembler.a",
"libLLVMAArch64Info.a",
"libLLVMAArch64Utils.a",
"libLLVMAggressiveInstCombine.a",
"libLLVMAMDGPUAsmParser.a",
"libLLVMAMDGPUCodeGen.a",
"libLLVMAMDGPUDesc.a",
"libLLVMAMDGPUDisassembler.a",
"libLLVMAMDGPUInfo.a",
"libLLVMAMDGPUTargetMCA.a",
"libLLVMAMDGPUUtils.a",
"libLLVMAnalysis.a",
"libLLVMARMAsmParser.a",
"libLLVMARMCodeGen.a",
"libLLVMARMDesc.a",
"libLLVMARMDisassembler.a",
"libLLVMARMInfo.a",
"libLLVMARMUtils.a",
"libLLVMAsmParser.a",
"libLLVMAsmPrinter.a",
"libLLVMAVRAsmParser.a",
"libLLVMAVRCodeGen.a",
"libLLVMAVRDesc.a",
"libLLVMAVRDisassembler.a",
"libLLVMAVRInfo.a",
"libLLVMBinaryFormat.a",
"libLLVMBitReader.a",
"libLLVMBitstreamReader.a",
"libLLVMBitWriter.a",
"libLLVMBPFAsmParser.a",
"libLLVMBPFCodeGen.a",
"libLLVMBPFDesc.a",
"libLLVMBPFDisassembler.a",
"libLLVMBPFInfo.a",
"libLLVMCFGuard.a",
"libLLVMCFIVerify.a",
"libLLVMCodeGen.a",
"libLLVMCodeGenTypes.a",
"libLLVMCore.a",
"libLLVMCoroutines.a",
"libLLVMCoverage.a",
"libLLVMDebugInfoBTF.a",
"libLLVMDebugInfoCodeView.a",
"libLLVMDebuginfod.a",
"libLLVMDebugInfoDWARF.a",
"libLLVMDebugInfoGSYM.a",
"libLLVMDebugInfoLogicalView.a",
"libLLVMDebugInfoMSF.a",
"libLLVMDebugInfoPDB.a",
"libLLVMDemangle.a",
"libLLVMDiff.a",
"libLLVMDlltoolDriver.a",
"libLLVMDWARFLinker.a",
"libLLVMDWARFLinkerParallel.a",
"libLLVMDWP.a",
"libLLVMExecutionEngine.a",
"libLLVMExtensions.a",
"libLLVMFileCheck.a",
"libLLVMFrontendHLSL.a",
"libLLVMFrontendOpenACC.a",
"libLLVMFrontendOpenMP.a",
"libLLVMFuzzerCLI.a",
"libLLVMFuzzMutate.a",
"libLLVMGlobalISel.a",
"libLLVMHexagonAsmParser.a",
"libLLVMHexagonCodeGen.a",
"libLLVMHexagonDesc.a",
"libLLVMHexagonDisassembler.a",
"libLLVMHexagonInfo.a",
"libLLVMInstCombine.a",
"libLLVMInstrumentation.a",
"libLLVMInterfaceStub.a",
"libLLVMInterpreter.a",
"libLLVMipo.a",
"libLLVMIRPrinter.a",
"libLLVMIRReader.a",
"libLLVMJITLink.a",
"libLLVMLanaiAsmParser.a",
"libLLVMLanaiCodeGen.a",
"libLLVMLanaiDesc.a",
"libLLVMLanaiDisassembler.a",
"libLLVMLanaiInfo.a",
"libLLVMLibDriver.a",
"libLLVMLineEditor.a",
"libLLVMLinker.a",
"libLLVMLoongArchAsmParser.a",
"libLLVMLoongArchCodeGen.a",
"libLLVMLoongArchDesc.a",
"libLLVMLoongArchDisassembler.a",
"libLLVMLoongArchInfo.a",
"libLLVMLTO.a",
"libLLVMMC.a",
"libLLVMMCA.a",
"libLLVMMCDisassembler.a",
"libLLVMMCJIT.a",
"libLLVMMCParser.a",
"libLLVMMipsAsmParser.a",
"libLLVMMipsCodeGen.a",
"libLLVMMipsDesc.a",
"libLLVMMipsDisassembler.a",
"libLLVMMipsInfo.a",
"libLLVMMIRParser.a",
"libLLVMMSP430AsmParser.a",
"libLLVMMSP430CodeGen.a",
"libLLVMMSP430Desc.a",
"libLLVMMSP430Disassembler.a",
"libLLVMMSP430Info.a",
"libLLVMNVPTXCodeGen.a",
"libLLVMNVPTXDesc.a",
"libLLVMNVPTXInfo.a",
"libLLVMObjCARCOpts.a",
"libLLVMObjCopy.a",
"libLLVMObject.a",
"libLLVMObjectYAML.a",
"libLLVMOption.a",
"libLLVMOrcJIT.a",
"libLLVMOrcShared.a",
"libLLVMOrcTargetProcess.a",
"libLLVMPasses.a",
"libLLVMPowerPCAsmParser.a",
"libLLVMPowerPCCodeGen.a",
"libLLVMPowerPCDesc.a",
"libLLVMPowerPCDisassembler.a",
"libLLVMPowerPCInfo.a",
"libLLVMProfileData.a",
"libLLVMRemarks.a",
"libLLVMRISCVAsmParser.a",
"libLLVMRISCVCodeGen.a",
"libLLVMRISCVDesc.a",
"libLLVMRISCVDisassembler.a",
"libLLVMRISCVInfo.a",
"libLLVMRISCVTargetMCA.a",
"libLLVMRuntimeDyld.a",
"libLLVMScalarOpts.a",
"libLLVMSelectionDAG.a",
"libLLVMSparcAsmParser.a",
"libLLVMSparcCodeGen.a",
"libLLVMSparcDesc.a",
"libLLVMSparcDisassembler.a",
"libLLVMSparcInfo.a",
"libLLVMSupport.a",
"libLLVMSymbolize.a",
"libLLVMSystemZAsmParser.a",
"libLLVMSystemZCodeGen.a",
"libLLVMSystemZDesc.a",
"libLLVMSystemZDisassembler.a",
"libLLVMSystemZInfo.a",
"libLLVMTableGen.a",
"libLLVMTableGenCommon.a",
"libLLVMTableGenGlobalISel.a",
"libLLVMTarget.a",
"libLLVMTargetParser.a",
"libLLVMTextAPI.a",
"libLLVMTransformUtils.a",
"libLLVMVEAsmParser.a",
"libLLVMVECodeGen.a",
"libLLVMVectorize.a",
"libLLVMVEDesc.a",
"libLLVMVEDisassembler.a",
"libLLVMVEInfo.a",
"libLLVMWebAssemblyAsmParser.a",
"libLLVMWebAssemblyCodeGen.a",
"libLLVMWebAssemblyDesc.a",
"libLLVMWebAssemblyDisassembler.a",
"libLLVMWebAssemblyInfo.a",
"libLLVMWebAssemblyUtils.a",
"libLLVMWindowsDriver.a",
"libLLVMWindowsManifest.a",
"libLLVMX86AsmParser.a",
"libLLVMX86CodeGen.a",
"libLLVMX86Desc.a",
"libLLVMX86Disassembler.a",
"libLLVMX86Info.a",
"libLLVMX86TargetMCA.a",
"libLLVMXCoreCodeGen.a",
"libLLVMXCoreDesc.a",
"libLLVMXCoreDisassembler.a",
"libLLVMXCoreInfo.a",
"libLLVMXRay.a",
// Zlib
"libz.a",
"libzstd.a",
//LLD
"liblldCOFF.a",
"liblldCommon.a",
"liblldELF.a",
"liblldMachO.a",
"liblldMinGW.a",
"liblldWasm.a",
};
inline for (llvm_libraries) |llvm_library| {
exe.addObjectFile(std.Build.LazyPath.relative(try std.mem.concat(b.allocator, u8, &.{ llvm_lib_dir, "/", llvm_library })));
}
const install_exe = b.addInstallArtifact(exe, .{});
b.getInstallStep().dependOn(&install_exe.step);

85
ci.sh
View File

@ -1,8 +1,19 @@
#!/usr/bin/env bash
argument_count=$#;
extra_args=""
use_debug="true"
if [ $argument_count -ne 0 ]; then
llvm_debug_path=$1
llvm_release_path=$2
use_debug="false"
extra_args="-Dllvm_debug_path=$llvm_debug_path -Dllvm_release_path=$llvm_release_path"
fi
echo -e "\e[90mCompiling Nativity with Zig...\e[0m"
nativity_use_llvm=true
zig build -Duse_llvm=$nativity_use_llvm
zig build -Dllvm_debug=$use_debug $extra_args
if [[ "$?" != 0 ]]; then
exit 1
fi
failed_test_count=0
passed_test_count=0
test_directory_name=test
@ -57,41 +68,41 @@ do
test_i=$(($test_i + 1))
done
for integral_test_case in $integral_test_directory_files
do
MY_TESTNAME=${integral_test_case##*/}
cd test/integral/$MY_TESTNAME
$nat_compiler
if [[ "$?" == "0" ]]; then
passed_compilation_count=$(($passed_compilation_count + 1))
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
nat/$MY_TESTNAME
if [[ "$?" == "0" ]]; then
passed_test_count=$(($passed_test_count + 1))
result="\e[32mPASSED\e[0m"
else
failed_test_count=$(($failed_test_count + 1))
result="\e[31mFAILED\e[0m"
failed_tests+=("$test_i. $MY_TESTNAME")
fi
ran_test_count=$(($ran_test_count + 1))
else
result="\e[31mOS NOT SUPPORTED\e[0m"
fi
else
failed_compilation_count=$(($failed_compilation_count + 1))
result="\e[31mCOMPILATION FAILURE\e[0m"
failed_compilations+=("$test_i. $MY_TESTNAME")
fi
echo -e "[$test_i/$total_test_count] [$result] [INTEGRAL] $MY_TESTNAME"
test_i=$(($test_i + 1))
cd $my_current_directory
done
# for integral_test_case in $integral_test_directory_files
# do
# MY_TESTNAME=${integral_test_case##*/}
# cd test/integral/$MY_TESTNAME
# $nat_compiler
#
# if [[ "$?" == "0" ]]; then
# passed_compilation_count=$(($passed_compilation_count + 1))
# if [[ "$OSTYPE" == "linux-gnu"* ]]; then
# nat/$MY_TESTNAME
#
# if [[ "$?" == "0" ]]; then
# passed_test_count=$(($passed_test_count + 1))
# result="\e[32mPASSED\e[0m"
# else
# failed_test_count=$(($failed_test_count + 1))
# result="\e[31mFAILED\e[0m"
# failed_tests+=("$test_i. $MY_TESTNAME")
# fi
#
# ran_test_count=$(($ran_test_count + 1))
# else
# result="\e[31mOS NOT SUPPORTED\e[0m"
# fi
# else
# failed_compilation_count=$(($failed_compilation_count + 1))
# result="\e[31mCOMPILATION FAILURE\e[0m"
# failed_compilations+=("$test_i. $MY_TESTNAME")
# fi
#
# echo -e "[$test_i/$total_test_count] [$result] [INTEGRAL] $MY_TESTNAME"
#
# test_i=$(($test_i + 1))
# cd $my_current_directory
# done
printf "\n"
echo -e "\e[35m[SUMMARY]\e[0m"

View File

@ -12,7 +12,7 @@ const Executable = struct{
const compile = fn(executable: Executable) bool {
const argument_count = std.start.argument_count;
const argument_values = std.start.argument_values;
assert(ok = argument_count == 3);
assert(ok = argument_count >= 3);
const compiler_path = argument_values[2];
const result = executable.compile_with_compiler_path(compiler_path);

View File

@ -17,5 +17,4 @@ const Abi = enum{
const CallingConvention = enum{
system_v,
naked,
};

View File

@ -9,7 +9,7 @@ const system = switch (current) {
const exit = fn(exit_code: s32) noreturn {
switch (current) {
.linux => _ = #syscall(#cast(linux.Syscall.exit_group), exit_code),
.linux => _ = #syscall(#cast(linux.Syscall.exit_group), #cast(exit_code)),
.macos => macos.exit(exit_code),
.windows => windows.ExitProcess(exit_code),
}
@ -30,7 +30,7 @@ const FileDescriptor = struct{
switch (current) {
.linux => {
const len: usize = #min(max_file_operation_byte_count, bytes.len);
if (linux.unwrapSyscall(syscall_result = #syscall(#cast(linux.Syscall.read), file_descriptor.handle, #cast(bytes.ptr), len))) |byte_count| {
if (linux.unwrapSyscall(syscall_result = #syscall(#cast(linux.Syscall.read), #cast(file_descriptor.handle), #cast(bytes.ptr), len))) |byte_count| {
return byte_count;
} else {
return null;
@ -47,7 +47,7 @@ const FileDescriptor = struct{
switch (current) {
.linux => {
const len: usize = #min(max_file_operation_byte_count, bytes.len);
const raw_result = #syscall(#cast(linux.Syscall.write), file_descriptor.handle, #cast(bytes.ptr), len);
const raw_result = #syscall(#cast(linux.Syscall.write), #cast(file_descriptor.handle), #cast(bytes.ptr), len);
if (linux.unwrapSyscall(syscall_result = raw_result)) |byte_count| {
return byte_count;
} else {

View File

@ -411,7 +411,7 @@ const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
}
const mmap = fn(address: ?[&]u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, fd: s32, offset: u64) usize {
const result = #syscall(#cast(Syscall.mmap), #cast(address), length, #cast(protection_flags), #cast(map_flags), fd, offset);
const result = #syscall(#cast(Syscall.mmap), #cast(address), length, #cast(protection_flags), #cast(map_flags), #cast(fd), offset);
return result;
}

View File

@ -8,7 +8,7 @@ comptime {
}
}
const _start = fn () noreturn export cc(.naked) {
const _start = fn naked, export () noreturn {
#asm({
xor ebp, ebp;
mov rdi, rsp;
@ -21,7 +21,7 @@ var argument_count: usize = 0;
var argument_values: [&]const [&:0]const u8 = undefined;
var environment_values: [&:null]const ?[&:null]const u8 = undefined;
const start = fn(argc_argv_address: usize) noreturn export {
const start = fn export (argc_argv_address: usize) noreturn {
var argument_address_iterator = argc_argv_address;
const argument_count_ptr: &usize = #cast(argument_address_iterator);
argument_count = argument_count_ptr.@;
@ -33,6 +33,6 @@ const start = fn(argc_argv_address: usize) noreturn export {
std.os.exit(exit_code = result);
}
const main = fn(argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 export {
const main = fn export (argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 {
return #import("main").main();
}

View File

@ -21,6 +21,38 @@ const print = fn(bytes: []const u8) void {
_ = file_writer.writeAll(bytes);
}
const format_usize = fn(n: usize, buffer: &[65]u8) []u8 {
var index: usize = buffer.len;
var absolute = n;
while (true) {
const digit: u8 = #cast(absolute % 10);
index -= 1;
buffer[index] = '0' + digit;
absolute /= 10;
if (absolute == 0) {
break;
}
}
return buffer[index..];
}
const print_usize = fn(n: usize) void {
var buffer: [65]u8 = undefined;
const bytes = format_usize(n, buffer = buffer.&);
const file_descriptor = os.StdFileDescriptor.get(descriptor = .stdout);
const file_writer = FileWriter{
.descriptor = file_descriptor,
};
_ = file_writer.writeAll(bytes);
}
const print_u8 = fn(n: u8) void {
print_usize(n);
}
const Allocator = struct {
handler: &const fn(allocator: &Allocator, old_ptr: ?[&]const u8, old_size: usize, new_size: usize, alignment: u16) ?[&]u8,
@ -135,6 +167,25 @@ const copy_bytes = fn(destination: []u8, source: []const u8) void {
}
}
const concatenate_bytes = fn(allocator: &Allocator, slices: []const []const u8) ?[]u8 {
var total_byte_count: usize = 0;
for (slices) |slice| {
total_byte_count += slice.len;
}
if (allocator.allocate(total_byte_count, 1)) |bytes| {
var offset: usize = 0;
for (slice) |slice| {
copy_bytes(bytes[offset..][0..slice.len], slice);
offset += slice.len;
}
return bytes;
} else {
return null;
}
}
const Target = struct {
cpu: builtin.Cpu,
os: builtin.Os,

View File

@ -0,0 +1,12 @@
const main = fn() s32 {
var i: s32 = 0;
const j: s32 = 5;
for (0..10) |_| {
if (i == j) {
break;
}
i += 1;
}
return i - j;
}

View File

@ -0,0 +1,3 @@
const main = fn() s32 {
return 0;
}

View File

@ -0,0 +1,30 @@
const std = #import("std");
const print = std.print;
const count_slice_byte_count = fn(slices: []const []const u8) usize {
var byte_count: usize = 0;
for (slices) |slice| {
byte_count += slice.len;
}
return byte_count;
}
const print_values = fn(slice: []const u8) void {
for (slice, 0..) |value, index| {
std.print_usize(n = index);
std.print(bytes = ": ");
std.print_u8(n = value);
std.print(bytes = "\n");
}
}
const main = fn () s32 {
const a = [_]u8{1, 1, 4, 5, 6};
const b = [_]u8{1, 4, 6};
const expected_result: usize = a.len + b.len;
const result = count_slice_byte_count(slices = .{a.&, b.&}.&);
print_values(slice = a.&);
return #cast(expected_result - result);
}

View File

@ -0,0 +1,8 @@
const foo = fn(slice: []u8) ?[]u8 {
return slice[0..1];
}
const main = fn() s32 {
_ = foo(slice = .{ 0, 1, 2, 3 }.&);
return 0;
}

View File

@ -2,5 +2,6 @@ const main = fn() s32 {
const a: u32 = 0xffff;
const b: u32 = 0xffff0000;
const c: u32 = 0xffffffff;
return c - (a | b);
const result = c - (a | b);
return #cast(result);
}

View File

@ -0,0 +1,14 @@
const main = fn () s32{
const a: [4]u8 = .{1, 2, 3, 4};
const b: []const []const u8 = .{a.&}.&;
var sum: u8 = 0;
for (b) |b_slice| {
for (b_slice) |a_element| {
sum += a_element;
}
}
return #cast(sum - 10);
}

View File

@ -0,0 +1,6 @@
const main = fn () s32{
const a: [4]u8 = .{1, 2, 3, 4};
const b: []const []const u8 = .{a.&}.&;
return #cast(b[0][0] - 1);
}

View File

@ -0,0 +1,10 @@
const main = fn () s32 {
_ = foo();
return 0;
}
const foo = fn () []u8 {
var buffer: [5]u8 = undefined;
const buffer_ptr: &[5]u8 = buffer.&;
return buffer_ptr[2..];
}