Implement basic C ABI support
This commit is contained in:
parent
953e0b7013
commit
ac3923f4d3
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -14,15 +14,17 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
self_hosted_linux:
|
||||
runs-on: [ self-hosted, Linux, x64 ]
|
||||
#runs-on: [ self-hosted, Linux, x64 ]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test
|
||||
run: |
|
||||
zig build test -Dself_hosted_ci=true -Dstatic=true -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native
|
||||
zig build test -Dself_hosted_ci=true -Dstatic=false
|
||||
echo "TODO"
|
||||
#zig build test -Dself_hosted_ci=true -Dstatic=true -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native
|
||||
#zig build test -Dself_hosted_ci=true -Dstatic=false
|
||||
# macos_m1:
|
||||
# runs-on: macos-14
|
||||
# timeout-minutes: 15
|
||||
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -12,7 +12,7 @@
|
||||
"args": [
|
||||
"exe",
|
||||
"-main_source_file",
|
||||
"test/standalone/hello_world/main.nat"
|
||||
"test/build/c-abi/main.nat",
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
},
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,3 +1,4 @@
|
||||
{
|
||||
"zig.initialSetupDone": true
|
||||
"zig.initialSetupDone": true,
|
||||
"cmake.configureOnOpen": false
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,7 @@ pub const LLVM = struct {
|
||||
llvm_instruction_map: MyHashMap(Compilation.Instruction.Index, *LLVM.Value) = .{},
|
||||
llvm_value_map: MyHashMap(Compilation.V, *LLVM.Value) = .{},
|
||||
llvm_block_map: MyHashMap(Compilation.BasicBlock.Index, *LLVM.Value.BasicBlock) = .{},
|
||||
llvm_external_functions: MyHashMap(*Compilation.Debug.Declaration.Global, *LLVM.Value.Constant.Function) = .{},
|
||||
global_variable_map: MyHashMap(*Compilation.Debug.Declaration.Global, *LLVM.Value.Constant.GlobalVariable) = .{},
|
||||
scope_map: MyHashMap(*Compilation.Debug.Scope, *LLVM.DebugInfo.Scope) = .{},
|
||||
pointer_type: ?*LLVM.Type.Pointer = null,
|
||||
@ -46,11 +47,20 @@ pub const LLVM = struct {
|
||||
return_phi_node: ?*LLVM.Value.Instruction.PhiNode = null,
|
||||
scope: *LLVM.DebugInfo.Scope = undefined,
|
||||
file: *LLVM.DebugInfo.File = undefined,
|
||||
attributes: Attributes,
|
||||
// subprogram: *LLVM.DebugInfo.Subprogram = undefined,
|
||||
arg_index: u32 = 0,
|
||||
tag_count: c_uint = 0,
|
||||
inside_branch: bool = false,
|
||||
|
||||
pub const Attributes = struct {
|
||||
noreturn: *Attribute,
|
||||
naked: *Attribute,
|
||||
nounwind: *Attribute,
|
||||
inreg: *Attribute,
|
||||
@"noalias": *Attribute,
|
||||
};
|
||||
|
||||
pub const Linkage = enum(c_uint) {
|
||||
@"extern" = 0,
|
||||
available_external = 1,
|
||||
@ -80,6 +90,10 @@ pub const LLVM = struct {
|
||||
const getPointerType = bindings.NativityLLVMGetPointerType;
|
||||
const getStructType = bindings.NativityLLVMGetStructType;
|
||||
const getIntrinsicType = bindings.NativityLLVMContextGetIntrinsicType;
|
||||
const getAttributeFromEnum = bindings.NativityLLVMContextGetAttributeFromEnum;
|
||||
const getAttributeFromString = bindings.NativityLLVMContextGetAttributeFromString;
|
||||
const getAttributeFromType = bindings.NativityLLVMContextGetAttributeFromType;
|
||||
const getAttributeSet = bindings.NativityLLVMContextGetAttributeSet;
|
||||
};
|
||||
|
||||
pub const Module = opaque {
|
||||
@ -130,6 +144,7 @@ pub const LLVM = struct {
|
||||
const createGlobalString = bindings.NativityLLVMBuilderCreateGlobalString;
|
||||
const createGlobalStringPointer = bindings.NativityLLVMBuilderCreateGlobalStringPointer;
|
||||
const createPhi = bindings.NativityLLVMBuilderCreatePhi;
|
||||
const createMemcpy = bindings.NativityLLVMBuilderCreateMemcpy;
|
||||
|
||||
const getInsertBlock = bindings.NativityLLVMBuilderGetInsertBlock;
|
||||
const isCurrentBlockTerminated = bindings.NativityLLVMBuilderIsCurrentBlockTerminated;
|
||||
@ -552,90 +567,93 @@ pub const LLVM = struct {
|
||||
pub const Tuple = opaque {};
|
||||
};
|
||||
|
||||
pub const Attribute = enum(u32) {
|
||||
AllocAlign = 1,
|
||||
AllocatedPointer = 2,
|
||||
AlwaysInline = 3,
|
||||
Builtin = 4,
|
||||
Cold = 5,
|
||||
Convergent = 6,
|
||||
DisableSanitizerInstrumentation = 7,
|
||||
FnRetThunkExtern = 8,
|
||||
Hot = 9,
|
||||
ImmArg = 10,
|
||||
InReg = 11,
|
||||
InlineHint = 12,
|
||||
JumpTable = 13,
|
||||
MinSize = 14,
|
||||
MustProgress = 15,
|
||||
Naked = 16,
|
||||
Nest = 17,
|
||||
NoAlias = 18,
|
||||
NoBuiltin = 19,
|
||||
NoCallback = 20,
|
||||
NoCapture = 21,
|
||||
NoCfCheck = 22,
|
||||
NoDuplicate = 23,
|
||||
NoFree = 24,
|
||||
NoImplicitFloat = 25,
|
||||
NoInline = 26,
|
||||
NoMerge = 27,
|
||||
NoProfile = 28,
|
||||
NoRecurse = 29,
|
||||
NoRedZone = 30,
|
||||
NoReturn = 31,
|
||||
NoSanitizeBounds = 32,
|
||||
NoSanitizeCoverage = 33,
|
||||
NoSync = 34,
|
||||
NoUndef = 35,
|
||||
NoUnwind = 36,
|
||||
NonLazyBind = 37,
|
||||
NonNull = 38,
|
||||
NullPointerIsValid = 39,
|
||||
OptForFuzzing = 40,
|
||||
OptimizeForSize = 41,
|
||||
OptimizeNone = 42,
|
||||
PresplitCoroutine = 43,
|
||||
ReadNone = 44,
|
||||
ReadOnly = 45,
|
||||
Returned = 46,
|
||||
ReturnsTwice = 47,
|
||||
SExt = 48,
|
||||
SafeStack = 49,
|
||||
SanitizeAddress = 50,
|
||||
SanitizeHWAddress = 51,
|
||||
SanitizeMemTag = 52,
|
||||
SanitizeMemory = 53,
|
||||
SanitizeThread = 54,
|
||||
ShadowCallStack = 55,
|
||||
SkipProfile = 56,
|
||||
Speculatable = 57,
|
||||
SpeculativeLoadHardening = 58,
|
||||
StackProtect = 59,
|
||||
StackProtectReq = 60,
|
||||
StackProtectStrong = 61,
|
||||
StrictFP = 62,
|
||||
SwiftAsync = 63,
|
||||
SwiftError = 64,
|
||||
SwiftSelf = 65,
|
||||
WillReturn = 66,
|
||||
WriteOnly = 67,
|
||||
ZExt = 68,
|
||||
ByRef = 69,
|
||||
ByVal = 70,
|
||||
ElementType = 71,
|
||||
InAlloca = 72,
|
||||
Preallocated = 73,
|
||||
StructRet = 74,
|
||||
Alignment = 75,
|
||||
AllocKind = 76,
|
||||
AllocSize = 77,
|
||||
Dereferenceable = 78,
|
||||
DereferenceableOrNull = 79,
|
||||
Memory = 80,
|
||||
StackAlignment = 81,
|
||||
UWTable = 82,
|
||||
VScaleRange = 83,
|
||||
pub const Attribute = opaque {
|
||||
pub const Set = opaque {};
|
||||
pub const Id = enum(u32) {
|
||||
AllocAlign = 1,
|
||||
AllocatedPointer = 2,
|
||||
AlwaysInline = 3,
|
||||
Builtin = 4,
|
||||
Cold = 5,
|
||||
Convergent = 6,
|
||||
DisableSanitizerInstrumentation = 7,
|
||||
FnRetThunkExtern = 8,
|
||||
Hot = 9,
|
||||
ImmArg = 10,
|
||||
InReg = 11,
|
||||
InlineHint = 12,
|
||||
JumpTable = 13,
|
||||
MinSize = 14,
|
||||
MustProgress = 15,
|
||||
Naked = 16,
|
||||
Nest = 17,
|
||||
NoAlias = 18,
|
||||
NoBuiltin = 19,
|
||||
NoCallback = 20,
|
||||
NoCapture = 21,
|
||||
NoCfCheck = 22,
|
||||
NoDuplicate = 23,
|
||||
NoFree = 24,
|
||||
NoImplicitFloat = 25,
|
||||
NoInline = 26,
|
||||
NoMerge = 27,
|
||||
NoProfile = 28,
|
||||
NoRecurse = 29,
|
||||
NoRedZone = 30,
|
||||
NoReturn = 31,
|
||||
NoSanitizeBounds = 32,
|
||||
NoSanitizeCoverage = 33,
|
||||
NoSync = 34,
|
||||
NoUndef = 35,
|
||||
NoUnwind = 36,
|
||||
NonLazyBind = 37,
|
||||
NonNull = 38,
|
||||
NullPointerIsValid = 39,
|
||||
OptForFuzzing = 40,
|
||||
OptimizeForSize = 41,
|
||||
OptimizeNone = 42,
|
||||
PresplitCoroutine = 43,
|
||||
ReadNone = 44,
|
||||
ReadOnly = 45,
|
||||
Returned = 46,
|
||||
ReturnsTwice = 47,
|
||||
SExt = 48,
|
||||
SafeStack = 49,
|
||||
SanitizeAddress = 50,
|
||||
SanitizeHWAddress = 51,
|
||||
SanitizeMemTag = 52,
|
||||
SanitizeMemory = 53,
|
||||
SanitizeThread = 54,
|
||||
ShadowCallStack = 55,
|
||||
SkipProfile = 56,
|
||||
Speculatable = 57,
|
||||
SpeculativeLoadHardening = 58,
|
||||
StackProtect = 59,
|
||||
StackProtectReq = 60,
|
||||
StackProtectStrong = 61,
|
||||
StrictFP = 62,
|
||||
SwiftAsync = 63,
|
||||
SwiftError = 64,
|
||||
SwiftSelf = 65,
|
||||
WillReturn = 66,
|
||||
WriteOnly = 67,
|
||||
ZExt = 68,
|
||||
ByRef = 69,
|
||||
ByVal = 70,
|
||||
ElementType = 71,
|
||||
InAlloca = 72,
|
||||
Preallocated = 73,
|
||||
StructRet = 74,
|
||||
Alignment = 75,
|
||||
AllocKind = 76,
|
||||
AllocSize = 77,
|
||||
Dereferenceable = 78,
|
||||
DereferenceableOrNull = 79,
|
||||
Memory = 80,
|
||||
StackAlignment = 81,
|
||||
UWTable = 82,
|
||||
VScaleRange = 83,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Type = opaque {
|
||||
@ -647,6 +665,7 @@ pub const LLVM = struct {
|
||||
const isPointer = bindings.NativityLLVMTypeIsPointer;
|
||||
const isInteger = bindings.NativityLLVMTypeIsInteger;
|
||||
const isVoid = bindings.NativityLLVMTypeIsVoid;
|
||||
const assertEqual = bindings.NativityLLVMTypeAssertEqual;
|
||||
|
||||
pub const Array = opaque {
|
||||
fn toType(integer: *@This()) *Type {
|
||||
@ -748,6 +767,7 @@ pub const LLVM = struct {
|
||||
|
||||
pub const Call = opaque {
|
||||
const setCallingConvention = bindings.NativityLLVMCallSetCallingConvention;
|
||||
const setAttributes = bindings.NativityLLVMCallSetAttributes;
|
||||
fn toValue(this: *@This()) *Value {
|
||||
return @ptrCast(this);
|
||||
}
|
||||
@ -860,15 +880,17 @@ pub const LLVM = struct {
|
||||
|
||||
pub const Constant = opaque {
|
||||
pub const Function = opaque {
|
||||
const getArgument = bindings.NativityLLVMFunctionGetArgument;
|
||||
const getArguments = bindings.NativityLLVMFunctionGetArguments;
|
||||
const getType = bindings.NativityLLVMFunctionGetType;
|
||||
const addAttributeKey = bindings.NativityLLVMFunctionAddAttributeKey;
|
||||
// const addAttributeKey = bindings.NativityLLVMFunctionAddAttributeKey;
|
||||
const verify = bindings.NativityLLVMVerifyFunction;
|
||||
const toString = bindings.NativityLLVMFunctionToString;
|
||||
const setCallingConvention = bindings.NativityLLVMFunctionSetCallingConvention;
|
||||
const getCallingConvention = bindings.NativityLLVMFunctionGetCallingConvention;
|
||||
const setSubprogram = bindings.NativityLLVMFunctionSetSubprogram;
|
||||
const getSubprogram = bindings.NativityLLVMFunctionGetSubprogram;
|
||||
const setAttributes = bindings.NativityLLVMFunctionSetAttributes;
|
||||
|
||||
fn toValue(this: *@This()) *Value {
|
||||
return @ptrCast(this);
|
||||
@ -1181,21 +1203,11 @@ pub const LLVM = struct {
|
||||
const llvm_type: *LLVM.Type = switch (sema_type.*) {
|
||||
.function => |function_prototype_index| blk: {
|
||||
const sema_function_prototype = unit.function_prototypes.get(function_prototype_index);
|
||||
const llvm_return_type = try llvm.getType(unit, context, sema_function_prototype.return_type);
|
||||
var parameter_types = try UnpinnedArray(*LLVM.Type).initialize_with_capacity(context.my_allocator, @intCast(sema_function_prototype.argument_types.len));
|
||||
const llvm_return_type = try llvm.getType(unit, context, sema_function_prototype.abi.return_type);
|
||||
var parameter_types = try UnpinnedArray(*LLVM.Type).initialize_with_capacity(context.my_allocator, @intCast(sema_function_prototype.abi.parameter_types.len));
|
||||
|
||||
for (sema_function_prototype.argument_types) |argument_type_index| {
|
||||
switch (unit.types.get(argument_type_index).*) {
|
||||
// TODO: ABI
|
||||
.integer,
|
||||
.pointer,
|
||||
// .@"enum",
|
||||
.@"struct",
|
||||
.slice,
|
||||
// .bool,
|
||||
=> parameter_types.append_with_capacity(try llvm.getType(unit, context, argument_type_index)),
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
for (sema_function_prototype.abi.parameter_types) |argument_type_index| {
|
||||
parameter_types.append_with_capacity(try llvm.getType(unit, context, argument_type_index));
|
||||
}
|
||||
|
||||
const is_var_args = false;
|
||||
@ -1265,6 +1277,16 @@ pub const LLVM = struct {
|
||||
|
||||
break :blk struct_type.toType();
|
||||
},
|
||||
.two_struct => |pair| blk: {
|
||||
const types = [2]*LLVM.Type{
|
||||
try llvm.getType(unit, context, pair[0]),
|
||||
try llvm.getType(unit, context, pair[1]),
|
||||
};
|
||||
const is_packed = false;
|
||||
const struct_type = llvm.context.getStructType(&types, types.len, is_packed) orelse return Type.Error.@"struct";
|
||||
|
||||
break :blk struct_type.toType();
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.array => |array| blk: {
|
||||
@ -1289,11 +1311,12 @@ pub const LLVM = struct {
|
||||
if (llvm.debug_info_file_map.get(sema_file_index)) |file| {
|
||||
return file;
|
||||
} else {
|
||||
// if (@intFromEnum(sema_file_index) == 4) @breakpoint();
|
||||
const sema_file = unit.files.get(sema_file_index);
|
||||
const sub_path = std.fs.path.dirname(sema_file.relative_path) orelse "";
|
||||
const file_path = std.fs.path.basename(sema_file.relative_path);
|
||||
const directory_path = try Compilation.joinPath(context, sema_file.package.directory.path, sub_path);
|
||||
const debug_file = llvm.debug_info_builder.createFile(file_path.ptr, file_path.len, directory_path.ptr, directory_path.len) orelse unreachable;
|
||||
const full_path = try Compilation.joinPath(context, sema_file.package.directory.path, sema_file.relative_path);
|
||||
const filename = std.fs.path.basename(full_path);
|
||||
const directory = full_path[0 .. full_path.len - filename.len];
|
||||
const debug_file = llvm.debug_info_builder.createFile(filename.ptr, filename.len, directory.ptr, directory.len) orelse unreachable;
|
||||
try llvm.debug_info_file_map.put_no_clobber(context.my_allocator, sema_file_index, debug_file);
|
||||
return debug_file;
|
||||
}
|
||||
@ -1868,6 +1891,7 @@ pub const LLVM = struct {
|
||||
.global => |global| {
|
||||
const constant = switch (global.initial_value) {
|
||||
.function_definition => llvm.function_definition_map.get(global).?.toConstant(),
|
||||
.function_declaration => llvm.llvm_external_functions.get(global).?.toConstant(),
|
||||
else => llvm.global_variable_map.get(global).?.toConstant(),
|
||||
};
|
||||
return constant;
|
||||
@ -1968,7 +1992,7 @@ pub const LLVM = struct {
|
||||
const len = llvm.context.getConstantInt(64, 0, false) orelse unreachable;
|
||||
break :b .{ ptr.toConstant(), len.toConstant() };
|
||||
};
|
||||
|
||||
|
||||
const constant_slice = slice_struct_type.getConstant(&slice_fields, slice_fields.len) orelse unreachable;
|
||||
return constant_slice;
|
||||
}
|
||||
@ -2040,7 +2064,97 @@ pub const LLVM = struct {
|
||||
return call.toValue();
|
||||
}
|
||||
|
||||
fn emitParameterAttributes(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, abi: Compilation.Function.AbiInfo, is_return: bool) !*const LLVM.Attribute.Set {
|
||||
var attributes = UnpinnedArray(*LLVM.Attribute){};
|
||||
if (abi.attributes.by_reg) {
|
||||
try attributes.append(context.my_allocator, llvm.attributes.inreg);
|
||||
}
|
||||
switch (abi.kind) {
|
||||
.ignore => {
|
||||
assert(is_return);
|
||||
},
|
||||
.direct, .direct_pair, .direct_coerce => {},
|
||||
.indirect => |indirect| {
|
||||
const indirect_type = try llvm.getType(unit, context, indirect.type);
|
||||
if (is_return) {
|
||||
const sret = llvm.context.getAttributeFromType(.StructRet, indirect_type);
|
||||
try attributes.append(context.my_allocator, sret);
|
||||
try attributes.append(context.my_allocator, llvm.attributes.@"noalias");
|
||||
// TODO: alignment
|
||||
} else {
|
||||
if (abi.attributes.by_value) {
|
||||
const byval = llvm.context.getAttributeFromType(.ByVal, indirect_type);
|
||||
try attributes.append(context.my_allocator, byval);
|
||||
}
|
||||
//TODO: alignment
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
const attribute_set = llvm.context.getAttributeSet(attributes.pointer, attributes.length);
|
||||
return attribute_set;
|
||||
}
|
||||
|
||||
fn getFunctionAttributes(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, function_prototype: *Compilation.Function.Prototype) !*const LLVM.Attribute.Set {
|
||||
var function_attributes = UnpinnedArray(*LLVM.Attribute){};
|
||||
try function_attributes.append(context.my_allocator, llvm.attributes.nounwind);
|
||||
|
||||
switch (unit.types.get(function_prototype.return_type).*) {
|
||||
.noreturn => {
|
||||
try function_attributes.append(context.my_allocator, llvm.attributes.noreturn);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (function_prototype.attributes.naked) {
|
||||
try function_attributes.append(context.my_allocator, llvm.attributes.naked);
|
||||
}
|
||||
|
||||
const function_attribute_set = llvm.context.getAttributeSet(function_attributes.pointer, function_attributes.length);
|
||||
return function_attribute_set;
|
||||
}
|
||||
|
||||
const CallOrFunction = union(enum) {
|
||||
call: *LLVM.Value.Instruction.Call,
|
||||
function: *LLVM.Value.Constant.Function,
|
||||
};
|
||||
|
||||
fn setCallOrFunctionAttributes(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, function_prototype: *Compilation.Function.Prototype, call_or_function: CallOrFunction) !void {
|
||||
const function_attribute_set = try llvm.getFunctionAttributes(unit, context, function_prototype);
|
||||
|
||||
var parameter_attribute_sets = try UnpinnedArray(*const LLVM.Attribute.Set).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.abi.parameter_types_abi.len + @intFromBool(function_prototype.abi.return_type_abi.kind == .indirect)));
|
||||
const return_attribute_set = blk: {
|
||||
const attribute_set = try llvm.emitParameterAttributes(unit, context, function_prototype.abi.return_type_abi, true);
|
||||
break :blk switch (function_prototype.abi.return_type_abi.kind) {
|
||||
.indirect => b: {
|
||||
parameter_attribute_sets.append_with_capacity(attribute_set);
|
||||
break :b llvm.context.getAttributeSet(null, 0);
|
||||
},
|
||||
else => attribute_set,
|
||||
};
|
||||
};
|
||||
|
||||
for (function_prototype.abi.parameter_types_abi) |parameter_type_abi| {
|
||||
const parameter_attribute_set = try llvm.emitParameterAttributes(unit, context, parameter_type_abi, false);
|
||||
parameter_attribute_sets.append_with_capacity(parameter_attribute_set);
|
||||
}
|
||||
|
||||
const calling_convention = getCallingConvention(function_prototype.calling_convention);
|
||||
|
||||
switch (call_or_function) {
|
||||
.call => |call| {
|
||||
call.setAttributes(llvm.context, function_attribute_set, return_attribute_set, parameter_attribute_sets.pointer, parameter_attribute_sets.length);
|
||||
call.setCallingConvention(calling_convention);
|
||||
},
|
||||
.function => |function| {
|
||||
function.setAttributes(llvm.context, function_attribute_set, return_attribute_set, parameter_attribute_sets.pointer, parameter_attribute_sets.length);
|
||||
function.setCallingConvention(calling_convention);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn emitFunctionDeclaration(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, declaration: *Compilation.Debug.Declaration.Global) !void {
|
||||
const name = unit.getIdentifier(declaration.declaration.name);
|
||||
const function_type = try llvm.getType(unit, context, declaration.declaration.type);
|
||||
const is_export = declaration.attributes.contains(.@"export");
|
||||
const is_extern = declaration.attributes.contains(.@"extern");
|
||||
@ -2053,23 +2167,35 @@ pub const LLVM = struct {
|
||||
// TODO: Check name collision
|
||||
const mangle_name = !export_or_extern;
|
||||
_ = mangle_name; // autofix
|
||||
const name = unit.getIdentifier(declaration.declaration.name);
|
||||
const function = llvm.module.createFunction(function_type.toFunction() orelse unreachable, linkage, address_space, name.ptr, name.len) orelse return Error.function;
|
||||
|
||||
const function_prototype = unit.function_prototypes.get(unit.types.get(declaration.declaration.type).function);
|
||||
switch (unit.types.get(function_prototype.return_type).*) {
|
||||
.noreturn => {
|
||||
function.addAttributeKey(.NoReturn);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
try llvm.setCallOrFunctionAttributes(unit, context, function_prototype, .{
|
||||
.function = function,
|
||||
});
|
||||
// const calling_convention = getCallingConvention(function_prototype.calling_convention);
|
||||
// function.setCallingConvention(calling_convention);
|
||||
//
|
||||
// const function_attribute_set = llvm.getFunctionAttributes(unit, context, function_prototype);
|
||||
//
|
||||
// var parameter_attribute_sets = try UnpinnedArray(*const LLVM.Attribute.Set).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.abi.parameter_types_abi.len + @intFromBool(function_prototype.abi.return_type_abi.kind == .indirect)));
|
||||
// const return_attribute_set = blk: {
|
||||
// const attribute_set = try llvm.emitParameterAttributes(unit, context, function_prototype.abi.return_type_abi, true);
|
||||
// break :blk switch (function_prototype.abi.return_type_abi.kind) {
|
||||
// .indirect => b: {
|
||||
// parameter_attribute_sets.append_with_capacity(attribute_set);
|
||||
// break :b llvm.context.getAttributeSet(null, 0);
|
||||
// },
|
||||
// else => attribute_set,
|
||||
// };
|
||||
// };
|
||||
//
|
||||
// for (function_prototype.abi.parameter_types_abi) |parameter_type_abi| {
|
||||
// const parameter_attribute_set = try llvm.emitParameterAttributes(unit, context, parameter_type_abi, false);
|
||||
// parameter_attribute_sets.append_with_capacity(parameter_attribute_set);
|
||||
// }
|
||||
|
||||
if (function_prototype.attributes.naked) {
|
||||
function.addAttributeKey(.Naked);
|
||||
}
|
||||
|
||||
const calling_convention = getCallingConvention(function_prototype.calling_convention);
|
||||
function.setCallingConvention(calling_convention);
|
||||
// function.setAttributes(llvm.context, function_attribute_set, return_attribute_set, parameter_attribute_sets.pointer, parameter_attribute_sets.length);
|
||||
|
||||
switch (declaration.initial_value) {
|
||||
.function_declaration => try llvm.function_declaration_map.put_no_clobber(context.my_allocator, declaration, function),
|
||||
@ -2078,6 +2204,7 @@ pub const LLVM = struct {
|
||||
}
|
||||
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
// if (data_structures.byte_equal(name, "nat_split_struct_ints")) @breakpoint();
|
||||
const debug_file = try llvm.getDebugInfoFile(unit, context, declaration.declaration.scope.file);
|
||||
var parameter_types = try UnpinnedArray(*LLVM.DebugInfo.Type).initialize_with_capacity(context.my_allocator, @intCast(function_prototype.argument_types.len));
|
||||
for (function_prototype.argument_types) |argument_type_index| {
|
||||
@ -2116,7 +2243,6 @@ pub const LLVM = struct {
|
||||
};
|
||||
const subroutine_type_calling_convention = LLVM.DebugInfo.CallingConvention.none;
|
||||
const subroutine_type = llvm.debug_info_builder.createSubroutineType(parameter_types.pointer, parameter_types.length, subroutine_type_flags, subroutine_type_calling_convention) orelse unreachable;
|
||||
const scope_line = 0;
|
||||
const subprogram_flags = LLVM.DebugInfo.Subprogram.Flags{
|
||||
.virtuality = .none,
|
||||
.local_to_unit = !export_or_extern,
|
||||
@ -2131,11 +2257,13 @@ pub const LLVM = struct {
|
||||
};
|
||||
const subprogram_declaration = null;
|
||||
const function_name = unit.getIdentifier(declaration.declaration.name);
|
||||
const subprogram = llvm.debug_info_builder.createFunction(debug_file.toScope(), function_name.ptr, function_name.len, function_name.ptr, function_name.len, debug_file, declaration.declaration.line + 1, subroutine_type, scope_line, subroutine_type_flags, subprogram_flags, subprogram_declaration) orelse unreachable;
|
||||
const subprogram = llvm.debug_info_builder.createFunction(debug_file.toScope(), function_name.ptr, function_name.len, function_name.ptr, function_name.len, debug_file, declaration.declaration.line + 1, subroutine_type, declaration.declaration.line + 1, subroutine_type_flags, subprogram_flags, subprogram_declaration) orelse unreachable;
|
||||
function.setSubprogram(subprogram);
|
||||
|
||||
switch (declaration.initial_value) {
|
||||
.function_declaration => {},
|
||||
.function_declaration => {
|
||||
try llvm.llvm_external_functions.put_no_clobber(context.my_allocator, declaration, function);
|
||||
},
|
||||
.function_definition => |function_definition_index| {
|
||||
const function_definition = unit.function_definitions.get(function_definition_index);
|
||||
const scope = subprogram.toLocalScope().toScope();
|
||||
@ -2185,12 +2313,20 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.module = module,
|
||||
.builder = builder,
|
||||
.debug_info_builder = module.createDebugInfoBuilder() orelse return Error.debug_info_builder,
|
||||
.attributes = .{
|
||||
.naked = llvm_context.getAttributeFromEnum(.Naked, 0),
|
||||
.noreturn = llvm_context.getAttributeFromEnum(.NoReturn, 0),
|
||||
.nounwind = llvm_context.getAttributeFromEnum(.NoUnwind, 0),
|
||||
.inreg = llvm_context.getAttributeFromEnum(.InReg, 0),
|
||||
.@"noalias" = llvm_context.getAttributeFromEnum(.NoAlias, 0),
|
||||
},
|
||||
};
|
||||
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const filename = "main";
|
||||
const directory = ".";
|
||||
const debug_info_file = llvm.debug_info_builder.createFile(filename, filename.len, directory, directory.len) orelse unreachable;
|
||||
const full_path = try std.fs.cwd().realpathAlloc(context.allocator, unit.descriptor.main_package_path);
|
||||
const filename = std.fs.path.basename(full_path);
|
||||
const directory = full_path[0 .. full_path.len - filename.len];
|
||||
const debug_info_file = llvm.debug_info_builder.createFile(filename.ptr, filename.len, directory.ptr, directory.len) orelse unreachable;
|
||||
const producer = "nativity";
|
||||
const is_optimized = false;
|
||||
const flags = "";
|
||||
@ -2291,7 +2427,6 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
llvm.scope = subprogram.toLocalScope().toScope();
|
||||
}
|
||||
|
||||
llvm.arg_index = 0;
|
||||
var alloca_map = MyHashMap(Compilation.Instruction.Index, *LLVM.Value){};
|
||||
|
||||
var block_command_list = BasicBlockList{};
|
||||
@ -2438,18 +2573,23 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call.toValue());
|
||||
},
|
||||
.stack_slot => |stack_slot| {
|
||||
// const stack_slot_type = unit.types.get(stack_slot.type);
|
||||
// const stack_slot_alignment = stack_slot_type.getAbiAlignment(unit);
|
||||
const declaration_type = try llvm.getType(unit, context, stack_slot.type);
|
||||
const type_alignment = unit.types.get(stack_slot.type).getAbiAlignment(unit);
|
||||
const alloca_array_size = null;
|
||||
const declaration_alloca = llvm.builder.createAlloca(declaration_type, address_space, alloca_array_size, "", "".len) orelse return LLVM.Value.Instruction.Error.alloca;
|
||||
const declaration_alloca = llvm.builder.createAlloca(declaration_type, address_space, alloca_array_size, "", "".len, type_alignment) orelse return LLVM.Value.Instruction.Error.alloca;
|
||||
try alloca_map.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue());
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue());
|
||||
},
|
||||
.store => |store| {
|
||||
const right = try llvm.emitRightValue(unit, context, store.source);
|
||||
const source_type = unit.types.get(store.source.type);
|
||||
const alignment = source_type.getAbiAlignment(unit);
|
||||
|
||||
const is_volatile = false;
|
||||
const left = try llvm.emitLeftValue(unit, context, store.destination);
|
||||
const store_instruction = llvm.builder.createStore(right, left, is_volatile) orelse return LLVM.Value.Instruction.Error.store;
|
||||
const store_instruction = llvm.builder.createStore(right, left, is_volatile, alignment) orelse return LLVM.Value.Instruction.Error.store;
|
||||
_ = store_instruction; // autofix
|
||||
},
|
||||
.cast => |cast| {
|
||||
@ -2469,6 +2609,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.slice_to_nullable,
|
||||
.slice_to_not_null,
|
||||
.slice_coerce_to_zero_termination,
|
||||
.slice_zero_to_no_termination,
|
||||
.pointer_to_nullable,
|
||||
.pointer_const_to_var,
|
||||
.pointer_to_array_to_pointer_to_many,
|
||||
@ -2515,9 +2656,11 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
break :blk value;
|
||||
};
|
||||
|
||||
const load_type = unit.types.get(load.type);
|
||||
const alignment = if (load.alignment) |alignment| alignment else load_type.getAbiAlignment(unit);
|
||||
const value_type = try llvm.getType(unit, context, load.type);
|
||||
const is_volatile = false;
|
||||
const load_i = llvm.builder.createLoad(value_type, value, is_volatile, "", "".len) orelse return LLVM.Value.Instruction.Error.load;
|
||||
const load_i = llvm.builder.createLoad(value_type, value, is_volatile, "", "".len, alignment) orelse return LLVM.Value.Instruction.Error.load;
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, load_i.toValue());
|
||||
},
|
||||
.integer_binary_operation => |binary_operation| {
|
||||
@ -2553,66 +2696,60 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
};
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, instruction);
|
||||
},
|
||||
.call => |call| {
|
||||
.call => |sema_call| {
|
||||
var argument_buffer: [32]*LLVM.Value = undefined;
|
||||
const argument_count = call.arguments.len;
|
||||
const argument_count = sema_call.arguments.len;
|
||||
const arguments = argument_buffer[0..argument_count];
|
||||
|
||||
switch (call.callable.value) {
|
||||
.@"comptime" => |ct| switch (ct) {
|
||||
.global => |call_function_declaration| {
|
||||
const call_function_type = call_function_declaration.declaration.type;
|
||||
const call_function_prototype = unit.function_prototypes.get(unit.types.get(call_function_type).function);
|
||||
assert(call_function_type == call.function_type);
|
||||
const call_function_type = unit.types.get(sema_call.function_type);
|
||||
const function_prototype = unit.function_prototypes.get(call_function_type.function);
|
||||
const call_type = try llvm.getType(unit, context, sema_call.function_type);
|
||||
|
||||
const call = switch (sema_call.callable.value) {
|
||||
.@"comptime" => |ct| switch (ct) {
|
||||
.global => |call_function_declaration| b: {
|
||||
const callee = switch (call_function_declaration.initial_value) {
|
||||
.function_definition => llvm.function_definition_map.get(call_function_declaration).?,
|
||||
.function_declaration => llvm.function_declaration_map.get(call_function_declaration).?,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
for (call.arguments, arguments) |argument_value, *argument| {
|
||||
for (sema_call.arguments, arguments) |argument_value, *argument| {
|
||||
argument.* = try llvm.emitRightValue(unit, context, argument_value);
|
||||
}
|
||||
|
||||
const llvm_calling_convention = callee.getCallingConvention();
|
||||
const name = "";
|
||||
const call_type = try llvm.getType(unit, context, call.function_type);
|
||||
const function_name = unit.getIdentifier(call_function_declaration.declaration.name);
|
||||
_ = function_name; // autofix
|
||||
const function_type = call_type.toFunction() orelse unreachable;
|
||||
for (call.arguments, arguments, call_function_prototype.argument_types, 0..) |sema_argument, argument, sema_argument_type, i| {
|
||||
for (sema_call.arguments, arguments, function_prototype.abi.parameter_types, 0..) |sema_argument, argument, sema_argument_type, i| {
|
||||
assert(sema_argument.type == sema_argument_type);
|
||||
const argument_type = function_type.getArgumentType(@intCast(i));
|
||||
assert(argument_type == argument.getType());
|
||||
argument_type.assertEqual(argument.getType());
|
||||
}
|
||||
const call_instruction = llvm.builder.createCall(function_type, callee.toValue(), arguments.ptr, arguments.len, name.ptr, name.len, null) orelse return LLVM.Value.Instruction.Error.call;
|
||||
call_instruction.setCallingConvention(llvm_calling_convention);
|
||||
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call_instruction.toValue());
|
||||
break :b call_instruction;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.runtime => |ii| {
|
||||
.runtime => |ii| b: {
|
||||
const callee = llvm.llvm_instruction_map.get(ii).?;
|
||||
const callable_type = unit.types.get(call.function_type);
|
||||
const sema_calling_convention = switch (callable_type.*) {
|
||||
.function => |function_prototype_index| unit.function_prototypes.get(function_prototype_index).calling_convention,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const calling_convention = getCallingConvention(sema_calling_convention);
|
||||
for (call.arguments, arguments) |argument_value, *argument| {
|
||||
for (sema_call.arguments, arguments) |argument_value, *argument| {
|
||||
argument.* = try llvm.emitRightValue(unit, context, argument_value);
|
||||
}
|
||||
|
||||
const name = "";
|
||||
const call_type = try llvm.getType(unit, context, call.function_type);
|
||||
const function_type = call_type.toFunction() orelse unreachable;
|
||||
const call_instruction = llvm.builder.createCall(function_type, callee, arguments.ptr, arguments.len, name.ptr, name.len, null) orelse return LLVM.Value.Instruction.Error.call;
|
||||
call_instruction.setCallingConvention(calling_convention);
|
||||
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call_instruction.toValue());
|
||||
break :b call_instruction;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
};
|
||||
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, call.toValue());
|
||||
|
||||
try llvm.setCallOrFunctionAttributes(unit, context, function_prototype, .{
|
||||
.call = call,
|
||||
});
|
||||
},
|
||||
.ret => |return_value| {
|
||||
const value = switch (return_value.type) {
|
||||
@ -2670,25 +2807,16 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.@"unreachable" => {
|
||||
_ = llvm.builder.createUnreachable() orelse return LLVM.Value.Instruction.Error.@"unreachable";
|
||||
},
|
||||
.argument_declaration => |argument_declaration| {
|
||||
var argument_buffer: [16]*LLVM.Value.Argument = undefined;
|
||||
var argument_count: usize = argument_buffer.len;
|
||||
llvm.function.getArguments(&argument_buffer, &argument_count);
|
||||
const arguments = argument_buffer[0..argument_count];
|
||||
const argument_index = llvm.arg_index;
|
||||
llvm.arg_index += 1;
|
||||
const argument = arguments[argument_index];
|
||||
const name = unit.getIdentifier(argument_declaration.declaration.name);
|
||||
argument.toValue().setName(name.ptr, name.len);
|
||||
const argument_type_index = argument_declaration.declaration.type;
|
||||
_ = argument_type_index; // autofix
|
||||
const argument_type = argument.toValue().getType();
|
||||
const alloca_array_size: ?*LLVM.Value = null;
|
||||
const argument_value = argument.toValue();
|
||||
const declaration_alloca = llvm.builder.createAlloca(argument_type, address_space, alloca_array_size, "", "".len) orelse return LLVM.Value.Instruction.Error.alloca;
|
||||
|
||||
.abi_argument => |argument_index| {
|
||||
const argument = llvm.function.getArgument(argument_index) orelse unreachable;
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, argument.toValue());
|
||||
},
|
||||
.debug_declare_argument => |debug_declare| {
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const debug_declaration_type = try llvm.getDebugType(unit, context, argument_declaration.declaration.type);
|
||||
const argument_index: c_uint = debug_declare.argument.index;
|
||||
const declaration = &debug_declare.argument.declaration;
|
||||
const debug_declaration_type = try llvm.getDebugType(unit, context, declaration.type);
|
||||
const declaration_alloca = llvm.llvm_instruction_map.get(debug_declare.stack).?;
|
||||
const always_preserve = true;
|
||||
const flags = LLVM.DebugInfo.Node.Flags{
|
||||
.visibility = .none,
|
||||
@ -2719,65 +2847,61 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.little_endian = false,
|
||||
.all_calls_described = false,
|
||||
};
|
||||
const declaration_name = unit.getIdentifier(argument_declaration.declaration.name);
|
||||
const line = argument_declaration.declaration.line;
|
||||
const column = argument_declaration.declaration.column;
|
||||
const declaration_name = unit.getIdentifier(declaration.name);
|
||||
const line = declaration.line;
|
||||
const column = declaration.column;
|
||||
const debug_parameter_variable = llvm.debug_info_builder.createParameterVariable(llvm.scope, declaration_name.ptr, declaration_name.len, argument_index + 1, llvm.file, line, debug_declaration_type, always_preserve, flags) orelse unreachable;
|
||||
|
||||
const insert_declare = llvm.debug_info_builder.insertDeclare(declaration_alloca.toValue(), debug_parameter_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable);
|
||||
const insert_declare = llvm.debug_info_builder.insertDeclare(declaration_alloca, debug_parameter_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable);
|
||||
_ = insert_declare;
|
||||
}
|
||||
|
||||
const is_volatile = false;
|
||||
const store = llvm.builder.createStore(argument_value, declaration_alloca.toValue(), is_volatile) orelse return LLVM.Value.Instruction.Error.store;
|
||||
_ = store; // autofix
|
||||
try llvm.argument_allocas.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue());
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, declaration_alloca.toValue());
|
||||
},
|
||||
.debug_declare_local_variable => |declare_local_variable| {
|
||||
const local_variable = declare_local_variable.variable;
|
||||
const debug_declaration_type = try llvm.getDebugType(unit, context, local_variable.declaration.type);
|
||||
const always_preserve = true;
|
||||
const flags = LLVM.DebugInfo.Node.Flags{
|
||||
.visibility = .none,
|
||||
.forward_declaration = false,
|
||||
.apple_block = false,
|
||||
.block_by_ref_struct = false,
|
||||
.virtual = false,
|
||||
.artificial = false,
|
||||
.explicit = false,
|
||||
.prototyped = false,
|
||||
.objective_c_class_complete = false,
|
||||
.object_pointer = false,
|
||||
.vector = false,
|
||||
.static_member = false,
|
||||
.lvalue_reference = false,
|
||||
.rvalue_reference = false,
|
||||
.reserved = false,
|
||||
.inheritance = .none,
|
||||
.introduced_virtual = false,
|
||||
.bit_field = false,
|
||||
.no_return = false,
|
||||
.type_pass_by_value = false,
|
||||
.type_pass_by_reference = false,
|
||||
.enum_class = false,
|
||||
.thunk = false,
|
||||
.non_trivial = false,
|
||||
.big_endian = false,
|
||||
.little_endian = false,
|
||||
.all_calls_described = false,
|
||||
};
|
||||
if (unit.descriptor.generate_debug_information) {
|
||||
const local_variable = declare_local_variable.variable;
|
||||
const debug_declaration_type = try llvm.getDebugType(unit, context, local_variable.declaration.type);
|
||||
const always_preserve = true;
|
||||
const flags = LLVM.DebugInfo.Node.Flags{
|
||||
.visibility = .none,
|
||||
.forward_declaration = false,
|
||||
.apple_block = false,
|
||||
.block_by_ref_struct = false,
|
||||
.virtual = false,
|
||||
.artificial = false,
|
||||
.explicit = false,
|
||||
.prototyped = false,
|
||||
.objective_c_class_complete = false,
|
||||
.object_pointer = false,
|
||||
.vector = false,
|
||||
.static_member = false,
|
||||
.lvalue_reference = false,
|
||||
.rvalue_reference = false,
|
||||
.reserved = false,
|
||||
.inheritance = .none,
|
||||
.introduced_virtual = false,
|
||||
.bit_field = false,
|
||||
.no_return = false,
|
||||
.type_pass_by_value = false,
|
||||
.type_pass_by_reference = false,
|
||||
.enum_class = false,
|
||||
.thunk = false,
|
||||
.non_trivial = false,
|
||||
.big_endian = false,
|
||||
.little_endian = false,
|
||||
.all_calls_described = false,
|
||||
};
|
||||
|
||||
const alignment = 0;
|
||||
const declaration_name = unit.getIdentifier(local_variable.declaration.name);
|
||||
const line = local_variable.declaration.line;
|
||||
const column = local_variable.declaration.column;
|
||||
const debug_local_variable = llvm.debug_info_builder.createAutoVariable(llvm.scope, declaration_name.ptr, declaration_name.len, llvm.file, line, debug_declaration_type, always_preserve, flags, alignment) orelse unreachable;
|
||||
const alignment = 0;
|
||||
const declaration_name = unit.getIdentifier(local_variable.declaration.name);
|
||||
const line = local_variable.declaration.line;
|
||||
const column = local_variable.declaration.column;
|
||||
const debug_local_variable = llvm.debug_info_builder.createAutoVariable(llvm.scope, declaration_name.ptr, declaration_name.len, llvm.file, line, debug_declaration_type, always_preserve, flags, alignment) orelse unreachable;
|
||||
|
||||
const local = alloca_map.get(declare_local_variable.stack).?;
|
||||
const local = alloca_map.get(declare_local_variable.stack).?;
|
||||
|
||||
const insert_declare = llvm.debug_info_builder.insertDeclare(local, debug_local_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable);
|
||||
_ = insert_declare;
|
||||
const insert_declare = llvm.debug_info_builder.insertDeclare(local, debug_local_variable, llvm.context, line, column, (llvm.function.getSubprogram() orelse unreachable).toLocalScope().toScope(), llvm.builder.getInsertBlock() orelse unreachable);
|
||||
_ = insert_declare;
|
||||
}
|
||||
},
|
||||
.insert_value => |insert_value| {
|
||||
const aggregate = try llvm.emitRightValue(unit, context, insert_value.expression);
|
||||
@ -2916,6 +3040,21 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
const switch_instruction = llvm.builder.createSwitch(condition, else_block, condition_array.pointer, basic_block_array.pointer, condition_array.length, branch_weights, unpredictable);
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, switch_instruction.toValue());
|
||||
},
|
||||
.memcpy => |memcpy| {
|
||||
const destination = try llvm.emitLeftValue(unit, context, memcpy.destination);
|
||||
const source = try llvm.emitLeftValue(unit, context, memcpy.source);
|
||||
const destination_alignment = if (memcpy.destination_alignment) |alignment| alignment else b: {
|
||||
const ty = unit.types.get(memcpy.destination.type);
|
||||
const alignment = ty.getAbiAlignment(unit);
|
||||
break :b alignment;
|
||||
};
|
||||
const source_alignment = if (memcpy.source_alignment) |alignment| alignment else b: {
|
||||
const ty = unit.types.get(memcpy.source.type);
|
||||
const alignment = ty.getAbiAlignment(unit);
|
||||
break :b alignment;
|
||||
};
|
||||
_ = llvm.builder.createMemcpy(destination, destination_alignment, source, source_alignment, memcpy.size, memcpy.is_volatile);
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
@ -2965,7 +3104,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
const module_dump = module_ptr[0..module_len];
|
||||
_ = module_dump; // autofix
|
||||
|
||||
try write(.llvm, function_ir);
|
||||
try write(.panic, function_ir);
|
||||
const error_message = message_ptr[0..message_len];
|
||||
try write(.panic, error_message);
|
||||
// std.debug.print("\nLLVM verification for function inside module failed:\nFull module: {s}\n```\n{s}\n```\n{s}\n", .{ module_dump, function_ir, error_message });
|
||||
@ -2982,6 +3121,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
// logln(.llvm, .print_module, "{s}", .{module_string});
|
||||
|
||||
const verify_module = true;
|
||||
const print_module = true;
|
||||
if (verify_module) {
|
||||
var message_ptr: [*]const u8 = undefined;
|
||||
var message_len: usize = 0;
|
||||
@ -2995,6 +3135,12 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
}
|
||||
}
|
||||
|
||||
if (print_module) {
|
||||
try write(.llvm, "Module: \n");
|
||||
try write(.llvm, module_string);
|
||||
try write(.llvm, "\n");
|
||||
}
|
||||
|
||||
// TODO: initialize only the target we are going to use
|
||||
bindings.NativityLLVMInitializeCodeGeneration();
|
||||
// TODO: proper target selection
|
||||
|
@ -50,21 +50,29 @@ pub extern fn NativityLLVMValueSetName(value: *LLVM.Value, name_ptr: [*]const u8
|
||||
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.Constant.Function, argument_ptr: [*]*LLVM.Value.Argument, argument_len: *usize) void;
|
||||
pub extern fn NativityLLVMFunctionGetArgument(function: *LLVM.Value.Constant.Function, index: c_uint) ?*LLVM.Value.Argument;
|
||||
pub extern fn NativityLLVMFunctionGetType(function: *LLVM.Value.Constant.Function) *LLVM.Type.Function;
|
||||
pub extern fn NativityLLVMFunctionTypeGetReturnType(function_type: *LLVM.Type.Function) *LLVM.Type;
|
||||
pub extern fn NativityLLVMTypeIsVoid(type: *LLVM.Type) bool;
|
||||
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 NativityLLVMBuilderCreateAlloca(builder: *LLVM.Builder, type: *LLVM.Type, address_space: c_uint, array_size: ?*LLVM.Value, name_ptr: [*]const u8, name_len: usize, alignment: u32) ?*LLVM.Value.Instruction.Alloca;
|
||||
pub extern fn NativityLLVMBuilderCreateStore(builder: *LLVM.Builder, value: *LLVM.Value, pointer: *LLVM.Value, is_volatile: bool, alignment: u32) ?*LLVM.Value.Instruction.Store;
|
||||
pub extern fn NativityLLVMBuilderCreateMemcpy(builder: *LLVM.Builder, destination: *LLVM.Value, destination_alignment: u32, source: *LLVM.Value, source_alignment: u32, size: u64, is_volatile: bool) *LLVM.Value.Instruction.Call;
|
||||
pub extern fn NativityLLVMContextGetConstantInt(context: *LLVM.Context, bit_count: c_uint, value: u64, is_signed: bool) ?*LLVM.Value.Constant.Int;
|
||||
pub extern fn NativityLLVMContextGetConstantString(context: *LLVM.Context, name_ptr: [*]const u8, name_len: usize, null_terminate: bool) ?*LLVM.Value.Constant;
|
||||
pub extern fn NativityLLVMGetConstantArray(array_type: *LLVM.Type.Array, value_ptr: [*]const *LLVM.Value.Constant, value_count: usize) ?*LLVM.Value.Constant;
|
||||
pub extern fn NativityLLVMGetConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) ?*LLVM.Value.Constant;
|
||||
pub extern fn NativityLLVMConstantToInt(constant: *LLVM.Value.Constant) ?*LLVM.Value.Constant.Int;
|
||||
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 NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize, alignment: u32) ?*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.Constant.Function, attribute_key: LLVM.Attribute) void;
|
||||
pub extern fn NativityLLVMContextGetAttributeFromEnum(context: *LLVM.Context, attribute_key: LLVM.Attribute.Id, attribute_value: u64) *LLVM.Attribute;
|
||||
pub extern fn NativityLLVMContextGetAttributeFromString(context: *LLVM.Context, key_ptr: [*]const u8, key_len: usize, value_ptr: [*]const u8, value_len: usize) *LLVM.Attribute;
|
||||
pub extern fn NativityLLVMContextGetAttributeFromType(context: *LLVM.Context, attribute_key: LLVM.Attribute.Id, type: *LLVM.Type) *LLVM.Attribute;
|
||||
pub extern fn NativityLLVMContextGetAttributeSet(context: *LLVM.Context, attribute_ptr: ?[*]const *LLVM.Attribute, attribute_count: usize) *const LLVM.Attribute.Set;
|
||||
pub extern fn NativityLLVMFunctionSetAttributes(function: *LLVM.Value.Constant.Function, context: *LLVM.Context, function_attributes: *const LLVM.Attribute.Set, return_attributes: *const LLVM.Attribute.Set, parameter_attribute_set_ptr: [*]const *const LLVM.Attribute.Set, parameter_attribute_set_count: usize) void;
|
||||
pub extern fn NativityLLVMCallSetAttributes(call: *LLVM.Value.Instruction.Call, context: *LLVM.Context, function_attributes: *const LLVM.Attribute.Set, return_attributes: *const LLVM.Attribute.Set, parameter_attribute_set_ptr: [*]const *const LLVM.Attribute.Set, parameter_attribute_set_count: usize) void;
|
||||
// pub extern fn NativityLLVMFunctionAddAttributeKey(builder: *LLVM.Value.Constant.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;
|
||||
@ -143,6 +151,7 @@ pub extern fn NativityLLVMTargetCreateTargetMachine(target: *LLVM.Target, target
|
||||
pub extern fn NativityLLVMModuleSetTargetMachineDataLayout(module: *LLVM.Module, target_machine: *LLVM.Target.Machine) void;
|
||||
pub extern fn NativityLLVMModuleSetTargetTriple(module: *LLVM.Module, target_triple_ptr: [*]const u8, target_triple_len: usize) void;
|
||||
pub extern fn NativityLLVMModuleAddPassesToEmitFile(module: *LLVM.Module, target_machine: *LLVM.Target.Machine, object_file_path_ptr: [*]const u8, object_file_path_len: usize, codegen_file_type: LLVM.CodeGenFileType, disable_verify: bool) bool;
|
||||
pub extern fn NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void;
|
||||
pub extern fn NativityLLDLinkELF(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
|
||||
pub extern fn NativityLLDLinkCOFF(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
|
||||
pub extern fn NativityLLDLinkMachO(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
|
||||
|
@ -67,7 +67,7 @@ pub fn analyze(allocator: *MyAllocator, text: []const u8, token_buffer: *Token.B
|
||||
var index: u32 = 0;
|
||||
var line_index: u32 = lexer.line_offset;
|
||||
|
||||
try token_buffer.ensure_with_capacity(allocator, len / 4);
|
||||
try token_buffer.ensure_with_capacity(allocator, len / 3);
|
||||
|
||||
// logln(.lexer, .end, "START LEXER - TOKEN OFFSET: {} - LINE OFFSET: {}", .{ Token.unwrap(lexer.offset), lexer.line_offset });
|
||||
|
||||
|
@ -420,13 +420,23 @@ const Analyzer = struct {
|
||||
if (data_structures.byte_equal(identifier_name, enum_field.name)) {
|
||||
const attribute = @field(Compilation.Function.Attribute, enum_field.name);
|
||||
const attribute_node = switch (attribute) {
|
||||
.naked,
|
||||
=> try analyzer.addNode(.{
|
||||
.naked => try analyzer.addNode(.{
|
||||
.id = @field(Node.Id, "function_attribute_" ++ @tagName(attribute)),
|
||||
.token = identifier,
|
||||
.left = .null,
|
||||
.right = .null,
|
||||
}),
|
||||
.cc => try analyzer.addNode(.{
|
||||
.id = .function_attribute_cc,
|
||||
.token = identifier,
|
||||
.left = b: {
|
||||
_ = try analyzer.expectToken(.operator_left_parenthesis);
|
||||
const cc = try analyzer.expression();
|
||||
_ = try analyzer.expectToken(.operator_right_parenthesis);
|
||||
break :b cc;
|
||||
},
|
||||
.right = .null,
|
||||
}),
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
break attribute_node;
|
||||
@ -462,7 +472,11 @@ const Analyzer = struct {
|
||||
var list = UnpinnedArray(Node.Index){};
|
||||
|
||||
while (analyzer.peekToken() != end_token) {
|
||||
const identifier = try analyzer.expectToken(.identifier);
|
||||
const identifier_token = analyzer.token_i;
|
||||
switch (analyzer.peekToken()) {
|
||||
.identifier, .discard => analyzer.consumeToken(),
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
_ = try analyzer.expectToken(.operator_colon);
|
||||
const type_expression = try analyzer.typeExpression();
|
||||
|
||||
@ -472,7 +486,7 @@ const Analyzer = struct {
|
||||
|
||||
try list.append(analyzer.my_allocator, try analyzer.addNode(.{
|
||||
.id = .argument_declaration,
|
||||
.token = identifier,
|
||||
.token = identifier_token,
|
||||
.left = type_expression,
|
||||
.right = Node.Index.null,
|
||||
}));
|
||||
|
@ -2,6 +2,7 @@ const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const os = builtin.os.tag;
|
||||
const arch = builtin.cpu.arch;
|
||||
const page_size = std.mem.page_size;
|
||||
|
||||
pub fn assert(ok: bool) void {
|
||||
if (!ok) unreachable;
|
||||
@ -257,7 +258,7 @@ pub fn MyHashMap(comptime K: type, comptime V: type) type {
|
||||
.Slice => byte_equal(k, key),
|
||||
else => k == key,
|
||||
},
|
||||
.Struct => equal(k, key),
|
||||
.Struct, .Array => equal(k, key),
|
||||
else => k == key,
|
||||
};
|
||||
|
||||
@ -331,7 +332,6 @@ pub fn enumFromString(comptime E: type, string: []const u8) ?E {
|
||||
} else null;
|
||||
}
|
||||
|
||||
const page_size = std.mem.page_size;
|
||||
extern fn pthread_jit_write_protect_np(enabled: bool) void;
|
||||
|
||||
pub fn allocate_virtual_memory(size: usize, flags: packed struct {
|
||||
@ -353,10 +353,10 @@ pub fn allocate_virtual_memory(size: usize, flags: packed struct {
|
||||
.linux => u32,
|
||||
.macos => c_int,
|
||||
else => @compileError("OS not supported"),
|
||||
} = if (flags.executable) std.os.PROT.EXEC else 0;
|
||||
const protection_flags: u32 = @intCast(std.os.PROT.READ | std.os.PROT.WRITE | execute_flag);
|
||||
} = if (flags.executable) std.posix.PROT.EXEC else 0;
|
||||
const protection_flags: u32 = @intCast(std.posix.PROT.READ | std.posix.PROT.WRITE | execute_flag);
|
||||
|
||||
const result = try std.os.mmap(null, size, protection_flags, .{
|
||||
const result = try std.posix.mmap(null, size, protection_flags, .{
|
||||
.TYPE = .PRIVATE,
|
||||
.ANONYMOUS = true,
|
||||
}, -1, 0);
|
||||
@ -372,13 +372,13 @@ pub fn allocate_virtual_memory(size: usize, flags: packed struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn free_virtual_memory(slice: []align(0x1000) const u8) void {
|
||||
pub fn free_virtual_memory(slice: []align(page_size) const u8) void {
|
||||
switch (os) {
|
||||
.windows => {
|
||||
std.os.windows.VirtualFree(slice.ptr, slice.len, std.os.windows.MEM_RELEASE);
|
||||
},
|
||||
else => {
|
||||
std.os.munmap(slice);
|
||||
std.posix.munmap(slice);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -726,7 +726,7 @@ pub fn span(ptr: [*:0]const u8) [:0]const u8 {
|
||||
|
||||
pub fn last(bytes: []const u8, byte: u8) ?usize {
|
||||
var i = bytes.len;
|
||||
while (i > 0) {
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
|
||||
if (bytes[i] == byte) {
|
||||
@ -736,3 +736,8 @@ pub fn last(bytes: []const u8, byte: u8) ?usize {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn align_forward(value: u64, alignment: u64) u64 {
|
||||
const mask = alignment - 1;
|
||||
return (value + mask) & ~mask;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ pub fn entry_point(arguments: [][*:0]u8) !void {
|
||||
return error.InvalidInput;
|
||||
}
|
||||
|
||||
if (std.process.can_execv and std.os.getenvZ(env_detecting_libc_paths) != null) {
|
||||
if (std.process.can_execv and std.posix.getenvZ(env_detecting_libc_paths) != null) {
|
||||
todo();
|
||||
}
|
||||
|
||||
|
558
build.zig
558
build.zig
@ -1,14 +1,32 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
const arch = builtin.cpu.arch;
|
||||
const os = builtin.os.tag;
|
||||
|
||||
fn discover_brew_prefix(b: *std.Build, library_name: []const u8) ![]const u8 {
|
||||
assert(os == .macos);
|
||||
const result = try std.ChildProcess.run(.{
|
||||
.allocator = b.allocator,
|
||||
.argv = &.{ "brew", "--prefix", library_name },
|
||||
});
|
||||
|
||||
var i = result.stdout.len - 1;
|
||||
while (result.stdout[i] == '\n' or result.stdout[i] == ' ') {
|
||||
i -= 1;
|
||||
}
|
||||
const trimmed_path = result.stdout[0 .. i + 1];
|
||||
return trimmed_path;
|
||||
}
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false;
|
||||
const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false;
|
||||
const is_ci = self_hosted_ci or third_party_ci;
|
||||
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or @import("builtin").os.tag == .macos;
|
||||
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or os == .macos;
|
||||
const native_target = b.resolveTargetQuery(.{});
|
||||
const optimization = b.standardOptimizeOption(.{});
|
||||
const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse false;
|
||||
const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse true;
|
||||
const compiler_options = b.addOptions();
|
||||
compiler_options.addOption(bool, "print_stack_trace", print_stack_trace);
|
||||
|
||||
@ -21,7 +39,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
|
||||
var target_query = b.standardTargetOptionsQueryOnly(.{});
|
||||
const abi = b.option(std.Target.Abi, "abi", "This option modifies the ABI used for the compiler") orelse if (static) switch (native_target.result.os.tag) {
|
||||
const abi = b.option(std.Target.Abi, "abi", "This option modifies the ABI used for the compiler") orelse if (static) switch (os) {
|
||||
else => target_query.abi,
|
||||
.linux => b: {
|
||||
const os_release = try std.fs.cwd().readFileAlloc(b.allocator, "/etc/os-release", 0xffff);
|
||||
@ -86,8 +104,249 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
compiler.linkLibC();
|
||||
|
||||
const zstd = if (target.result.os.tag == .windows) "zstd.lib" else "libzstd.a";
|
||||
|
||||
const static_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",
|
||||
//LLD
|
||||
"liblldCOFF.a",
|
||||
"liblldCommon.a",
|
||||
"liblldELF.a",
|
||||
"liblldMachO.a",
|
||||
"liblldMinGW.a",
|
||||
"liblldWasm.a",
|
||||
// Zlib
|
||||
"libz.a",
|
||||
// Zstd
|
||||
zstd,
|
||||
// Clang
|
||||
"libclangAnalysis.a",
|
||||
"libclangAnalysisFlowSensitive.a",
|
||||
"libclangAnalysisFlowSensitiveModels.a",
|
||||
"libclangAPINotes.a",
|
||||
"libclangARCMigrate.a",
|
||||
"libclangAST.a",
|
||||
"libclangASTMatchers.a",
|
||||
"libclangBasic.a",
|
||||
"libclangCodeGen.a",
|
||||
"libclangCrossTU.a",
|
||||
"libclangDependencyScanning.a",
|
||||
"libclangDirectoryWatcher.a",
|
||||
"libclangDriver.a",
|
||||
"libclangDynamicASTMatchers.a",
|
||||
"libclangEdit.a",
|
||||
"libclangExtractAPI.a",
|
||||
"libclangFormat.a",
|
||||
"libclangFrontend.a",
|
||||
"libclangFrontendTool.a",
|
||||
"libclangHandleCXX.a",
|
||||
"libclangHandleLLVM.a",
|
||||
"libclangIndex.a",
|
||||
"libclangIndexSerialization.a",
|
||||
"libclangInterpreter.a",
|
||||
"libclangLex.a",
|
||||
"libclangParse.a",
|
||||
"libclangRewrite.a",
|
||||
"libclangRewriteFrontend.a",
|
||||
"libclangSema.a",
|
||||
"libclangSerialization.a",
|
||||
"libclangStaticAnalyzerCheckers.a",
|
||||
"libclangStaticAnalyzerCore.a",
|
||||
"libclangStaticAnalyzerFrontend.a",
|
||||
"libclangSupport.a",
|
||||
"libclangTooling.a",
|
||||
"libclangToolingASTDiff.a",
|
||||
"libclangToolingCore.a",
|
||||
"libclangToolingInclusions.a",
|
||||
"libclangToolingInclusionsStdlib.a",
|
||||
"libclangToolingRefactoring.a",
|
||||
"libclangToolingSyntax.a",
|
||||
"libclangTransformer.a",
|
||||
};
|
||||
|
||||
if (static) {
|
||||
compiler.linkage = .static;
|
||||
if (os == .linux) compiler.linkage = .static;
|
||||
compiler.linkLibCpp();
|
||||
|
||||
const prefix = "nat/cache";
|
||||
@ -137,257 +396,11 @@ pub fn build(b: *std.Build) !void {
|
||||
compiler.addIncludePath(std.Build.LazyPath.relative(llvm_include_dir));
|
||||
const llvm_lib_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_path, "/lib" });
|
||||
|
||||
const zstd = if (target.result.os.tag == .windows) "zstd.lib" else "libzstd.a";
|
||||
|
||||
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",
|
||||
//LLD
|
||||
"liblldCOFF.a",
|
||||
"liblldCommon.a",
|
||||
"liblldELF.a",
|
||||
"liblldMachO.a",
|
||||
"liblldMinGW.a",
|
||||
"liblldWasm.a",
|
||||
// Zlib
|
||||
"libz.a",
|
||||
// Zstd
|
||||
zstd,
|
||||
// Clang
|
||||
"libclangAnalysis.a",
|
||||
"libclangAnalysisFlowSensitive.a",
|
||||
"libclangAnalysisFlowSensitiveModels.a",
|
||||
"libclangAPINotes.a",
|
||||
"libclangARCMigrate.a",
|
||||
"libclangAST.a",
|
||||
"libclangASTMatchers.a",
|
||||
"libclangBasic.a",
|
||||
"libclangCodeGen.a",
|
||||
"libclangCrossTU.a",
|
||||
"libclangDependencyScanning.a",
|
||||
"libclangDirectoryWatcher.a",
|
||||
"libclangDriver.a",
|
||||
"libclangDynamicASTMatchers.a",
|
||||
"libclangEdit.a",
|
||||
"libclangExtractAPI.a",
|
||||
"libclangFormat.a",
|
||||
"libclangFrontend.a",
|
||||
"libclangFrontendTool.a",
|
||||
"libclangHandleCXX.a",
|
||||
"libclangHandleLLVM.a",
|
||||
"libclangIndex.a",
|
||||
"libclangIndexSerialization.a",
|
||||
"libclangInterpreter.a",
|
||||
"libclangLex.a",
|
||||
"libclangParse.a",
|
||||
"libclangRewrite.a",
|
||||
"libclangRewriteFrontend.a",
|
||||
"libclangSema.a",
|
||||
"libclangSerialization.a",
|
||||
"libclangStaticAnalyzerCheckers.a",
|
||||
"libclangStaticAnalyzerCore.a",
|
||||
"libclangStaticAnalyzerFrontend.a",
|
||||
"libclangSupport.a",
|
||||
"libclangTooling.a",
|
||||
"libclangToolingASTDiff.a",
|
||||
"libclangToolingCore.a",
|
||||
"libclangToolingInclusions.a",
|
||||
"libclangToolingInclusionsStdlib.a",
|
||||
"libclangToolingRefactoring.a",
|
||||
"libclangToolingSyntax.a",
|
||||
"libclangTransformer.a",
|
||||
};
|
||||
|
||||
for (llvm_libraries) |llvm_library| {
|
||||
for (static_llvm_libraries) |llvm_library| {
|
||||
compiler.addObjectFile(std.Build.LazyPath.relative(try std.mem.concat(b.allocator, u8, &.{ llvm_lib_dir, "/", llvm_library })));
|
||||
}
|
||||
} else {
|
||||
compiler.addObjectFile(.{ .cwd_relative = "/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../lib/libstdc++.so" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1/x86_64-pc-linux-gnu" });
|
||||
compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib" });
|
||||
compiler.linkSystemLibrary("LLVM");
|
||||
compiler.linkSystemLibrary("LLVM-17");
|
||||
compiler.linkSystemLibrary("clang-cpp");
|
||||
compiler.linkSystemLibrary("lldCommon");
|
||||
compiler.linkSystemLibrary("lldCOFF");
|
||||
@ -395,6 +408,45 @@ pub fn build(b: *std.Build) !void {
|
||||
compiler.linkSystemLibrary("lldMachO");
|
||||
compiler.linkSystemLibrary("lldWasm");
|
||||
compiler.linkSystemLibrary("unwind");
|
||||
compiler.linkSystemLibrary("zlib");
|
||||
compiler.linkSystemLibrary("zstd");
|
||||
|
||||
switch (target.result.os.tag) {
|
||||
.linux => {
|
||||
compiler.addObjectFile(.{ .cwd_relative = "/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../lib/libstdc++.so" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include/c++/13.2.1/x86_64-pc-linux-gnu" });
|
||||
compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib" });
|
||||
},
|
||||
.macos => {
|
||||
compiler.linkLibCpp();
|
||||
|
||||
if (discover_brew_prefix(b, "llvm")) |llvm_prefix| {
|
||||
const llvm_include_path = try std.mem.concat(b.allocator, u8, &.{ llvm_prefix, "/include" });
|
||||
const llvm_lib_path = try std.mem.concat(b.allocator, u8, &.{ llvm_prefix, "/lib" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = llvm_include_path });
|
||||
compiler.addLibraryPath(.{ .cwd_relative = llvm_lib_path });
|
||||
} else |err| {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (discover_brew_prefix(b, "zstd")) |zstd_prefix| {
|
||||
const zstd_lib_path = try std.mem.concat(b.allocator, u8, &.{ zstd_prefix, "/lib" });
|
||||
compiler.addLibraryPath(.{ .cwd_relative = zstd_lib_path });
|
||||
} else |err| {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (discover_brew_prefix(b, "zlib")) |zlib_prefix| {
|
||||
const zlib_lib_path = try std.mem.concat(b.allocator, u8, &.{ zlib_prefix, "/lib" });
|
||||
compiler.addLibraryPath(.{ .cwd_relative = zlib_lib_path });
|
||||
} else |err| {
|
||||
return err;
|
||||
}
|
||||
},
|
||||
else => |tag| @panic(@tagName(tag)),
|
||||
}
|
||||
}
|
||||
|
||||
const install_exe = b.addInstallArtifact(compiler, .{});
|
||||
@ -409,7 +461,7 @@ pub fn build(b: *std.Build) !void {
|
||||
const run_command = b.addSystemCommand(&.{compiler_exe_path});
|
||||
run_command.step.dependOn(b.getInstallStep());
|
||||
|
||||
const debug_command = switch (@import("builtin").os.tag) {
|
||||
const debug_command = switch (os) {
|
||||
.linux => blk: {
|
||||
const result = b.addSystemCommand(&.{"gf2"});
|
||||
result.addArgs(&.{ "-ex", "set disassembly-flavor intel" });
|
||||
|
@ -8,7 +8,7 @@ pub fn main() !void {
|
||||
var url_arg: ?[:0]const u8 = null;
|
||||
var prefix_arg: [:0]const u8 = "nat";
|
||||
|
||||
const State = enum{
|
||||
const State = enum {
|
||||
none,
|
||||
prefix,
|
||||
url,
|
||||
@ -16,7 +16,6 @@ pub fn main() !void {
|
||||
|
||||
var state = State.none;
|
||||
|
||||
|
||||
for (arguments[1..]) |argument| {
|
||||
switch (state) {
|
||||
.none => {
|
||||
@ -43,8 +42,8 @@ pub fn main() !void {
|
||||
if (state != .none) return error.InvalidInput;
|
||||
|
||||
const dot_index = std.mem.lastIndexOfScalar(u8, url, '.') orelse return error.InvalidInput;
|
||||
const extension_string = url[dot_index + 1..];
|
||||
const Extension = enum{
|
||||
const extension_string = url[dot_index + 1 ..];
|
||||
const Extension = enum {
|
||||
xz,
|
||||
gz,
|
||||
zip,
|
||||
@ -61,7 +60,7 @@ pub fn main() !void {
|
||||
};
|
||||
defer http_client.deinit();
|
||||
|
||||
var buffer: [16*1024]u8 = undefined;
|
||||
var buffer: [16 * 1024]u8 = undefined;
|
||||
var request = try http_client.open(.GET, uri, .{
|
||||
.server_header_buffer = &buffer,
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ const TestError = error{
|
||||
fail,
|
||||
};
|
||||
|
||||
fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const []const u8{
|
||||
fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const []const u8 {
|
||||
var dir = try std.fs.cwd().openDir(path, .{
|
||||
.iterate = true,
|
||||
});
|
||||
@ -48,11 +48,11 @@ fn runStandalone(allocator: Allocator, args: struct {
|
||||
|
||||
for (test_names) |test_name| {
|
||||
std.debug.print("{s}... ", .{test_name});
|
||||
const source_file_path = try std.mem.concat(allocator, u8, &.{args.directory_path, "/", test_name, "/main.nat"});
|
||||
const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" });
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{"zig-out/bin/nat", if (args.is_test) "test" else "exe", "-main_source_file", source_file_path},
|
||||
.argv = &.{ "zig-out/bin/nat", if (args.is_test) "test" else "exe", "-main_source_file", source_file_path },
|
||||
});
|
||||
ran_compilation_count += 1;
|
||||
|
||||
@ -77,11 +77,11 @@ fn runStandalone(allocator: Allocator, args: struct {
|
||||
}
|
||||
|
||||
if (compilation_success) {
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{"nat/", test_name});
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name });
|
||||
const test_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ test_path },
|
||||
.argv = &.{test_path},
|
||||
});
|
||||
ran_test_count += 1;
|
||||
const test_result: TestError!bool = switch (test_run.term) {
|
||||
@ -107,8 +107,8 @@ fn runStandalone(allocator: Allocator, args: struct {
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{args.group_name, total_compilation_count, failed_compilation_count});
|
||||
std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{args.group_name, total_test_count, ran_test_count, failed_test_count});
|
||||
std.debug.print("\n{s} COMPILATIONS: {}. FAILED: {}\n", .{ args.group_name, total_compilation_count, failed_compilation_count });
|
||||
std.debug.print("{s} TESTS: {}. RAN: {}. FAILED: {}\n", .{ args.group_name, total_test_count, ran_test_count, failed_test_count });
|
||||
|
||||
if (failed_compilation_count > 0 or failed_test_count > 0) {
|
||||
return error.fail;
|
||||
@ -129,11 +129,11 @@ fn runStandaloneTests(allocator: Allocator) !void {
|
||||
|
||||
for (standalone_test_names) |standalone_test_name| {
|
||||
std.debug.print("{s}... ", .{standalone_test_name});
|
||||
const source_file_path = try std.mem.concat(allocator, u8, &.{standalone_test_dir_path, "/", standalone_test_name, "/main.nat"});
|
||||
const source_file_path = try std.mem.concat(allocator, u8, &.{ standalone_test_dir_path, "/", standalone_test_name, "/main.nat" });
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{"zig-out/bin/nat", "exe", "-main_source_file", source_file_path},
|
||||
.argv = &.{ "zig-out/bin/nat", "exe", "-main_source_file", source_file_path },
|
||||
});
|
||||
ran_compilation_count += 1;
|
||||
|
||||
@ -158,11 +158,11 @@ fn runStandaloneTests(allocator: Allocator) !void {
|
||||
}
|
||||
|
||||
if (compilation_success) {
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{"nat/", standalone_test_name});
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", standalone_test_name });
|
||||
const test_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ test_path },
|
||||
.argv = &.{test_path},
|
||||
});
|
||||
ran_test_count += 1;
|
||||
const test_result: TestError!bool = switch (test_run.term) {
|
||||
@ -188,8 +188,8 @@ fn runStandaloneTests(allocator: Allocator) !void {
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{total_compilation_count, failed_compilation_count});
|
||||
std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{total_test_count, ran_test_count, failed_test_count});
|
||||
std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{ total_compilation_count, failed_compilation_count });
|
||||
std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{ total_test_count, ran_test_count, failed_test_count });
|
||||
|
||||
if (failed_compilation_count > 0 or failed_test_count > 0) {
|
||||
return error.fail;
|
||||
@ -203,7 +203,7 @@ fn runBuildTests(allocator: Allocator) !void {
|
||||
const test_names = try collectDirectoryDirEntries(allocator, test_dir_path);
|
||||
const test_dir_realpath = try std.fs.cwd().realpathAlloc(allocator, test_dir_path);
|
||||
const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, "zig-out/bin/nat");
|
||||
try std.os.chdir(test_dir_realpath);
|
||||
try std.posix.chdir(test_dir_realpath);
|
||||
|
||||
const total_compilation_count = test_names.len;
|
||||
var ran_compilation_count: usize = 0;
|
||||
@ -215,12 +215,12 @@ fn runBuildTests(allocator: Allocator) !void {
|
||||
|
||||
for (test_names) |test_name| {
|
||||
std.debug.print("{s}... ", .{test_name});
|
||||
try std.os.chdir(test_name);
|
||||
try std.posix.chdir(test_name);
|
||||
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{compiler_realpath, "build"},
|
||||
.argv = &.{ compiler_realpath, "build" },
|
||||
});
|
||||
|
||||
ran_compilation_count += 1;
|
||||
@ -246,11 +246,11 @@ fn runBuildTests(allocator: Allocator) !void {
|
||||
}
|
||||
|
||||
if (compilation_success) {
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{"nat/", test_name});
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name });
|
||||
const test_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ test_path },
|
||||
.argv = &.{test_path},
|
||||
});
|
||||
ran_test_count += 1;
|
||||
const test_result: TestError!bool = switch (test_run.term) {
|
||||
@ -275,13 +275,13 @@ fn runBuildTests(allocator: Allocator) !void {
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
try std.os.chdir(test_dir_realpath);
|
||||
try std.posix.chdir(test_dir_realpath);
|
||||
}
|
||||
|
||||
std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{total_compilation_count, failed_compilation_count});
|
||||
std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{total_test_count, ran_test_count, failed_test_count});
|
||||
std.debug.print("\nTOTAL COMPILATIONS: {}. FAILED: {}\n", .{ total_compilation_count, failed_compilation_count });
|
||||
std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{ total_test_count, ran_test_count, failed_test_count });
|
||||
|
||||
try std.os.chdir(previous_cwd);
|
||||
try std.posix.chdir(previous_cwd);
|
||||
|
||||
if (failed_compilation_count > 0 or failed_test_count > 0) {
|
||||
return error.fail;
|
||||
@ -289,24 +289,31 @@ fn runBuildTests(allocator: Allocator) !void {
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var errors = false;
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
const allocator = arena.allocator();
|
||||
try runStandalone(allocator, .{
|
||||
runStandalone(allocator, .{
|
||||
.directory_path = "test/standalone",
|
||||
.group_name = "STANDALONE",
|
||||
.is_test = false,
|
||||
});
|
||||
try runBuildTests(allocator);
|
||||
try runStandalone(allocator, .{
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
runBuildTests(allocator) catch {
|
||||
errors = true;
|
||||
};
|
||||
runStandalone(allocator, .{
|
||||
.directory_path = "test/tests",
|
||||
.group_name = "TEST EXECUTABLE",
|
||||
.is_test = true,
|
||||
});
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
std.debug.print("std... ", .{});
|
||||
|
||||
const result = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
.argv = &.{ "zig-out/bin/nat", "test", "-main_source_file", "lib/std/std.nat", "-name", "std" },
|
||||
});
|
||||
const compilation_result: TestError!bool = switch (result.term) {
|
||||
@ -317,6 +324,7 @@ pub fn main() !void {
|
||||
};
|
||||
|
||||
const compilation_success = compilation_result catch b: {
|
||||
errors = true;
|
||||
break :b false;
|
||||
};
|
||||
|
||||
@ -330,9 +338,9 @@ pub fn main() !void {
|
||||
|
||||
if (compilation_success) {
|
||||
const test_run = try std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ "nat/std" },
|
||||
.argv = &.{"nat/std"},
|
||||
});
|
||||
const test_result: TestError!bool = switch (test_run.term) {
|
||||
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
||||
@ -342,6 +350,7 @@ pub fn main() !void {
|
||||
};
|
||||
|
||||
const test_success = test_result catch b: {
|
||||
errors = true;
|
||||
break :b false;
|
||||
};
|
||||
std.debug.print("[TEST {s}]\n", .{if (test_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
|
||||
@ -352,4 +361,8 @@ pub fn main() !void {
|
||||
std.debug.print("STDERR:\n\n{s}\n\n", .{test_run.stderr});
|
||||
}
|
||||
}
|
||||
|
||||
if (errors) {
|
||||
return error.fail;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ const Abi = enum{
|
||||
};
|
||||
|
||||
const CallingConvention = enum{
|
||||
c,
|
||||
system_v,
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,83 @@
|
||||
const std = #import("std");
|
||||
const linux = std.os.linux;
|
||||
const macos = std.os.macos;
|
||||
const builtin = #import("builtin");
|
||||
const os = builtin.os;
|
||||
|
||||
const Error = switch (os) {
|
||||
.linux => linux.Error,
|
||||
.macos => macos.Error,
|
||||
else => #error("OS not supported"),
|
||||
};
|
||||
|
||||
const unwrap_syscall = fn(syscall_result: ssize) Error!usize {
|
||||
if (syscall_result == -1) {
|
||||
const absolute_error: u64 = #cast(-syscall_result);
|
||||
const error_int: u32 = #cast(absolute_error);
|
||||
const err: Error = #cast(error_int);
|
||||
return err;
|
||||
} else {
|
||||
const result: usize = #cast(syscall_result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const MapFlags = switch (os) {
|
||||
.macos => bitfield(u32){
|
||||
shared: bool,
|
||||
private: bool,
|
||||
reserved: u2 = 0,
|
||||
fixed: bool,
|
||||
reserved0: bool = 0,
|
||||
noreserve: bool,
|
||||
reserved1: u2 = 0,
|
||||
has_semaphore: bool,
|
||||
no_cache: bool,
|
||||
reserved2: u1 = 0,
|
||||
anonymous: bool,
|
||||
reserved3: u19 = 0,
|
||||
},
|
||||
.linux => linux.MapFlags,
|
||||
else => #error("OS not supported"),
|
||||
};
|
||||
|
||||
const FileDescriptor = s32;
|
||||
const ProcessId = s32;
|
||||
const MAP_FAILED = 0xffffffffffffffff;
|
||||
|
||||
const ProtectionFlags = bitfield(u32) {
|
||||
read: bool,
|
||||
write: bool,
|
||||
execute: bool,
|
||||
};
|
||||
|
||||
const get_protection_flags = fn(flags: std.os.ProtectionFlags) ProtectionFlags {
|
||||
return ProtectionFlags{
|
||||
.read = flags.read,
|
||||
.write = flags.write,
|
||||
.execute = flags.execute,
|
||||
};
|
||||
}
|
||||
|
||||
const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
|
||||
return MapFlags{
|
||||
.shared = false,
|
||||
.private = true,
|
||||
.fixed = false,
|
||||
.noreserve = false,
|
||||
.has_semaphore = false,
|
||||
.no_cache = false,
|
||||
.anonymous = true,
|
||||
};
|
||||
}
|
||||
|
||||
const write :: extern = fn cc(.c) (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize;
|
||||
const exit :: extern = fn cc(.c) (exit_code: s32) noreturn;
|
||||
const fork :: extern = fn cc(.c) () ProcessId;
|
||||
const mmap :: extern = fn cc(.c) (address: ?[&]const u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, file_descriptor: FileDescriptor, offset: u64) usize;
|
||||
const munmap :: extern = fn cc(.c) (address: [&]const u8, length: usize) s32;
|
||||
const execve :: extern = fn cc(.c) (path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32;
|
||||
const realpath :: extern = fn cc(.c) (path: [&:0]const u8, resolved_path: [&:0]u8) ?[&:0]u8;
|
||||
const waitpid :: extern = fn cc(.c) (pid: ProcessId, status: &s32, flags: s32) s32;
|
||||
|
||||
const _NSGetExecutablePath :: extern = fn cc(.c) (buffer: [&:0]u8, buffer_size: &u32) s32;
|
@ -15,7 +15,7 @@ const system = switch (link_libc) {
|
||||
true => c,
|
||||
false => switch (current) {
|
||||
.linux => linux,
|
||||
.macos => macos,
|
||||
.macos => c,
|
||||
.windows => windows,
|
||||
},
|
||||
};
|
||||
@ -25,7 +25,7 @@ const unwrap_syscall = system.unwrap_syscall;
|
||||
const exit = fn(exit_code: s32) noreturn {
|
||||
switch (current) {
|
||||
.linux => _ = #syscall(#cast(linux.Syscall.exit_group), #cast(exit_code)),
|
||||
.macos => macos.exit(exit_code),
|
||||
.macos => system.exit(exit_code),
|
||||
.windows => windows.ExitProcess(#cast(exit_code)),
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,15 @@ const FileDescriptor = struct{
|
||||
const read = fn(file_descriptor: FileDescriptor, bytes: []u8) ReadError!usize {
|
||||
if (bytes.len > 0) {
|
||||
switch (current) {
|
||||
.linux, .macos => {
|
||||
.linux => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const syscall_result = system.read(file_descriptor, bytes);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => unreachable,
|
||||
};
|
||||
return byte_count;
|
||||
},
|
||||
.macos => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const syscall_result = system.read(file_descriptor, bytes);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
@ -67,7 +75,7 @@ const FileDescriptor = struct{
|
||||
|
||||
const write = fn (file_descriptor: FileDescriptor, bytes: []const u8) WriteError!usize {
|
||||
switch (current) {
|
||||
.linux, .macos => {
|
||||
.linux => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const syscall_result = system.write(file_descriptor.handle, bytes[0..len]);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
@ -75,6 +83,14 @@ const FileDescriptor = struct{
|
||||
};
|
||||
return byte_count;
|
||||
},
|
||||
.macos => {
|
||||
const len: usize = #min(max_file_operation_byte_count, bytes.len);
|
||||
const syscall_result = system.write(file_descriptor.handle, bytes.ptr, bytes.len);
|
||||
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => return WriteError.write_failed,
|
||||
};
|
||||
return byte_count;
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
}
|
||||
}
|
||||
@ -122,8 +138,8 @@ const allocate_virtual_memory = fn(address: ?[&]u8, length: usize, general_prote
|
||||
.linux, .macos => {
|
||||
const syscall_result = system.mmap(address, length, protection_flags, map_flags, file_descriptor, offset);
|
||||
if (link_libc) {
|
||||
if (result != system.MAP_FAILED) {
|
||||
const result_address: [&]u8 = #cast(result);
|
||||
if (syscall_result != system.MAP_FAILED) {
|
||||
const result_address: [&]u8 = #cast(syscall_result);
|
||||
return result_address;
|
||||
} else {
|
||||
// TODO:
|
||||
@ -147,12 +163,18 @@ const FreeError = error{
|
||||
};
|
||||
const free_virtual_memory = fn(bytes: []const u8) FreeError!void {
|
||||
switch (current) {
|
||||
.linux, .macos => {
|
||||
.linux => {
|
||||
const syscall_result = system.munmap(bytes);
|
||||
_ = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
.macos => {
|
||||
const syscall_result = system.munmap(bytes.ptr, bytes.len);
|
||||
_ = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
}
|
||||
}
|
||||
@ -194,32 +216,31 @@ const current_executable_path = fn(buffer: [:0]u8) CurrentExecutablePath![]u8 {
|
||||
};
|
||||
return bytes;
|
||||
},
|
||||
//.macos => {
|
||||
// TODO:
|
||||
//var symlink_path_buffer: [max_path_byte_count:0]u8 = undefined;
|
||||
//var symlink_path_len: u32 = symlink_path_buffer.len + 1;
|
||||
//const ns_result = macos._NSGetExecutablePath(symlink_path_buffer.&, symlink_path_len.&);
|
||||
//if (ns_result == 0) {
|
||||
// const symlink_path = symlink_path_buffer[0..symlink_path_len];
|
||||
// const result = macos.realpath(symlink_path.ptr, buffer.ptr);
|
||||
// if (result != null) {
|
||||
// var i: usize = 0;
|
||||
// while (i < buffer.len) {
|
||||
// if (result[i] == 0) {
|
||||
// break;
|
||||
// }
|
||||
// i += 1;
|
||||
// }
|
||||
// assert(i < buffer.len);
|
||||
.macos => {
|
||||
var symlink_path_buffer: [max_path_byte_count:0]u8 = undefined;
|
||||
var symlink_path_len: u32 = symlink_path_buffer.len + 1;
|
||||
const ns_result = c._NSGetExecutablePath(symlink_path_buffer.&, symlink_path_len.&);
|
||||
if (ns_result == 0) {
|
||||
const symlink_path = symlink_path_buffer[0..symlink_path_len];
|
||||
if (c.realpath(symlink_path.ptr, buffer.ptr)) |result| {
|
||||
var i: usize = 0;
|
||||
while (i < buffer.len) {
|
||||
if (result[i] == 0) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
assert(i < buffer.len);
|
||||
|
||||
// return result[0..i];
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
//} else {
|
||||
// return null;
|
||||
//}
|
||||
//},
|
||||
const r: []u8 = result[0..i];
|
||||
return r;
|
||||
} else {
|
||||
return CurrentExecutablePath.failed;
|
||||
}
|
||||
} else {
|
||||
return CurrentExecutablePath.failed;
|
||||
}
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
}
|
||||
}
|
||||
@ -256,13 +277,11 @@ const ExecveError = error{
|
||||
const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) ExecveError!noreturn {
|
||||
switch (current) {
|
||||
.linux, .macos => {
|
||||
const syscall_result = linux.execve(path, argv, env);
|
||||
const signed_syscall_result: ssize = #cast(syscall_result);
|
||||
if (signed_syscall_result == -1) {
|
||||
return ExecveError.execve_failed;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const syscall_result = system.execve(path, argv, env);
|
||||
_ = unwrap_syscall(syscall_result) catch |err| switch (err) {
|
||||
else => return ExecveError.execve_failed,
|
||||
};
|
||||
unreachable;
|
||||
},
|
||||
else => #error("OS not supported"),
|
||||
}
|
||||
@ -410,7 +429,7 @@ const waitpid = fn(pid: Process.Id, flags: u32) WaitPidError!u32 {
|
||||
},
|
||||
.macos => {
|
||||
var status: s32 = undefined;
|
||||
if (macos.waitpid(pid, status.&, #cast(flags)) != -1) {
|
||||
if (system.waitpid(pid, status.&, #cast(flags)) != -1) {
|
||||
const status_u: u32 = #cast(status);
|
||||
return status_u;
|
||||
} else {
|
||||
|
@ -1,57 +1,337 @@
|
||||
const std = #import("std");
|
||||
|
||||
const FileDescriptor = s32;
|
||||
const ProcessId = s32;
|
||||
const MAP_FAILED = 0xffffffffffffffff;
|
||||
const Error = error{
|
||||
/// No error occurred.
|
||||
SUCCESS = 0,
|
||||
|
||||
const MapFlags = bitfield(u32){
|
||||
shared: bool,
|
||||
private: bool,
|
||||
reserved: u2 = 0,
|
||||
fixed: bool,
|
||||
reserved0: bool = 0,
|
||||
noreserve: bool,
|
||||
reserved1: u2 = 0,
|
||||
has_semaphore: bool,
|
||||
no_cache: bool,
|
||||
reserved2: u1 = 0,
|
||||
anonymous: bool,
|
||||
reserved3: u19 = 0,
|
||||
/// Operation not permitted
|
||||
PERM = 1,
|
||||
|
||||
/// No such file or directory
|
||||
NOENT = 2,
|
||||
|
||||
/// No such process
|
||||
SRCH = 3,
|
||||
|
||||
/// Interrupted system call
|
||||
INTR = 4,
|
||||
|
||||
/// Input/output error
|
||||
IO = 5,
|
||||
|
||||
/// Device not configured
|
||||
NXIO = 6,
|
||||
|
||||
/// Argument list too long
|
||||
TOO_BIG = 7,
|
||||
|
||||
/// Exec format error
|
||||
NOEXEC = 8,
|
||||
|
||||
/// Bad file descriptor
|
||||
BADF = 9,
|
||||
|
||||
/// No child processes
|
||||
CHILD = 10,
|
||||
|
||||
/// Resource deadlock avoided
|
||||
DEADLK = 11,
|
||||
|
||||
/// Cannot allocate memory
|
||||
NOMEM = 12,
|
||||
|
||||
/// Permission denied
|
||||
ACCES = 13,
|
||||
|
||||
/// Bad address
|
||||
FAULT = 14,
|
||||
|
||||
/// Block device required
|
||||
NOTBLK = 15,
|
||||
|
||||
/// Device / Resource busy
|
||||
BUSY = 16,
|
||||
|
||||
/// File exists
|
||||
EXIST = 17,
|
||||
|
||||
/// Cross-device link
|
||||
XDEV = 18,
|
||||
|
||||
/// Operation not supported by device
|
||||
NODEV = 19,
|
||||
|
||||
/// Not a directory
|
||||
NOTDIR = 20,
|
||||
|
||||
/// Is a directory
|
||||
ISDIR = 21,
|
||||
|
||||
/// Invalid argument
|
||||
INVAL = 22,
|
||||
|
||||
/// Too many open files in system
|
||||
NFILE = 23,
|
||||
|
||||
/// Too many open files
|
||||
MFILE = 24,
|
||||
|
||||
/// Inappropriate ioctl for device
|
||||
NOTTY = 25,
|
||||
|
||||
/// Text file busy
|
||||
TXTBSY = 26,
|
||||
|
||||
/// File too large
|
||||
FBIG = 27,
|
||||
|
||||
/// No space left on device
|
||||
NOSPC = 28,
|
||||
|
||||
/// Illegal seek
|
||||
SPIPE = 29,
|
||||
|
||||
/// Read-only file system
|
||||
ROFS = 30,
|
||||
|
||||
/// Too many links
|
||||
MLINK = 31,
|
||||
|
||||
/// Broken pipe
|
||||
PIPE = 32,
|
||||
|
||||
// math software
|
||||
|
||||
/// Numerical argument out of domain
|
||||
DOM = 33,
|
||||
|
||||
/// Result too large
|
||||
RANGE = 34,
|
||||
|
||||
// non-blocking and interrupt i/o
|
||||
|
||||
/// Resource temporarily unavailable
|
||||
/// This is the same code used for `WOULDBLOCK`.
|
||||
AGAIN = 35,
|
||||
|
||||
/// Operation now in progress
|
||||
INPROGRESS = 36,
|
||||
|
||||
/// Operation already in progress
|
||||
ALREADY = 37,
|
||||
|
||||
// ipc/network software -- argument errors
|
||||
|
||||
/// Socket operation on non-socket
|
||||
NOTSOCK = 38,
|
||||
|
||||
/// Destination address required
|
||||
DESTADDRREQ = 39,
|
||||
|
||||
/// Message too long
|
||||
MSGSIZE = 40,
|
||||
|
||||
/// Protocol wrong type for socket
|
||||
PROTOTYPE = 41,
|
||||
|
||||
/// Protocol not available
|
||||
NOPROTOOPT = 42,
|
||||
|
||||
/// Protocol not supported
|
||||
PROTONOSUPPORT = 43,
|
||||
|
||||
/// Socket type not supported
|
||||
SOCKTNOSUPPORT = 44,
|
||||
|
||||
/// Operation not supported
|
||||
/// The same code is used for `NOTSUP`.
|
||||
OPNOTSUPP = 45,
|
||||
|
||||
/// Protocol family not supported
|
||||
PFNOSUPPORT = 46,
|
||||
|
||||
/// Address family not supported by protocol family
|
||||
AFNOSUPPORT = 47,
|
||||
|
||||
/// Address already in use
|
||||
ADDRINUSE = 48,
|
||||
/// Can't assign requested address
|
||||
|
||||
// ipc/network software -- operational errors
|
||||
ADDRNOTAVAIL = 49,
|
||||
|
||||
/// Network is down
|
||||
NETDOWN = 50,
|
||||
|
||||
/// Network is unreachable
|
||||
NETUNREACH = 51,
|
||||
|
||||
/// Network dropped connection on reset
|
||||
NETRESET = 52,
|
||||
|
||||
/// Software caused connection abort
|
||||
CONNABORTED = 53,
|
||||
|
||||
/// Connection reset by peer
|
||||
CONNRESET = 54,
|
||||
|
||||
/// No buffer space available
|
||||
NOBUFS = 55,
|
||||
|
||||
/// Socket is already connected
|
||||
ISCONN = 56,
|
||||
|
||||
/// Socket is not connected
|
||||
NOTCONN = 57,
|
||||
|
||||
/// Can't send after socket shutdown
|
||||
SHUTDOWN = 58,
|
||||
|
||||
/// Too many references: can't splice
|
||||
TOOMANYREFS = 59,
|
||||
|
||||
/// Operation timed out
|
||||
TIMEDOUT = 60,
|
||||
|
||||
/// Connection refused
|
||||
CONNREFUSED = 61,
|
||||
|
||||
/// Too many levels of symbolic links
|
||||
LOOP = 62,
|
||||
|
||||
/// File name too long
|
||||
NAMETOOLONG = 63,
|
||||
|
||||
/// Host is down
|
||||
HOSTDOWN = 64,
|
||||
|
||||
/// No route to host
|
||||
HOSTUNREACH = 65,
|
||||
/// Directory not empty
|
||||
|
||||
// quotas & mush
|
||||
NOTEMPTY = 66,
|
||||
|
||||
/// Too many processes
|
||||
PROCLIM = 67,
|
||||
|
||||
/// Too many users
|
||||
USERS = 68,
|
||||
/// Disc quota exceeded
|
||||
|
||||
// Network File System
|
||||
DQUOT = 69,
|
||||
|
||||
/// Stale NFS file handle
|
||||
STALE = 70,
|
||||
|
||||
/// Too many levels of remote in path
|
||||
REMOTE = 71,
|
||||
|
||||
/// RPC struct is bad
|
||||
BADRPC = 72,
|
||||
|
||||
/// RPC version wrong
|
||||
RPCMISMATCH = 73,
|
||||
|
||||
/// RPC prog. not avail
|
||||
PROGUNAVAIL = 74,
|
||||
|
||||
/// Program version wrong
|
||||
PROGMISMATCH = 75,
|
||||
|
||||
/// Bad procedure for program
|
||||
PROCUNAVAIL = 76,
|
||||
|
||||
/// No locks available
|
||||
NOLCK = 77,
|
||||
|
||||
/// Function not implemented
|
||||
NOSYS = 78,
|
||||
|
||||
/// Inappropriate file type or format
|
||||
FTYPE = 79,
|
||||
|
||||
/// Authentication error
|
||||
AUTH = 80,
|
||||
|
||||
/// Need authenticator
|
||||
NEEDAUTH = 81,
|
||||
|
||||
// Intelligent device errors
|
||||
|
||||
/// Device power is off
|
||||
PWROFF = 82,
|
||||
|
||||
/// Device error, e.g. paper out
|
||||
DEVERR = 83,
|
||||
|
||||
/// Value too large to be stored in data type
|
||||
OVERFLOW = 84,
|
||||
|
||||
// Program loading errors
|
||||
|
||||
/// Bad executable
|
||||
BADEXEC = 85,
|
||||
|
||||
/// Bad CPU type in executable
|
||||
BADARCH = 86,
|
||||
|
||||
/// Shared library version mismatch
|
||||
SHLIBVERS = 87,
|
||||
|
||||
/// Malformed Macho file
|
||||
BADMACHO = 88,
|
||||
|
||||
/// Operation canceled
|
||||
CANCELED = 89,
|
||||
|
||||
/// Identifier removed
|
||||
IDRM = 90,
|
||||
|
||||
/// No message of desired type
|
||||
NOMSG = 91,
|
||||
|
||||
/// Illegal byte sequence
|
||||
ILSEQ = 92,
|
||||
|
||||
/// Attribute not found
|
||||
NOATTR = 93,
|
||||
|
||||
/// Bad message
|
||||
BADMSG = 94,
|
||||
|
||||
/// Reserved
|
||||
MULTIHOP = 95,
|
||||
|
||||
/// No message available on STREAM
|
||||
NODATA = 96,
|
||||
|
||||
/// Reserved
|
||||
NOLINK = 97,
|
||||
|
||||
/// No STREAM resources
|
||||
NOSR = 98,
|
||||
|
||||
/// Not a STREAM
|
||||
NOSTR = 99,
|
||||
|
||||
/// Protocol error
|
||||
PROTO = 100,
|
||||
|
||||
/// STREAM ioctl timeout
|
||||
TIME = 101,
|
||||
|
||||
/// No such policy registered
|
||||
NOPOLICY = 103,
|
||||
|
||||
/// State not recoverable
|
||||
NOTRECOVERABLE = 104,
|
||||
|
||||
/// Previous owner died
|
||||
OWNERDEAD = 105,
|
||||
|
||||
/// Interface output queue is full
|
||||
QFULL = 106,
|
||||
};
|
||||
|
||||
const ProtectionFlags = bitfield(u32) {
|
||||
read: bool,
|
||||
write: bool,
|
||||
execute: bool,
|
||||
};
|
||||
|
||||
const get_protection_flags = fn(flags: std.os.ProtectionFlags) ProtectionFlags {
|
||||
return ProtectionFlags{
|
||||
.read = flags.read,
|
||||
.write = flags.write,
|
||||
.execute = flags.execute,
|
||||
};
|
||||
}
|
||||
|
||||
const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
|
||||
return MapFlags{
|
||||
.shared = false,
|
||||
.private = true,
|
||||
.fixed = false,
|
||||
.noreserve = false,
|
||||
.has_semaphore = false,
|
||||
.no_cache = false,
|
||||
.anonymous = true,
|
||||
};
|
||||
}
|
||||
|
||||
const write :: extern = fn (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize;
|
||||
const exit :: extern = fn (exit_code: s32) noreturn;
|
||||
const fork :: extern = fn () ProcessId;
|
||||
const mmap :: extern = fn (address: ?[&]const u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, file_descriptor: FileDescriptor, offset: u64) usize;
|
||||
const munmap :: extern = fn (address: [&]const u8, length: usize) s32;
|
||||
const execve :: extern = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32;
|
||||
const realpath :: extern = fn(path: [&:0]const u8, resolved_path: [&:0]u8) [&:0]u8;
|
||||
const waitpid :: extern = fn(pid: ProcessId, status: &s32, flags: s32) s32;
|
||||
|
||||
const _NSGetExecutablePath :: extern = fn (buffer: [&:0]u8, buffer_size: &u32) s32;
|
||||
|
@ -2,13 +2,13 @@ const std = #import("std");
|
||||
const builtin = #import("builtin");
|
||||
comptime {
|
||||
if (builtin.link_libc) {
|
||||
_ = main;
|
||||
#export(main);
|
||||
} else {
|
||||
_ = _start;
|
||||
#export(_start);
|
||||
}
|
||||
}
|
||||
|
||||
const _start :: export = fn naked() noreturn {
|
||||
const _start = fn naked cc(.c) () 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 :: export = fn (argc_argv_address: usize) noreturn {
|
||||
const start = fn cc(.c) (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.@;
|
||||
@ -35,7 +35,7 @@ const start :: export = fn (argc_argv_address: usize) noreturn {
|
||||
std.os.exit(0);
|
||||
}
|
||||
|
||||
const main :: export = fn (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 {
|
||||
const main = fn cc(.c) (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 {
|
||||
const argc_u: u32 = #cast(argc);
|
||||
argument_count = argc_u;
|
||||
argument_values = argv;
|
||||
|
@ -12,6 +12,7 @@ test {
|
||||
const build = #import("build.nat");
|
||||
const builtin = #import("builtin.nat");
|
||||
const os = #import("os.nat");
|
||||
const c = #import("c.nat");
|
||||
const start = #import("start.nat");
|
||||
const testing = #import("testing.nat");
|
||||
|
||||
|
@ -288,6 +288,7 @@ extern "C" Function* NativityLLVMModuleGetFunction(Module& module, const char* n
|
||||
|
||||
extern "C" void NativityLLVMFunctionAddAttributeKey(Function& function, Attribute::AttrKind attribute)
|
||||
{
|
||||
static_assert(sizeof(Attribute) == sizeof(size_t));
|
||||
function.addFnAttr(attribute);
|
||||
}
|
||||
|
||||
@ -357,6 +358,12 @@ extern "C" void NativityLLVMFunctionGetArguments(Function& function, Argument**
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" Argument* NativityLLVMFunctionGetArgument(Function& function, unsigned index)
|
||||
{
|
||||
auto* arg = function.getArg(index);
|
||||
return arg;
|
||||
}
|
||||
|
||||
extern "C" void NativityLLVMFunctionSetSubprogram(Function& function, DISubprogram* subprogram)
|
||||
{
|
||||
function.setSubprogram(subprogram);
|
||||
@ -386,16 +393,21 @@ extern "C" ConstantInt* NativityLLVMConstantToInt(Constant* constant)
|
||||
return constant_int;
|
||||
}
|
||||
|
||||
extern "C" StoreInst* NativityLLVMBuilderCreateStore(IRBuilder<>& builder, Value* value, Value* pointer, bool is_volatile)
|
||||
extern "C" StoreInst* NativityLLVMBuilderCreateStore(IRBuilder<>& builder, Value* value, Value* pointer, bool is_volatile, uint32_t alignment)
|
||||
{
|
||||
auto* store = builder.CreateStore(value, pointer, is_volatile);
|
||||
auto align = Align{alignment};
|
||||
auto* basic_block = builder.GetInsertBlock();
|
||||
auto* store = new StoreInst(value, pointer, is_volatile, align,
|
||||
AtomicOrdering::NotAtomic, SyncScope::System, basic_block);
|
||||
return store;
|
||||
}
|
||||
|
||||
extern "C" AllocaInst* NativityLLVMBuilderCreateAlloca(IRBuilder<>& builder, Type* type, unsigned address_space, Value* array_size, const char* name_ptr, size_t name_len)
|
||||
extern "C" AllocaInst* NativityLLVMBuilderCreateAlloca(IRBuilder<>& builder, Type* type, unsigned address_space, Value* array_size, const char* name_ptr, size_t name_len, uint32_t alignment)
|
||||
{
|
||||
auto name = StringRef(name_ptr, name_len);
|
||||
auto* alloca = builder.CreateAlloca(type, address_space, array_size, name);
|
||||
auto align = Align{ alignment };
|
||||
BasicBlock* insert_block = builder.GetInsertBlock();
|
||||
AllocaInst* alloca = new AllocaInst(type, address_space, array_size, align, name, insert_block);
|
||||
return alloca;
|
||||
}
|
||||
|
||||
@ -412,10 +424,13 @@ extern "C" Value* NativityLLVMBuilderCreateICmp(IRBuilder<>& builder, CmpInst::P
|
||||
return icmp;
|
||||
}
|
||||
|
||||
extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* value, bool is_volatile, const char* name_ptr, size_t name_len)
|
||||
extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* pointer, bool is_volatile, const char* name_ptr, size_t name_len, uint32_t alignment)
|
||||
{
|
||||
auto align = Align{alignment};
|
||||
auto name = StringRef(name_ptr, name_len);
|
||||
auto* load = builder.CreateLoad(type, value, is_volatile, name);
|
||||
auto* basic_block = builder.GetInsertBlock();
|
||||
auto* load = new LoadInst(type, pointer, name, is_volatile,
|
||||
align, AtomicOrdering::NotAtomic, SyncScope::System, basic_block);
|
||||
return load;
|
||||
}
|
||||
|
||||
@ -940,15 +955,61 @@ extern "C" bool NativityLLVMModuleAddPassesToEmitFile(Module& module, TargetMach
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool NativityLLVMCompareTypes(Type* a, Type* b)
|
||||
extern "C" Attribute NativityLLVMContextGetAttributeFromEnum(LLVMContext& context, Attribute::AttrKind kind, uint64_t value)
|
||||
{
|
||||
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;
|
||||
static_assert(sizeof(Attribute) == sizeof(uintptr_t));
|
||||
auto attribute = Attribute::get(context, kind, value);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
extern "C" Attribute NativityLLVMContextGetAttributeFromType(LLVMContext& context, Attribute::AttrKind kind, Type* type)
|
||||
{
|
||||
static_assert(sizeof(Attribute) == sizeof(uintptr_t));
|
||||
auto attribute = Attribute::get(context, kind, type);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
extern "C" Attribute NativityLLVMContextGetAttributeFromString(LLVMContext& context, const char* kind_ptr, size_t kind_len, const char* value_ptr, size_t value_len)
|
||||
{
|
||||
static_assert(sizeof(Attribute) == sizeof(uintptr_t));
|
||||
auto kind = StringRef(kind_ptr, kind_len);
|
||||
auto value = StringRef(value_ptr, value_len);
|
||||
auto attribute = Attribute::get(context, kind, value);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
extern "C" AttributeSet NativityLLVMContextGetAttributeSet(LLVMContext& context, const Attribute* attribute_ptr, size_t attribute_count)
|
||||
{
|
||||
static_assert(sizeof(AttributeSet) == sizeof(uintptr_t));
|
||||
auto attributes = ArrayRef<Attribute>(attribute_ptr, attribute_count);
|
||||
auto attribute_set = AttributeSet::get(context, attributes);
|
||||
return attribute_set;
|
||||
}
|
||||
|
||||
extern "C" void NativityLLVMFunctionSetAttributes(Function& function, LLVMContext& context, AttributeSet function_attributes, AttributeSet return_attributes, const AttributeSet* parameter_attribute_set_ptr, size_t parameter_attribute_set_count)
|
||||
{
|
||||
auto parameter_attribute_sets = ArrayRef<AttributeSet>(parameter_attribute_set_ptr, parameter_attribute_set_count);
|
||||
auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, parameter_attribute_sets);
|
||||
function.setAttributes(attribute_list);
|
||||
}
|
||||
|
||||
extern "C" void NativityLLVMCallSetAttributes(CallInst& call, LLVMContext& context, AttributeSet function_attributes, AttributeSet return_attributes, const AttributeSet* parameter_attribute_set_ptr, size_t parameter_attribute_set_count)
|
||||
{
|
||||
auto parameter_attribute_sets = ArrayRef<AttributeSet>(parameter_attribute_set_ptr, parameter_attribute_set_count);
|
||||
auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, parameter_attribute_sets);
|
||||
call.setAttributes(attribute_list);
|
||||
}
|
||||
|
||||
extern "C" CallInst* NativityLLVMBuilderCreateMemcpy(IRBuilder<>& builder, Value* destination, uint32_t destination_alignment, Value* source, uint32_t source_alignment, uint64_t size, bool is_volatile)
|
||||
{
|
||||
auto dst_alignment = MaybeAlign(destination_alignment);
|
||||
auto src_alignment = MaybeAlign(source_alignment);
|
||||
auto memcpy = builder.CreateMemCpy(destination, dst_alignment, source, src_alignment, size, is_volatile);
|
||||
|
||||
return memcpy;
|
||||
}
|
||||
|
||||
extern "C" void NativityLLVMTypeAssertEqual(Type* a, Type* b)
|
||||
{
|
||||
assert(a == b);
|
||||
}
|
||||
|
17
test/build/c-abi/.vscode/launch.json
vendored
Normal file
17
test/build/c-abi/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceFolder}/nat/c-abi",
|
||||
"args": [],
|
||||
"MIMode": "lldb",
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
@ -10,7 +10,7 @@ const main = fn() *!void {
|
||||
},
|
||||
.main_source_path = "main.nat",
|
||||
.name = "c-abi",
|
||||
.c_source_files = .{ "foo.c" }.&,
|
||||
.c_source_files = .{ "c.c" }.&,
|
||||
};
|
||||
|
||||
try executable.compile();
|
||||
|
5483
test/build/c-abi/c.c
Normal file
5483
test/build/c-abi/c.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
||||
typedef unsigned u32;
|
||||
u32 foo(u32 arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
@ -1,7 +1,490 @@
|
||||
const std = #import("std");
|
||||
const expect = std.testing.expect;
|
||||
const foo :: extern = fn(arg: u32) u32;
|
||||
const run_c_tests :: extern = fn cc(.c) () void;
|
||||
const has_i128 = false;
|
||||
|
||||
const main = fn () *!void {
|
||||
const arg = 0xabcdef;
|
||||
try expect(foo(arg) == arg);
|
||||
run_c_tests();
|
||||
|
||||
c_u8(0xff);
|
||||
c_u16(0xfffe);
|
||||
c_u32(0xfffffffd);
|
||||
c_u64(0xfffffffffffffffc);
|
||||
|
||||
if (has_i128) {
|
||||
c_struct_u128(.{ .value = 0xfffffffffffffffc, });
|
||||
}
|
||||
|
||||
c_s8(-1);
|
||||
c_s16(-2);
|
||||
c_s32(-3);
|
||||
c_s64(-4);
|
||||
|
||||
if (has_i128) {
|
||||
c_struct_i128(.{ .value = -6, });
|
||||
}
|
||||
|
||||
c_bool(true);
|
||||
|
||||
c_five_integers(12, 34, 56, 78, 90);
|
||||
|
||||
const s = c_ret_struct_u64_u64();
|
||||
try expect(s.a == 21);
|
||||
try expect(s.b == 22);
|
||||
c_struct_u64_u64_0(.{ .a = 23, .b = 24, });
|
||||
c_struct_u64_u64_1(0, .{ .a = 25, .b = 26, });
|
||||
c_struct_u64_u64_2(0, 1, .{ .a = 27, .b = 28, });
|
||||
c_struct_u64_u64_3(0, 1, 2, .{ .a = 29, .b = 30, });
|
||||
c_struct_u64_u64_4(0, 1, 2, 3, .{ .a = 31, .b = 32, });
|
||||
c_struct_u64_u64_5(0, 1, 2, 3, 4, .{ .a = 33, .b = 34, });
|
||||
c_struct_u64_u64_6(0, 1, 2, 3, 4, 5, .{ .a = 35, .b = 36, });
|
||||
c_struct_u64_u64_7(0, 1, 2, 3, 4, 5, 6, .{ .a = 37, .b = 38, });
|
||||
c_struct_u64_u64_8(0, 1, 2, 3, 4, 5, 6, 7, .{ .a = 39, .b = 40, });
|
||||
|
||||
const big_struct = BigStruct{
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
.d = 4,
|
||||
.e = 5,
|
||||
};
|
||||
c_big_struct(big_struct);
|
||||
|
||||
const small = SmallStructInts{
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
.d = 4,
|
||||
};
|
||||
c_small_struct_ints(small);
|
||||
const small2 = c_ret_small_struct_ints();
|
||||
try expect(small2.a == 1);
|
||||
try expect(small2.b == 2);
|
||||
try expect(small2.c == 3);
|
||||
try expect(small2.d == 4);
|
||||
|
||||
const med = MedStructInts{
|
||||
.x = 1,
|
||||
.y = 2,
|
||||
.z = 3,
|
||||
};
|
||||
c_med_struct_ints(med);
|
||||
const med2 = c_ret_med_struct_ints();
|
||||
try expect(med2.x == 1);
|
||||
try expect(med2.y == 2);
|
||||
try expect(med2.z == 3);
|
||||
|
||||
const p = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, };
|
||||
c_small_packed_struct(p);
|
||||
const p2 = c_ret_small_packed_struct();
|
||||
try expect(p2.a == 0);
|
||||
try expect(p2.b == 1);
|
||||
try expect(p2.c == 2);
|
||||
try expect(p2.d == 3);
|
||||
|
||||
const split = SplitStructInt{
|
||||
.a = 1234,
|
||||
.b = 100,
|
||||
.c = 1337,
|
||||
};
|
||||
c_split_struct_ints(split);
|
||||
|
||||
const big = BigStruct{
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
.d = 4,
|
||||
.e = 5,
|
||||
};
|
||||
const big2 = c_big_struct_both(big);
|
||||
try expect(big2.a == 10);
|
||||
try expect(big2.b == 11);
|
||||
try expect(big2.c == 12);
|
||||
try expect(big2.d == 13);
|
||||
try expect(big2.e == 14);
|
||||
|
||||
const r1 = Rect{
|
||||
.left = 1,
|
||||
.right = 21,
|
||||
.top = 16,
|
||||
.bottom = 4,
|
||||
};
|
||||
const r2 = Rect{
|
||||
.left = 178,
|
||||
.right = 189,
|
||||
.top = 21,
|
||||
.bottom = 15,
|
||||
};
|
||||
c_multiple_struct_ints(r1, r2);
|
||||
|
||||
try expect(c_ret_bool() == true);
|
||||
|
||||
try expect(c_ret_u8() == 0xff);
|
||||
try expect(c_ret_u16() == 0xffff);
|
||||
try expect(c_ret_u32() == 0xffffffff);
|
||||
try expect(c_ret_u64() == 0xffffffffffffffff);
|
||||
|
||||
try expect(c_ret_s8() == -1);
|
||||
try expect(c_ret_s16() == -1);
|
||||
try expect(c_ret_s32() == -1);
|
||||
try expect(c_ret_s64() == -1);
|
||||
|
||||
c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2, });
|
||||
|
||||
const x = c_ret_struct_with_array();
|
||||
try expect(x.a == 4);
|
||||
try expect(x.b == 155);
|
||||
|
||||
const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined, });
|
||||
try expect(res.val == 42);
|
||||
|
||||
var function_pointer = c_func_ptr_byval.&;
|
||||
function_pointer(1, 2, .{ .origin = .{ .x = 9, .y = 10, .z = 11, }, .size = .{ .width = 12, .height = 13, .depth = 14, }, }, 3, 4, 5);
|
||||
}
|
||||
|
||||
const ByRef = struct {
|
||||
val: s32,
|
||||
arr: [15]s32,
|
||||
};
|
||||
|
||||
const ByVal = struct {
|
||||
origin: ByValOrigin,
|
||||
size: ByValSize,
|
||||
};
|
||||
|
||||
const ByValOrigin = struct{
|
||||
x: u64,
|
||||
y: u64,
|
||||
z: u64,
|
||||
};
|
||||
|
||||
const ByValSize = struct{
|
||||
width: u64,
|
||||
height: u64,
|
||||
depth: u64,
|
||||
};
|
||||
|
||||
const c_u8 :: extern = fn cc(.c) (x: u8) void;
|
||||
const c_u16 :: extern = fn cc(.c) (x: u16) void;
|
||||
const c_u32 :: extern = fn cc(.c) (x: u32) void;
|
||||
const c_u64 :: extern = fn cc(.c) (x: u64) void;
|
||||
|
||||
const c_s8 :: extern = fn cc(.c) (x: s8) void;
|
||||
const c_s16 :: extern = fn cc(.c) (x: s16) void;
|
||||
const c_s32 :: extern = fn cc(.c) (x: s32) void;
|
||||
const c_s64 :: extern = fn cc(.c) (x: s64) void;
|
||||
|
||||
const c_bool :: extern = fn cc(.c) (x: bool) void;
|
||||
|
||||
const c_five_integers :: extern = fn cc(.c) (a: s32, b: s32, c: s32, d: s32, e: s32) void;
|
||||
|
||||
const c_ret_struct_u64_u64 :: extern = fn cc(.c) () Struct_u64_u64;
|
||||
|
||||
const c_struct_u64_u64_0 :: extern = fn cc(.c) (x: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_1 :: extern = fn cc(.c) (a: usize, b: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_2 :: extern = fn cc(.c) (a: usize, b: usize, c: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_3 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_4 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_5 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_6 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_7 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: Struct_u64_u64) void;
|
||||
const c_struct_u64_u64_8 :: extern = fn cc(.c) (a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: Struct_u64_u64) void;
|
||||
|
||||
const c_big_struct :: extern = fn cc(.c) (x: BigStruct) void;
|
||||
|
||||
const c_small_struct_ints :: extern = fn cc(.c) (x: SmallStructInts) void;
|
||||
const c_ret_small_struct_ints :: extern = fn cc(.c) () SmallStructInts;
|
||||
|
||||
const c_med_struct_ints :: extern = fn cc(.c) (x: MedStructInts) void;
|
||||
const c_ret_med_struct_ints :: extern = fn cc(.c) () MedStructInts;
|
||||
|
||||
const c_small_packed_struct :: extern = fn cc(.c) (x: SmallPackedStruct) void;
|
||||
const c_ret_small_packed_struct :: extern = fn cc(.c) () SmallPackedStruct;
|
||||
|
||||
const c_split_struct_ints :: extern = fn cc(.c) (x: SplitStructInt) void;
|
||||
|
||||
const c_big_struct_both :: extern = fn cc(.c) (x: BigStruct) BigStruct;
|
||||
|
||||
const c_multiple_struct_ints :: extern = fn cc(.c) (r1: Rect, r2: Rect) void;
|
||||
|
||||
const c_ret_bool :: extern = fn cc(.c) () bool;
|
||||
|
||||
const c_ret_u8 :: extern = fn cc(.c) () u8;
|
||||
const c_ret_u16 :: extern = fn cc(.c) () u16;
|
||||
const c_ret_u32 :: extern = fn cc(.c) () u32;
|
||||
const c_ret_u64 :: extern = fn cc(.c) () u64;
|
||||
|
||||
const c_ret_s8 :: extern = fn cc(.c) () s8;
|
||||
const c_ret_s16 :: extern = fn cc(.c) () s16;
|
||||
const c_ret_s32 :: extern = fn cc(.c) () s32;
|
||||
const c_ret_s64 :: extern = fn cc(.c) () s64;
|
||||
|
||||
const StructWithArray = struct{
|
||||
a: s32,
|
||||
padding: [4]u8,
|
||||
b: s64,
|
||||
};
|
||||
|
||||
const c_struct_with_array :: extern = fn cc(.c) (x: StructWithArray) void;
|
||||
const c_ret_struct_with_array :: extern = fn cc(.c) () StructWithArray;
|
||||
const c_modify_by_ref_param :: extern = fn cc(.c) (x: ByRef) ByRef;
|
||||
|
||||
const c_func_ptr_byval :: extern = fn cc(.c) (a: usize, b: usize, c: ByVal, d: u64, e: u64, f: u64) void;
|
||||
|
||||
const nat_u8 :: export = fn cc(.c) (x: u8) void {
|
||||
expect(x == 0xff) catch #trap();
|
||||
}
|
||||
|
||||
const nat_u16 :: export = fn cc(.c) (x: u16) void {
|
||||
expect(x == 0xfffe) catch #trap();
|
||||
}
|
||||
|
||||
const nat_u32 :: export = fn cc(.c) (x: u32) void {
|
||||
expect(x == 0xfffffffd) catch #trap();
|
||||
}
|
||||
|
||||
const nat_u64 :: export = fn cc(.c) (x: u64) void {
|
||||
expect(x == 0xfffffffffffffffc) catch #trap();
|
||||
}
|
||||
|
||||
const nat_s8 :: export = fn cc(.c) (x: s8) void {
|
||||
expect(x == -1) catch #trap();
|
||||
}
|
||||
|
||||
const nat_s16 :: export = fn cc(.c) (x: s16) void {
|
||||
expect(x == -2) catch #trap();
|
||||
}
|
||||
|
||||
const nat_s32 :: export = fn cc(.c) (x: s32) void {
|
||||
expect(x == -3) catch #trap();
|
||||
}
|
||||
|
||||
const nat_s64 :: export = fn cc(.c) (x: s64) void {
|
||||
expect(x == -4) catch #trap();
|
||||
}
|
||||
|
||||
// TODO: transform into a real pointer
|
||||
const nat_ptr :: export = fn cc(.c) (x: usize) void {
|
||||
expect(x == 0xdeadbeef) catch #trap();
|
||||
}
|
||||
|
||||
const nat_five_integers :: export = fn cc(.c) (a: s32, b: s32, c: s32, d: s32, e: s32) void {
|
||||
expect(a == 12) catch #trap();
|
||||
expect(b == 34) catch #trap();
|
||||
expect(c == 56) catch #trap();
|
||||
expect(d == 78) catch #trap();
|
||||
expect(e == 90) catch #trap();
|
||||
}
|
||||
|
||||
const nat_bool:: export = fn cc(.c) (x: bool) void {
|
||||
expect(x) catch #trap();
|
||||
}
|
||||
|
||||
const Struct_u64_u64 = struct{
|
||||
a: u64,
|
||||
b: u64,
|
||||
};
|
||||
|
||||
const nat_ret_struct_u64_u64 :: export = fn cc(.c) () Struct_u64_u64 {
|
||||
return .{ .a = 1, .b = 2, };
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_0 :: export = fn cc(.c) (s: Struct_u64_u64) void {
|
||||
expect(s.a == 3) catch #trap();
|
||||
expect(s.b == 4) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_1 :: export = fn cc(.c) (_: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 5) catch #trap();
|
||||
expect(s.b == 6) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_2 :: export = fn cc(.c) (_: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 7) catch #trap();
|
||||
expect(s.b == 8) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_3 :: export = fn cc(.c) (_: usize, _: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 9) catch #trap();
|
||||
expect(s.b == 10) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_4 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 11) catch #trap();
|
||||
expect(s.b == 12) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_5 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 13) catch #trap();
|
||||
expect(s.b == 14) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_6 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 15) catch #trap();
|
||||
expect(s.b == 16) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_7 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 17) catch #trap();
|
||||
expect(s.b == 18) catch #trap();
|
||||
}
|
||||
|
||||
const nat_struct_u64_u64_8 :: export = fn cc(.c) (_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64) void {
|
||||
expect(s.a == 19) catch #trap();
|
||||
expect(s.b == 20) catch #trap();
|
||||
}
|
||||
|
||||
const BigStruct = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
e: u8,
|
||||
};
|
||||
|
||||
const nat_big_struct:: export = fn cc(.c) (x: BigStruct) void {
|
||||
expect(x.a == 1) catch #trap();
|
||||
expect(x.b == 2) catch #trap();
|
||||
expect(x.c == 3) catch #trap();
|
||||
expect(x.d == 4) catch #trap();
|
||||
expect(x.e == 5) catch #trap();
|
||||
}
|
||||
|
||||
const SmallStructInts = struct {
|
||||
a: u8,
|
||||
b: u8,
|
||||
c: u8,
|
||||
d: u8,
|
||||
};
|
||||
|
||||
const nat_small_struct_ints :: export = fn cc(.c) (x: SmallStructInts) void {
|
||||
expect(x.a == 1) catch #trap();
|
||||
expect(x.b == 2) catch #trap();
|
||||
expect(x.c == 3) catch #trap();
|
||||
expect(x.d == 4) catch #trap();
|
||||
}
|
||||
|
||||
const MedStructInts = struct {
|
||||
x: s32,
|
||||
y: s32,
|
||||
z: s32,
|
||||
};
|
||||
|
||||
const nat_med_struct_ints :: export = fn cc(.c) (s: MedStructInts) void {
|
||||
expect(s.x == 1) catch #trap();
|
||||
expect(s.y == 2) catch #trap();
|
||||
expect(s.z == 3) catch #trap();
|
||||
}
|
||||
|
||||
const SmallPackedStruct = bitfield(u8) {
|
||||
a: u2,
|
||||
b: u2,
|
||||
c: u2,
|
||||
d: u2,
|
||||
};
|
||||
|
||||
const nat_small_packed_struct :: export = fn cc(.c) (x: SmallPackedStruct) void {
|
||||
expect(x.a == 0) catch #trap();
|
||||
expect(x.b == 1) catch #trap();
|
||||
expect(x.c == 2) catch #trap();
|
||||
expect(x.d == 3) catch #trap();
|
||||
}
|
||||
|
||||
const SplitStructInt = struct {
|
||||
a: u64,
|
||||
b: u8,
|
||||
c: u32,
|
||||
};
|
||||
|
||||
const nat_split_struct_ints :: export = fn cc(.c) (x: SplitStructInt) void {
|
||||
expect(x.a == 1234) catch #trap();
|
||||
expect(x.b == 100) catch #trap();
|
||||
expect(x.c == 1337) catch #trap();
|
||||
}
|
||||
|
||||
const nat_big_struct_both :: export = fn cc(.c) (x: BigStruct) BigStruct {
|
||||
expect(x.a == 30) catch #trap();
|
||||
expect(x.b == 31) catch #trap();
|
||||
expect(x.c == 32) catch #trap();
|
||||
expect(x.d == 33) catch #trap();
|
||||
expect(x.e == 34) catch #trap();
|
||||
const s = BigStruct{
|
||||
.a = 20,
|
||||
.b = 21,
|
||||
.c = 22,
|
||||
.d = 23,
|
||||
.e = 24,
|
||||
};
|
||||
return s;
|
||||
}
|
||||
|
||||
const Rect = struct {
|
||||
left: u32,
|
||||
right: u32,
|
||||
top: u32,
|
||||
bottom: u32,
|
||||
};
|
||||
|
||||
const nat_multiple_struct_ints :: export = fn cc(.c) (x: Rect, y: Rect) void {
|
||||
expect(x.left == 1) catch #trap();
|
||||
expect(x.right == 21) catch #trap();
|
||||
expect(x.top == 16) catch #trap();
|
||||
expect(x.bottom == 4) catch #trap();
|
||||
expect(y.left == 178) catch #trap();
|
||||
expect(y.right == 189) catch #trap();
|
||||
expect(y.top == 21) catch #trap();
|
||||
expect(y.bottom == 15) catch #trap();
|
||||
}
|
||||
|
||||
const nat_ret_bool :: export = fn cc(.c) () bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
const nat_ret_u8 :: export = fn cc(.c) () u8 {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
const nat_ret_u16 :: export = fn cc(.c) () u16 {
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
const nat_ret_u32 :: export = fn cc(.c) () u32 {
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
const nat_ret_u64 :: export = fn cc(.c) () u64 {
|
||||
return 0xffffffffffffffff;
|
||||
}
|
||||
|
||||
const nat_ret_s8 :: export = fn cc(.c) () s8 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const nat_ret_s16 :: export = fn cc(.c) () s16 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const nat_ret_s32 :: export = fn cc(.c) () s32 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const nat_ret_s64 :: export = fn cc(.c) () s64 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const nat_ret_small_struct_ints :: export = fn cc(.c) () SmallStructInts {
|
||||
return .{
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
.d = 4,
|
||||
};
|
||||
}
|
||||
|
||||
const nat_ret_med_struct_ints :: export = fn cc(.c) () MedStructInts {
|
||||
return .{
|
||||
.x = 1,
|
||||
.y = 2,
|
||||
.z = 3,
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user